1 /* Control Panel management
3 * Copyright 2001 Eric Pouech
4 * Copyright 2008 Owen Rudge
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
32 #include "wine/winbase16.h"
34 #include "wine/debug.h"
36 #include "wine/unicode.h"
39 #define NO_SHLWAPI_REG
44 #include "shell32_main.h"
46 #define MAX_STRING_LEN 1024
48 WINE_DEFAULT_DEBUG_CHANNEL(shlctrl
);
50 CPlApplet
* Control_UnloadApplet(CPlApplet
* applet
)
55 for (i
= 0; i
< applet
->count
; i
++) {
56 if (!applet
->info
[i
].dwSize
) continue;
57 applet
->proc(applet
->hWnd
, CPL_STOP
, i
, applet
->info
[i
].lData
);
59 if (applet
->proc
) applet
->proc(applet
->hWnd
, CPL_EXIT
, 0L, 0L);
60 FreeLibrary(applet
->hModule
);
62 HeapFree(GetProcessHeap(), 0, applet
);
66 CPlApplet
* Control_LoadApplet(HWND hWnd
, LPCWSTR cmd
, CPanel
* panel
)
73 if (!(applet
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*applet
))))
78 if (!(applet
->hModule
= LoadLibraryW(cmd
))) {
79 WARN("Cannot load control panel applet %s\n", debugstr_w(cmd
));
82 if (!(applet
->proc
= (APPLET_PROC
)GetProcAddress(applet
->hModule
, "CPlApplet"))) {
83 WARN("Not a valid control panel applet %s\n", debugstr_w(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(NEWCPLINFOW
));
98 for (i
= 0; i
< applet
->count
; i
++) {
99 ZeroMemory(&newinfo
, sizeof(newinfo
));
100 newinfo
.dwSize
= sizeof(NEWCPLINFOA
);
101 applet
->info
[i
].dwSize
= sizeof(NEWCPLINFOW
);
102 applet
->info
[i
].dwFlags
= 0;
103 applet
->info
[i
].dwHelpContext
= 0;
104 applet
->info
[i
].szHelpFile
[0] = '\0';
105 /* proc is supposed to return a null value upon success for
106 * CPL_INQUIRE and CPL_NEWINQUIRE
107 * However, real drivers don't seem to behave like this
108 * So, use introspection rather than return value
110 applet
->proc(hWnd
, CPL_INQUIRE
, i
, (LPARAM
)&info
);
111 applet
->info
[i
].lData
= info
.lData
;
112 if (info
.idIcon
!= CPL_DYNAMIC_RES
)
113 applet
->info
[i
].hIcon
= LoadIconW(applet
->hModule
,
114 MAKEINTRESOURCEW(info
.idIcon
));
115 if (info
.idName
!= CPL_DYNAMIC_RES
)
116 LoadStringW(applet
->hModule
, info
.idName
,
117 applet
->info
[i
].szName
, sizeof(applet
->info
[i
].szName
) / sizeof(WCHAR
));
118 if (info
.idInfo
!= CPL_DYNAMIC_RES
)
119 LoadStringW(applet
->hModule
, info
.idInfo
,
120 applet
->info
[i
].szInfo
, sizeof(applet
->info
[i
].szInfo
) / sizeof(WCHAR
));
122 /* some broken control panels seem to return incorrect values in CPL_INQUIRE,
123 but proper data in CPL_NEWINQUIRE. if we get an empty string or a null
124 icon, see what we can get from CPL_NEWINQUIRE */
126 if ((applet
->info
[i
].szName
== 0) || (lstrlenW(applet
->info
[i
].szName
) == 0))
127 info
.idName
= CPL_DYNAMIC_RES
;
129 /* zero-length szInfo may not be a buggy applet, but it doesn't hurt for us
132 if ((applet
->info
[i
].szInfo
== 0) || (lstrlenW(applet
->info
[i
].szInfo
) == 0))
133 info
.idInfo
= CPL_DYNAMIC_RES
;
135 if (applet
->info
[i
].hIcon
== NULL
)
136 info
.idIcon
= CPL_DYNAMIC_RES
;
138 if ((info
.idIcon
== CPL_DYNAMIC_RES
) || (info
.idName
== CPL_DYNAMIC_RES
) ||
139 (info
.idInfo
== CPL_DYNAMIC_RES
)) {
140 applet
->proc(hWnd
, CPL_NEWINQUIRE
, i
, (LPARAM
)&newinfo
);
142 applet
->info
[i
].dwFlags
= newinfo
.dwFlags
;
143 applet
->info
[i
].dwHelpContext
= newinfo
.dwHelpContext
;
144 applet
->info
[i
].lData
= newinfo
.lData
;
145 if (info
.idIcon
== CPL_DYNAMIC_RES
) {
146 if (!newinfo
.hIcon
) WARN("couldn't get icon for applet %u\n", i
);
147 applet
->info
[i
].hIcon
= newinfo
.hIcon
;
149 if (newinfo
.dwSize
== sizeof(NEWCPLINFOW
)) {
150 if (info
.idName
== CPL_DYNAMIC_RES
)
151 memcpy(applet
->info
[i
].szName
, newinfo
.szName
, sizeof(newinfo
.szName
));
152 if (info
.idInfo
== CPL_DYNAMIC_RES
)
153 memcpy(applet
->info
[i
].szInfo
, newinfo
.szInfo
, sizeof(newinfo
.szInfo
));
154 memcpy(applet
->info
[i
].szHelpFile
, newinfo
.szHelpFile
, sizeof(newinfo
.szHelpFile
));
156 if (info
.idName
== CPL_DYNAMIC_RES
)
157 MultiByteToWideChar(CP_ACP
, 0, ((LPNEWCPLINFOA
)&newinfo
)->szName
,
158 sizeof(((LPNEWCPLINFOA
)&newinfo
)->szName
) / sizeof(CHAR
),
159 applet
->info
[i
].szName
,
160 sizeof(applet
->info
[i
].szName
) / sizeof(WCHAR
));
161 if (info
.idInfo
== CPL_DYNAMIC_RES
)
162 MultiByteToWideChar(CP_ACP
, 0, ((LPNEWCPLINFOA
)&newinfo
)->szInfo
,
163 sizeof(((LPNEWCPLINFOA
)&newinfo
)->szInfo
) / sizeof(CHAR
),
164 applet
->info
[i
].szInfo
,
165 sizeof(applet
->info
[i
].szInfo
) / sizeof(WCHAR
));
166 MultiByteToWideChar(CP_ACP
, 0, ((LPNEWCPLINFOA
)&newinfo
)->szHelpFile
,
167 sizeof(((LPNEWCPLINFOA
)&newinfo
)->szHelpFile
) / sizeof(CHAR
),
168 applet
->info
[i
].szHelpFile
,
169 sizeof(applet
->info
[i
].szHelpFile
) / sizeof(WCHAR
));
174 applet
->next
= panel
->first
;
175 panel
->first
= applet
;
180 Control_UnloadApplet(applet
);
184 #define IDC_LISTVIEW 1000
185 #define IDC_STATUSBAR 1001
187 #define NUM_COLUMNS 2
188 #define LISTVIEW_DEFSTYLE (WS_CHILD | WS_VISIBLE | WS_TABSTOP |\
189 LVS_SORTASCENDING | LVS_AUTOARRANGE | LVS_SINGLESEL)
191 static BOOL
Control_CreateListView (CPanel
*panel
)
194 WCHAR empty_string
[] = {0};
195 WCHAR buf
[MAX_STRING_LEN
];
198 /* Create list view */
199 GetClientRect(panel
->hWndStatusBar
, &sb
);
200 GetClientRect(panel
->hWnd
, &ws
);
202 panel
->hWndListView
= CreateWindowExW(WS_EX_CLIENTEDGE
, WC_LISTVIEWW
,
203 empty_string
, LISTVIEW_DEFSTYLE
| LVS_ICON
,
204 0, 0, ws
.right
- ws
.left
, ws
.bottom
- ws
.top
-
205 (sb
.bottom
- sb
.top
), panel
->hWnd
,
206 (HMENU
) IDC_LISTVIEW
, panel
->hInst
, NULL
);
208 if (!panel
->hWndListView
)
211 /* Create image lists for list view */
212 panel
->hImageListSmall
= ImageList_Create(GetSystemMetrics(SM_CXSMICON
),
213 GetSystemMetrics(SM_CYSMICON
), ILC_MASK
, 1, 1);
214 panel
->hImageListLarge
= ImageList_Create(GetSystemMetrics(SM_CXICON
),
215 GetSystemMetrics(SM_CYICON
), ILC_MASK
, 1, 1);
217 (void) ListView_SetImageList(panel
->hWndListView
, panel
->hImageListSmall
, LVSIL_SMALL
);
218 (void) ListView_SetImageList(panel
->hWndListView
, panel
->hImageListLarge
, LVSIL_NORMAL
);
220 /* Create columns for list view */
221 lvc
.mask
= LVCF_FMT
| LVCF_TEXT
| LVCF_SUBITEM
| LVCF_WIDTH
;
223 lvc
.fmt
= LVCFMT_LEFT
;
227 lvc
.cx
= (ws
.right
- ws
.left
) / 3;
228 LoadStringW(shell32_hInstance
, IDS_CPANEL_NAME
, buf
, sizeof(buf
) / sizeof(buf
[0]));
230 if (ListView_InsertColumnW(panel
->hWndListView
, 0, &lvc
) == -1)
233 /* Description column */
235 lvc
.cx
= ((ws
.right
- ws
.left
) / 3) * 2;
236 LoadStringW(shell32_hInstance
, IDS_CPANEL_DESCRIPTION
, buf
, sizeof(buf
) /
239 if (ListView_InsertColumnW(panel
->hWndListView
, 1, &lvc
) == -1)
245 static void Control_WndProc_Create(HWND hWnd
, const CREATESTRUCTW
* cs
)
247 CPanel
* panel
= (CPanel
*)cs
->lpCreateParams
;
248 HMENU hMenu
, hSubMenu
;
251 int menucount
, i
, index
;
254 INITCOMMONCONTROLSEX icex
;
258 SetWindowLongPtrW(hWnd
, 0, (LONG_PTR
)panel
);
261 /* Initialise common control DLL */
262 icex
.dwSize
= sizeof(INITCOMMONCONTROLSEX
);
263 icex
.dwICC
= ICC_LISTVIEW_CLASSES
| ICC_BAR_CLASSES
;
264 InitCommonControlsEx(&icex
);
266 /* create the status bar */
267 if (!(panel
->hWndStatusBar
= CreateStatusWindowW(WS_CHILD
| WS_VISIBLE
| CCS_BOTTOM
| SBARS_SIZEGRIP
, NULL
, hWnd
, IDC_STATUSBAR
)))
271 SendMessageW(panel
->hWndStatusBar
, SB_SETPARTS
, 1, (LPARAM
) &sb_parts
);
273 /* create the list view */
274 if (!Control_CreateListView(panel
))
277 hMenu
= LoadMenuW(shell32_hInstance
, MAKEINTRESOURCEW(MENU_CPANEL
));
279 /* insert menu items for applets */
280 hSubMenu
= GetSubMenu(hMenu
, 0);
283 for (applet
= panel
->first
; applet
; applet
= applet
->next
) {
284 for (i
= 0; i
< applet
->count
; i
++) {
285 if (!applet
->info
[i
].dwSize
)
288 /* set up a CPlItem for this particular subprogram */
289 item
= HeapAlloc(GetProcessHeap(), 0, sizeof(CPlItem
));
294 item
->applet
= (CPlApplet
*) applet
;
297 mii
.cbSize
= sizeof(MENUITEMINFOW
);
298 mii
.fMask
= MIIM_ID
| MIIM_STRING
| MIIM_DATA
;
299 mii
.dwTypeData
= applet
->info
[i
].szName
;
300 mii
.cch
= sizeof(applet
->info
[i
].szName
) / sizeof(applet
->info
[i
].szName
[0]);
301 mii
.wID
= IDM_CPANEL_APPLET_BASE
+ menucount
;
302 mii
.dwItemData
= (DWORD
) item
;
304 if (InsertMenuItemW(hSubMenu
, menucount
, TRUE
, &mii
)) {
305 /* add the list view item */
306 index
= ImageList_AddIcon(panel
->hImageListLarge
, applet
->info
[i
].hIcon
);
307 ImageList_AddIcon(panel
->hImageListSmall
, applet
->info
[i
].hIcon
);
309 lvItem
.mask
= LVIF_IMAGE
| LVIF_TEXT
| LVIF_PARAM
;
310 lvItem
.iItem
= menucount
;
312 lvItem
.pszText
= applet
->info
[i
].szName
;
313 lvItem
.iImage
= index
;
314 lvItem
.lParam
= (LPARAM
) item
;
316 itemidx
= ListView_InsertItemW(panel
->hWndListView
, &lvItem
);
318 /* add the description */
319 ListView_SetItemTextW(panel
->hWndListView
, itemidx
, 1,
320 applet
->info
[i
].szInfo
);
322 /* update menu bar, increment count */
329 panel
->total_subprogs
= menucount
;
331 /* check the "large items" icon in the View menu */
332 hSubMenu
= GetSubMenu(hMenu
, 1);
333 CheckMenuRadioItem(hSubMenu
, FCIDM_SHVIEW_BIGICON
, FCIDM_SHVIEW_REPORTVIEW
,
334 FCIDM_SHVIEW_BIGICON
, MF_BYCOMMAND
);
336 SetMenu(hWnd
, hMenu
);
339 static void Control_FreeCPlItems(HWND hWnd
, CPanel
*panel
)
341 HMENU hMenu
, hSubMenu
;
345 /* get the File menu */
346 hMenu
= GetMenu(hWnd
);
351 hSubMenu
= GetSubMenu(hMenu
, 0);
356 /* loop and free the item data */
357 for (i
= IDM_CPANEL_APPLET_BASE
; i
<= IDM_CPANEL_APPLET_BASE
+ panel
->total_subprogs
; i
++)
359 mii
.cbSize
= sizeof(MENUITEMINFOW
);
360 mii
.fMask
= MIIM_DATA
;
362 if (!GetMenuItemInfoW(hSubMenu
, i
, FALSE
, &mii
))
365 HeapFree(GetProcessHeap(), 0, (LPVOID
) mii
.dwItemData
);
369 static void Control_UpdateListViewStyle(CPanel
*panel
, UINT style
, UINT id
)
371 HMENU hMenu
, hSubMenu
;
373 SetWindowLongW(panel
->hWndListView
, GWL_STYLE
, LISTVIEW_DEFSTYLE
| style
);
375 /* update the menu */
376 hMenu
= GetMenu(panel
->hWnd
);
377 hSubMenu
= GetSubMenu(hMenu
, 1);
379 CheckMenuRadioItem(hSubMenu
, FCIDM_SHVIEW_BIGICON
, FCIDM_SHVIEW_REPORTVIEW
,
383 static CPlItem
* Control_GetCPlItem_From_MenuID(HWND hWnd
, UINT id
)
385 HMENU hMenu
, hSubMenu
;
388 /* retrieve the CPlItem structure from the menu item data */
389 hMenu
= GetMenu(hWnd
);
394 hSubMenu
= GetSubMenu(hMenu
, 0);
399 mii
.cbSize
= sizeof(MENUITEMINFOW
);
400 mii
.fMask
= MIIM_DATA
;
402 if (!GetMenuItemInfoW(hSubMenu
, id
, FALSE
, &mii
))
405 return (CPlItem
*) mii
.dwItemData
;
408 static CPlItem
* Control_GetCPlItem_From_ListView(CPanel
*panel
)
413 selitem
= SendMessageW(panel
->hWndListView
, LVM_GETNEXTITEM
, -1, LVNI_FOCUSED
418 lvItem
.iItem
= selitem
;
419 lvItem
.mask
= LVIF_PARAM
;
421 if (SendMessageW(panel
->hWndListView
, LVM_GETITEMW
, 0, (LPARAM
) &lvItem
))
422 return (CPlItem
*) lvItem
.lParam
;
428 static LRESULT WINAPI
Control_WndProc(HWND hWnd
, UINT wMsg
,
429 WPARAM lParam1
, LPARAM lParam2
)
431 CPanel
* panel
= (CPanel
*)GetWindowLongPtrW(hWnd
, 0);
433 if (panel
|| wMsg
== WM_CREATE
) {
436 Control_WndProc_Create(hWnd
, (CREATESTRUCTW
*)lParam2
);
440 CPlApplet
* applet
= panel
->first
;
442 applet
= Control_UnloadApplet(applet
);
444 Control_FreeCPlItems(hWnd
, panel
);
448 switch (LOWORD(lParam1
))
450 case IDM_CPANEL_EXIT
:
451 SendMessageW(hWnd
, WM_CLOSE
, 0, 0);
454 case IDM_CPANEL_ABOUT
:
456 WCHAR appName
[MAX_STRING_LEN
];
458 LoadStringW(shell32_hInstance
, IDS_CPANEL_TITLE
, appName
,
459 sizeof(appName
) / sizeof(appName
[0]));
460 ShellAboutW(hWnd
, appName
, NULL
, NULL
);
465 case FCIDM_SHVIEW_BIGICON
:
466 Control_UpdateListViewStyle(panel
, LVS_ICON
, FCIDM_SHVIEW_BIGICON
);
469 case FCIDM_SHVIEW_SMALLICON
:
470 Control_UpdateListViewStyle(panel
, LVS_SMALLICON
, FCIDM_SHVIEW_SMALLICON
);
473 case FCIDM_SHVIEW_LISTVIEW
:
474 Control_UpdateListViewStyle(panel
, LVS_LIST
, FCIDM_SHVIEW_LISTVIEW
);
477 case FCIDM_SHVIEW_REPORTVIEW
:
478 Control_UpdateListViewStyle(panel
, LVS_REPORT
, FCIDM_SHVIEW_REPORTVIEW
);
482 /* check if this is an applet */
483 if ((LOWORD(lParam1
) >= IDM_CPANEL_APPLET_BASE
) &&
484 (LOWORD(lParam1
) <= IDM_CPANEL_APPLET_BASE
+ panel
->total_subprogs
))
486 CPlItem
*item
= Control_GetCPlItem_From_MenuID(hWnd
, LOWORD(lParam1
));
488 /* execute the applet if item is valid */
490 item
->applet
->proc(item
->applet
->hWnd
, CPL_DBLCLK
, item
->id
,
491 item
->applet
->info
[item
->id
].lData
);
503 LPNMHDR nmh
= (LPNMHDR
) lParam2
;
513 CPlItem
*item
= Control_GetCPlItem_From_ListView(panel
);
515 /* execute the applet if item is valid */
517 item
->applet
->proc(item
->applet
->hWnd
, CPL_DBLCLK
,
518 item
->id
, item
->applet
->info
[item
->id
].lData
);
522 case LVN_ITEMCHANGED
:
524 CPlItem
*item
= Control_GetCPlItem_From_ListView(panel
);
526 /* update the status bar if item is valid */
528 SetWindowTextW(panel
->hWndStatusBar
,
529 item
->applet
->info
[item
->id
].szInfo
);
531 SetWindowTextW(panel
->hWndStatusBar
, NULL
);
544 /* check if this is an applet */
545 if ((LOWORD(lParam1
) >= IDM_CPANEL_APPLET_BASE
) &&
546 (LOWORD(lParam1
) <= IDM_CPANEL_APPLET_BASE
+ panel
->total_subprogs
))
548 CPlItem
*item
= Control_GetCPlItem_From_MenuID(hWnd
, LOWORD(lParam1
));
550 /* update the status bar if item is valid */
552 SetWindowTextW(panel
->hWndStatusBar
, item
->applet
->info
[item
->id
].szInfo
);
554 else if ((HIWORD(lParam1
) == 0xFFFF) && (lParam2
== 0))
556 /* reset status bar description to that of the selected icon */
557 CPlItem
*item
= Control_GetCPlItem_From_ListView(panel
);
560 SetWindowTextW(panel
->hWndStatusBar
, item
->applet
->info
[item
->id
].szInfo
);
562 SetWindowTextW(panel
->hWndStatusBar
, NULL
);
567 SetWindowTextW(panel
->hWndStatusBar
, NULL
);
576 hdwp
= BeginDeferWindowPos(2);
581 GetClientRect(panel
->hWndStatusBar
, &sb
);
583 hdwp
= DeferWindowPos(hdwp
, panel
->hWndListView
, NULL
, 0, 0,
584 LOWORD(lParam2
), HIWORD(lParam2
) - (sb
.bottom
- sb
.top
),
585 SWP_NOZORDER
| SWP_NOMOVE
);
590 hdwp
= DeferWindowPos(hdwp
, panel
->hWndStatusBar
, NULL
, 0, 0,
591 LOWORD(lParam2
), LOWORD(lParam1
), SWP_NOZORDER
| SWP_NOMOVE
);
594 EndDeferWindowPos(hdwp
);
601 return DefWindowProcW(hWnd
, wMsg
, lParam1
, lParam2
);
604 static void Control_DoInterface(CPanel
* panel
, HWND hWnd
, HINSTANCE hInst
)
608 WCHAR appName
[MAX_STRING_LEN
];
609 const WCHAR className
[] = {'S','h','e','l','l','_','C','o','n','t','r','o',
610 'l','_','W','n','d','C','l','a','s','s',0};
612 LoadStringW(shell32_hInstance
, IDS_CPANEL_TITLE
, appName
, sizeof(appName
) / sizeof(appName
[0]));
614 wc
.style
= CS_HREDRAW
|CS_VREDRAW
;
615 wc
.lpfnWndProc
= Control_WndProc
;
617 wc
.cbWndExtra
= sizeof(CPlApplet
*);
618 wc
.hInstance
= panel
->hInst
= hInst
;
620 wc
.hCursor
= LoadCursorW( 0, (LPWSTR
)IDC_ARROW
);
621 wc
.hbrBackground
= GetStockObject(WHITE_BRUSH
);
622 wc
.lpszMenuName
= NULL
;
623 wc
.lpszClassName
= className
;
625 if (!RegisterClassW(&wc
)) return;
627 CreateWindowExW(0, wc
.lpszClassName
, appName
,
628 WS_OVERLAPPEDWINDOW
| WS_VISIBLE
,
629 CW_USEDEFAULT
, CW_USEDEFAULT
,
630 CW_USEDEFAULT
, CW_USEDEFAULT
,
631 hWnd
, NULL
, hInst
, panel
);
632 if (!panel
->hWnd
) return;
634 while (GetMessageW(&msg
, panel
->hWnd
, 0, 0)) {
635 TranslateMessage(&msg
);
636 DispatchMessageW(&msg
);
640 static void Control_RegisterRegistryApplets(HWND hWnd
, CPanel
*panel
, HKEY hkey_root
, LPCWSTR szRepPath
)
642 WCHAR name
[MAX_PATH
];
643 WCHAR value
[MAX_PATH
];
646 if (RegOpenKeyW(hkey_root
, szRepPath
, &hkey
) == ERROR_SUCCESS
)
652 DWORD nameLen
= MAX_PATH
;
653 DWORD valueLen
= MAX_PATH
;
655 if (RegEnumValueW(hkey
, idx
, name
, &nameLen
, NULL
, NULL
, (LPBYTE
)value
, &valueLen
) != ERROR_SUCCESS
)
658 Control_LoadApplet(hWnd
, value
, panel
);
664 static void Control_DoWindow(CPanel
* panel
, HWND hWnd
, HINSTANCE hInst
)
668 WCHAR buffer
[MAX_PATH
];
669 static const WCHAR wszAllCpl
[] = {'*','.','c','p','l',0};
670 static const WCHAR wszRegPath
[] = {'S','O','F','T','W','A','R','E','\\','M','i','c','r','o','s','o','f','t',
671 '\\','W','i','n','d','o','w','s','\\','C','u','r','r','e','n','t','V','e','r','s','i','o','n',
672 '\\','C','o','n','t','r','o','l',' ','P','a','n','e','l','\\','C','p','l','s',0};
675 /* first add .cpl files in the system directory */
676 GetSystemDirectoryW( buffer
, MAX_PATH
);
677 p
= buffer
+ strlenW(buffer
);
679 lstrcpyW(p
, wszAllCpl
);
681 if ((h
= FindFirstFileW(buffer
, &fd
)) != INVALID_HANDLE_VALUE
) {
683 lstrcpyW(p
, fd
.cFileName
);
684 Control_LoadApplet(hWnd
, buffer
, panel
);
685 } while (FindNextFileW(h
, &fd
));
689 /* now check for cpls in the registry */
690 Control_RegisterRegistryApplets(hWnd
, panel
, HKEY_LOCAL_MACHINE
, wszRegPath
);
691 Control_RegisterRegistryApplets(hWnd
, panel
, HKEY_CURRENT_USER
, wszRegPath
);
693 Control_DoInterface(panel
, hWnd
, hInst
);
696 static void Control_DoLaunch(CPanel
* panel
, HWND hWnd
, LPCWSTR wszCmd
)
712 LPWSTR extraPmtsBuf
= NULL
;
713 LPWSTR extraPmts
= NULL
;
716 buffer
= HeapAlloc(GetProcessHeap(), 0, (lstrlenW(wszCmd
) + 1) * sizeof(*wszCmd
));
719 end
= lstrcpyW(buffer
, wszCmd
);
723 if (ch
== '"') quoted
= !quoted
;
724 if (!quoted
&& (ch
== ' ' || ch
== ',' || ch
== '\0')) {
729 } else if (*beg
== '\0') {
735 if (ch
== '\0') break;
737 if (ch
== ' ') while (end
[1] == ' ') end
++;
741 while ((ptr
= StrChrW(buffer
, '"')))
742 memmove(ptr
, ptr
+1, lstrlenW(ptr
)*sizeof(WCHAR
));
744 /* now check for any quotes in extraPmtsBuf and remove */
745 if (extraPmtsBuf
!= NULL
)
747 beg
= end
= extraPmtsBuf
;
752 if (ch
== '"') quoted
= !quoted
;
753 if (!quoted
&& (ch
== ' ' || ch
== ',' || ch
== '\0')) {
760 if (ch
== '\0') break;
762 if (ch
== ' ') while (end
[1] == ' ') end
++;
767 while ((ptr
= StrChrW(extraPmts
, '"')))
768 memmove(ptr
, ptr
+1, lstrlenW(ptr
)*sizeof(WCHAR
));
770 if (extraPmts
== NULL
)
771 extraPmts
= extraPmtsBuf
;
774 TRACE("cmd %s, extra %s, sp %d\n", debugstr_w(buffer
), debugstr_w(extraPmts
), sp
);
776 Control_LoadApplet(hWnd
, buffer
, panel
);
779 CPlApplet
* applet
= panel
->first
;
781 assert(applet
&& applet
->next
== NULL
);
783 /* we've been given a textual parameter (or none at all) */
785 while ((++sp
) != applet
->count
) {
786 if (applet
->info
[sp
].dwSize
) {
787 TRACE("sp %d, name %s\n", sp
, debugstr_w(applet
->info
[sp
].szName
));
789 if (StrCmpIW(extraPmts
, applet
->info
[sp
].szName
) == 0)
795 if (sp
>= applet
->count
) {
796 WARN("Out of bounds (%u >= %u), setting to 0\n", sp
, applet
->count
);
800 if (applet
->info
[sp
].dwSize
) {
801 if (!applet
->proc(applet
->hWnd
, CPL_STARTWPARMSA
, sp
, (LPARAM
)extraPmts
))
802 applet
->proc(applet
->hWnd
, CPL_DBLCLK
, sp
, applet
->info
[sp
].lData
);
805 Control_UnloadApplet(applet
);
808 HeapFree(GetProcessHeap(), 0, buffer
);
811 /*************************************************************************
812 * Control_RunDLLW [SHELL32.@]
815 void WINAPI
Control_RunDLLW(HWND hWnd
, HINSTANCE hInst
, LPCWSTR cmd
, DWORD nCmdShow
)
819 TRACE("(%p, %p, %s, 0x%08x)\n",
820 hWnd
, hInst
, debugstr_w(cmd
), nCmdShow
);
822 memset(&panel
, 0, sizeof(panel
));
825 Control_DoWindow(&panel
, hWnd
, hInst
);
827 Control_DoLaunch(&panel
, hWnd
, cmd
);
831 /*************************************************************************
832 * Control_RunDLLA [SHELL32.@]
835 void WINAPI
Control_RunDLLA(HWND hWnd
, HINSTANCE hInst
, LPCSTR cmd
, DWORD nCmdShow
)
837 DWORD len
= MultiByteToWideChar(CP_ACP
, 0, cmd
, -1, NULL
, 0 );
838 LPWSTR wszCmd
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
839 if (wszCmd
&& MultiByteToWideChar(CP_ACP
, 0, cmd
, -1, wszCmd
, len
))
841 Control_RunDLLW(hWnd
, hInst
, wszCmd
, nCmdShow
);
843 HeapFree(GetProcessHeap(), 0, wszCmd
);
846 /*************************************************************************
847 * Control_FillCache_RunDLLW [SHELL32.@]
850 HRESULT WINAPI
Control_FillCache_RunDLLW(HWND hWnd
, HANDLE hModule
, DWORD w
, DWORD x
)
852 FIXME("%p %p 0x%08x 0x%08x stub\n", hWnd
, hModule
, w
, x
);
856 /*************************************************************************
857 * Control_FillCache_RunDLLA [SHELL32.@]
860 HRESULT WINAPI
Control_FillCache_RunDLLA(HWND hWnd
, HANDLE hModule
, DWORD w
, DWORD x
)
862 return Control_FillCache_RunDLLW(hWnd
, hModule
, w
, x
);
866 /*************************************************************************
867 * RunDLL_CallEntry16 [SHELL32.122]
868 * the name is probably wrong
870 void WINAPI
RunDLL_CallEntry16( DWORD proc
, HWND hwnd
, HINSTANCE inst
,
871 LPCSTR cmdline
, INT cmdshow
)
876 TRACE( "proc %x hwnd %p inst %p cmdline %s cmdshow %d\n",
877 proc
, hwnd
, inst
, debugstr_a(cmdline
), cmdshow
);
879 cmdline_seg
= MapLS( cmdline
);
880 args
[4] = HWND_16(hwnd
);
881 args
[3] = MapHModuleLS(inst
);
882 args
[2] = SELECTOROF(cmdline_seg
);
883 args
[1] = OFFSETOF(cmdline_seg
);
885 WOWCallback16Ex( proc
, WCB16_PASCAL
, sizeof(args
), args
, NULL
);
886 UnMapLS( cmdline_seg
);
889 /*************************************************************************
890 * CallCPLEntry16 [SHELL32.166]
892 * called by desk.cpl on "Advanced" with:
893 * hMod("DeskCp16.Dll"), pFunc("CplApplet"), 0, 1, 0xc, 0
896 DWORD WINAPI
CallCPLEntry16(HMODULE hMod
, FARPROC pFunc
, DWORD dw3
, DWORD dw4
, DWORD dw5
, DWORD dw6
)
898 FIXME("(%p, %p, %08x, %08x, %08x, %08x): stub.\n", hMod
, pFunc
, dw3
, dw4
, dw5
, dw6
);