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/debug.h"
34 #include "wine/unicode.h"
37 #define NO_SHLWAPI_REG
42 #include "shell32_main.h"
44 #define MAX_STRING_LEN 1024
46 WINE_DEFAULT_DEBUG_CHANNEL(shlctrl
);
48 void Control_UnloadApplet(CPlApplet
* applet
)
52 for (i
= 0; i
< applet
->count
; i
++)
53 applet
->proc(applet
->hWnd
, CPL_STOP
, i
, applet
->info
[i
].data
);
55 if (applet
->proc
) applet
->proc(applet
->hWnd
, CPL_EXIT
, 0L, 0L);
56 FreeLibrary(applet
->hModule
);
57 list_remove( &applet
->entry
);
58 heap_free(applet
->cmd
);
62 CPlApplet
* Control_LoadApplet(HWND hWnd
, LPCWSTR cmd
, CPanel
* panel
)
70 if (!(applet
= heap_alloc_zero(sizeof(*applet
))))
73 len
= ExpandEnvironmentStringsW(cmd
, NULL
, 0);
76 if (!(applet
->cmd
= heap_alloc((len
+1) * sizeof(WCHAR
))))
78 WARN("Cannot allocate memory for applet path\n");
81 ExpandEnvironmentStringsW(cmd
, applet
->cmd
, len
+1);
85 WARN("Cannot expand applet path\n");
91 if (!(applet
->hModule
= LoadLibraryW(applet
->cmd
))) {
92 WARN("Cannot load control panel applet %s\n", debugstr_w(applet
->cmd
));
95 if (!(applet
->proc
= (APPLET_PROC
)GetProcAddress(applet
->hModule
, "CPlApplet"))) {
96 WARN("Not a valid control panel applet %s\n", debugstr_w(applet
->cmd
));
99 if (!applet
->proc(hWnd
, CPL_INIT
, 0L, 0L)) {
100 WARN("Init of applet has failed\n");
103 if ((applet
->count
= applet
->proc(hWnd
, CPL_GETCOUNT
, 0L, 0L)) == 0) {
104 WARN("No subprogram in applet\n");
105 applet
->proc(applet
->hWnd
, CPL_EXIT
, 0, 0);
109 applet
= HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, applet
,
110 FIELD_OFFSET( CPlApplet
, info
[applet
->count
] ));
112 for (i
= 0; i
< applet
->count
; i
++) {
113 ZeroMemory(&newinfo
, sizeof(newinfo
));
114 newinfo
.dwSize
= sizeof(NEWCPLINFOA
);
115 applet
->info
[i
].helpfile
[0] = 0;
116 /* proc is supposed to return a null value upon success for
117 * CPL_INQUIRE and CPL_NEWINQUIRE
118 * However, real drivers don't seem to behave like this
119 * So, use introspection rather than return value
121 applet
->proc(hWnd
, CPL_INQUIRE
, i
, (LPARAM
)&info
);
122 applet
->info
[i
].data
= info
.lData
;
123 if (info
.idIcon
!= CPL_DYNAMIC_RES
)
124 applet
->info
[i
].icon
= LoadIconW(applet
->hModule
, MAKEINTRESOURCEW(info
.idIcon
));
125 if (info
.idName
!= CPL_DYNAMIC_RES
)
126 LoadStringW(applet
->hModule
, info
.idName
,
127 applet
->info
[i
].name
, ARRAY_SIZE(applet
->info
[i
].name
));
128 if (info
.idInfo
!= CPL_DYNAMIC_RES
)
129 LoadStringW(applet
->hModule
, info
.idInfo
,
130 applet
->info
[i
].info
, ARRAY_SIZE(applet
->info
[i
].info
));
132 /* some broken control panels seem to return incorrect values in CPL_INQUIRE,
133 but proper data in CPL_NEWINQUIRE. if we get an empty string or a null
134 icon, see what we can get from CPL_NEWINQUIRE */
136 if (!applet
->info
[i
].name
[0]) info
.idName
= CPL_DYNAMIC_RES
;
138 /* zero-length szInfo may not be a buggy applet, but it doesn't hurt for us
141 if (!applet
->info
[i
].info
[0]) info
.idInfo
= CPL_DYNAMIC_RES
;
143 if (applet
->info
[i
].icon
== NULL
)
144 info
.idIcon
= CPL_DYNAMIC_RES
;
146 if ((info
.idIcon
== CPL_DYNAMIC_RES
) || (info
.idName
== CPL_DYNAMIC_RES
) ||
147 (info
.idInfo
== CPL_DYNAMIC_RES
)) {
148 applet
->proc(hWnd
, CPL_NEWINQUIRE
, i
, (LPARAM
)&newinfo
);
150 applet
->info
[i
].data
= newinfo
.lData
;
151 if (info
.idIcon
== CPL_DYNAMIC_RES
) {
152 if (!newinfo
.hIcon
) WARN("couldn't get icon for applet %u\n", i
);
153 applet
->info
[i
].icon
= newinfo
.hIcon
;
155 if (newinfo
.dwSize
== sizeof(NEWCPLINFOW
)) {
156 if (info
.idName
== CPL_DYNAMIC_RES
)
157 memcpy(applet
->info
[i
].name
, newinfo
.szName
, sizeof(newinfo
.szName
));
158 if (info
.idInfo
== CPL_DYNAMIC_RES
)
159 memcpy(applet
->info
[i
].info
, newinfo
.szInfo
, sizeof(newinfo
.szInfo
));
160 memcpy(applet
->info
[i
].helpfile
, newinfo
.szHelpFile
, sizeof(newinfo
.szHelpFile
));
162 NEWCPLINFOA
*infoA
= (NEWCPLINFOA
*)&newinfo
;
164 if (info
.idName
== CPL_DYNAMIC_RES
)
165 MultiByteToWideChar(CP_ACP
, 0, infoA
->szName
, ARRAY_SIZE(infoA
->szName
),
166 applet
->info
[i
].name
, ARRAY_SIZE(applet
->info
[i
].name
));
167 if (info
.idInfo
== CPL_DYNAMIC_RES
)
168 MultiByteToWideChar(CP_ACP
, 0, infoA
->szInfo
, ARRAY_SIZE(infoA
->szInfo
),
169 applet
->info
[i
].info
, ARRAY_SIZE(applet
->info
[i
].info
));
170 MultiByteToWideChar(CP_ACP
, 0, infoA
->szHelpFile
, ARRAY_SIZE(infoA
->szHelpFile
),
171 applet
->info
[i
].helpfile
, ARRAY_SIZE(applet
->info
[i
].helpfile
));
176 list_add_head( &panel
->applets
, &applet
->entry
);
180 FreeLibrary(applet
->hModule
);
181 heap_free(applet
->cmd
);
186 #define IDC_LISTVIEW 1000
187 #define IDC_STATUSBAR 1001
189 #define NUM_COLUMNS 2
190 #define LISTVIEW_DEFSTYLE (WS_CHILD | WS_VISIBLE | WS_TABSTOP |\
191 LVS_SORTASCENDING | LVS_AUTOARRANGE | LVS_SINGLESEL)
193 static BOOL
Control_CreateListView (CPanel
*panel
)
195 static const WCHAR empty_string
[] = {0};
197 WCHAR buf
[MAX_STRING_LEN
];
200 /* Create list view */
201 GetClientRect(panel
->hWndStatusBar
, &sb
);
202 GetClientRect(panel
->hWnd
, &ws
);
204 panel
->hWndListView
= CreateWindowExW(WS_EX_CLIENTEDGE
, WC_LISTVIEWW
,
205 empty_string
, LISTVIEW_DEFSTYLE
| LVS_ICON
,
206 0, 0, ws
.right
- ws
.left
, ws
.bottom
- ws
.top
-
207 (sb
.bottom
- sb
.top
), panel
->hWnd
,
208 (HMENU
) IDC_LISTVIEW
, panel
->hInst
, NULL
);
210 if (!panel
->hWndListView
)
213 /* Create image lists for list view */
214 panel
->hImageListSmall
= ImageList_Create(GetSystemMetrics(SM_CXSMICON
),
215 GetSystemMetrics(SM_CYSMICON
), ILC_COLOR32
| ILC_MASK
, 1, 1);
216 panel
->hImageListLarge
= ImageList_Create(GetSystemMetrics(SM_CXICON
),
217 GetSystemMetrics(SM_CYICON
), ILC_COLOR32
| ILC_MASK
, 1, 1);
219 SendMessageW(panel
->hWndListView
, LVM_SETIMAGELIST
, LVSIL_SMALL
, (LPARAM
)panel
->hImageListSmall
);
220 SendMessageW(panel
->hWndListView
, LVM_SETIMAGELIST
, LVSIL_NORMAL
, (LPARAM
)panel
->hImageListLarge
);
222 /* Create columns for list view */
223 lvc
.mask
= LVCF_FMT
| LVCF_TEXT
| LVCF_SUBITEM
| LVCF_WIDTH
;
225 lvc
.fmt
= LVCFMT_LEFT
;
229 lvc
.cx
= (ws
.right
- ws
.left
) / 3;
230 LoadStringW(shell32_hInstance
, IDS_CPANEL_NAME
, buf
, ARRAY_SIZE(buf
));
232 if (ListView_InsertColumnW(panel
->hWndListView
, 0, &lvc
) == -1)
235 /* Description column */
237 lvc
.cx
= ((ws
.right
- ws
.left
) / 3) * 2;
238 LoadStringW(shell32_hInstance
, IDS_CPANEL_DESCRIPTION
, buf
, ARRAY_SIZE(buf
));
240 if (ListView_InsertColumnW(panel
->hWndListView
, 1, &lvc
) == -1)
246 static void Control_WndProc_Create(HWND hWnd
, const CREATESTRUCTW
* cs
)
248 CPanel
* panel
= cs
->lpCreateParams
;
249 HMENU hMenu
, hSubMenu
;
253 int menucount
, index
;
256 INITCOMMONCONTROLSEX icex
;
260 SetWindowLongPtrW(hWnd
, 0, (LONG_PTR
)panel
);
263 /* Initialise common control DLL */
264 icex
.dwSize
= sizeof(INITCOMMONCONTROLSEX
);
265 icex
.dwICC
= ICC_LISTVIEW_CLASSES
| ICC_BAR_CLASSES
;
266 InitCommonControlsEx(&icex
);
268 /* create the status bar */
269 if (!(panel
->hWndStatusBar
= CreateStatusWindowW(WS_CHILD
| WS_VISIBLE
| CCS_BOTTOM
| SBARS_SIZEGRIP
, NULL
, hWnd
, IDC_STATUSBAR
)))
273 SendMessageW(panel
->hWndStatusBar
, SB_SETPARTS
, 1, (LPARAM
) &sb_parts
);
275 /* create the list view */
276 if (!Control_CreateListView(panel
))
279 hMenu
= LoadMenuW(shell32_hInstance
, MAKEINTRESOURCEW(MENU_CPANEL
));
281 /* insert menu items for applets */
282 hSubMenu
= GetSubMenu(hMenu
, 0);
285 LIST_FOR_EACH_ENTRY( applet
, &panel
->applets
, CPlApplet
, entry
)
287 for (i
= 0; i
< applet
->count
; i
++) {
288 /* set up a CPlItem for this particular subprogram */
289 item
= heap_alloc(sizeof(CPlItem
));
294 item
->applet
= applet
;
297 mii
.cbSize
= sizeof(MENUITEMINFOW
);
298 mii
.fMask
= MIIM_ID
| MIIM_STRING
| MIIM_DATA
;
299 mii
.dwTypeData
= applet
->info
[i
].name
;
300 mii
.cch
= ARRAY_SIZE(applet
->info
[i
].name
);
301 mii
.wID
= IDM_CPANEL_APPLET_BASE
+ menucount
;
302 mii
.dwItemData
= (ULONG_PTR
)item
;
304 if (InsertMenuItemW(hSubMenu
, menucount
, TRUE
, &mii
)) {
305 /* add the list view item */
306 HICON icon
= applet
->info
[i
].icon
;
307 if (!icon
) icon
= LoadImageW( 0, (LPCWSTR
)IDI_WINLOGO
, IMAGE_ICON
, 0, 0, LR_SHARED
);
308 index
= ImageList_AddIcon(panel
->hImageListLarge
, icon
);
309 ImageList_AddIcon(panel
->hImageListSmall
, icon
);
311 lvItem
.mask
= LVIF_IMAGE
| LVIF_TEXT
| LVIF_PARAM
;
312 lvItem
.iItem
= menucount
;
314 lvItem
.pszText
= applet
->info
[i
].name
;
315 lvItem
.iImage
= index
;
316 lvItem
.lParam
= (LPARAM
) item
;
318 itemidx
= ListView_InsertItemW(panel
->hWndListView
, &lvItem
);
320 /* add the description */
321 ListView_SetItemTextW(panel
->hWndListView
, itemidx
, 1, applet
->info
[i
].info
);
323 /* update menu bar, increment count */
330 panel
->total_subprogs
= menucount
;
332 /* check the "large items" icon in the View menu */
333 hSubMenu
= GetSubMenu(hMenu
, 1);
334 CheckMenuRadioItem(hSubMenu
, FCIDM_SHVIEW_BIGICON
, FCIDM_SHVIEW_REPORTVIEW
,
335 FCIDM_SHVIEW_BIGICON
, MF_BYCOMMAND
);
337 SetMenu(hWnd
, hMenu
);
340 static void Control_FreeCPlItems(HWND hWnd
, CPanel
*panel
)
342 HMENU hMenu
, hSubMenu
;
346 /* get the File menu */
347 hMenu
= GetMenu(hWnd
);
352 hSubMenu
= GetSubMenu(hMenu
, 0);
357 /* loop and free the item data */
358 for (i
= IDM_CPANEL_APPLET_BASE
; i
<= IDM_CPANEL_APPLET_BASE
+ panel
->total_subprogs
; i
++)
360 mii
.cbSize
= sizeof(MENUITEMINFOW
);
361 mii
.fMask
= MIIM_DATA
;
363 if (!GetMenuItemInfoW(hSubMenu
, i
, FALSE
, &mii
))
366 heap_free((void *)mii
.dwItemData
);
370 static void Control_UpdateListViewStyle(CPanel
*panel
, UINT style
, UINT id
)
372 HMENU hMenu
, hSubMenu
;
374 SetWindowLongW(panel
->hWndListView
, GWL_STYLE
, LISTVIEW_DEFSTYLE
| style
);
376 /* update the menu */
377 hMenu
= GetMenu(panel
->hWnd
);
378 hSubMenu
= GetSubMenu(hMenu
, 1);
380 CheckMenuRadioItem(hSubMenu
, FCIDM_SHVIEW_BIGICON
, FCIDM_SHVIEW_REPORTVIEW
,
384 static CPlItem
* Control_GetCPlItem_From_MenuID(HWND hWnd
, UINT id
)
386 HMENU hMenu
, hSubMenu
;
389 /* retrieve the CPlItem structure from the menu item data */
390 hMenu
= GetMenu(hWnd
);
395 hSubMenu
= GetSubMenu(hMenu
, 0);
400 mii
.cbSize
= sizeof(MENUITEMINFOW
);
401 mii
.fMask
= MIIM_DATA
;
403 if (!GetMenuItemInfoW(hSubMenu
, id
, FALSE
, &mii
))
406 return (CPlItem
*) mii
.dwItemData
;
409 static CPlItem
* Control_GetCPlItem_From_ListView(CPanel
*panel
)
414 selitem
= SendMessageW(panel
->hWndListView
, LVM_GETNEXTITEM
, -1, LVNI_FOCUSED
419 lvItem
.iItem
= selitem
;
420 lvItem
.mask
= LVIF_PARAM
;
422 if (SendMessageW(panel
->hWndListView
, LVM_GETITEMW
, 0, (LPARAM
) &lvItem
))
423 return (CPlItem
*) lvItem
.lParam
;
429 static void Control_StartApplet(HWND hWnd
, CPlItem
*item
)
431 static const WCHAR verbOpen
[] = {'c','p','l','o','p','e','n',0};
432 static const WCHAR format
[] = {'@','%','d',0};
433 WCHAR param
[MAX_PATH
];
435 /* execute the applet if item is valid */
438 wsprintfW(param
, format
, item
->id
);
439 ShellExecuteW(hWnd
, verbOpen
, item
->applet
->cmd
, param
, NULL
, SW_SHOW
);
443 static LRESULT WINAPI
Control_WndProc(HWND hWnd
, UINT wMsg
,
444 WPARAM lParam1
, LPARAM lParam2
)
446 CPanel
* panel
= (CPanel
*)GetWindowLongPtrW(hWnd
, 0);
448 if (panel
|| wMsg
== WM_CREATE
) {
451 Control_WndProc_Create(hWnd
, (CREATESTRUCTW
*)lParam2
);
455 CPlApplet
*applet
, *next
;
456 LIST_FOR_EACH_ENTRY_SAFE( applet
, next
, &panel
->applets
, CPlApplet
, entry
)
457 Control_UnloadApplet(applet
);
459 Control_FreeCPlItems(hWnd
, panel
);
463 switch (LOWORD(lParam1
))
465 case IDM_CPANEL_EXIT
:
466 SendMessageW(hWnd
, WM_CLOSE
, 0, 0);
469 case IDM_CPANEL_ABOUT
:
471 WCHAR appName
[MAX_STRING_LEN
];
472 HICON icon
= LoadImageW(shell32_hInstance
, MAKEINTRESOURCEW(IDI_SHELL_CONTROL_PANEL
),
473 IMAGE_ICON
, 48, 48, LR_SHARED
);
475 LoadStringW(shell32_hInstance
, IDS_CPANEL_TITLE
, appName
, ARRAY_SIZE(appName
));
476 ShellAboutW(hWnd
, appName
, NULL
, icon
);
481 case FCIDM_SHVIEW_BIGICON
:
482 Control_UpdateListViewStyle(panel
, LVS_ICON
, FCIDM_SHVIEW_BIGICON
);
485 case FCIDM_SHVIEW_SMALLICON
:
486 Control_UpdateListViewStyle(panel
, LVS_SMALLICON
, FCIDM_SHVIEW_SMALLICON
);
489 case FCIDM_SHVIEW_LISTVIEW
:
490 Control_UpdateListViewStyle(panel
, LVS_LIST
, FCIDM_SHVIEW_LISTVIEW
);
493 case FCIDM_SHVIEW_REPORTVIEW
:
494 Control_UpdateListViewStyle(panel
, LVS_REPORT
, FCIDM_SHVIEW_REPORTVIEW
);
498 /* check if this is an applet */
499 if ((LOWORD(lParam1
) >= IDM_CPANEL_APPLET_BASE
) &&
500 (LOWORD(lParam1
) <= IDM_CPANEL_APPLET_BASE
+ panel
->total_subprogs
))
502 Control_StartApplet(hWnd
, Control_GetCPlItem_From_MenuID(hWnd
, LOWORD(lParam1
)));
513 LPNMHDR nmh
= (LPNMHDR
) lParam2
;
523 Control_StartApplet(hWnd
, Control_GetCPlItem_From_ListView(panel
));
526 case LVN_ITEMCHANGED
:
528 CPlItem
*item
= Control_GetCPlItem_From_ListView(panel
);
530 /* update the status bar if item is valid */
532 SetWindowTextW(panel
->hWndStatusBar
, item
->applet
->info
[item
->id
].info
);
534 SetWindowTextW(panel
->hWndStatusBar
, NULL
);
547 /* check if this is an applet */
548 if ((LOWORD(lParam1
) >= IDM_CPANEL_APPLET_BASE
) &&
549 (LOWORD(lParam1
) <= IDM_CPANEL_APPLET_BASE
+ panel
->total_subprogs
))
551 CPlItem
*item
= Control_GetCPlItem_From_MenuID(hWnd
, LOWORD(lParam1
));
553 /* update the status bar if item is valid */
555 SetWindowTextW(panel
->hWndStatusBar
, item
->applet
->info
[item
->id
].info
);
557 else if ((HIWORD(lParam1
) == 0xFFFF) && (lParam2
== 0))
559 /* reset status bar description to that of the selected icon */
560 CPlItem
*item
= Control_GetCPlItem_From_ListView(panel
);
563 SetWindowTextW(panel
->hWndStatusBar
, item
->applet
->info
[item
->id
].info
);
565 SetWindowTextW(panel
->hWndStatusBar
, NULL
);
570 SetWindowTextW(panel
->hWndStatusBar
, NULL
);
579 hdwp
= BeginDeferWindowPos(2);
584 GetClientRect(panel
->hWndStatusBar
, &sb
);
586 hdwp
= DeferWindowPos(hdwp
, panel
->hWndListView
, NULL
, 0, 0,
587 LOWORD(lParam2
), HIWORD(lParam2
) - (sb
.bottom
- sb
.top
),
588 SWP_NOZORDER
| SWP_NOMOVE
);
593 hdwp
= DeferWindowPos(hdwp
, panel
->hWndStatusBar
, NULL
, 0, 0,
594 LOWORD(lParam2
), LOWORD(lParam1
), SWP_NOZORDER
| SWP_NOMOVE
);
597 EndDeferWindowPos(hdwp
);
604 return DefWindowProcW(hWnd
, wMsg
, lParam1
, lParam2
);
607 static void Control_DoInterface(CPanel
* panel
, HWND hWnd
, HINSTANCE hInst
)
609 static 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};
613 WCHAR appName
[MAX_STRING_LEN
];
615 LoadStringW(shell32_hInstance
, IDS_CPANEL_TITLE
, appName
, ARRAY_SIZE(appName
));
617 wc
.cbSize
= sizeof(wc
);
618 wc
.style
= CS_HREDRAW
|CS_VREDRAW
;
619 wc
.lpfnWndProc
= Control_WndProc
;
621 wc
.cbWndExtra
= sizeof(CPlApplet
*);
622 wc
.hInstance
= panel
->hInst
= hInst
;
623 wc
.hIcon
= LoadIconW( shell32_hInstance
, MAKEINTRESOURCEW(IDI_SHELL_CONTROL_PANEL
) );
624 wc
.hCursor
= LoadCursorW( 0, (LPWSTR
)IDC_ARROW
);
625 wc
.hbrBackground
= GetStockObject(WHITE_BRUSH
);
626 wc
.lpszMenuName
= NULL
;
627 wc
.lpszClassName
= className
;
628 wc
.hIconSm
= LoadImageW( shell32_hInstance
, MAKEINTRESOURCEW(IDI_SHELL_CONTROL_PANEL
), IMAGE_ICON
,
629 GetSystemMetrics(SM_CXSMICON
), GetSystemMetrics(SM_CYSMICON
), LR_SHARED
);
631 if (!RegisterClassExW(&wc
)) return;
633 CreateWindowExW(0, wc
.lpszClassName
, appName
,
634 WS_OVERLAPPEDWINDOW
| WS_VISIBLE
,
635 CW_USEDEFAULT
, CW_USEDEFAULT
,
636 CW_USEDEFAULT
, CW_USEDEFAULT
,
637 hWnd
, NULL
, hInst
, panel
);
638 if (!panel
->hWnd
) return;
640 while (GetMessageW(&msg
, 0, 0, 0)) {
641 TranslateMessage(&msg
);
642 DispatchMessageW(&msg
);
646 static void Control_RegisterRegistryApplets(HWND hWnd
, CPanel
*panel
, HKEY hkey_root
, LPCWSTR szRepPath
)
648 WCHAR name
[MAX_PATH
];
649 WCHAR value
[MAX_PATH
];
652 if (RegOpenKeyW(hkey_root
, szRepPath
, &hkey
) == ERROR_SUCCESS
)
658 DWORD nameLen
= MAX_PATH
;
659 DWORD valueLen
= MAX_PATH
;
661 if (RegEnumValueW(hkey
, idx
, name
, &nameLen
, NULL
, NULL
, (LPBYTE
)value
, &valueLen
) != ERROR_SUCCESS
)
664 Control_LoadApplet(hWnd
, value
, panel
);
670 static void Control_DoWindow(CPanel
* panel
, HWND hWnd
, HINSTANCE hInst
)
674 WCHAR buffer
[MAX_PATH
];
675 static const WCHAR wszAllCpl
[] = {'*','.','c','p','l',0};
676 static const WCHAR wszRegPath
[] = {'S','O','F','T','W','A','R','E','\\','M','i','c','r','o','s','o','f','t',
677 '\\','W','i','n','d','o','w','s','\\','C','u','r','r','e','n','t','V','e','r','s','i','o','n',
678 '\\','C','o','n','t','r','o','l',' ','P','a','n','e','l','\\','C','p','l','s',0};
681 /* first add .cpl files in the system directory */
682 GetSystemDirectoryW( buffer
, MAX_PATH
);
683 p
= buffer
+ strlenW(buffer
);
685 lstrcpyW(p
, wszAllCpl
);
687 if ((h
= FindFirstFileW(buffer
, &fd
)) != INVALID_HANDLE_VALUE
) {
689 lstrcpyW(p
, fd
.cFileName
);
690 Control_LoadApplet(hWnd
, buffer
, panel
);
691 } while (FindNextFileW(h
, &fd
));
695 /* now check for cpls in the registry */
696 Control_RegisterRegistryApplets(hWnd
, panel
, HKEY_LOCAL_MACHINE
, wszRegPath
);
697 Control_RegisterRegistryApplets(hWnd
, panel
, HKEY_CURRENT_USER
, wszRegPath
);
699 Control_DoInterface(panel
, hWnd
, hInst
);
702 static void Control_DoLaunch(CPanel
* panel
, HWND hWnd
, LPCWSTR wszCmd
)
718 LPWSTR extraPmtsBuf
= NULL
;
719 LPWSTR extraPmts
= NULL
;
723 buffer
= heap_alloc((lstrlenW(wszCmd
) + 1) * sizeof(*wszCmd
));
726 end
= lstrcpyW(buffer
, wszCmd
);
730 if (ch
== '"') quoted
= !quoted
;
731 if (!quoted
&& (ch
== ' ' || ch
== ',' || ch
== '\0')) {
736 } else if (*beg
== '\0') {
742 if (ch
== '\0') break;
744 if (ch
== ' ') while (end
[1] == ' ') end
++;
748 while ((ptr
= StrChrW(buffer
, '"')))
749 memmove(ptr
, ptr
+1, lstrlenW(ptr
)*sizeof(WCHAR
));
751 /* now check for any quotes in extraPmtsBuf and remove */
752 if (extraPmtsBuf
!= NULL
)
754 beg
= end
= extraPmtsBuf
;
759 if (ch
== '"') quoted
= !quoted
;
760 if (!quoted
&& (ch
== ' ' || ch
== ',' || ch
== '\0')) {
767 if (ch
== '\0') break;
769 if (ch
== ' ') while (end
[1] == ' ') end
++;
774 while ((ptr
= StrChrW(extraPmts
, '"')))
775 memmove(ptr
, ptr
+1, lstrlenW(ptr
)*sizeof(WCHAR
));
777 if (extraPmts
== NULL
)
778 extraPmts
= extraPmtsBuf
;
781 /* Now check if there had been a numerical value in the extra params */
782 if ((extraPmts
) && (*extraPmts
== '@') && (sp
== -1)) {
783 sp
= atoiW(extraPmts
+ 1);
786 TRACE("cmd %s, extra %s, sp %d\n", debugstr_w(buffer
), debugstr_w(extraPmts
), sp
);
788 applet
= Control_LoadApplet(hWnd
, buffer
, panel
);
791 /* we've been given a textual parameter (or none at all) */
793 while ((++sp
) != applet
->count
) {
794 TRACE("sp %d, name %s\n", sp
, debugstr_w(applet
->info
[sp
].name
));
796 if (StrCmpIW(extraPmts
, applet
->info
[sp
].name
) == 0)
801 if (sp
>= applet
->count
) {
802 WARN("Out of bounds (%u >= %u), setting to 0\n", sp
, applet
->count
);
806 if (!applet
->proc(applet
->hWnd
, CPL_STARTWPARMSW
, sp
, (LPARAM
)extraPmts
))
807 applet
->proc(applet
->hWnd
, CPL_DBLCLK
, sp
, applet
->info
[sp
].data
);
809 Control_UnloadApplet(applet
);
815 /*************************************************************************
816 * Control_RunDLLW [SHELL32.@]
819 void WINAPI
Control_RunDLLW(HWND hWnd
, HINSTANCE hInst
, LPCWSTR cmd
, DWORD nCmdShow
)
823 TRACE("(%p, %p, %s, 0x%08x)\n",
824 hWnd
, hInst
, debugstr_w(cmd
), nCmdShow
);
826 memset(&panel
, 0, sizeof(panel
));
827 list_init( &panel
.applets
);
830 Control_DoWindow(&panel
, hWnd
, hInst
);
832 Control_DoLaunch(&panel
, hWnd
, cmd
);
836 /*************************************************************************
837 * Control_RunDLLA [SHELL32.@]
840 void WINAPI
Control_RunDLLA(HWND hWnd
, HINSTANCE hInst
, LPCSTR cmd
, DWORD nCmdShow
)
842 DWORD len
= MultiByteToWideChar(CP_ACP
, 0, cmd
, -1, NULL
, 0 );
843 LPWSTR wszCmd
= heap_alloc(len
* sizeof(WCHAR
));
844 if (wszCmd
&& MultiByteToWideChar(CP_ACP
, 0, cmd
, -1, wszCmd
, len
))
846 Control_RunDLLW(hWnd
, hInst
, wszCmd
, nCmdShow
);
851 /*************************************************************************
852 * Control_FillCache_RunDLLW [SHELL32.@]
855 HRESULT WINAPI
Control_FillCache_RunDLLW(HWND hWnd
, HANDLE hModule
, DWORD w
, DWORD x
)
857 FIXME("%p %p 0x%08x 0x%08x stub\n", hWnd
, hModule
, w
, x
);
861 /*************************************************************************
862 * Control_FillCache_RunDLLA [SHELL32.@]
865 HRESULT WINAPI
Control_FillCache_RunDLLA(HWND hWnd
, HANDLE hModule
, DWORD w
, DWORD x
)
867 return Control_FillCache_RunDLLW(hWnd
, hModule
, w
, x
);
870 /*************************************************************************
871 * CallCPLEntry16 [SHELL32.166]
873 * called by desk.cpl on "Advanced" with:
874 * hMod("DeskCp16.Dll"), pFunc("CplApplet"), 0, 1, 0xc, 0
877 DWORD WINAPI
CallCPLEntry16(HMODULE hMod
, FARPROC pFunc
, DWORD dw3
, DWORD dw4
, DWORD dw5
, DWORD dw6
)
879 FIXME("(%p, %p, %08x, %08x, %08x, %08x): stub.\n", hMod
, pFunc
, dw3
, dw4
, dw5
, dw6
);
883 /*************************************************************************
884 * RunDLL_CallEntry16 [SHELL32.122]
885 * Manually relay this function to make Tages Protection v5 happy
887 void WINAPI
RunDLL_CallEntry16( DWORD proc
, HWND hwnd
, HINSTANCE inst
,
888 LPCSTR cmdline
, INT cmdshow
)
890 static HMODULE shell16
= NULL
;
891 static void (WINAPI
*pRunDLL_CallEntry16
)( DWORD proc
, HWND hwnd
, HINSTANCE inst
,
892 LPCSTR cmdline
, INT cmdshow
) = NULL
;
894 if (!pRunDLL_CallEntry16
)
896 if (!shell16
&& !(shell16
= LoadLibraryA( "shell.dll16" )))
898 if (!(pRunDLL_CallEntry16
= (void *)GetProcAddress( shell16
, "RunDLL_CallEntry16" )))
902 pRunDLL_CallEntry16( proc
, hwnd
, inst
, cmdline
, cmdshow
);