1 /* Control Panel management
3 * Copyright 2001 Eric Pouech
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
28 #include "wine/debug.h"
31 WINE_DEFAULT_DEBUG_CHANNEL(shlctrl
);
33 typedef struct CPlApplet
{
34 struct CPlApplet
* next
; /* linked list */
36 unsigned count
; /* number of subprograms */
37 HMODULE hModule
; /* module of loaded applet */
38 APPLET_PROC proc
; /* entry point address */
39 NEWCPLINFOA info
[1]; /* array of count information.
40 * dwSize field is 0 if entry is invalid */
43 typedef struct CPanel
{
44 CPlApplet
* first
; /* linked list */
51 static CPlApplet
* Control_UnloadApplet(CPlApplet
* applet
)
56 for (i
= 0; i
< applet
->count
; i
++) {
57 if (!applet
->info
[i
].dwSize
) continue;
58 applet
->proc(applet
->hWnd
, CPL_STOP
, i
, applet
->info
[i
].lData
);
60 if (applet
->proc
) applet
->proc(applet
->hWnd
, CPL_EXIT
, 0L, 0L);
61 FreeLibrary(applet
->hModule
);
63 HeapFree(GetProcessHeap(), 0, applet
);
67 static CPlApplet
* Control_LoadApplet(HWND hWnd
, LPCSTR cmd
, CPanel
* panel
)
73 if (!(applet
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*applet
))))
78 if (!(applet
->hModule
= LoadLibraryA(cmd
))) {
79 WARN("Cannot load control panel applet %s\n", cmd
);
82 if (!(applet
->proc
= (APPLET_PROC
)GetProcAddress(applet
->hModule
, "CPlApplet"))) {
83 WARN("Not a valid control panel applet %s\n", cmd
);
86 if (!applet
->proc(hWnd
, CPL_INIT
, 0L, 0L)) {
87 WARN("Init of applet has failed\n");
90 if ((applet
->count
= applet
->proc(hWnd
, CPL_GETCOUNT
, 0L, 0L)) == 0) {
91 WARN("No subprogram in applet\n");
95 applet
= HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, applet
,
96 sizeof(*applet
) + (applet
->count
- 1) * sizeof(NEWCPLINFOA
));
98 for (i
= 0; i
< applet
->count
; i
++) {
99 applet
->info
[i
].dwSize
= sizeof(NEWCPLINFOA
);
100 /* proc is supposed to return a null value upon success for
101 * CPL_INQUIRE and CPL_NEWINQUIRE
102 * However, real drivers don't seem to behave like this
103 * So, use introspection rather than return value
105 applet
->proc(hWnd
, CPL_NEWINQUIRE
, i
, (LPARAM
)&applet
->info
[i
]);
106 if (applet
->info
[i
].hIcon
== 0) {
107 applet
->proc(hWnd
, CPL_INQUIRE
, i
, (LPARAM
)&info
);
108 if (info
.idIcon
== 0 || info
.idName
== 0) {
109 WARN("Couldn't get info from sp %u\n", i
);
110 applet
->info
[i
].dwSize
= 0;
112 /* convert the old data into the new structure */
113 applet
->info
[i
].dwFlags
= 0;
114 applet
->info
[i
].dwHelpContext
= 0;
115 applet
->info
[i
].lData
= info
.lData
;
116 applet
->info
[i
].hIcon
= LoadIconA(applet
->hModule
,
117 MAKEINTRESOURCEA(info
.idIcon
));
118 LoadStringA(applet
->hModule
, info
.idName
,
119 applet
->info
[i
].szName
, sizeof(applet
->info
[i
].szName
));
120 LoadStringA(applet
->hModule
, info
.idInfo
,
121 applet
->info
[i
].szInfo
, sizeof(applet
->info
[i
].szInfo
));
122 applet
->info
[i
].szHelpFile
[0] = '\0';
127 applet
->next
= panel
->first
;
128 panel
->first
= applet
;
133 Control_UnloadApplet(applet
);
137 static void Control_WndProc_Create(HWND hWnd
, const CREATESTRUCTA
* cs
)
139 CPanel
* panel
= (CPanel
*)cs
->lpCreateParams
;
141 SetWindowLongA(hWnd
, 0, (LPARAM
)panel
);
151 static BOOL
Control_Localize(const CPanel
* panel
, unsigned cx
, unsigned cy
,
152 CPlApplet
** papplet
, unsigned* psp
)
154 unsigned i
, x
= (XSTEP
-XICON
)/2, y
= 0;
158 GetClientRect(panel
->hWnd
, &rc
);
159 for (applet
= panel
->first
; applet
; applet
= applet
= applet
->next
) {
160 for (i
= 0; i
< applet
->count
; i
++) {
161 if (!applet
->info
[i
].dwSize
) continue;
162 if (x
+ XSTEP
>= rc
.right
- rc
.left
) {
166 if (cx
>= x
&& cx
< x
+ XICON
&& cy
>= y
&& cy
< y
+ YSTEP
) {
177 static LRESULT
Control_WndProc_Paint(const CPanel
* panel
, WPARAM wParam
)
182 unsigned i
, x
= 0, y
= 0;
186 hdc
= (wParam
) ? (HDC
)wParam
: BeginPaint(panel
->hWnd
, &ps
);
187 hOldFont
= SelectObject(hdc
, GetStockObject(ANSI_VAR_FONT
));
188 GetClientRect(panel
->hWnd
, &rc
);
189 for (applet
= panel
->first
; applet
; applet
= applet
= applet
->next
) {
190 for (i
= 0; i
< applet
->count
; i
++) {
191 if (x
+ XSTEP
>= rc
.right
- rc
.left
) {
195 if (!applet
->info
[i
].dwSize
) continue;
196 DrawIcon(hdc
, x
+ (XSTEP
-XICON
)/2, y
, applet
->info
[i
].hIcon
);
198 txtRect
.right
= x
+ XSTEP
;
199 txtRect
.top
= y
+ YICON
;
200 txtRect
.bottom
= y
+ YSTEP
;
201 DrawTextA(hdc
, applet
->info
[i
].szName
, -1, &txtRect
,
202 DT_CENTER
| DT_VCENTER
);
206 SelectObject(hdc
, hOldFont
);
207 if (!wParam
) EndPaint(panel
->hWnd
, &ps
);
211 static LRESULT
Control_WndProc_LButton(CPanel
* panel
, LPARAM lParam
, BOOL up
)
216 if (Control_Localize(panel
, LOWORD(lParam
), HIWORD(lParam
), &applet
, &i
)) {
218 if (panel
->clkApplet
== applet
&& panel
->clkSP
== i
) {
219 applet
->proc(applet
->hWnd
, CPL_DBLCLK
, i
, applet
->info
[i
].lData
);
222 panel
->clkApplet
= applet
;
229 static LRESULT WINAPI
Control_WndProc(HWND hWnd
, UINT wMsg
,
230 WPARAM lParam1
, LPARAM lParam2
)
232 CPanel
* panel
= (CPanel
*)GetWindowLongA(hWnd
, 0);
234 if (panel
|| wMsg
== WM_CREATE
) {
237 Control_WndProc_Create(hWnd
, (CREATESTRUCTA
*)lParam2
);
240 while ((panel
->first
= Control_UnloadApplet(panel
->first
)));
243 return Control_WndProc_Paint(panel
, lParam1
);
245 return Control_WndProc_LButton(panel
, lParam2
, TRUE
);
247 return Control_WndProc_LButton(panel
, lParam2
, FALSE
);
248 /* EPP case WM_COMMAND: */
249 /* EPP return Control_WndProc_Command(mwi, lParam1, lParam2); */
253 return DefWindowProcA(hWnd
, wMsg
, lParam1
, lParam2
);
256 static void Control_DoInterface(CPanel
* panel
, HWND hWnd
, HINSTANCE hInst
)
261 wc
.style
= CS_HREDRAW
|CS_VREDRAW
;
262 wc
.lpfnWndProc
= Control_WndProc
;
264 wc
.cbWndExtra
= sizeof(CPlApplet
*);
265 wc
.hInstance
= hInst
;
268 wc
.hbrBackground
= GetStockObject(WHITE_BRUSH
);
269 wc
.lpszMenuName
= NULL
;
270 wc
.lpszClassName
= "Shell_Control_WndClass";
272 if (!RegisterClassA(&wc
)) return;
274 CreateWindowExA(0, wc
.lpszClassName
, "Wine Control Panel",
275 WS_OVERLAPPEDWINDOW
| WS_VISIBLE
,
276 CW_USEDEFAULT
, CW_USEDEFAULT
,
277 CW_USEDEFAULT
, CW_USEDEFAULT
,
278 hWnd
, (HMENU
)0, hInst
, panel
);
279 if (!panel
->hWnd
) return;
280 while (GetMessageA(&msg
, panel
->hWnd
, 0, 0)) {
281 TranslateMessage(&msg
);
282 DispatchMessageA(&msg
);
283 if (!panel
->first
) break;
287 static void Control_DoWindow(CPanel
* panel
, HWND hWnd
, HINSTANCE hInst
)
291 char buffer
[MAX_PATH
];
293 /* FIXME: should grab path somewhere from configuration */
294 if ((h
= FindFirstFileA("c:\\windows\\system\\*.cpl", &fd
)) != 0) {
296 sprintf(buffer
, "c:\\windows\\system\\%s", fd
.cFileName
);
297 Control_LoadApplet(hWnd
, buffer
, panel
);
298 } while (FindNextFileA(h
, &fd
));
302 if (panel
->first
) Control_DoInterface(panel
, hWnd
, hInst
);
305 static void Control_DoLaunch(CPanel
* panel
, HWND hWnd
, LPCSTR cmd
)
319 char* extraPmts
= NULL
;
321 buffer
= HeapAlloc(GetProcessHeap(), 0, strlen(cmd
) + 1);
324 end
= strcpy(buffer
, cmd
);
328 if (ch
== ' ' || ch
== ',' || ch
== '\0') {
333 } else if (*beg
== '\0') {
339 if (ch
== '\0') break;
341 if (ch
== ' ') while (end
[1] == ' ') end
++;
345 Control_LoadApplet(hWnd
, buffer
, panel
);
348 CPlApplet
* applet
= panel
->first
;
350 assert(applet
&& applet
->next
== NULL
);
351 if (sp
>= applet
->count
) {
352 WARN("Out of bounds (%u >= %u), setting to 0\n", sp
, applet
->count
);
355 if (applet
->info
[sp
].dwSize
) {
356 if (!applet
->proc(applet
->hWnd
, CPL_STARTWPARMSA
, sp
, (LPARAM
)extraPmts
))
357 applet
->proc(applet
->hWnd
, CPL_DBLCLK
, sp
, applet
->info
[sp
].lData
);
359 Control_UnloadApplet(applet
);
361 HeapFree(GetProcessHeap(), 0, buffer
);
364 /*************************************************************************
365 * Control_RunDLL [SHELL32.@]
368 void WINAPI
Control_RunDLL(HWND hWnd
, HINSTANCE hInst
, LPCSTR cmd
, DWORD nCmdShow
)
372 TRACE("(0x%08x, 0x%08lx, %s, 0x%08lx)\n",
373 hWnd
, (DWORD
)hInst
, debugstr_a(cmd
), nCmdShow
);
375 memset(&panel
, 0, sizeof(panel
));
378 Control_DoWindow(&panel
, hWnd
, hInst
);
380 Control_DoLaunch(&panel
, hWnd
, cmd
);
384 /*************************************************************************
385 * Control_FillCache_RunDLL [SHELL32.@]
388 HRESULT WINAPI
Control_FillCache_RunDLL(HWND hWnd
, HANDLE hModule
, DWORD w
, DWORD x
)
390 FIXME("0x%04x 0x%04x 0x%04lx 0x%04lx stub\n",hWnd
, hModule
, w
, x
);
394 /*************************************************************************
395 * RunDLL_CallEntry16 [SHELL32.122]
396 * the name is probably wrong
398 HRESULT WINAPI
RunDLL_CallEntry16(DWORD v
, DWORD w
, DWORD x
, DWORD y
, DWORD z
)
400 FIXME("0x%04lx 0x%04lx 0x%04lx 0x%04lx 0x%04lx stub\n",v
,w
,x
,y
,z
);
404 /*************************************************************************
405 * CallCPLEntry16 [SHELL32.166]
407 * called by desk.cpl on "Advanced" with:
408 * hMod("DeskCp16.Dll"), pFunc("CplApplet"), 0, 1, 0xc, 0
411 DWORD WINAPI
CallCPLEntry16(HMODULE hMod
, FARPROC pFunc
, DWORD dw3
, DWORD dw4
, DWORD dw5
, DWORD dw6
)
413 FIXME("(%04x, %p, %08lx, %08lx, %08lx, %08lx): stub.\n", hMod
, pFunc
, dw3
, dw4
, dw5
, dw6
);