1 /* Control Panel management */
12 #include "debugtools.h"
15 DEFAULT_DEBUG_CHANNEL(shlctrl);
17 typedef struct CPlApplet {
18 struct CPlApplet* next; /* linked list */
20 unsigned count; /* number of subprograms */
21 HMODULE hModule; /* module of loaded applet */
22 APPLET_PROC proc; /* entry point address */
23 NEWCPLINFOA info[1]; /* array of count information.
24 * dwSize field is 0 if entry is invalid */
27 typedef struct CPanel {
28 CPlApplet* first; /* linked list */
35 static CPlApplet* Control_UnloadApplet(CPlApplet* applet)
40 for (i = 0; i < applet->count; i++) {
41 if (!applet->info[i].dwSize) continue;
42 applet->proc(applet->hWnd, CPL_STOP, i, applet->info[i].lData);
44 if (applet->proc) applet->proc(applet->hWnd, CPL_EXIT, 0L, 0L);
45 FreeLibrary(applet->hModule);
47 HeapFree(GetProcessHeap(), 0, applet);
51 static CPlApplet* Control_LoadApplet(HWND hWnd, LPCSTR cmd, CPanel* panel)
57 if (!(applet = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*applet))))
62 if (!(applet->hModule = LoadLibraryA(cmd))) {
63 WARN("Cannot load control panel applet %s\n", cmd);
66 if (!(applet->proc = (APPLET_PROC)GetProcAddress(applet->hModule, "CPlApplet"))) {
67 WARN("Not a valid control panel applet %s\n", cmd);
70 if (!applet->proc(hWnd, CPL_INIT, 0L, 0L)) {
71 WARN("Init of applet has failed\n");
74 if ((applet->count = applet->proc(hWnd, CPL_GETCOUNT, 0L, 0L)) == 0) {
75 WARN("No subprogram in applet\n");
79 applet = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, applet,
80 sizeof(*applet) + (applet->count - 1) * sizeof(NEWCPLINFOA));
82 for (i = 0; i < applet->count; i++) {
83 applet->info[i].dwSize = sizeof(NEWCPLINFOA);
84 /* proc is supposed to return a null value upon success for
85 * CPL_INQUIRE and CPL_NEWINQUIRE
86 * However, real drivers don't seem to behave like this
87 * So, use introspection rather than return value
89 applet->proc(hWnd, CPL_NEWINQUIRE, i, (LPARAM)&applet->info[i]);
90 if (applet->info[i].hIcon == 0) {
91 applet->proc(hWnd, CPL_INQUIRE, i, (LPARAM)&info);
92 if (info.idIcon == 0 || info.idName == 0) {
93 WARN("Couldn't get info from sp %u\n", i);
94 applet->info[i].dwSize = 0;
96 /* convert the old data into the new structure */
97 applet->info[i].dwFlags = 0;
98 applet->info[i].dwHelpContext = 0;
99 applet->info[i].lData = info.lData;
100 applet->info[i].hIcon = LoadIconA(applet->hModule,
101 MAKEINTRESOURCEA(info.idIcon));
102 LoadStringA(applet->hModule, info.idName,
103 applet->info[i].szName, sizeof(applet->info[i].szName));
104 LoadStringA(applet->hModule, info.idInfo,
105 applet->info[i].szInfo, sizeof(applet->info[i].szInfo));
106 applet->info[i].szHelpFile[0] = '\0';
111 applet->next = panel->first;
112 panel->first = applet;
117 Control_UnloadApplet(applet);
121 static void Control_WndProc_Create(HWND hWnd, const CREATESTRUCTA* cs)
123 CPanel* panel = (CPanel*)cs->lpCreateParams;
125 SetWindowLongA(hWnd, 0, (LPARAM)panel);
135 static BOOL Control_Localize(const CPanel* panel, unsigned cx, unsigned cy,
136 CPlApplet** papplet, unsigned* psp)
138 unsigned i, x = (XSTEP-XICON)/2, y = 0;
142 GetClientRect(panel->hWnd, &rc);
143 for (applet = panel->first; applet; applet = applet = applet->next) {
144 for (i = 0; i < applet->count; i++) {
145 if (!applet->info[i].dwSize) continue;
146 if (x + XSTEP >= rc.right - rc.left) {
150 if (cx >= x && cx < x + XICON && cy >= y && cy < y + YSTEP) {
161 static LRESULT Control_WndProc_Paint(const CPanel* panel, WPARAM wParam)
166 unsigned i, x = 0, y = 0;
170 hdc = (wParam) ? (HDC)wParam : BeginPaint(panel->hWnd, &ps);
171 hOldFont = SelectObject(hdc, GetStockObject(ANSI_VAR_FONT));
172 GetClientRect(panel->hWnd, &rc);
173 for (applet = panel->first; applet; applet = applet = applet->next) {
174 for (i = 0; i < applet->count; i++) {
175 if (x + XSTEP >= rc.right - rc.left) {
179 if (!applet->info[i].dwSize) continue;
180 DrawIcon(hdc, x + (XSTEP-XICON)/2, y, applet->info[i].hIcon);
182 txtRect.right = x + XSTEP;
183 txtRect.top = y + YICON;
184 txtRect.bottom = y + YSTEP;
185 DrawTextA(hdc, applet->info[i].szName, -1, &txtRect,
186 DT_CENTER | DT_VCENTER);
190 SelectObject(hdc, hOldFont);
191 if (!wParam) EndPaint(panel->hWnd, &ps);
195 static LRESULT Control_WndProc_LButton(CPanel* panel, LPARAM lParam, BOOL up)
200 if (Control_Localize(panel, LOWORD(lParam), HIWORD(lParam), &applet, &i)) {
202 if (panel->clkApplet == applet && panel->clkSP == i) {
203 applet->proc(applet->hWnd, CPL_DBLCLK, i, applet->info[i].lData);
206 panel->clkApplet = applet;
213 static LRESULT WINAPI Control_WndProc(HWND hWnd, UINT wMsg,
214 WPARAM lParam1, LPARAM lParam2)
216 CPanel* panel = (CPanel*)GetWindowLongA(hWnd, 0);
218 if (panel || wMsg == WM_CREATE) {
221 Control_WndProc_Create(hWnd, (CREATESTRUCTA*)lParam2);
224 while ((panel->first = Control_UnloadApplet(panel->first)));
227 return Control_WndProc_Paint(panel, lParam1);
229 return Control_WndProc_LButton(panel, lParam2, TRUE);
231 return Control_WndProc_LButton(panel, lParam2, FALSE);
232 /* EPP case WM_COMMAND: */
233 /* EPP return Control_WndProc_Command(mwi, lParam1, lParam2); */
237 return DefWindowProcA(hWnd, wMsg, lParam1, lParam2);
240 static void Control_DoInterface(CPanel* panel, HWND hWnd, HINSTANCE hInst)
245 wc.style = CS_HREDRAW|CS_VREDRAW;
246 wc.lpfnWndProc = Control_WndProc;
248 wc.cbWndExtra = sizeof(CPlApplet*);
249 wc.hInstance = hInst;
252 wc.hbrBackground = GetStockObject(WHITE_BRUSH);
253 wc.lpszMenuName = NULL;
254 wc.lpszClassName = "Shell_Control_WndClass";
256 if (!RegisterClassA(&wc)) return;
258 CreateWindowExA(0, wc.lpszClassName, "Wine Control Panel",
259 WS_OVERLAPPEDWINDOW | WS_VISIBLE,
260 CW_USEDEFAULT, CW_USEDEFAULT,
261 CW_USEDEFAULT, CW_USEDEFAULT,
262 hWnd, (HMENU)0, hInst, panel);
263 if (!panel->hWnd) return;
264 while (GetMessageA(&msg, panel->hWnd, 0, 0)) {
265 TranslateMessage(&msg);
266 DispatchMessageA(&msg);
267 if (!panel->first) break;
271 static void Control_DoWindow(CPanel* panel, HWND hWnd, HINSTANCE hInst)
275 char buffer[MAX_PATH];
277 /* FIXME: should grab path somewhere from configuration */
278 if ((h = FindFirstFileA("c:\\windows\\system\\*.cpl", &fd)) != 0) {
280 sprintf(buffer, "c:\\windows\\system\\%s", fd.cFileName);
281 Control_LoadApplet(hWnd, buffer, panel);
282 } while (FindNextFileA(h, &fd));
286 if (panel->first) Control_DoInterface(panel, hWnd, hInst);
289 static void Control_DoLaunch(CPanel* panel, HWND hWnd, LPCSTR cmd)
303 char* extraPmts = NULL;
305 buffer = HeapAlloc(GetProcessHeap(), 0, strlen(cmd) + 1);
308 end = strcpy(buffer, cmd);
312 if (ch == ' ' || ch == ',' || ch == '\0') {
317 } else if (*beg == '\0') {
323 if (ch == '\0') break;
325 if (ch == ' ') while (end[1] == ' ') end++;
329 Control_LoadApplet(hWnd, buffer, panel);
332 CPlApplet* applet = panel->first;
334 assert(applet && applet->next == NULL);
335 if (sp >= applet->count) {
336 WARN("Out of bounds (%u >= %u), setting to 0\n", sp, applet->count);
339 if (applet->info[sp].dwSize) {
340 if (!applet->proc(applet->hWnd, CPL_STARTWPARMSA, sp, (LPARAM)extraPmts))
341 applet->proc(applet->hWnd, CPL_DBLCLK, sp, applet->info[sp].lData);
343 Control_UnloadApplet(applet);
345 HeapFree(GetProcessHeap(), 0, buffer);
348 /*************************************************************************
349 * Control_RunDLL [SHELL32.@]
352 void WINAPI Control_RunDLL(HWND hWnd, HINSTANCE hInst, LPCSTR cmd, DWORD nCmdShow)
356 TRACE("(0x%08x, 0x%08lx, %s, 0x%08lx)\n",
357 hWnd, (DWORD)hInst, debugstr_a(cmd), nCmdShow);
359 memset(&panel, 0, sizeof(panel));
362 Control_DoWindow(&panel, hWnd, hInst);
364 Control_DoLaunch(&panel, hWnd, cmd);
368 /*************************************************************************
369 * Control_FillCache_RunDLL [SHELL32.@]
372 HRESULT WINAPI Control_FillCache_RunDLL(HWND hWnd, HANDLE hModule, DWORD w, DWORD x)
374 FIXME("0x%04x 0x%04x 0x%04lx 0x%04lx stub\n",hWnd, hModule, w, x);
378 /*************************************************************************
379 * RunDLL_CallEntry16 [SHELL32.122]
380 * the name is propably wrong
382 HRESULT WINAPI RunDLL_CallEntry16(DWORD v, DWORD w, DWORD x, DWORD y, DWORD z)
384 FIXME("0x%04lx 0x%04lx 0x%04lx 0x%04lx 0x%04lx stub\n",v,w,x,y,z);