2 * ReactOS shell32 - Control Panel
6 * Copyright (C) 2002 Robert Dickenson <robd@reactos.org>
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 #define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
33 //#include <process.h>
42 //#define _USE_WINE_WND_
44 //WINE_DEFAULT_DEBUG_CHANNEL(shlctrl);
46 ////////////////////////////////////////////////////////////////////////////////
55 TCHAR szTitle[MAX_LOADSTRING];
56 TCHAR szWindowClass[MAX_LOADSTRING];
59 ////////////////////////////////////////////////////////////////////////////////
61 BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
64 WNDCLASSEX wcFrame = {
66 CS_HREDRAW | CS_VREDRAW/*style*/,
71 LoadIcon(hInstance, (LPCTSTR)MAKEINTRESOURCE(IDI_CONTROL)),
72 LoadCursor(0, IDC_ARROW),
76 (HICON)LoadImage(hInstance, (LPCTSTR)MAKEINTRESOURCE(IDI_CONTROL), IMAGE_ICON,
77 GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), LR_SHARED)
79 ATOM hFrameWndClass = RegisterClassEx(&wcFrame); // register frame window class
81 hMenuFrame = LoadMenu(hInstance, (LPCTSTR)MAKEINTRESOURCE(IDR_CONTROL_MENU));
83 // Initialize the Windows Common Controls DLL
86 if (LoadSettings(&rect)) {
87 hFrameWnd = CreateWindowEx(0, (LPCTSTR)(int)hFrameWndClass, szTitle,
88 WS_OVERLAPPEDWINDOW | WS_EX_CLIENTEDGE,
89 rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top,
90 NULL, hMenuFrame, hInstance, NULL/*lpParam*/);
92 hFrameWnd = CreateWindowEx(0, (LPCTSTR)(int)hFrameWndClass, szTitle,
93 WS_OVERLAPPEDWINDOW | WS_EX_CLIENTEDGE,
94 CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
95 NULL, hMenuFrame, hInstance, NULL/*lpParam*/);
103 // Create the status bar
104 hStatusBar = CreateStatusWindow(WS_VISIBLE|WS_CHILD|WS_CLIPSIBLINGS|SBT_NOBORDERS,
105 _T(""), hFrameWnd, STATUS_WINDOW);
107 // Create the status bar panes
108 SetupStatusBar(hFrameWnd, FALSE);
109 CheckMenuItem(GetSubMenu(hMenuFrame, ID_VIEW_MENU), ID_VIEW_STATUSBAR, MF_BYCOMMAND|MF_CHECKED);
111 ShowWindow(hFrameWnd, nCmdShow);
112 UpdateWindow(hFrameWnd);
116 ////////////////////////////////////////////////////////////////////////////////
118 void ExitInstance(void)
120 DestroyMenu(hMenuFrame);
124 int APIENTRY ControlMain(HINSTANCE hInstance,
125 HINSTANCE hPrevInstance,
132 // Initialize global strings
133 LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
134 LoadString(hInstance, IDC_CONTROL, szWindowClass, MAX_LOADSTRING);
136 // Store instance handle in our global variable
139 // Perform application initialization:
140 if (!InitInstance(hInstance, nCmdShow)) {
143 hAccel = LoadAccelerators(hInstance, (LPCTSTR)IDC_CONTROL);
145 // Main message loop:
146 while (GetMessage(&msg, (HWND)NULL, 0, 0)) {
147 if (!TranslateAccelerator(msg.hwnd, hAccel, &msg)) {
148 TranslateMessage(&msg);
149 DispatchMessage(&msg);
156 ////////////////////////////////////////////////////////////////////////////////
158 CPlApplet* Control_UnloadApplet(CPlApplet* applet)
163 for (i = 0; i < applet->count; i++) {
164 if (!applet->info[i].dwSize) continue;
165 applet->proc(applet->hWnd, CPL_STOP, i, applet->info[i].lData);
167 if (applet->proc) applet->proc(applet->hWnd, CPL_EXIT, 0L, 0L);
168 FreeLibrary(applet->hModule);
170 HeapFree(GetProcessHeap(), 0, applet);
174 CPlApplet* Control_LoadApplet(HWND hWnd, LPCTSTR cmd, CPlApplet** pListHead)
180 if (!(applet = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*applet))))
183 if (!(applet->hModule = LoadLibrary(cmd))) {
184 TRACE(_T("Cannot load control panel applet %s\n"), cmd);
187 if (!(applet->proc = (APPLET_PROC)GetProcAddress(applet->hModule, "CPlApplet"))) {
188 // if (!(applet->proc = (APPLET_PROC)GetProcAddress(applet->hModule, "_CPlApplet@16"))) {
189 TRACE(_T("Not a valid control panel applet %s\n"), cmd);
192 if (!applet->proc(hWnd, CPL_INIT, 0L, 0L)) {
193 TRACE(_T("Init of applet has failed\n"));
196 if ((applet->count = applet->proc(hWnd, CPL_GETCOUNT, 0L, 0L)) == 0) {
197 TRACE(_T("No subprogram in applet\n"));
200 applet = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, applet,
201 // sizeof(*applet) + (applet->count - 1) * sizeof(NEWCPLINFOA));
202 sizeof(*applet) + (applet->count - 0) * sizeof(NEWCPLINFO));
203 for (i = 0; i < applet->count; i++) {
204 // applet->info[i].dwSize = sizeof(NEWCPLINFOA);
205 applet->info[i].dwSize = sizeof(NEWCPLINFO);
206 /* proc is supposed to return a null value upon success for
207 * CPL_INQUIRE and CPL_NEWINQUIRE
208 * However, real drivers don't seem to behave like this
209 * So, use introspection rather than return value
211 applet->info[i].hIcon = 0;
212 applet->proc(hWnd, CPL_NEWINQUIRE, i, (LPARAM)&applet->info[i]);
213 if (applet->info[i].hIcon == 0) {
214 applet->proc(hWnd, CPL_INQUIRE, i, (LPARAM)&info);
215 if (info.idIcon == 0 || info.idName == 0) {
216 TRACE(_T("Couldn't get info from sp %u\n"), i);
217 applet->info[i].dwSize = 0;
219 /* convert the old data into the new structure */
220 applet->info[i].dwFlags = 0;
221 applet->info[i].dwHelpContext = 0;
222 applet->info[i].lData = info.lData;
223 // applet->info[i].hIcon = LoadIcon(applet->hModule, (LPCTSTR)MAKEINTRESOURCEA(info.idIcon));
224 // applet->info[i].hIcon = LoadIcon(applet->hModule, (LPCTSTR)MAKEINTRESOURCE(info.idIcon));
225 applet->info[i].hIcon = LoadImage(applet->hModule, (LPCTSTR)info.idIcon, IMAGE_ICON, 0, 0, LR_DEFAULTSIZE);
227 LoadString(applet->hModule, info.idName, applet->info[i].szName, sizeof(applet->info[i].szName)/sizeof(TCHAR));
228 //LoadString(applet->hModule, info.idInfo, applet->info[i].szInfo, sizeof(applet->info[i].szInfo)/sizeof(TCHAR));
229 //applet->info[i].szHelpFile[0] = '\0';
230 LoadString(applet->hModule, info.idInfo, applet->info[i].szInfo, 192);
233 TRACE(_T("Using CPL_NEWINQUIRE data\n"));
236 applet->next = *pListHead;
240 Control_UnloadApplet(applet);
244 void Control_DoLaunch(CPlApplet** pListHead, HWND hWnd, LPCTSTR cmd)
258 TCHAR* extraPmts = NULL;
260 buffer = HeapAlloc(GetProcessHeap(), 0, _tcslen(cmd) + 1);
263 end = _tcscpy(buffer, cmd);
267 if (ch == _T(' ') || ch == _T(',') || ch == _T('\0')) {
270 if (*beg == _T('@')) {
272 } else if (*beg == _T('\0')) {
278 if (ch == _T('\0')) break;
280 if (ch == _T(' ')) while (end[1] == _T(' ')) end++;
285 Control_LoadApplet(hWnd, buffer, pListHead);
287 CPlApplet* applet = *pListHead;
288 assert(applet && applet->next == NULL);
289 if (sp >= applet->count) {
290 TRACE(_T("Out of bounds (%u >= %u), setting to 0\n"), sp, applet->count);
293 if (applet->info[sp].dwSize) {
294 if (!applet->proc(applet->hWnd, CPL_STARTWPARMS, sp, (LPARAM)extraPmts))
295 applet->proc(applet->hWnd, CPL_DBLCLK, sp, applet->info[sp].lData);
297 Control_UnloadApplet(applet);
301 //static void Control_LaunchApplet(HWND hWnd, CPlEntry* pCPlEntry)
304 HeapFree(GetProcessHeap(), 0, buffer);
307 //int APIENTRY ControlMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPCTSTR lpCmdLine, int nCmdShow);
309 VOID Control_RunDLL(HWND hWnd, HINSTANCE hInst_unused, LPCTSTR lpCmdLine, DWORD nCmdShow)
312 // TRACE("(0x%08x, 0x%08lx, %s, 0x%08lx)\n", hWnd, (DWORD)hInst, debugstr_a(lpCmdLine), nCmdShow);
314 memset(&panel, 0, sizeof(panel));
316 if (!lpCmdLine || !*lpCmdLine) {
317 #ifdef _USE_WINE_WND_
318 Control_DoWindow(&panel, hWnd, hInst);
320 ControlMain(hInst, NULL, lpCmdLine, nCmdShow);
323 Control_DoLaunch(&panel.first, hWnd, lpCmdLine);
328 ////////////////////////////////////////////////////////////////////////////////
329 #ifdef _USE_WINE_WND_
331 static void Control_WndProc_Create(HWND hWnd, const CREATESTRUCTA* cs)
333 CPanel* panel = (CPanel*)cs->lpCreateParams;
335 SetWindowLong(hWnd, 0, (LPARAM)panel);
345 static BOOL Control_Localize(const CPanel* panel, unsigned cx, unsigned cy,
346 CPlApplet** papplet, unsigned* psp)
348 unsigned i, x = (XSTEP-XICON)/2, y = 0;
352 GetClientRect(panel->hWnd, &rc);
353 for (applet = panel->first; applet; applet = applet = applet->next) {
354 for (i = 0; i < applet->count; i++) {
355 if (!applet->info[i].dwSize) continue;
356 if (x + XSTEP >= rc.right - rc.left) {
360 if (cx >= x && cx < x + XICON && cy >= y && cy < y + YSTEP) {
371 static LRESULT Control_WndProc_Paint(const CPanel* panel, WPARAM wParam)
376 unsigned i, x = 0, y = 0;
380 hdc = (wParam) ? (HDC)wParam : BeginPaint(panel->hWnd, &ps);
381 hOldFont = SelectObject(hdc, GetStockObject(ANSI_VAR_FONT));
382 GetClientRect(panel->hWnd, &rc);
383 for (applet = panel->first; applet; applet = applet = applet->next) {
384 for (i = 0; i < applet->count; i++) {
385 if (x + XSTEP >= rc.right - rc.left) {
389 if (!applet->info[i].dwSize) continue;
390 DrawIcon(hdc, x + (XSTEP-XICON)/2, y, applet->info[i].hIcon);
392 txtRect.right = x + XSTEP;
393 txtRect.top = y + YICON;
394 txtRect.bottom = y + YSTEP;
395 DrawText(hdc, applet->info[i].szName, -1, &txtRect,
396 DT_CENTER | DT_VCENTER);
400 SelectObject(hdc, hOldFont);
401 if (!wParam) EndPaint(panel->hWnd, &ps);
405 static LRESULT Control_WndProc_LButton(CPanel* panel, LPARAM lParam, BOOL up)
410 if (Control_Localize(panel, LOWORD(lParam), HIWORD(lParam), &applet, &i)) {
412 if (panel->clkApplet == applet && panel->clkSP == i) {
413 applet->proc(applet->hWnd, CPL_DBLCLK, i, applet->info[i].lData);
416 panel->clkApplet = applet;
423 //static LRESULT WINAPI Control_WndProc(HWND hWnd, UINT wMsg,
424 static LRESULT __stdcall Control_WndProc(HWND hWnd, UINT wMsg,
425 WPARAM lParam1, LPARAM lParam2)
427 CPanel* panel = (CPanel*)GetWindowLongA(hWnd, 0);
429 if (panel || wMsg == WM_CREATE) {
432 Control_WndProc_Create(hWnd, (CREATESTRUCTA*)lParam2);
435 while ((panel->first = Control_UnloadApplet(panel->first)));
438 return Control_WndProc_Paint(panel, lParam1);
440 return Control_WndProc_LButton(panel, lParam2, TRUE);
442 return Control_WndProc_LButton(panel, lParam2, FALSE);
443 /* EPP case WM_COMMAND: */
444 /* EPP return Control_WndProc_Command(mwi, lParam1, lParam2); */
448 return DefWindowProcA(hWnd, wMsg, lParam1, lParam2);
451 static void Control_DoInterface(CPanel* panel, HWND hWnd, HINSTANCE hInst)
456 wc.style = CS_HREDRAW|CS_VREDRAW;
457 wc.lpfnWndProc = Control_WndProc;
459 wc.cbWndExtra = sizeof(CPlApplet*);
460 wc.hInstance = hInst;
463 wc.hbrBackground = GetStockObject(WHITE_BRUSH);
464 wc.lpszMenuName = NULL;
465 wc.lpszClassName = "Shell_Control_WndClass";
467 if (!RegisterClass(&wc)) return;
469 CreateWindowEx(0, wc.lpszClassName, "Wine Control Panel",
470 WS_OVERLAPPEDWINDOW | WS_VISIBLE,
471 CW_USEDEFAULT, CW_USEDEFAULT,
472 CW_USEDEFAULT, CW_USEDEFAULT,
473 hWnd, (HMENU)0, hInst, panel);
474 if (!panel->hWnd) return;
475 while (GetMessage(&msg, panel->hWnd, 0, 0)) {
476 TranslateMessage(&msg);
477 DispatchMessage(&msg);
478 if (!panel->first) break;
482 static void Control_DoWindow(CPanel* panel, HWND hWnd, HINSTANCE hInst)
486 TCHAR buffer[MAX_PATH];
488 /* TRACE: should grab path somewhere from configuration */
489 if ((h = FindFirstFile("c:\\winnt\\system32\\*.cpl", &fd)) != 0) {
491 sprintf(buffer, "c:\\winnt\\system32\\%s", fd.cFileName);
492 if (!strstr(fd.cFileName, "powercfg")) {
493 Control_LoadApplet(hWnd, buffer, panel);
495 } while (FindNextFile(h, &fd));
499 if (panel->first) Control_DoInterface(panel, hWnd, hInst);
502 #endif // _USE_WINE_WND_
505 /*************************************************************************
506 * Control_RunDLL [SHELL32.@]
511 Control_RunDLL(HWND hWnd, HINSTANCE hInst_unused, LPCSTR lpCmdLine, DWORD nCmdShow)
513 // TRACE("(0x%08x, 0x%08lx, %s, 0x%08lx)\n", hWnd, (DWORD)hInst, debugstr_a(lpCmdLine), nCmdShow);
516 /*************************************************************************
517 * Control_FillCache_RunDLL [SHELL32.@]
521 Control_FillCache_RunDLL(HWND hWnd, HANDLE hModule, DWORD w, DWORD x)
523 TRACE(_T("0x%04x 0x%04x 0x%04lx 0x%04lx stub\n"), hWnd, hModule, w, x);
527 /*************************************************************************
528 * RunDLL_CallEntry16 [SHELL32.122]
529 * the name is probably wrong
532 RunDLL_CallEntry16(DWORD v, DWORD w, DWORD x, DWORD y, DWORD z)
534 TRACE(_T("0x%04lx 0x%04lx 0x%04lx 0x%04lx 0x%04lx stub\n"),v,w,x,y,z);
538 /*************************************************************************
539 * CallCPLEntry16 [SHELL32.166]
541 * called by desk.cpl on "Advanced" with:
542 * hMod("DeskCp16.Dll"), pFunc("CplApplet"), 0, 1, 0xc, 0
546 CallCPLEntry16(HMODULE hMod, FARPROC pFunc, DWORD dw3, DWORD dw4, DWORD dw5, DWORD dw6)
548 TRACE(_T("(%04x, %p, %08lx, %08lx, %08lx, %08lx): stub.\n"), hMod, pFunc, dw3, dw4, dw5, dw6);