source: trunk/src/shell32/control.c@ 6666

Last change on this file since 6666 was 6650, checked in by bird, 24 years ago

Added $Id:$ keyword.

File size: 11.1 KB
Line 
1/* $Id: control.c,v 1.2 2001-09-05 13:46:56 bird Exp $ */
2/* Control Panel management */
3/* Eric Pouech 2001 */
4
5#include <assert.h>
6#include <stdio.h>
7#include <stdlib.h>
8#include <string.h>
9
10#include "winbase.h"
11#include "wingdi.h"
12#include "winuser.h"
13#include "debugtools.h"
14#include "cpl.h"
15
16DEFAULT_DEBUG_CHANNEL(shlctrl);
17
18typedef struct CPlApplet {
19 struct CPlApplet* next; /* linked list */
20 HWND hWnd;
21 unsigned count; /* number of subprograms */
22 HMODULE hModule; /* module of loaded applet */
23 APPLET_PROC proc; /* entry point address */
24 NEWCPLINFOA info[1]; /* array of count information.
25 * dwSize field is 0 if entry is invalid */
26} CPlApplet;
27
28typedef struct CPanel {
29 CPlApplet* first; /* linked list */
30 HWND hWnd;
31 unsigned status;
32 CPlApplet* clkApplet;
33 unsigned clkSP;
34} CPanel;
35
36static CPlApplet* Control_UnloadApplet(CPlApplet* applet)
37{
38 unsigned i;
39 CPlApplet* next;
40
41 for (i = 0; i < applet->count; i++) {
42 if (!applet->info[i].dwSize) continue;
43 applet->proc(applet->hWnd, CPL_STOP, i, applet->info[i].lData);
44 }
45 if (applet->proc) applet->proc(applet->hWnd, CPL_EXIT, 0L, 0L);
46 FreeLibrary(applet->hModule);
47 next = applet->next;
48 HeapFree(GetProcessHeap(), 0, applet);
49 return next;
50}
51
52static CPlApplet* Control_LoadApplet(HWND hWnd, LPCSTR cmd, CPanel* panel)
53{
54 CPlApplet* applet;
55 unsigned i;
56 CPLINFO info;
57
58 if (!(applet = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*applet))))
59 return applet;
60
61 applet->hWnd = hWnd;
62
63 if (!(applet->hModule = LoadLibraryA(cmd))) {
64 WARN("Cannot load control panel applet %s\n", cmd);
65 goto theError;
66 }
67 if (!(applet->proc = (APPLET_PROC)GetProcAddress(applet->hModule, "CPlApplet"))) {
68 WARN("Not a valid control panel applet %s\n", cmd);
69 goto theError;
70 }
71 if (!applet->proc(hWnd, CPL_INIT, 0L, 0L)) {
72 WARN("Init of applet has failed\n");
73 goto theError;
74 }
75 if ((applet->count = applet->proc(hWnd, CPL_GETCOUNT, 0L, 0L)) == 0) {
76 WARN("No subprogram in applet\n");
77 goto theError;
78 }
79
80 applet = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, applet,
81 sizeof(*applet) + (applet->count - 1) * sizeof(NEWCPLINFOA));
82
83 for (i = 0; i < applet->count; i++) {
84 applet->info[i].dwSize = sizeof(NEWCPLINFOA);
85 /* proc is supposed to return a null value upon success for
86 * CPL_INQUIRE and CPL_NEWINQUIRE
87 * However, real drivers don't seem to behave like this
88 * So, use introspection rather than return value
89 */
90 applet->proc(hWnd, CPL_NEWINQUIRE, i, (LPARAM)&applet->info[i]);
91 if (applet->info[i].hIcon == 0) {
92 applet->proc(hWnd, CPL_INQUIRE, i, (LPARAM)&info);
93 if (info.idIcon == 0 || info.idName == 0) {
94 WARN("Couldn't get info from sp %u\n", i);
95 applet->info[i].dwSize = 0;
96 } else {
97 /* convert the old data into the new structure */
98 applet->info[i].dwFlags = 0;
99 applet->info[i].dwHelpContext = 0;
100 applet->info[i].lData = info.lData;
101 applet->info[i].hIcon = LoadIconA(applet->hModule,
102 MAKEINTRESOURCEA(info.idIcon));
103 LoadStringA(applet->hModule, info.idName,
104 applet->info[i].szName, sizeof(applet->info[i].szName));
105 LoadStringA(applet->hModule, info.idInfo,
106 applet->info[i].szInfo, sizeof(applet->info[i].szInfo));
107 applet->info[i].szHelpFile[0] = '\0';
108 }
109 }
110 }
111
112 applet->next = panel->first;
113 panel->first = applet;
114
115 return applet;
116
117 theError:
118 Control_UnloadApplet(applet);
119 return NULL;
120}
121
122static void Control_WndProc_Create(HWND hWnd, const CREATESTRUCTA* cs)
123{
124 CPanel* panel = (CPanel*)cs->lpCreateParams;
125
126 SetWindowLongA(hWnd, 0, (LPARAM)panel);
127 panel->status = 0;
128 panel->hWnd = hWnd;
129}
130
131#define XICON 32
132#define XSTEP 128
133#define YICON 32
134#define YSTEP 64
135
136static BOOL Control_Localize(const CPanel* panel, unsigned cx, unsigned cy,
137 CPlApplet** papplet, unsigned* psp)
138{
139 unsigned i, x = (XSTEP-XICON)/2, y = 0;
140 CPlApplet* applet;
141 RECT rc;
142
143 GetClientRect(panel->hWnd, &rc);
144 for (applet = panel->first; applet; applet = applet = applet->next) {
145 for (i = 0; i < applet->count; i++) {
146 if (!applet->info[i].dwSize) continue;
147 if (x + XSTEP >= rc.right - rc.left) {
148 x = (XSTEP-XICON)/2;
149 y += YSTEP;
150 }
151 if (cx >= x && cx < x + XICON && cy >= y && cy < y + YSTEP) {
152 *papplet = applet;
153 *psp = i;
154 return TRUE;
155 }
156 x += XSTEP;
157 }
158 }
159 return FALSE;
160}
161
162static LRESULT Control_WndProc_Paint(const CPanel* panel, WPARAM wParam)
163{
164 HDC hdc;
165 PAINTSTRUCT ps;
166 RECT rc, txtRect;
167 unsigned i, x = 0, y = 0;
168 CPlApplet* applet;
169 HGDIOBJ hOldFont;
170
171 hdc = (wParam) ? (HDC)wParam : BeginPaint(panel->hWnd, &ps);
172 hOldFont = SelectObject(hdc, GetStockObject(ANSI_VAR_FONT));
173 GetClientRect(panel->hWnd, &rc);
174 for (applet = panel->first; applet; applet = applet = applet->next) {
175 for (i = 0; i < applet->count; i++) {
176 if (x + XSTEP >= rc.right - rc.left) {
177 x = 0;
178 y += YSTEP;
179 }
180 if (!applet->info[i].dwSize) continue;
181 DrawIcon(hdc, x + (XSTEP-XICON)/2, y, applet->info[i].hIcon);
182 txtRect.left = x;
183 txtRect.right = x + XSTEP;
184 txtRect.top = y + YICON;
185 txtRect.bottom = y + YSTEP;
186 DrawTextA(hdc, applet->info[i].szName, -1, &txtRect,
187 DT_CENTER | DT_VCENTER);
188 x += XSTEP;
189 }
190 }
191 SelectObject(hdc, hOldFont);
192 if (!wParam) EndPaint(panel->hWnd, &ps);
193 return 0;
194}
195
196static LRESULT Control_WndProc_LButton(CPanel* panel, LPARAM lParam, BOOL up)
197{
198 unsigned i;
199 CPlApplet* applet;
200
201 if (Control_Localize(panel, LOWORD(lParam), HIWORD(lParam), &applet, &i)) {
202 if (up) {
203 if (panel->clkApplet == applet && panel->clkSP == i) {
204 applet->proc(applet->hWnd, CPL_DBLCLK, i, applet->info[i].lData);
205 }
206 } else {
207 panel->clkApplet = applet;
208 panel->clkSP = i;
209 }
210 }
211 return 0;
212}
213
214static LRESULT WINAPI Control_WndProc(HWND hWnd, UINT wMsg,
215 WPARAM lParam1, LPARAM lParam2)
216{
217 CPanel* panel = (CPanel*)GetWindowLongA(hWnd, 0);
218
219 if (panel || wMsg == WM_CREATE) {
220 switch (wMsg) {
221 case WM_CREATE:
222 Control_WndProc_Create(hWnd, (CREATESTRUCTA*)lParam2);
223 return 0;
224 case WM_DESTROY:
225 while ((panel->first = Control_UnloadApplet(panel->first)));
226 break;
227 case WM_PAINT:
228 return Control_WndProc_Paint(panel, lParam1);
229 case WM_LBUTTONUP:
230 return Control_WndProc_LButton(panel, lParam2, TRUE);
231 case WM_LBUTTONDOWN:
232 return Control_WndProc_LButton(panel, lParam2, FALSE);
233/* EPP case WM_COMMAND: */
234/* EPP return Control_WndProc_Command(mwi, lParam1, lParam2); */
235 }
236 }
237
238 return DefWindowProcA(hWnd, wMsg, lParam1, lParam2);
239}
240
241static void Control_DoInterface(CPanel* panel, HWND hWnd, HINSTANCE hInst)
242{
243 WNDCLASSA wc;
244 MSG msg;
245
246 wc.style = CS_HREDRAW|CS_VREDRAW;
247 wc.lpfnWndProc = Control_WndProc;
248 wc.cbClsExtra = 0;
249 wc.cbWndExtra = sizeof(CPlApplet*);
250 wc.hInstance = hInst;
251 wc.hIcon = 0;
252 wc.hCursor = 0;
253 wc.hbrBackground = GetStockObject(WHITE_BRUSH);
254 wc.lpszMenuName = NULL;
255 wc.lpszClassName = "Shell_Control_WndClass";
256
257 if (!RegisterClassA(&wc)) return;
258
259 CreateWindowExA(0, wc.lpszClassName, "Wine Control Panel",
260 WS_OVERLAPPEDWINDOW | WS_VISIBLE,
261 CW_USEDEFAULT, CW_USEDEFAULT,
262 CW_USEDEFAULT, CW_USEDEFAULT,
263 hWnd, (HMENU)0, hInst, panel);
264 if (!panel->hWnd) return;
265 while (GetMessageA(&msg, panel->hWnd, 0, 0)) {
266 TranslateMessage(&msg);
267 DispatchMessageA(&msg);
268 if (!panel->first) break;
269 }
270}
271
272static void Control_DoWindow(CPanel* panel, HWND hWnd, HINSTANCE hInst)
273{
274 HANDLE h;
275 WIN32_FIND_DATAA fd;
276 char buffer[MAX_PATH];
277
278 /* FIXME: should grab path somewhere from configuration */
279 if ((h = FindFirstFileA("c:\\windows\\system\\*.cpl", &fd)) != 0) {
280 do {
281 sprintf(buffer, "c:\\windows\\system\\%s", fd.cFileName);
282 Control_LoadApplet(hWnd, buffer, panel);
283 } while (FindNextFileA(h, &fd));
284 FindClose(h);
285 }
286
287 if (panel->first) Control_DoInterface(panel, hWnd, hInst);
288}
289
290static void Control_DoLaunch(CPanel* panel, HWND hWnd, LPCSTR cmd)
291 /* forms to parse:
292 * foo.cpl,@sp,str
293 * foo.cpl,@sp
294 * foo.cpl,,str
295 * foo.cpl @sp
296 * foo.cpl str
297 */
298{
299 char* buffer;
300 char* beg = NULL;
301 char* end;
302 char ch;
303 unsigned sp = 0;
304 char* extraPmts = NULL;
305
306 buffer = HeapAlloc(GetProcessHeap(), 0, strlen(cmd) + 1);
307 if (!buffer) return;
308
309 end = strcpy(buffer, cmd);
310
311 for (;;) {
312 ch = *end;
313 if (ch == ' ' || ch == ',' || ch == '\0') {
314 *end = '\0';
315 if (beg) {
316 if (*beg == '@') {
317 sp = atoi(beg + 1);
318 } else if (*beg == '\0') {
319 sp = 0;
320 } else {
321 extraPmts = beg;
322 }
323 }
324 if (ch == '\0') break;
325 beg = end + 1;
326 if (ch == ' ') while (end[1] == ' ') end++;
327 }
328 end++;
329 }
330 Control_LoadApplet(hWnd, buffer, panel);
331
332 if (panel->first) {
333 CPlApplet* applet = panel->first;
334
335 assert(applet && applet->next == NULL);
336 if (sp >= applet->count) {
337 WARN("Out of bounds (%u >= %u), setting to 0\n", sp, applet->count);
338 sp = 0;
339 }
340 if (applet->info[sp].dwSize) {
341 if (!applet->proc(applet->hWnd, CPL_STARTWPARMSA, sp, (LPARAM)extraPmts))
342 applet->proc(applet->hWnd, CPL_DBLCLK, sp, applet->info[sp].lData);
343 }
344 Control_UnloadApplet(applet);
345 }
346 HeapFree(GetProcessHeap(), 0, buffer);
347}
348
349/*************************************************************************
350 * Control_RunDLL [SHELL32.12]
351 *
352 */
353void WINAPI Control_RunDLL(HWND hWnd, HINSTANCE hInst, LPCSTR cmd, DWORD nCmdShow)
354{
355 CPanel panel;
356
357 TRACE("(0x%08x, 0x%08lx, %s, 0x%08lx)\n",
358 hWnd, (DWORD)hInst, debugstr_a(cmd), nCmdShow);
359
360 memset(&panel, 0, sizeof(panel));
361
362 if (!cmd || !*cmd) {
363 Control_DoWindow(&panel, hWnd, hInst);
364 } else {
365 Control_DoLaunch(&panel, hWnd, cmd);
366 }
367}
368
369/*************************************************************************
370 * Control_FillCache_RunDLL [SHELL32.8]
371 *
372 */
373HRESULT WINAPI Control_FillCache_RunDLL(HWND hWnd, HANDLE hModule, DWORD w, DWORD x)
374{
375 FIXME("0x%04x 0x%04x 0x%04lx 0x%04lx stub\n",hWnd, hModule, w, x);
376 return 0;
377}
378
379/*************************************************************************
380 * RunDLL_CallEntry16 [SHELL32.122]
381 * the name is propably wrong
382 */
383HRESULT WINAPI RunDLL_CallEntry16(DWORD v, DWORD w, DWORD x, DWORD y, DWORD z)
384{
385 FIXME("0x%04lx 0x%04lx 0x%04lx 0x%04lx 0x%04lx stub\n",v,w,x,y,z);
386 return 0;
387}
Note: See TracBrowser for help on using the repository browser.