xref: /reactos/dll/win32/shell32/wine/control.c (revision 2d9a4b4a)
1 /* Control Panel management
2  *
3  * Copyright 2001 Eric Pouech
4  * Copyright 2008 Owen Rudge
5  * Copyright 2022 Raymond Czerny
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20  */
21 
22 #include <assert.h>
23 
24 #define WIN32_NO_STATUS
25 #define _INC_WINDOWS
26 
27 #include <windef.h>
28 #include <winbase.h>
29 #define NO_SHLWAPI_REG
30 #include <shlwapi.h>
31 #include <shellapi.h>
32 #define COBJMACROS
33 #include <shlobj.h>
34 #include <shobjidl.h>
35 #include <wine/debug.h>
36 #include <wine/unicode.h>
37 
38 #include <strsafe.h>
39 
40 #include "cpanel.h"
41 #include "shell32_main.h"
42 
43 WINE_DEFAULT_DEBUG_CHANNEL(shlctrl);
44 
Control_UnloadApplet(CPlApplet * applet)45 void Control_UnloadApplet(CPlApplet* applet)
46 {
47     unsigned	i;
48 
49     for (i = 0; i < applet->count; i++)
50         applet->proc(applet->hWnd, CPL_STOP, i, applet->info[i].data);
51 
52     if (applet->proc) applet->proc(applet->hWnd, CPL_EXIT, 0L, 0L);
53     FreeLibrary(applet->hModule);
54 #ifndef __REACTOS__
55     list_remove( &applet->entry );
56 #endif
57     HeapFree(GetProcessHeap(), 0, applet->cmd);
58     HeapFree(GetProcessHeap(), 0, applet);
59 }
60 
Control_LoadApplet(HWND hWnd,LPCWSTR cmd,CPanel * panel)61 CPlApplet*	Control_LoadApplet(HWND hWnd, LPCWSTR cmd, CPanel* panel)
62 {
63 #ifdef __REACTOS__
64     ACTCTXW ActCtx = {sizeof(ACTCTX), ACTCTX_FLAG_RESOURCE_NAME_VALID};
65     ULONG_PTR cookie;
66     BOOL bActivated;
67     WCHAR fileBuffer[MAX_PATH];
68 #endif
69     CPlApplet*	applet;
70     DWORD len;
71     unsigned 	i;
72     CPLINFO	info;
73     NEWCPLINFOW newinfo;
74 
75     if (!(applet = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*applet))))
76        return applet;
77 
78     len = ExpandEnvironmentStringsW(cmd, NULL, 0);
79     if (len > 0)
80     {
81         if (!(applet->cmd = HeapAlloc(GetProcessHeap(), 0, (len+1) * sizeof(WCHAR))))
82         {
83             WARN("Cannot allocate memory for applet path\n");
84             goto theError;
85         }
86         ExpandEnvironmentStringsW(cmd, applet->cmd, len+1);
87     }
88     else
89     {
90         WARN("Cannot expand applet path\n");
91         goto theError;
92     }
93 
94     applet->hWnd = hWnd;
95 
96 #ifdef __REACTOS__
97     StringCchCopy(fileBuffer, MAX_PATH, applet->cmd);
98     if (PathIsFileSpecW(fileBuffer))
99         SearchPath(NULL, fileBuffer, NULL, MAX_PATH, fileBuffer, NULL);
100     ActCtx.lpSource = fileBuffer;
101     ActCtx.lpResourceName = (LPCWSTR)123;
102     applet->hActCtx = CreateActCtx(&ActCtx);
103     bActivated = (applet->hActCtx != INVALID_HANDLE_VALUE ? ActivateActCtx(applet->hActCtx, &cookie) : FALSE);
104 #endif
105 
106     if (!(applet->hModule = LoadLibraryW(applet->cmd))) {
107         WARN("Cannot load control panel applet %s\n", debugstr_w(applet->cmd));
108 	goto theError;
109     }
110     if (!(applet->proc = (APPLET_PROC)GetProcAddress(applet->hModule, "CPlApplet"))) {
111         WARN("Not a valid control panel applet %s\n", debugstr_w(applet->cmd));
112 	goto theError;
113     }
114     if (!applet->proc(hWnd, CPL_INIT, 0L, 0L)) {
115         WARN("Init of applet has failed\n");
116 	goto theError;
117     }
118     if ((applet->count = applet->proc(hWnd, CPL_GETCOUNT, 0L, 0L)) == 0) {
119         WARN("No subprogram in applet\n");
120         applet->proc(applet->hWnd, CPL_EXIT, 0, 0);
121 	goto theError;
122     }
123 
124     applet = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, applet,
125                          FIELD_OFFSET( CPlApplet, info[applet->count] ));
126 
127     for (i = 0; i < applet->count; i++) {
128        ZeroMemory(&newinfo, sizeof(newinfo));
129        newinfo.dwSize = sizeof(NEWCPLINFOA);
130        applet->info[i].helpfile[0] = 0;
131        /* proc is supposed to return a null value upon success for
132 	* CPL_INQUIRE and CPL_NEWINQUIRE
133 	* However, real drivers don't seem to behave like this
134 	* So, use introspection rather than return value
135 	*/
136        applet->proc(hWnd, CPL_INQUIRE, i, (LPARAM)&info);
137        applet->info[i].data = info.lData;
138 #ifdef __REACTOS__
139        applet->info[i].idIcon = info.idIcon;
140 #endif
141 
142        if (info.idIcon != CPL_DYNAMIC_RES)
143 	   applet->info[i].icon = LoadIconW(applet->hModule, MAKEINTRESOURCEW(info.idIcon));
144        if (info.idName != CPL_DYNAMIC_RES)
145 	   LoadStringW(applet->hModule, info.idName,
146 		       applet->info[i].name, sizeof(applet->info[i].name) / sizeof(WCHAR));
147        if (info.idInfo != CPL_DYNAMIC_RES)
148 	   LoadStringW(applet->hModule, info.idInfo,
149 		       applet->info[i].info, sizeof(applet->info[i].info) / sizeof(WCHAR));
150 
151        /* some broken control panels seem to return incorrect values in CPL_INQUIRE,
152           but proper data in CPL_NEWINQUIRE. if we get an empty string or a null
153           icon, see what we can get from CPL_NEWINQUIRE */
154 
155        if (!applet->info[i].name[0]) info.idName = CPL_DYNAMIC_RES;
156 
157        /* zero-length szInfo may not be a buggy applet, but it doesn't hurt for us
158           to check anyway */
159 
160        if (!applet->info[i].info[0]) info.idInfo = CPL_DYNAMIC_RES;
161 
162        if (applet->info[i].icon == NULL)
163            info.idIcon = CPL_DYNAMIC_RES;
164 
165        if ((info.idIcon == CPL_DYNAMIC_RES) || (info.idName == CPL_DYNAMIC_RES) ||
166            (info.idInfo == CPL_DYNAMIC_RES)) {
167 	   applet->proc(hWnd, CPL_NEWINQUIRE, i, (LPARAM)&newinfo);
168 
169 	   applet->info[i].data = newinfo.lData;
170 	   if (info.idIcon == CPL_DYNAMIC_RES) {
171 	       if (!newinfo.hIcon) WARN("couldn't get icon for applet %u\n", i);
172 	       applet->info[i].icon = newinfo.hIcon;
173 	   }
174 	   if (newinfo.dwSize == sizeof(NEWCPLINFOW)) {
175 	       if (info.idName == CPL_DYNAMIC_RES)
176 	           memcpy(applet->info[i].name, newinfo.szName, sizeof(newinfo.szName));
177 	       if (info.idInfo == CPL_DYNAMIC_RES)
178 	           memcpy(applet->info[i].info, newinfo.szInfo, sizeof(newinfo.szInfo));
179 	       memcpy(applet->info[i].helpfile, newinfo.szHelpFile, sizeof(newinfo.szHelpFile));
180 	   } else {
181 	       if (info.idName == CPL_DYNAMIC_RES)
182                    MultiByteToWideChar(CP_ACP, 0, ((LPNEWCPLINFOA)&newinfo)->szName,
183 	                               sizeof(((LPNEWCPLINFOA)&newinfo)->szName) / sizeof(CHAR),
184 			               applet->info[i].name, sizeof(applet->info[i].name) / sizeof(WCHAR));
185 	       if (info.idInfo == CPL_DYNAMIC_RES)
186                    MultiByteToWideChar(CP_ACP, 0, ((LPNEWCPLINFOA)&newinfo)->szInfo,
187 	                               sizeof(((LPNEWCPLINFOA)&newinfo)->szInfo) / sizeof(CHAR),
188 			               applet->info[i].info, sizeof(applet->info[i].info) / sizeof(WCHAR));
189                MultiByteToWideChar(CP_ACP, 0, ((LPNEWCPLINFOA)&newinfo)->szHelpFile,
190 	                           sizeof(((LPNEWCPLINFOA)&newinfo)->szHelpFile) / sizeof(CHAR),
191 			           applet->info[i].helpfile,
192                                    sizeof(applet->info[i].helpfile) / sizeof(WCHAR));
193            }
194        }
195     }
196 
197 #ifdef __REACTOS__
198     if (bActivated)
199         DeactivateActCtx(0, cookie);
200 #endif
201 
202 #ifndef __REACTOS__
203     list_add_head( &panel->applets, &applet->entry );
204 #endif
205 
206     return applet;
207 
208  theError:
209     FreeLibrary(applet->hModule);
210     HeapFree(GetProcessHeap(), 0, applet->cmd);
211     HeapFree(GetProcessHeap(), 0, applet);
212     return NULL;
213 }
214 
215 #ifndef __REACTOS__
216 
217 #define IDC_LISTVIEW        1000
218 #define IDC_STATUSBAR       1001
219 
220 #define NUM_COLUMNS            2
221 #define LISTVIEW_DEFSTYLE   (WS_CHILD | WS_VISIBLE | WS_TABSTOP |\
222                              LVS_SORTASCENDING | LVS_AUTOARRANGE | LVS_SINGLESEL)
223 
Control_CreateListView(CPanel * panel)224 static BOOL Control_CreateListView (CPanel *panel)
225 {
226     RECT ws, sb;
227     WCHAR empty_string[] = {0};
228     WCHAR buf[MAX_STRING_LEN];
229     LVCOLUMNW lvc;
230 
231     /* Create list view */
232     GetClientRect(panel->hWndStatusBar, &sb);
233     GetClientRect(panel->hWnd, &ws);
234 
235     panel->hWndListView = CreateWindowExW(WS_EX_CLIENTEDGE, WC_LISTVIEWW,
236                           empty_string, LISTVIEW_DEFSTYLE | LVS_ICON,
237                           0, 0, ws.right - ws.left, ws.bottom - ws.top -
238                           (sb.bottom - sb.top), panel->hWnd,
239                           (HMENU) IDC_LISTVIEW, panel->hInst, NULL);
240 
241     if (!panel->hWndListView)
242         return FALSE;
243 
244     /* Create image lists for list view */
245     panel->hImageListSmall = ImageList_Create(GetSystemMetrics(SM_CXSMICON),
246         GetSystemMetrics(SM_CYSMICON), ILC_COLOR32 | ILC_MASK, 1, 1);
247     panel->hImageListLarge = ImageList_Create(GetSystemMetrics(SM_CXICON),
248         GetSystemMetrics(SM_CYICON), ILC_COLOR32 | ILC_MASK, 1, 1);
249 
250     SendMessageW(panel->hWndListView, LVM_SETIMAGELIST, LVSIL_SMALL, (LPARAM)panel->hImageListSmall);
251     SendMessageW(panel->hWndListView, LVM_SETIMAGELIST, LVSIL_NORMAL, (LPARAM)panel->hImageListLarge);
252 
253     /* Create columns for list view */
254     lvc.mask = LVCF_FMT | LVCF_TEXT | LVCF_SUBITEM | LVCF_WIDTH;
255     lvc.pszText = buf;
256     lvc.fmt = LVCFMT_LEFT;
257 
258     /* Name column */
259     lvc.iSubItem = 0;
260     lvc.cx = (ws.right - ws.left) / 3;
261     LoadStringW(shell32_hInstance, IDS_CPANEL_NAME, buf, sizeof(buf) / sizeof(buf[0]));
262 
263     if (ListView_InsertColumnW(panel->hWndListView, 0, &lvc) == -1)
264         return FALSE;
265 
266     /* Description column */
267     lvc.iSubItem = 1;
268     lvc.cx = ((ws.right - ws.left) / 3) * 2;
269     LoadStringW(shell32_hInstance, IDS_CPANEL_DESCRIPTION, buf, sizeof(buf) /
270         sizeof(buf[0]));
271 
272     if (ListView_InsertColumnW(panel->hWndListView, 1, &lvc) == -1)
273         return FALSE;
274 
275     return(TRUE);
276 }
277 
Control_WndProc_Create(HWND hWnd,const CREATESTRUCTW * cs)278 static void 	 Control_WndProc_Create(HWND hWnd, const CREATESTRUCTW* cs)
279 {
280    CPanel* panel = cs->lpCreateParams;
281    HMENU hMenu, hSubMenu;
282    CPlApplet* applet;
283    MENUITEMINFOW mii;
284    unsigned int i;
285    int menucount, index;
286    CPlItem *item;
287    LVITEMW lvItem;
288    INITCOMMONCONTROLSEX icex;
289    INT sb_parts;
290    int itemidx;
291 
292    SetWindowLongPtrW(hWnd, 0, (LONG_PTR)panel);
293    panel->hWnd = hWnd;
294 
295    /* Initialise common control DLL */
296    icex.dwSize = sizeof(INITCOMMONCONTROLSEX);
297    icex.dwICC = ICC_LISTVIEW_CLASSES | ICC_BAR_CLASSES;
298    InitCommonControlsEx(&icex);
299 
300    /* create the status bar */
301    if (!(panel->hWndStatusBar = CreateStatusWindowW(WS_CHILD | WS_VISIBLE | CCS_BOTTOM | SBARS_SIZEGRIP, NULL, hWnd, IDC_STATUSBAR)))
302        return;
303 
304    sb_parts = -1;
305    SendMessageW(panel->hWndStatusBar, SB_SETPARTS, 1, (LPARAM) &sb_parts);
306 
307    /* create the list view */
308    if (!Control_CreateListView(panel))
309        return;
310 
311    hMenu = LoadMenuW(shell32_hInstance, MAKEINTRESOURCEW(MENU_CPANEL));
312 
313    /* insert menu items for applets */
314    hSubMenu = GetSubMenu(hMenu, 0);
315    menucount = 0;
316 
317    LIST_FOR_EACH_ENTRY( applet, &panel->applets, CPlApplet, entry )
318    {
319       for (i = 0; i < applet->count; i++) {
320          /* set up a CPlItem for this particular subprogram */
321          item = HeapAlloc(GetProcessHeap(), 0, sizeof(CPlItem));
322 
323          if (!item)
324             continue;
325 
326          item->applet = applet;
327          item->id = i;
328 
329          mii.cbSize = sizeof(MENUITEMINFOW);
330          mii.fMask = MIIM_ID | MIIM_STRING | MIIM_DATA;
331          mii.dwTypeData = applet->info[i].name;
332          mii.cch = sizeof(applet->info[i].name) / sizeof(WCHAR);
333          mii.wID = IDM_CPANEL_APPLET_BASE + menucount;
334          mii.dwItemData = (ULONG_PTR)item;
335 
336          if (InsertMenuItemW(hSubMenu, menucount, TRUE, &mii)) {
337             /* add the list view item */
338             HICON icon = applet->info[i].icon;
339             if (!icon) icon = LoadImageW( 0, (LPCWSTR)IDI_WINLOGO, IMAGE_ICON, 0, 0, LR_SHARED );
340             index = ImageList_AddIcon(panel->hImageListLarge, icon);
341             ImageList_AddIcon(panel->hImageListSmall, icon);
342 
343             lvItem.mask = LVIF_IMAGE | LVIF_TEXT | LVIF_PARAM;
344             lvItem.iItem = menucount;
345             lvItem.iSubItem = 0;
346             lvItem.pszText = applet->info[i].name;
347             lvItem.iImage = index;
348             lvItem.lParam = (LPARAM) item;
349 
350             itemidx = ListView_InsertItemW(panel->hWndListView, &lvItem);
351 
352             /* add the description */
353             ListView_SetItemTextW(panel->hWndListView, itemidx, 1, applet->info[i].info);
354 
355             /* update menu bar, increment count */
356             DrawMenuBar(hWnd);
357             menucount++;
358          }
359       }
360    }
361 
362    panel->total_subprogs = menucount;
363 
364    /* check the "large items" icon in the View menu */
365    hSubMenu = GetSubMenu(hMenu, 1);
366    CheckMenuRadioItem(hSubMenu, FCIDM_SHVIEW_BIGICON, FCIDM_SHVIEW_REPORTVIEW,
367       FCIDM_SHVIEW_BIGICON, MF_BYCOMMAND);
368 
369    SetMenu(hWnd, hMenu);
370 }
371 
Control_FreeCPlItems(HWND hWnd,CPanel * panel)372 static void Control_FreeCPlItems(HWND hWnd, CPanel *panel)
373 {
374     HMENU hMenu, hSubMenu;
375     MENUITEMINFOW mii;
376     unsigned int i;
377 
378     /* get the File menu */
379     hMenu = GetMenu(hWnd);
380 
381     if (!hMenu)
382         return;
383 
384     hSubMenu = GetSubMenu(hMenu, 0);
385 
386     if (!hSubMenu)
387         return;
388 
389     /* loop and free the item data */
390     for (i = IDM_CPANEL_APPLET_BASE; i <= IDM_CPANEL_APPLET_BASE + panel->total_subprogs; i++)
391     {
392         mii.cbSize = sizeof(MENUITEMINFOW);
393         mii.fMask = MIIM_DATA;
394 
395         if (!GetMenuItemInfoW(hSubMenu, i, FALSE, &mii))
396             continue;
397 
398         HeapFree(GetProcessHeap(), 0, (LPVOID) mii.dwItemData);
399     }
400 }
401 
Control_UpdateListViewStyle(CPanel * panel,UINT style,UINT id)402 static void Control_UpdateListViewStyle(CPanel *panel, UINT style, UINT id)
403 {
404     HMENU hMenu, hSubMenu;
405 
406     SetWindowLongW(panel->hWndListView, GWL_STYLE, LISTVIEW_DEFSTYLE | style);
407 
408     /* update the menu */
409     hMenu = GetMenu(panel->hWnd);
410     hSubMenu = GetSubMenu(hMenu, 1);
411 
412     CheckMenuRadioItem(hSubMenu, FCIDM_SHVIEW_BIGICON, FCIDM_SHVIEW_REPORTVIEW,
413         id, MF_BYCOMMAND);
414 }
415 
Control_GetCPlItem_From_MenuID(HWND hWnd,UINT id)416 static CPlItem* Control_GetCPlItem_From_MenuID(HWND hWnd, UINT id)
417 {
418     HMENU hMenu, hSubMenu;
419     MENUITEMINFOW mii;
420 
421     /* retrieve the CPlItem structure from the menu item data */
422     hMenu = GetMenu(hWnd);
423 
424     if (!hMenu)
425         return NULL;
426 
427     hSubMenu = GetSubMenu(hMenu, 0);
428 
429     if (!hSubMenu)
430         return NULL;
431 
432     mii.cbSize = sizeof(MENUITEMINFOW);
433     mii.fMask = MIIM_DATA;
434 
435     if (!GetMenuItemInfoW(hSubMenu, id, FALSE, &mii))
436         return NULL;
437 
438     return (CPlItem *) mii.dwItemData;
439 }
440 
Control_GetCPlItem_From_ListView(CPanel * panel)441 static CPlItem* Control_GetCPlItem_From_ListView(CPanel *panel)
442 {
443     LVITEMW lvItem;
444     int selitem;
445 
446     selitem = SendMessageW(panel->hWndListView, LVM_GETNEXTITEM, -1, LVNI_FOCUSED
447         | LVNI_SELECTED);
448 
449     if (selitem != -1)
450     {
451         lvItem.iItem = selitem;
452         lvItem.mask = LVIF_PARAM;
453 
454         if (SendMessageW(panel->hWndListView, LVM_GETITEMW, 0, (LPARAM) &lvItem))
455             return (CPlItem *) lvItem.lParam;
456     }
457 
458     return NULL;
459 }
460 
Control_StartApplet(HWND hWnd,CPlItem * item)461 static void Control_StartApplet(HWND hWnd, CPlItem *item)
462 {
463     WCHAR verbOpen[] = {'c','p','l','o','p','e','n',0};
464     WCHAR format[] = {'@','%','d',0};
465     WCHAR param[MAX_PATH];
466 
467     /* execute the applet if item is valid */
468     if (item)
469     {
470         wsprintfW(param, format, item->id);
471         ShellExecuteW(hWnd, verbOpen, item->applet->cmd, param, NULL, SW_SHOW);
472     }
473 }
474 
Control_WndProc(HWND hWnd,UINT wMsg,WPARAM lParam1,LPARAM lParam2)475 static LRESULT WINAPI	Control_WndProc(HWND hWnd, UINT wMsg,
476 					WPARAM lParam1, LPARAM lParam2)
477 {
478    CPanel*	panel = (CPanel*)GetWindowLongPtrW(hWnd, 0);
479 
480    if (panel || wMsg == WM_CREATE) {
481       switch (wMsg) {
482       case WM_CREATE:
483 	 Control_WndProc_Create(hWnd, (CREATESTRUCTW*)lParam2);
484 	 return 0;
485       case WM_DESTROY:
486          {
487              CPlApplet *applet, *next;
488              LIST_FOR_EACH_ENTRY_SAFE( applet, next, &panel->applets, CPlApplet, entry )
489                  Control_UnloadApplet(applet);
490          }
491          Control_FreeCPlItems(hWnd, panel);
492          PostQuitMessage(0);
493 	 break;
494       case WM_COMMAND:
495          switch (LOWORD(lParam1))
496          {
497              case IDM_CPANEL_EXIT:
498                  SendMessageW(hWnd, WM_CLOSE, 0, 0);
499                  return 0;
500 
501              case IDM_CPANEL_ABOUT:
502                  {
503                      WCHAR appName[MAX_STRING_LEN];
504                      HICON icon = LoadImageW(shell32_hInstance, MAKEINTRESOURCEW(IDI_SHELL_CONTROL_PANEL),
505                                              IMAGE_ICON, 48, 48, LR_SHARED);
506 
507                      LoadStringW(shell32_hInstance, IDS_CPANEL_TITLE, appName,
508                          sizeof(appName) / sizeof(appName[0]));
509                      ShellAboutW(hWnd, appName, NULL, icon);
510 
511                      return 0;
512                  }
513 
514              case FCIDM_SHVIEW_BIGICON:
515                  Control_UpdateListViewStyle(panel, LVS_ICON, FCIDM_SHVIEW_BIGICON);
516                  return 0;
517 
518              case FCIDM_SHVIEW_SMALLICON:
519                  Control_UpdateListViewStyle(panel, LVS_SMALLICON, FCIDM_SHVIEW_SMALLICON);
520                  return 0;
521 
522              case FCIDM_SHVIEW_LISTVIEW:
523                  Control_UpdateListViewStyle(panel, LVS_LIST, FCIDM_SHVIEW_LISTVIEW);
524                  return 0;
525 
526              case FCIDM_SHVIEW_REPORTVIEW:
527                  Control_UpdateListViewStyle(panel, LVS_REPORT, FCIDM_SHVIEW_REPORTVIEW);
528                  return 0;
529 
530              default:
531                  /* check if this is an applet */
532                  if ((LOWORD(lParam1) >= IDM_CPANEL_APPLET_BASE) &&
533                      (LOWORD(lParam1) <= IDM_CPANEL_APPLET_BASE + panel->total_subprogs))
534                  {
535                      Control_StartApplet(hWnd, Control_GetCPlItem_From_MenuID(hWnd, LOWORD(lParam1)));
536                      return 0;
537                  }
538 
539                  break;
540          }
541 
542          break;
543 
544       case WM_NOTIFY:
545       {
546           LPNMHDR nmh = (LPNMHDR) lParam2;
547 
548           switch (nmh->idFrom)
549           {
550               case IDC_LISTVIEW:
551                   switch (nmh->code)
552                   {
553                       case NM_RETURN:
554                       case NM_DBLCLK:
555                       {
556                           Control_StartApplet(hWnd, Control_GetCPlItem_From_ListView(panel));
557                           return 0;
558                       }
559                       case LVN_ITEMCHANGED:
560                       {
561                           CPlItem *item = Control_GetCPlItem_From_ListView(panel);
562 
563                           /* update the status bar if item is valid */
564                           if (item)
565                               SetWindowTextW(panel->hWndStatusBar, item->applet->info[item->id].info);
566                           else
567                               SetWindowTextW(panel->hWndStatusBar, NULL);
568 
569                           return 0;
570                       }
571                   }
572 
573                   break;
574           }
575 
576           break;
577       }
578 
579       case WM_MENUSELECT:
580           /* check if this is an applet */
581           if ((LOWORD(lParam1) >= IDM_CPANEL_APPLET_BASE) &&
582               (LOWORD(lParam1) <= IDM_CPANEL_APPLET_BASE + panel->total_subprogs))
583           {
584               CPlItem *item = Control_GetCPlItem_From_MenuID(hWnd, LOWORD(lParam1));
585 
586               /* update the status bar if item is valid */
587               if (item)
588                   SetWindowTextW(panel->hWndStatusBar, item->applet->info[item->id].info);
589           }
590           else if ((HIWORD(lParam1) == 0xFFFF) && (lParam2 == 0))
591           {
592               /* reset status bar description to that of the selected icon */
593               CPlItem *item = Control_GetCPlItem_From_ListView(panel);
594 
595               if (item)
596                   SetWindowTextW(panel->hWndStatusBar, item->applet->info[item->id].info);
597               else
598                   SetWindowTextW(panel->hWndStatusBar, NULL);
599 
600               return 0;
601           }
602           else
603               SetWindowTextW(panel->hWndStatusBar, NULL);
604 
605           return 0;
606 
607       case WM_SIZE:
608       {
609           HDWP hdwp;
610           RECT sb;
611 
612           hdwp = BeginDeferWindowPos(2);
613 
614           if (hdwp == NULL)
615               break;
616 
617           GetClientRect(panel->hWndStatusBar, &sb);
618 
619           hdwp = DeferWindowPos(hdwp, panel->hWndListView, NULL, 0, 0,
620               LOWORD(lParam2), HIWORD(lParam2) - (sb.bottom - sb.top),
621               SWP_NOZORDER | SWP_NOMOVE);
622 
623           if (hdwp == NULL)
624               break;
625 
626           hdwp = DeferWindowPos(hdwp, panel->hWndStatusBar, NULL, 0, 0,
627               LOWORD(lParam2), LOWORD(lParam1), SWP_NOZORDER | SWP_NOMOVE);
628 
629           if (hdwp != NULL)
630               EndDeferWindowPos(hdwp);
631 
632           return 0;
633       }
634      }
635    }
636 
637    return DefWindowProcW(hWnd, wMsg, lParam1, lParam2);
638 }
639 
Control_DoInterface(CPanel * panel,HWND hWnd,HINSTANCE hInst)640 static void    Control_DoInterface(CPanel* panel, HWND hWnd, HINSTANCE hInst)
641 {
642     WNDCLASSEXW wc;
643     MSG		msg;
644     WCHAR appName[MAX_STRING_LEN];
645     const WCHAR className[] = {'S','h','e','l','l','_','C','o','n','t','r','o',
646         'l','_','W','n','d','C','l','a','s','s',0};
647 
648     LoadStringW(shell32_hInstance, IDS_CPANEL_TITLE, appName, sizeof(appName) / sizeof(appName[0]));
649 
650     wc.cbSize = sizeof(wc);
651     wc.style = CS_HREDRAW|CS_VREDRAW;
652     wc.lpfnWndProc = Control_WndProc;
653     wc.cbClsExtra = 0;
654     wc.cbWndExtra = sizeof(CPlApplet*);
655     wc.hInstance = panel->hInst = hInst;
656     wc.hIcon = LoadIconW( shell32_hInstance, MAKEINTRESOURCEW(IDI_SHELL_CONTROL_PANEL) );
657     wc.hCursor = LoadCursorW( 0, (LPWSTR)IDC_ARROW );
658     wc.hbrBackground = GetStockObject(WHITE_BRUSH);
659     wc.lpszMenuName = NULL;
660     wc.lpszClassName = className;
661     wc.hIconSm = LoadImageW( shell32_hInstance, MAKEINTRESOURCEW(IDI_SHELL_CONTROL_PANEL), IMAGE_ICON,
662                              GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), LR_SHARED);
663 
664     if (!RegisterClassExW(&wc)) return;
665 
666     CreateWindowExW(0, wc.lpszClassName, appName,
667 		    WS_OVERLAPPEDWINDOW | WS_VISIBLE,
668 		    CW_USEDEFAULT, CW_USEDEFAULT,
669 		    CW_USEDEFAULT, CW_USEDEFAULT,
670 		    hWnd, NULL, hInst, panel);
671     if (!panel->hWnd) return;
672 
673     while (GetMessageW(&msg, panel->hWnd, 0, 0)) {
674         TranslateMessage(&msg);
675         DispatchMessageW(&msg);
676     }
677 }
678 
Control_RegisterRegistryApplets(HWND hWnd,CPanel * panel,HKEY hkey_root,LPCWSTR szRepPath)679 static void Control_RegisterRegistryApplets(HWND hWnd, CPanel *panel, HKEY hkey_root, LPCWSTR szRepPath)
680 {
681     WCHAR name[MAX_PATH];
682     WCHAR value[MAX_PATH];
683     HKEY hkey;
684 
685     if (RegOpenKeyW(hkey_root, szRepPath, &hkey) == ERROR_SUCCESS)
686     {
687         int idx = 0;
688 
689         for(;; ++idx)
690         {
691             DWORD nameLen = MAX_PATH;
692             DWORD valueLen = MAX_PATH;
693 
694             if (RegEnumValueW(hkey, idx, name, &nameLen, NULL, NULL, (LPBYTE)value, &valueLen) != ERROR_SUCCESS)
695                 break;
696 
697             Control_LoadApplet(hWnd, value, panel);
698         }
699         RegCloseKey(hkey);
700     }
701 }
702 
Control_DoWindow(CPanel * panel,HWND hWnd,HINSTANCE hInst)703 static	void	Control_DoWindow(CPanel* panel, HWND hWnd, HINSTANCE hInst)
704 {
705     static const WCHAR wszRegPath[] = L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Control Panel\\Cpls";
706     HANDLE		h;
707     WIN32_FIND_DATAW	fd;
708     WCHAR		buffer[MAX_PATH];
709     WCHAR *p;
710 
711     /* first add .cpl files in the system directory */
712     GetSystemDirectoryW( buffer, MAX_PATH );
713     p = buffer + strlenW(buffer);
714     *p++ = '\\';
715     lstrcpyW(p, L"*.cpl");
716 
717     if ((h = FindFirstFileW(buffer, &fd)) != INVALID_HANDLE_VALUE) {
718         do {
719 	   lstrcpyW(p, fd.cFileName);
720 	   Control_LoadApplet(hWnd, buffer, panel);
721 	} while (FindNextFileW(h, &fd));
722 	FindClose(h);
723     }
724 
725     /* now check for cpls in the registry */
726     Control_RegisterRegistryApplets(hWnd, panel, HKEY_LOCAL_MACHINE, wszRegPath);
727     Control_RegisterRegistryApplets(hWnd, panel, HKEY_CURRENT_USER, wszRegPath);
728 
729     Control_DoInterface(panel, hWnd, hInst);
730 }
731 
732 #else
Control_DoWindow(CPanel * panel,HWND hWnd,HINSTANCE hInst)733 static	void	Control_DoWindow(CPanel* panel, HWND hWnd, HINSTANCE hInst)
734 {
735     /* NOTE: If Explorer shell is not available, use ReactOS's alternative file browser instead */
736     ShellExecuteW(NULL,
737                   L"open",
738                   GetShellWindow() ? L"explorer.exe" : L"filebrowser.exe",
739                   L"::{20D04FE0-3AEA-1069-A2D8-08002B30309D}\\::{21EC2020-3AEA-1069-A2DD-08002B30309D}",
740                   NULL,
741                   SW_SHOWDEFAULT);
742 }
743 #endif
744 
745 #ifdef __REACTOS__
746 
747 /** Structure for in and out data when
748  *  search for the cpl dialog of first instance
749  */
750 typedef struct tagAppDlgFindData
751 {
752     PCWSTR    szAppFile;  /**< Full path to applet library as search parameter */
753     UINT_PTR  sAppletNo;  /**< Number of applet in a system control library as search parameter */
754     ATOM      aCPLName;   /**< to read window property 'CPLName' */
755     ATOM      aCPLFlags;  /**< to read window property 'CPLFlags'*/
756     HWND      hRunDLL;    /**< to skip self instance */
757     HWND      hDlgResult; /**< Returned dialog handle or NULL if not found */
758 } AppDlgFindData;
759 
760 /**
761  * Callback function to search applet dialog
762  * @param hwnd A handle to a top-level window.
763  * @param lParam Pointer of AppDlgFindData
764  * @return TRUE: continue enumeration, FALSE: stop enumeration
765  */
766 static BOOL CALLBACK
Control_EnumWinProc(_In_ HWND hwnd,_In_ LPARAM lParam)767 Control_EnumWinProc(
768     _In_ HWND   hwnd,
769     _In_ LPARAM lParam)
770 {
771     AppDlgFindData* pData = (AppDlgFindData*)lParam;
772     UINT_PTR sAppletNo;
773     HANDLE hRes;
774     WCHAR szAppFile[MAX_PATH];
775 
776     if (pData->hRunDLL == hwnd)
777         return TRUE; /* Skip self instance */
778 
779     sAppletNo = (UINT_PTR)GetPropW(hwnd, (LPTSTR)MAKEINTATOM(pData->aCPLFlags));
780     if (sAppletNo != pData->sAppletNo)
781         return TRUE; /* Continue enumeration */
782 
783     hRes = GetPropW(hwnd, (LPTSTR)MAKEINTATOM(pData->aCPLName));
784     GlobalGetAtomNameW((ATOM)HandleToUlong(hRes), szAppFile, _countof(szAppFile));
785     if (wcscmp(szAppFile, pData->szAppFile) == 0)
786     {
787         HWND hDialog = GetLastActivePopup(hwnd);
788         if (IsWindow(hDialog))
789         {
790             pData->hDlgResult = hDialog;
791             return FALSE; /* Stop enumeration */
792         }
793     }
794 
795     return TRUE; /* Continue enumeration */
796 }
797 
798 /**
799  * This function makes the system control applet accessible via the taskbar.
800  *
801  * @param applet
802  * Pointer of system control applet.
803  *
804  * @param index
805  * Number of applet in a system control library.
806  */
807 static void
Control_ShowAppletInTaskbar(CPlApplet * applet,UINT index)808 Control_ShowAppletInTaskbar(CPlApplet* applet, UINT index)
809 {
810     HICON hSmallIcon;
811     ITaskbarList* pTaskbar = NULL;
812 
813     /* Try to add a taskbar button only if the applet's parent window is the desktop */
814     if (GetParent(applet->hWnd) != NULL)
815     {
816         return;
817     }
818 
819     SetWindowTextW(applet->hWnd, applet->info[index].name);
820 
821     /* Set large icon for the taskbar button */
822     if (applet->info[index].icon)
823     {
824         SendMessageW(applet->hWnd, WM_SETICON, ICON_BIG, (LPARAM)applet->info[index].icon);
825     }
826 
827     /* Try loading the small icon for the taskbar button */
828     hSmallIcon = (HICON)LoadImageW(applet->hModule,
829                                    MAKEINTRESOURCEW(applet->info[index].idIcon),
830                                    IMAGE_ICON,
831                                    GetSystemMetrics(SM_CXSMICON),
832                                    GetSystemMetrics(SM_CYSMICON),
833                                    0);
834     if (hSmallIcon)
835     {
836         SendMessageW(applet->hWnd, WM_SETICON, ICON_SMALL, (LPARAM)hSmallIcon);
837     }
838     else
839     {
840         if (applet->info[index].icon)
841         {
842             SendMessageW(applet->hWnd, WM_SETICON, ICON_SMALL, (LPARAM)applet->info[index].icon);
843         }
844     }
845 
846     /* Add button to the taskbar */
847     ShowWindow(applet->hWnd, SW_SHOWMINNOACTIVE);
848 
849     /* Activate the corresponding button in the taskbar */
850     CoInitialize(NULL);
851     if (CoCreateInstance(&CLSID_TaskbarList,
852                          NULL, CLSCTX_INPROC_SERVER,
853                          &IID_ITaskbarList,
854                          (LPVOID*)&pTaskbar) == S_OK)
855     {
856         if (ITaskbarList_HrInit(pTaskbar) == S_OK)
857         {
858             ITaskbarList_ActivateTab(pTaskbar, applet->hWnd);
859         }
860         ITaskbarList_Release(pTaskbar);
861     }
862     CoUninitialize();
863 }
864 
865 #endif /* __REACTOS__ */
866 
Control_DoLaunch(CPanel * panel,HWND hWnd,LPCWSTR wszCmd)867 static	void	Control_DoLaunch(CPanel* panel, HWND hWnd, LPCWSTR wszCmd)
868    /* forms to parse:
869     *	foo.cpl,@sp,str
870     *	foo.cpl,@sp
871     *	foo.cpl,,str
872     *	foo.cpl @sp
873     *	foo.cpl str
874     *   "a path\foo.cpl"
875     */
876 {
877 #ifndef __REACTOS__
878     LPWSTR	buffer;
879     LPWSTR	beg = NULL;
880     LPWSTR	end;
881     WCHAR	ch;
882     LPWSTR       ptr;
883     signed 	sp = -1;
884     LPWSTR	extraPmtsBuf = NULL;
885     LPWSTR	extraPmts = NULL;
886     BOOL        quoted = FALSE;
887     CPlApplet *applet;
888 
889     buffer = HeapAlloc(GetProcessHeap(), 0, (lstrlenW(wszCmd) + 1) * sizeof(*wszCmd));
890     if (!buffer) return;
891 
892     end = lstrcpyW(buffer, wszCmd);
893 
894     for (;;) {
895         ch = *end;
896         if (ch == '"') quoted = !quoted;
897         if (!quoted && (ch == ' ' || ch == ',' || ch == '\0')) {
898             *end = '\0';
899             if (beg) {
900                 if (*beg == '@') {
901                     sp = atoiW(beg + 1);
902                 } else if (*beg == '\0') {
903                     sp = -1;
904                 } else {
905                     extraPmtsBuf = beg;
906                 }
907             }
908             if (ch == '\0') break;
909             beg = end + 1;
910             if (ch == ' ') while (end[1] == ' ') end++;
911         }
912         end++;
913     }
914     while ((ptr = StrChrW(buffer, '"')))
915 	memmove(ptr, ptr+1, lstrlenW(ptr)*sizeof(WCHAR));
916 
917     /* now check for any quotes in extraPmtsBuf and remove */
918     if (extraPmtsBuf != NULL)
919     {
920         beg = end = extraPmtsBuf;
921         quoted = FALSE;
922 
923         for (;;) {
924             ch = *end;
925             if (ch == '"') quoted = !quoted;
926             if (!quoted && (ch == ' ' || ch == ',' || ch == '\0')) {
927                 *end = '\0';
928                 if (beg) {
929                     if (*beg != '\0') {
930                         extraPmts = beg;
931                     }
932                 }
933                 if (ch == '\0') break;
934                 beg = end + 1;
935                 if (ch == ' ') while (end[1] == ' ') end++;
936             }
937             end++;
938         }
939 
940         while ((ptr = StrChrW(extraPmts, '"')))
941             memmove(ptr, ptr+1, lstrlenW(ptr)*sizeof(WCHAR));
942 
943         if (extraPmts == NULL)
944             extraPmts = extraPmtsBuf;
945     }
946 
947     /* Now check if there had been a numerical value in the extra params */
948     if ((extraPmts) && (*extraPmts == '@') && (sp == -1)) {
949         sp = atoiW(extraPmts + 1);
950     }
951 
952     TRACE("cmd %s, extra %s, sp %d\n", debugstr_w(buffer), debugstr_w(extraPmts), sp);
953 
954     applet = Control_LoadApplet(hWnd, buffer, panel);
955     if (applet)
956     {
957         /* we've been given a textual parameter (or none at all) */
958         if (sp == -1) {
959             while ((++sp) != applet->count) {
960                 TRACE("sp %d, name %s\n", sp, debugstr_w(applet->info[sp].name));
961 
962                 if (StrCmpIW(extraPmts, applet->info[sp].name) == 0)
963                     break;
964             }
965         }
966 
967         if (sp >= applet->count) {
968             WARN("Out of bounds (%u >= %u), setting to 0\n", sp, applet->count);
969             sp = 0;
970         }
971 
972         if (!applet->proc(applet->hWnd, CPL_STARTWPARMSW, sp, (LPARAM)extraPmts))
973             applet->proc(applet->hWnd, CPL_DBLCLK, sp, applet->info[sp].data);
974 
975         Control_UnloadApplet(applet);
976     }
977 
978     HeapFree(GetProcessHeap(), 0, buffer);
979 #else
980     LPWSTR	buffer;
981     LPWSTR       ptr;
982     signed 	sp = -1;
983     LPCWSTR	extraPmts = L"";
984     BOOL        quoted = FALSE;
985     CPlApplet *applet;
986     LPCWSTR pchFirstComma = NULL, pchSecondComma = NULL;
987     LPCWSTR pchLastUnquotedSpace = NULL;
988     LPWSTR wszDialogBoxName;
989     int i = 0;
990     SIZE_T nLen = lstrlenW(wszCmd);
991 
992     buffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*buffer) * (nLen + 1));
993     wszDialogBoxName = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*wszDialogBoxName) * (nLen + 1));
994     if (wszDialogBoxName == NULL || buffer == NULL)
995     {
996         if (buffer != NULL)
997             HeapFree(GetProcessHeap(), 0, buffer);
998         if (wszDialogBoxName != NULL)
999             HeapFree(GetProcessHeap(), 0, wszDialogBoxName);
1000         return;
1001     }
1002 
1003     /* Search for unquoted commas and spaces. */
1004     for (i = 0; i < nLen; i++)
1005     {
1006         if (quoted && wszCmd[i] != L'"')
1007             continue;
1008         switch (wszCmd[i])
1009         {
1010             case L'"':
1011                 quoted = !quoted;
1012                 break;
1013             case L',':
1014                 if (!pchFirstComma)
1015                     pchFirstComma = &wszCmd[i];
1016                 else if (!pchSecondComma)
1017                     pchSecondComma = &wszCmd[i];
1018                 break;
1019             case L' ':
1020                 pchLastUnquotedSpace = &wszCmd[i];
1021                 break;
1022         }
1023     }
1024 
1025     /* If no unquoted commas are found, parameters are either space separated, or the entire string
1026      * is a CPL path. */
1027     if (!pchFirstComma)
1028     {
1029         /* An unquoted space was found in the string. Assume the last word is the dialog box
1030          * name/number. */
1031         if (pchLastUnquotedSpace)
1032         {
1033             int nSpaces = 0;
1034 
1035             while (pchLastUnquotedSpace[nSpaces] == L' ')
1036                 nSpaces++;
1037 
1038             StringCchCopyNW(buffer, nLen + 1, wszCmd, pchLastUnquotedSpace - wszCmd);
1039             StringCchCopyW(wszDialogBoxName, nLen + 1, pchLastUnquotedSpace + nSpaces);
1040         }
1041         /* No parameters were passed, the entire string is the CPL path. */
1042         else
1043         {
1044             StringCchCopyW(buffer, nLen + 1, wszCmd);
1045         }
1046     }
1047     /* If an unquoted comma was found, there are at least two parts of the string:
1048      * - the CPL path
1049      * - either a dialog box number preceeded by @, or a dialog box name.
1050      * If there was a second unqoted comma, there is another part of the string:
1051      * - the rest of the parameters. */
1052     else
1053     {
1054         /* If there was no second unquoted comma in the string, the CPL path ends at thes
1055           * null terminator. */
1056         if (!pchSecondComma)
1057             pchSecondComma = wszCmd + nLen;
1058 
1059         StringCchCopyNW(buffer, nLen + 1, wszCmd, pchFirstComma - wszCmd);
1060         StringCchCopyNW(wszDialogBoxName,
1061                         nLen + 1,
1062                         pchFirstComma + 1,
1063                         pchSecondComma - pchFirstComma - 1);
1064 
1065         if (pchSecondComma != wszCmd + nLen)
1066         {
1067             extraPmts = pchSecondComma + 1;
1068         }
1069     }
1070 
1071     /* Remove the quotes from both buffers. */
1072     while ((ptr = StrChrW(buffer, '"')))
1073         memmove(ptr, ptr+1, lstrlenW(ptr)*sizeof(WCHAR));
1074 
1075     while ((ptr = StrChrW(wszDialogBoxName, '"')))
1076         memmove(ptr, ptr+1, lstrlenW(ptr)*sizeof(WCHAR));
1077 
1078     if (wszDialogBoxName[0] == L'@')
1079     {
1080         sp = _wtoi(wszDialogBoxName + 1);
1081     }
1082 
1083     TRACE("cmd %s, extra %s, sp %d\n", debugstr_w(buffer), debugstr_w(extraPmts), sp);
1084 
1085     applet = Control_LoadApplet(hWnd, buffer, panel);
1086     if (applet)
1087     {
1088         ULONG_PTR cookie;
1089         BOOL bActivated;
1090         ATOM aCPLName;
1091         ATOM aCPLFlags;
1092         ATOM aCPLPath;
1093         AppDlgFindData findData;
1094 
1095         /* we've been given a textual parameter (or none at all) */
1096         if (sp == -1)
1097         {
1098             while ((++sp) != applet->count)
1099             {
1100                 TRACE("sp %d, name %s\n", sp, debugstr_w(applet->info[sp].name));
1101 
1102                 if (StrCmpIW(wszDialogBoxName, applet->info[sp].name) == 0)
1103                     break;
1104             }
1105         }
1106 
1107         if (sp >= applet->count && wszDialogBoxName[0] == L'\0')
1108         {
1109             sp = 0;
1110         }
1111 
1112         bActivated = (applet->hActCtx != INVALID_HANDLE_VALUE ? ActivateActCtx(applet->hActCtx, &cookie) : FALSE);
1113 
1114         if (sp < applet->count)
1115         {
1116             aCPLPath = GlobalFindAtomW(applet->cmd);
1117             if (!aCPLPath)
1118                 aCPLPath = GlobalAddAtomW(applet->cmd);
1119 
1120             aCPLName = GlobalFindAtomW(L"CPLName");
1121             if (!aCPLName)
1122                 aCPLName = GlobalAddAtomW(L"CPLName");
1123 
1124             aCPLFlags = GlobalFindAtomW(L"CPLFlags");
1125             if (!aCPLFlags)
1126                 aCPLFlags = GlobalAddAtomW(L"CPLFlags");
1127 
1128             findData.szAppFile = applet->cmd;
1129             findData.sAppletNo = (UINT_PTR)(sp + 1);
1130             findData.aCPLName = aCPLName;
1131             findData.aCPLFlags = aCPLFlags;
1132             findData.hRunDLL = applet->hWnd;
1133             findData.hDlgResult = NULL;
1134             // Find the dialog of this applet in the first instance.
1135             // Note: The simpler functions "FindWindow" or "FindWindowEx" does not find this type of dialogs.
1136             EnumWindows(Control_EnumWinProc, (LPARAM)&findData);
1137             if (findData.hDlgResult)
1138             {
1139                 BringWindowToTop(findData.hDlgResult);
1140             }
1141             else
1142             {
1143                 SetPropW(applet->hWnd, (LPTSTR)MAKEINTATOM(aCPLName), (HANDLE)MAKEINTATOM(aCPLPath));
1144                 SetPropW(applet->hWnd, (LPTSTR)MAKEINTATOM(aCPLFlags), UlongToHandle(sp + 1));
1145                 Control_ShowAppletInTaskbar(applet, sp);
1146 
1147                 if (extraPmts[0] == L'\0' ||
1148                     !applet->proc(applet->hWnd, CPL_STARTWPARMSW, sp, (LPARAM)extraPmts))
1149                 {
1150                     applet->proc(applet->hWnd, CPL_DBLCLK, sp, applet->info[sp].data);
1151                 }
1152 
1153                 RemovePropW(applet->hWnd, applet->cmd);
1154                 GlobalDeleteAtom(aCPLPath);
1155             }
1156         }
1157 
1158         Control_UnloadApplet(applet);
1159 
1160         if (bActivated)
1161             DeactivateActCtx(0, cookie);
1162     }
1163 
1164     HeapFree(GetProcessHeap(), 0, buffer);
1165     HeapFree(GetProcessHeap(), 0, wszDialogBoxName);
1166 #endif
1167 }
1168 
1169 /*************************************************************************
1170  * Control_RunDLLW			[SHELL32.@]
1171  *
1172  */
Control_RunDLLW(HWND hWnd,HINSTANCE hInst,LPCWSTR cmd,DWORD nCmdShow)1173 void WINAPI Control_RunDLLW(HWND hWnd, HINSTANCE hInst, LPCWSTR cmd, DWORD nCmdShow)
1174 {
1175     CPanel	panel;
1176 
1177     TRACE("(%p, %p, %s, 0x%08x)\n",
1178 	  hWnd, hInst, debugstr_w(cmd), nCmdShow);
1179 
1180 #ifndef __REACTOS__
1181     memset(&panel, 0, sizeof(panel));
1182     list_init( &panel.applets );
1183 #endif
1184 
1185     if (!cmd || !*cmd) {
1186         Control_DoWindow(&panel, hWnd, hInst);
1187     } else {
1188         Control_DoLaunch(&panel, hWnd, cmd);
1189     }
1190 }
1191 
1192 /*************************************************************************
1193  * Control_RunDLLA			[SHELL32.@]
1194  *
1195  */
Control_RunDLLA(HWND hWnd,HINSTANCE hInst,LPCSTR cmd,DWORD nCmdShow)1196 void WINAPI Control_RunDLLA(HWND hWnd, HINSTANCE hInst, LPCSTR cmd, DWORD nCmdShow)
1197 {
1198     DWORD len = MultiByteToWideChar(CP_ACP, 0, cmd, -1, NULL, 0 );
1199     LPWSTR wszCmd = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1200     if (wszCmd && MultiByteToWideChar(CP_ACP, 0, cmd, -1, wszCmd, len ))
1201     {
1202         Control_RunDLLW(hWnd, hInst, wszCmd, nCmdShow);
1203     }
1204     HeapFree(GetProcessHeap(), 0, wszCmd);
1205 }
1206 
1207 /*************************************************************************
1208  * Control_FillCache_RunDLLW			[SHELL32.@]
1209  *
1210  */
Control_FillCache_RunDLLW(HWND hWnd,HANDLE hModule,DWORD w,DWORD x)1211 HRESULT WINAPI Control_FillCache_RunDLLW(HWND hWnd, HANDLE hModule, DWORD w, DWORD x)
1212 {
1213     FIXME("%p %p 0x%08x 0x%08x stub\n", hWnd, hModule, w, x);
1214     return S_OK;
1215 }
1216 
1217 /*************************************************************************
1218  * Control_FillCache_RunDLLA			[SHELL32.@]
1219  *
1220  */
Control_FillCache_RunDLLA(HWND hWnd,HANDLE hModule,DWORD w,DWORD x)1221 HRESULT WINAPI Control_FillCache_RunDLLA(HWND hWnd, HANDLE hModule, DWORD w, DWORD x)
1222 {
1223     return Control_FillCache_RunDLLW(hWnd, hModule, w, x);
1224 }
1225 
1226 
1227 #ifdef __REACTOS__
1228 /*************************************************************************
1229  * RunDll_CallEntry16                [SHELL32.122]
1230  * the name is OK (when written with Dll, and not DLL as in Wine!)
1231  */
RunDll_CallEntry16(DWORD proc,HWND hwnd,HINSTANCE inst,LPCSTR cmdline,INT cmdshow)1232 void WINAPI RunDll_CallEntry16( DWORD proc, HWND hwnd, HINSTANCE inst,
1233                                 LPCSTR cmdline, INT cmdshow )
1234 {
1235     FIXME( "proc %lx hwnd %p inst %p cmdline %s cmdshow %d\n",
1236            proc, hwnd, inst, debugstr_a(cmdline), cmdshow );
1237 }
1238 #endif
1239 
1240 /*************************************************************************
1241  * CallCPLEntry16				[SHELL32.166]
1242  *
1243  * called by desk.cpl on "Advanced" with:
1244  * hMod("DeskCp16.Dll"), pFunc("CplApplet"), 0, 1, 0xc, 0
1245  *
1246  */
1247 #ifndef __REACTOS__
CallCPLEntry16(HMODULE hMod,FARPROC pFunc,DWORD dw3,DWORD dw4,DWORD dw5,DWORD dw6)1248 DWORD WINAPI CallCPLEntry16(HMODULE hMod, FARPROC pFunc, DWORD dw3, DWORD dw4, DWORD dw5, DWORD dw6)
1249 #else
1250 DECLARE_HANDLE(FARPROC16);
1251 LRESULT WINAPI CallCPLEntry16(HINSTANCE hMod, FARPROC16 pFunc, HWND dw3, UINT dw4, LPARAM dw5, LPARAM dw6)
1252 #endif
1253 {
1254     FIXME("(%p, %p, %08x, %08x, %08x, %08x): stub.\n", hMod, pFunc, dw3, dw4, dw5, dw6);
1255     return 0x0deadbee;
1256 }
1257