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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
23 WINE_DEFAULT_DEBUG_CHANNEL(shlctrl
);
25 CPlApplet
* Control_UnloadApplet(CPlApplet
* applet
)
30 for (i
= 0; i
< applet
->count
; i
++) {
31 if (!applet
->info
[i
].dwSize
) continue;
32 applet
->proc(applet
->hWnd
, CPL_STOP
, i
, applet
->info
[i
].lData
);
34 if (applet
->proc
) applet
->proc(applet
->hWnd
, CPL_EXIT
, 0L, 0L);
35 FreeLibrary(applet
->hModule
);
37 HeapFree(GetProcessHeap(), 0, applet
);
41 CPlApplet
* Control_LoadApplet(HWND hWnd
, LPCWSTR cmd
, CPanel
* panel
)
48 if (!(applet
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*applet
))))
53 if (!(applet
->hModule
= LoadLibraryW(cmd
))) {
54 WARN("Cannot load control panel applet %s\n", debugstr_w(cmd
));
57 if (!(applet
->proc
= (APPLET_PROC
)GetProcAddress(applet
->hModule
, "CPlApplet"))) {
58 WARN("Not a valid control panel applet %s\n", debugstr_w(cmd
));
61 if (!applet
->proc(hWnd
, CPL_INIT
, 0L, 0L)) {
62 WARN("Init of applet has failed\n");
65 if ((applet
->count
= applet
->proc(hWnd
, CPL_GETCOUNT
, 0L, 0L)) == 0) {
66 WARN("No subprogram in applet\n");
70 applet
= HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, applet
,
71 sizeof(*applet
) + (applet
->count
- 1) * sizeof(NEWCPLINFOW
));
73 for (i
= 0; i
< applet
->count
; i
++) {
74 ZeroMemory(&newinfo
, sizeof(newinfo
));
75 newinfo
.dwSize
= sizeof(NEWCPLINFOW
);
76 applet
->info
[i
].dwSize
= sizeof(NEWCPLINFOW
);
77 /* proc is supposed to return a null value upon success for
78 * CPL_INQUIRE and CPL_NEWINQUIRE
79 * However, real drivers don't seem to behave like this
80 * So, use introspection rather than return value
82 applet
->proc(hWnd
, CPL_NEWINQUIRE
, i
, (LPARAM
)&newinfo
);
83 if (newinfo
.hIcon
== 0) {
84 applet
->proc(hWnd
, CPL_INQUIRE
, i
, (LPARAM
)&info
);
85 if (info
.idIcon
== 0 || info
.idName
== 0) {
86 WARN("Couldn't get info from sp %u\n", i
);
87 applet
->info
[i
].dwSize
= 0;
89 /* convert the old data into the new structure */
90 applet
->info
[i
].dwFlags
= 0;
91 applet
->info
[i
].dwHelpContext
= 0;
92 applet
->info
[i
].lData
= info
.lData
;
93 applet
->info
[i
].hIcon
= LoadIconW(applet
->hModule
,
94 MAKEINTRESOURCEW(info
.idIcon
));
95 LoadStringW(applet
->hModule
, info
.idName
,
96 applet
->info
[i
].szName
, sizeof(applet
->info
[i
].szName
) / sizeof(WCHAR
));
97 LoadStringW(applet
->hModule
, info
.idInfo
,
98 applet
->info
[i
].szInfo
, sizeof(applet
->info
[i
].szInfo
) / sizeof(WCHAR
));
99 applet
->info
[i
].szHelpFile
[0] = '\0';
104 CopyMemory(&applet
->info
[i
], &newinfo
, newinfo
.dwSize
);
105 if (newinfo
.dwSize
!= sizeof(NEWCPLINFOW
))
107 applet
->info
[i
].dwSize
= sizeof(NEWCPLINFOW
);
108 lstrcpyW(applet
->info
[i
].szName
, newinfo
.szName
);
109 lstrcpyW(applet
->info
[i
].szInfo
, newinfo
.szInfo
);
110 lstrcpyW(applet
->info
[i
].szHelpFile
, newinfo
.szHelpFile
);
115 applet
->next
= panel
->first
;
116 panel
->first
= applet
;
121 Control_UnloadApplet(applet
);
125 static void Control_WndProc_Create(HWND hWnd
, const CREATESTRUCTW
* cs
)
127 CPanel
* panel
= (CPanel
*)cs
->lpCreateParams
;
129 SetWindowLongPtrW(hWnd
, 0, (LONG_PTR
)panel
);
139 static BOOL
Control_Localize(const CPanel
* panel
, int cx
, int cy
,
140 CPlApplet
** papplet
, unsigned* psp
)
142 unsigned i
, x
= (XSTEP
-XICON
)/2, y
= 0;
146 GetClientRect(panel
->hWnd
, &rc
);
147 for (applet
= panel
->first
; applet
; applet
= applet
->next
) {
148 for (i
= 0; i
< applet
->count
; i
++) {
149 if (!applet
->info
[i
].dwSize
) continue;
150 if (x
+ XSTEP
>= rc
.right
- rc
.left
) {
154 if (cx
>= x
&& cx
< x
+ XICON
&& cy
>= y
&& cy
< y
+ YSTEP
) {
165 static LRESULT
Control_WndProc_Paint(const CPanel
* panel
, WPARAM wParam
)
170 unsigned i
, x
= 0, y
= 0;
174 hdc
= (wParam
) ? (HDC
)wParam
: BeginPaint(panel
->hWnd
, &ps
);
175 hOldFont
= SelectObject(hdc
, GetStockObject(ANSI_VAR_FONT
));
176 GetClientRect(panel
->hWnd
, &rc
);
177 for (applet
= panel
->first
; applet
; applet
= applet
->next
) {
178 for (i
= 0; i
< applet
->count
; i
++) {
179 if (x
+ XSTEP
>= rc
.right
- rc
.left
) {
183 if (!applet
->info
[i
].dwSize
) continue;
184 DrawIcon(hdc
, x
+ (XSTEP
-XICON
)/2, y
, applet
->info
[i
].hIcon
);
186 txtRect
.right
= x
+ XSTEP
;
187 txtRect
.top
= y
+ YICON
;
188 txtRect
.bottom
= y
+ YSTEP
;
189 DrawTextW(hdc
, applet
->info
[i
].szName
, -1, &txtRect
,
190 DT_CENTER
| DT_VCENTER
);
194 SelectObject(hdc
, hOldFont
);
195 if (!wParam
) EndPaint(panel
->hWnd
, &ps
);
199 static LRESULT
Control_WndProc_LButton(CPanel
* panel
, LPARAM lParam
, BOOL up
)
204 if (Control_Localize(panel
, (short)LOWORD(lParam
), (short)HIWORD(lParam
), &applet
, &i
)) {
206 if (panel
->clkApplet
== applet
&& panel
->clkSP
== i
) {
207 applet
->proc(applet
->hWnd
, CPL_DBLCLK
, i
, applet
->info
[i
].lData
);
210 panel
->clkApplet
= applet
;
217 static LRESULT WINAPI
Control_WndProc(HWND hWnd
, UINT wMsg
,
218 WPARAM lParam1
, LPARAM lParam2
)
220 CPanel
* panel
= (CPanel
*)GetWindowLongPtrW(hWnd
, 0);
222 if (panel
|| wMsg
== WM_CREATE
) {
225 Control_WndProc_Create(hWnd
, (CREATESTRUCTW
*)lParam2
);
229 CPlApplet
* applet
= panel
->first
;
231 applet
= Control_UnloadApplet(applet
);
236 return Control_WndProc_Paint(panel
, lParam1
);
238 return Control_WndProc_LButton(panel
, lParam2
, TRUE
);
240 return Control_WndProc_LButton(panel
, lParam2
, FALSE
);
241 /* EPP case WM_COMMAND: */
242 /* EPP return Control_WndProc_Command(mwi, lParam1, lParam2); */
246 return DefWindowProcW(hWnd
, wMsg
, lParam1
, lParam2
);
249 static void Control_DoInterface(CPanel
* panel
, HWND hWnd
, HINSTANCE hInst
)
253 const WCHAR
* appName
= L
"ReactOS Control Panel";
254 wc
.style
= CS_HREDRAW
|CS_VREDRAW
;
255 wc
.lpfnWndProc
= Control_WndProc
;
257 wc
.cbWndExtra
= sizeof(CPlApplet
*);
258 wc
.hInstance
= hInst
;
261 wc
.hbrBackground
= GetStockObject(WHITE_BRUSH
);
262 wc
.lpszMenuName
= NULL
;
263 wc
.lpszClassName
= L
"Shell_Control_WndClass";
265 if (!RegisterClassW(&wc
)) return;
267 CreateWindowExW(0, wc
.lpszClassName
, appName
,
268 WS_OVERLAPPEDWINDOW
| WS_VISIBLE
,
269 CW_USEDEFAULT
, CW_USEDEFAULT
,
270 CW_USEDEFAULT
, CW_USEDEFAULT
,
271 hWnd
, NULL
, hInst
, panel
);
272 if (!panel
->hWnd
) return;
275 /* FIXME appName & message should be localized */
276 MessageBoxW(panel
->hWnd
, L
"Cannot load any applets", appName
, MB_OK
);
280 while (GetMessageW(&msg
, panel
->hWnd
, 0, 0)) {
281 TranslateMessage(&msg
);
282 DispatchMessageW(&msg
);
286 static void Control_DoWindow(CPanel
* panel
, HWND hWnd
, HINSTANCE hInst
)
290 WCHAR buffer
[MAX_PATH
];
291 static const WCHAR wszAllCpl
[] = {'*','.','c','p','l',0};
294 GetSystemDirectoryW( buffer
, MAX_PATH
);
295 p
= buffer
+ wcslen(buffer
);
297 wcscpy(p
, wszAllCpl
);
299 if ((h
= FindFirstFileW(buffer
, &fd
)) != INVALID_HANDLE_VALUE
) {
301 wcscpy(p
, fd
.cFileName
);
302 Control_LoadApplet(hWnd
, buffer
, panel
);
303 } while (FindNextFileW(h
, &fd
));
307 Control_DoInterface(panel
, hWnd
, hInst
);
310 static void Control_DoLaunch(CPanel
* panel
, HWND hWnd
, LPCWSTR wszCmd
)
325 WCHAR szName
[MAX_PATH
];
327 LPWSTR extraPmts
= NULL
;
333 ptr
= wcsrchr(wszCmd
, L
'\\');
334 ptr2
= wcsrchr(wszCmd
, L
',');
337 ptr2
= wszCmd
+ wcslen(wszCmd
) + 1;
345 Length
= (ptr2
- ptr
);
346 if (Length
>= MAX_PATH
)
349 memcpy(szName
, (LPVOID
)ptr
, Length
* sizeof(WCHAR
));
350 szName
[Length
] = L
'\0';
351 hMutex
= CreateMutexW(NULL
, TRUE
, szName
);
353 if ((!hMutex
) || (GetLastError() == ERROR_ALREADY_EXISTS
))
355 buffer
= HeapAlloc(GetProcessHeap(), 0, (wcslen(wszCmd
) + 1) * sizeof(*wszCmd
));
361 end
= wcscpy(buffer
, wszCmd
);
364 if (ch
== '"') quoted
= !quoted
;
365 if (!quoted
&& (ch
== ' ' || ch
== ',' || ch
== '\0')) {
371 } else if (*beg
== '\0') {
378 if (ch
== '\0') break;
380 if (ch
== ' ') while (end
[1] == ' ') end
++;
384 while ((ptr
= StrChrW(buffer
, '"')))
385 memmove((LPVOID
)ptr
, ptr
+1, wcslen(ptr
)*sizeof(WCHAR
));
387 while ((ptr
= StrChrW(extraPmts
, '"')))
388 memmove((LPVOID
)ptr
, ptr
+1, wcslen(ptr
)*sizeof(WCHAR
));
390 TRACE("cmd %s, extra %s, sp %d\n", debugstr_w(buffer
), debugstr_w(extraPmts
), sp
);
392 Control_LoadApplet(hWnd
, buffer
, panel
);
395 CPlApplet
* applet
= panel
->first
;
397 assert(applet
&& applet
->next
== NULL
);
398 if (sp
>= applet
->count
) {
399 WARN("Out of bounds (%u >= %u), setting to 0\n", sp
, applet
->count
);
403 if ((extraPmts
) && extraPmts
[0] &&(!spSet
))
405 while ((lstrcmpiW(extraPmts
, applet
->info
[sp
].szName
)) && (sp
< applet
->count
))
408 if (sp
>= applet
->count
)
410 ReleaseMutex(hMutex
);
412 Control_UnloadApplet(applet
);
413 HeapFree(GetProcessHeap(), 0, buffer
);
417 if (applet
->info
[sp
].dwSize
) {
418 if (!applet
->proc(applet
->hWnd
, CPL_DBLCLK
, sp
, applet
->info
[sp
].lData
))
419 applet
->proc(applet
->hWnd
, CPL_STARTWPARMSA
, sp
, (LPARAM
)extraPmts
);
421 Control_UnloadApplet(applet
);
423 ReleaseMutex(hMutex
);
425 HeapFree(GetProcessHeap(), 0, buffer
);
428 /*************************************************************************
429 * Control_RunDLLW [SHELL32.@]
432 void WINAPI
Control_RunDLLW(HWND hWnd
, HINSTANCE hInst
, LPCWSTR cmd
, DWORD nCmdShow
)
436 TRACE("(%p, %p, %s, 0x%08x)\n",
437 hWnd
, hInst
, debugstr_w(cmd
), nCmdShow
);
439 memset(&panel
, 0, sizeof(panel
));
442 Control_DoWindow(&panel
, hWnd
, hInst
);
444 Control_DoLaunch(&panel
, hWnd
, cmd
);
448 /*************************************************************************
449 * Control_RunDLLA [SHELL32.@]
452 void WINAPI
Control_RunDLLA(HWND hWnd
, HINSTANCE hInst
, LPCSTR cmd
, DWORD nCmdShow
)
454 DWORD len
= MultiByteToWideChar(CP_ACP
, 0, cmd
, -1, NULL
, 0 );
455 LPWSTR wszCmd
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
456 if (wszCmd
&& MultiByteToWideChar(CP_ACP
, 0, cmd
, -1, wszCmd
, len
))
458 Control_RunDLLW(hWnd
, hInst
, wszCmd
, nCmdShow
);
460 HeapFree(GetProcessHeap(), 0, wszCmd
);
463 /*************************************************************************
464 * Control_FillCache_RunDLLW [SHELL32.@]
467 HRESULT WINAPI
Control_FillCache_RunDLLW(HWND hWnd
, HANDLE hModule
, DWORD w
, DWORD x
)
469 FIXME("%p %p 0x%08x 0x%08x stub\n", hWnd
, hModule
, w
, x
);
473 /*************************************************************************
474 * Control_FillCache_RunDLLA [SHELL32.@]
477 HRESULT WINAPI
Control_FillCache_RunDLLA(HWND hWnd
, HANDLE hModule
, DWORD w
, DWORD x
)
479 return Control_FillCache_RunDLLW(hWnd
, hModule
, w
, x
);
483 /*************************************************************************
484 * RunDLL_CallEntry16 [SHELL32.122]
485 * the name is probably wrong
487 void WINAPI
RunDLL_CallEntry16( DWORD proc
, HWND hwnd
, HINSTANCE inst
,
488 LPCSTR cmdline
, INT cmdshow
)
490 #if !defined(__CYGWIN__) && !defined (__MINGW32__) && !defined(_MSC_VER)
494 TRACE( "proc %x hwnd %p inst %p cmdline %s cmdshow %d\n",
495 proc
, hwnd
, inst
, debugstr_a(cmdline
), cmdshow
);
497 cmdline_seg
= MapLS( cmdline
);
498 args
[4] = HWND_16(hwnd
);
499 args
[3] = MapHModuleLS(inst
);
500 args
[2] = SELECTOROF(cmdline_seg
);
501 args
[1] = OFFSETOF(cmdline_seg
);
503 WOWCallback16Ex( proc
, WCB16_PASCAL
, sizeof(args
), args
, NULL
);
504 UnMapLS( cmdline_seg
);
506 FIXME( "proc %lx hwnd %p inst %p cmdline %s cmdshow %d\n",
507 proc
, hwnd
, inst
, debugstr_a(cmdline
), cmdshow
);
511 /*************************************************************************
512 * CallCPLEntry16 [SHELL32.166]
514 * called by desk.cpl on "Advanced" with:
515 * hMod("DeskCp16.Dll"), pFunc("CplApplet"), 0, 1, 0xc, 0
518 DWORD WINAPI
CallCPLEntry16(HMODULE hMod
, FARPROC pFunc
, DWORD dw3
, DWORD dw4
, DWORD dw5
, DWORD dw6
)
520 FIXME("(%p, %p, %08x, %08x, %08x, %08x): stub.\n", hMod
, pFunc
, dw3
, dw4
, dw5
, dw6
);