4b260421fe48f522a55b9c7400cb8bd66b9d5662
[reactos.git] / reactos / base / applications / control / control.c
1 /*
2 * ReactOS
3 * Copyright (C) 2004 ReactOS Team
4 * Copyright (C) 2004 GkWare e.K.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 */
20 /* $Id$
21 *
22 * PROJECT: ReactOS System Control Panel
23 * FILE: lib/cpl/system/control.c
24 * PURPOSE: ReactOS System Control Panel
25 * PROGRAMMER: Gero Kuehn (reactos.filter@gkware.com)
26 * UPDATE HISTORY:
27 * 06-13-2004 Created
28 */
29 #include <windows.h>
30 #include <commctrl.h>
31 #include <cpl.h>
32
33 #include <stdlib.h>
34 #include <stdio.h>
35 #include <stdarg.h>
36 #include <tchar.h>
37
38 #include "resource.h"
39
40 //#define CONTROL_DEBUG_ENABLE
41
42 #ifdef CONTROL_DEBUG_ENABLE
43 #define CTL_DEBUG(x) dbgprint x
44 #else
45 #define CTL_DEBUG(x)
46 #endif
47
48 #define MYWNDCLASS _T("CTLPANELCLASS")
49
50 typedef LONG (CALLBACK *CPLAPPLETFUNC)(HWND hwndCPL, UINT uMsg, LPARAM lParam1, LPARAM lParam2);
51
52 typedef struct CPLLISTENTRY
53 {
54 TCHAR pszPath[MAX_PATH];
55 HMODULE hDll;
56 CPLAPPLETFUNC pFunc;
57 CPLINFO CplInfo;
58 int nIndex;
59 } CPLLISTENTRY, *PCPLLISTENTRY;
60
61
62 HWND hListView;
63 HINSTANCE hInst;
64 HWND hMainWnd;
65 DEVMODE pDevMode;
66
67 VOID dbgprint(TCHAR *format,...)
68 {
69 TCHAR buf[1000];
70 va_list va;
71
72 va_start(va,format);
73 _vstprintf(buf,format,va);
74 OutputDebugString(buf);
75 va_end(va);
76 }
77
78 VOID PopulateCPLList(HWND hLisCtrl)
79 {
80 WIN32_FIND_DATA fd;
81 HANDLE hFind;
82 TCHAR pszSearchPath[MAX_PATH];
83 HIMAGELIST hImgListSmall;
84 HIMAGELIST hImgListLarge;
85 int ColorDepth;
86 HMODULE hDll;
87 CPLAPPLETFUNC pFunc;
88 TCHAR pszPath[MAX_PATH];
89
90 /* Icon drawing mode */
91 pDevMode.dmSize = sizeof(DEVMODE);
92 pDevMode.dmDriverExtra = 0;
93
94 EnumDisplaySettings(NULL,ENUM_CURRENT_SETTINGS,&pDevMode);
95 switch (pDevMode.dmBitsPerPel)
96 {
97 case 32: ColorDepth = ILC_COLOR32; break;
98 case 24: ColorDepth = ILC_COLOR24; break;
99 case 16: ColorDepth = ILC_COLOR16; break;
100 case 8: ColorDepth = ILC_COLOR8; break;
101 case 4: ColorDepth = ILC_COLOR4; break;
102 default: ColorDepth = ILC_COLOR; break;
103 }
104
105 hImgListSmall = ImageList_Create(16,16,ColorDepth | ILC_MASK,5,5);
106 hImgListLarge = ImageList_Create(32,32,ColorDepth | ILC_MASK,5,5);
107
108 GetSystemDirectory(pszSearchPath,MAX_PATH);
109 _tcscat(pszSearchPath,_T("\\*.cpl"));
110
111 hFind = FindFirstFile(pszSearchPath,&fd);
112 while (hFind != INVALID_HANDLE_VALUE)
113 {
114 PCPLLISTENTRY pEntry;
115 CTL_DEBUG((_T("Found %s\r\n"), fd.cFileName));
116
117 _tcscpy(pszPath, pszSearchPath);
118 *_tcsrchr(pszPath, '\\')=0;
119 _tcscat(pszPath, _T("\\"));
120 _tcscat(pszPath, fd.cFileName);
121
122 hDll = LoadLibrary(pszPath);
123 CTL_DEBUG((_T("Handle %08X\r\n"), hDll));
124
125 pFunc = (CPLAPPLETFUNC)GetProcAddress(hDll, "CPlApplet");
126 CTL_DEBUG((_T("CPLFunc %08X\r\n"), pFunc));
127
128 if (pFunc && pFunc(hLisCtrl, CPL_INIT, 0, 0))
129 {
130 UINT i, uPanelCount;
131
132 uPanelCount = (UINT)pFunc(hLisCtrl, CPL_GETCOUNT, 0, 0);
133 for (i = 0; i < uPanelCount; i++)
134 {
135 HICON hIcon;
136 TCHAR Name[MAX_PATH];
137 int index;
138
139 pEntry = (PCPLLISTENTRY)malloc(sizeof(CPLLISTENTRY));
140 if (pEntry == NULL)
141 return;
142
143 memset(pEntry, 0, sizeof(CPLLISTENTRY));
144 pEntry->hDll = hDll;
145 pEntry->pFunc = pFunc;
146 _tcscpy(pEntry->pszPath, pszPath);
147
148 pEntry->pFunc(hLisCtrl, CPL_INQUIRE, (LPARAM)i, (LPARAM)&pEntry->CplInfo);
149 hIcon = LoadImage(pEntry->hDll,MAKEINTRESOURCE(pEntry->CplInfo.idIcon),IMAGE_ICON,16,16,LR_DEFAULTCOLOR);
150 index = ImageList_AddIcon(hImgListSmall,hIcon);
151 DestroyIcon(hIcon);
152 hIcon = LoadImage(pEntry->hDll,MAKEINTRESOURCE(pEntry->CplInfo.idIcon),IMAGE_ICON,32,32,LR_DEFAULTCOLOR);
153 ImageList_AddIcon(hImgListLarge,hIcon);
154 DestroyIcon(hIcon);
155
156 if (LoadString(pEntry->hDll, pEntry->CplInfo.idName, Name, MAX_PATH))
157 {
158 LV_ITEM lvi;
159
160 memset(&lvi,0x00,sizeof(lvi));
161 lvi.mask = LVIF_TEXT | LVIF_PARAM | LVIF_STATE | LVIF_IMAGE;
162 lvi.pszText = Name;
163 lvi.state = 0;
164 lvi.iImage = index;
165 lvi.lParam = (LPARAM)pEntry;
166 pEntry->nIndex = ListView_InsertItem(hLisCtrl,&lvi);
167
168 if (LoadString(pEntry->hDll, pEntry->CplInfo.idInfo, Name, MAX_PATH))
169 ListView_SetItemText(hLisCtrl, pEntry->nIndex, 1, Name);
170 }
171 }
172 }
173
174 if (!FindNextFile(hFind,&fd))
175 hFind = INVALID_HANDLE_VALUE;
176 }
177
178 (void)ListView_SetImageList(hLisCtrl,hImgListSmall,LVSIL_SMALL);
179 (void)ListView_SetImageList(hLisCtrl,hImgListLarge,LVSIL_NORMAL);
180 }
181
182 LRESULT CALLBACK MyWindowProc(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam)
183 {
184 TCHAR szBuf[1024];
185
186 switch (uMsg)
187 {
188 case WM_CREATE:
189 {
190 RECT rect;
191 LV_COLUMN column;
192
193 GetClientRect(hWnd,&rect);
194 hListView = CreateWindow(WC_LISTVIEW,_T(""),LVS_REPORT | LVS_ALIGNLEFT | LVS_SORTASCENDING | LVS_AUTOARRANGE | LVS_SINGLESEL | WS_VISIBLE | WS_CHILD | WS_TABSTOP,0,0,rect.right ,rect.bottom,hWnd,NULL,hInst,0);
195 CTL_DEBUG((_T("Listview Window %08X\r\n"),hListView));
196
197 memset(&column,0x00,sizeof(column));
198 column.mask = LVCF_FMT | LVCF_WIDTH | LVCF_SUBITEM | LVCF_TEXT;
199 column.fmt = LVCFMT_LEFT;
200 column.cx = (rect.right - rect.left) / 3;
201 column.iSubItem = 0;
202 LoadString(hInst, IDS_NAME, szBuf, sizeof(szBuf) / sizeof(TCHAR));
203 column.pszText = szBuf;
204 (void)ListView_InsertColumn(hListView,0,&column);
205 column.cx = (rect.right - rect.left) - ((rect.right - rect.left) / 3) - 1;
206 column.iSubItem = 1;
207 LoadString(hInst, IDS_COMMENT, szBuf, sizeof(szBuf) / sizeof(TCHAR));
208 column.pszText = szBuf;
209 (void)ListView_InsertColumn(hListView,1,&column);
210 PopulateCPLList(hListView);
211 (void)ListView_SetColumnWidth(hListView,2,LVSCW_AUTOSIZE_USEHEADER);
212 (void)ListView_Update(hListView,0);
213
214 SetFocus(hListView);
215 }
216 break;
217
218 case WM_DESTROY:
219 PostQuitMessage(0);
220 break;
221
222 case WM_SIZE:
223 {
224 RECT rect;
225
226 GetClientRect(hWnd,&rect);
227 MoveWindow(hListView,0,0,rect.right,rect.bottom,TRUE);
228 }
229 break;
230
231 case WM_NOTIFY:
232 {
233 NMHDR *phdr;
234 phdr = (NMHDR*)lParam;
235 switch(phdr->code)
236 {
237 case NM_RETURN:
238 case NM_DBLCLK:
239 {
240 int nSelect;
241 LV_ITEM lvi;
242 PCPLLISTENTRY pEntry;
243
244 nSelect=SendMessage(hListView,LVM_GETNEXTITEM,(WPARAM)-1,LVNI_FOCUSED);
245
246 if (nSelect==-1)
247 {
248 /* no items */
249 LoadString(hInst, IDS_NO_ITEMS, szBuf, sizeof(szBuf) / sizeof(TCHAR));
250 MessageBox(hWnd,(LPCTSTR)szBuf,NULL,MB_OK|MB_ICONINFORMATION);
251 break;
252 }
253
254 CTL_DEBUG((_T("Select %d\r\n"),nSelect));
255 memset(&lvi,0x00,sizeof(lvi));
256 lvi.iItem = nSelect;
257 lvi.mask = LVIF_PARAM;
258 (void)ListView_GetItem(hListView,&lvi);
259 pEntry = (PCPLLISTENTRY)lvi.lParam;
260 CTL_DEBUG((_T("Listview DblClk Entry %08X\r\n"),pEntry));
261 if (pEntry)
262 {
263 CTL_DEBUG((_T("Listview DblClk Entry Func %08X\r\n"),pEntry->pFunc));
264 }
265
266 if (pEntry && pEntry->pFunc)
267 pEntry->pFunc(hListView,CPL_DBLCLK,pEntry->CplInfo.lData,0);
268 }
269 }
270 }
271 break;
272
273 case WM_COMMAND:
274 switch (LOWORD(wParam))
275 {
276 case IDM_LARGEICONS:
277 SetWindowLong(hListView,GWL_STYLE,LVS_ICON | LVS_ALIGNLEFT | LVS_AUTOARRANGE | LVS_SINGLESEL | WS_VISIBLE | WS_CHILD|WS_BORDER|WS_TABSTOP);
278 break;
279 case IDM_SMALLICONS:
280 SetWindowLong(hListView,GWL_STYLE,LVS_SMALLICON | LVS_ALIGNLEFT | LVS_AUTOARRANGE | LVS_SINGLESEL | WS_VISIBLE | WS_CHILD|WS_BORDER|WS_TABSTOP);
281 break;
282 case IDM_LIST:
283 SetWindowLong(hListView,GWL_STYLE,LVS_LIST | LVS_ALIGNLEFT | LVS_AUTOARRANGE | LVS_SINGLESEL | WS_VISIBLE | WS_CHILD|WS_BORDER|WS_TABSTOP);
284 break;
285 case IDM_DETAILS:
286 SetWindowLong(hListView,GWL_STYLE,LVS_REPORT | LVS_ALIGNLEFT | LVS_AUTOARRANGE | LVS_SINGLESEL | WS_VISIBLE | WS_CHILD|WS_BORDER|WS_TABSTOP);
287 break;
288 case IDM_CLOSE:
289 DestroyWindow(hWnd);
290 break;
291 case IDM_ABOUT:
292 {
293 TCHAR Title[256];
294
295 LoadString(hInst, IDS_ABOUT, szBuf, sizeof(szBuf) / sizeof(TCHAR));
296 LoadString(hInst, IDS_ABOUT_TITLE, Title, sizeof(Title) / sizeof(TCHAR));
297
298 MessageBox(hWnd,(LPCTSTR)szBuf,(LPCTSTR)Title,MB_OK | MB_ICONINFORMATION);
299 }
300 break;
301 }
302 break;
303
304 default:
305 return DefWindowProc(hWnd,uMsg,wParam,lParam);
306 }
307
308 return 0;
309 }
310
311
312 static INT
313 RunControlPanelWindow(int nCmdShow)
314 {
315 MSG msg;
316 WNDCLASS wc;
317 TCHAR szBuf[256];
318
319 memset(&wc,0x00,sizeof(wc));
320 wc.hIcon = LoadIcon(hInst,MAKEINTRESOURCE(IDI_MAINICON));
321 wc.lpszClassName = MYWNDCLASS;
322 wc.lpszMenuName = _T("MAINMENU");
323 wc.lpfnWndProc = MyWindowProc;
324 RegisterClass(&wc);
325
326 InitCommonControls();
327
328 LoadString(hInst, IDS_WINDOW_TITLE, szBuf, sizeof(szBuf) / sizeof(TCHAR));
329 hMainWnd = CreateWindowEx(WS_EX_CLIENTEDGE,
330 MYWNDCLASS,
331 (LPCTSTR)szBuf,
332 WS_OVERLAPPEDWINDOW,
333 CW_USEDEFAULT,
334 CW_USEDEFAULT,
335 CW_USEDEFAULT,
336 CW_USEDEFAULT,
337 NULL,
338 LoadMenu(hInst, MAKEINTRESOURCE(IDM_MAINMENU)),
339 hInst,
340 0);
341 if (!hMainWnd)
342 {
343 CTL_DEBUG((_T("Unable to create window\r\n")));
344 return -1;
345 }
346
347 ShowWindow(hMainWnd, nCmdShow);
348 while (GetMessage(&msg, 0, 0, 0))
349 {
350 TranslateMessage(&msg);
351 DispatchMessage(&msg);
352 }
353
354 return 0;
355 }
356
357
358 static INT
359 RunControlPanel(LPCTSTR lpName, UINT uIndex)
360 {
361 CPLINFO CplInfo;
362 HMODULE hDll;
363 CPLAPPLETFUNC pFunc;
364 UINT uPanelCount;
365
366 hDll = LoadLibrary(lpName);
367 if (hDll == 0)
368 {
369 return -1;
370 }
371 CTL_DEBUG((_T("Handle %08X\r\n"), hDll));
372
373 pFunc = (CPLAPPLETFUNC)GetProcAddress(hDll, "CPlApplet");
374 if (pFunc == NULL)
375 {
376 FreeLibrary(hDll);
377 return -1;
378 }
379 CTL_DEBUG((_T("CPLFunc %08X\r\n"), pFunc));
380
381 if (!pFunc(NULL, CPL_INIT, 0, 0))
382 {
383 FreeLibrary(hDll);
384 return -1;
385 }
386
387 uPanelCount = (UINT)pFunc(NULL, CPL_GETCOUNT, 0, 0);
388 if (uIndex >= uPanelCount)
389 {
390 FreeLibrary(hDll);
391 return -1;
392 }
393
394 pFunc(NULL, CPL_INQUIRE, (LPARAM)uIndex, (LPARAM)&CplInfo);
395
396 pFunc(NULL, CPL_DBLCLK, CplInfo.lData, 0);
397
398 FreeLibrary(hDll);
399
400 return 0;
401 }
402
403 int
404 _tmain(int argc, const TCHAR *argv[])
405 {
406 STARTUPINFO si;
407 TCHAR * szExt;
408
409 si.cb = sizeof(si);
410 GetStartupInfo(&si);
411
412 hInst = GetModuleHandle(NULL);
413
414 if (argc <= 1)
415 {
416 /* No argument on the command line */
417 return RunControlPanelWindow(si.wShowWindow);
418 }
419
420 if (_tcsicmp(argv[1], _T("desktop")) == 0)
421 {
422 return RunControlPanel(_T("desk.cpl"), 0);
423 }
424 else if (_tcsicmp(argv[1], _T("date/time")) == 0)
425 {
426 return RunControlPanel(_T("timedate.cpl"), 0);
427 }
428 else if (_tcsicmp(argv[1], _T("international")) == 0)
429 {
430 return RunControlPanel(_T("intl.cpl"), 0);
431 }
432 else if (_tcsicmp(argv[1], _T("mouse")) == 0)
433 {
434 return RunControlPanel(_T("main.cpl"), 0);
435 }
436 else if (_tcsicmp(argv[1], _T("keyboard")) == 0)
437 {
438 return RunControlPanel(_T("main.cpl"), 1);
439 }
440 else if ((szExt = _tcsstr(argv[1], _T(".cpl"))))
441 {
442 TCHAR * szSep;
443 TCHAR szCPL[MAX_PATH];
444 UINT selPage = 0;
445
446 _tcscpy(szCPL, argv[1]);
447 szSep = _tcsstr(szCPL, _T(".cpl,"));
448
449 if (szSep)
450 {
451 /* FIXME for now ignore page index */
452 szSep[4] = _T('\0');
453 }
454 return RunControlPanel(szCPL, selPage);
455 }
456
457 return 0;
458 }