xref: /reactos/dll/win32/shell32/wine/control.c (revision ffd06029)
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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
733 static	void	Control_DoWindow(CPanel* panel, HWND hWnd, HINSTANCE hInst)
734 {
735     ShellExecuteW(NULL,
736                   L"open",
737                   L"explorer.exe",
738                   L"::{20D04FE0-3AEA-1069-A2D8-08002B30309D}\\::{21EC2020-3AEA-1069-A2DD-08002B30309D}",
739                   NULL,
740                   SW_SHOWDEFAULT);
741 }
742 #endif
743 
744 #ifdef __REACTOS__
745 
746 /** Structure for in and out data when
747  *  search for the cpl dialog of first instance
748  */
749 typedef struct tagAppDlgFindData
750 {
751     PCWSTR    szAppFile;  /**< Full path to applet library as search parameter */
752     UINT_PTR  sAppletNo;  /**< Number of applet in a system control library as search parameter */
753     ATOM      aCPLName;   /**< to read window property 'CPLName' */
754     ATOM      aCPLFlags;  /**< to read window property 'CPLFlags'*/
755     HWND      hRunDLL;    /**< to skip self instance */
756     HWND      hDlgResult; /**< Returned dialog handle or NULL if not found */
757 } AppDlgFindData;
758 
759 /**
760  * Callback function to search applet dialog
761  * @param hwnd A handle to a top-level window.
762  * @param lParam Pointer of AppDlgFindData
763  * @return TRUE: continue enumeration, FALSE: stop enumeration
764  */
765 static BOOL CALLBACK
766 Control_EnumWinProc(
767     _In_ HWND   hwnd,
768     _In_ LPARAM lParam)
769 {
770     AppDlgFindData* pData = (AppDlgFindData*)lParam;
771     UINT_PTR sAppletNo;
772     HANDLE hRes;
773     WCHAR szAppFile[MAX_PATH];
774 
775     if (pData->hRunDLL == hwnd)
776         return TRUE; /* Skip self instance */
777 
778     sAppletNo = (UINT_PTR)GetPropW(hwnd, (LPTSTR)MAKEINTATOM(pData->aCPLFlags));
779     if (sAppletNo != pData->sAppletNo)
780         return TRUE; /* Continue enumeration */
781 
782     hRes = GetPropW(hwnd, (LPTSTR)MAKEINTATOM(pData->aCPLName));
783     GlobalGetAtomNameW((ATOM)HandleToUlong(hRes), szAppFile, _countof(szAppFile));
784     if (wcscmp(szAppFile, pData->szAppFile) == 0)
785     {
786         HWND hDialog = GetLastActivePopup(hwnd);
787         if (IsWindow(hDialog))
788         {
789             pData->hDlgResult = hDialog;
790             return FALSE; /* Stop enumeration */
791         }
792     }
793 
794     return TRUE; /* Continue enumeration */
795 }
796 
797 /**
798  * This function makes the system control applet accessible via the taskbar.
799  *
800  * @param applet
801  * Pointer of system control applet.
802  *
803  * @param index
804  * Number of applet in a system control library.
805  */
806 static void
807 Control_ShowAppletInTaskbar(CPlApplet* applet, UINT index)
808 {
809     HICON hSmallIcon;
810     ITaskbarList* pTaskbar = NULL;
811 
812     /* Try to add a taskbar button only if the applet's parent window is the desktop */
813     if (GetParent(applet->hWnd) != NULL)
814     {
815         return;
816     }
817 
818     SetWindowTextW(applet->hWnd, applet->info[index].name);
819 
820     /* Set large icon for the taskbar button */
821     if (applet->info[index].icon)
822     {
823         SendMessageW(applet->hWnd, WM_SETICON, ICON_BIG, (LPARAM)applet->info[index].icon);
824     }
825 
826     /* Try loading the small icon for the taskbar button */
827     hSmallIcon = (HICON)LoadImageW(applet->hModule,
828                                    MAKEINTRESOURCEW(applet->info[index].idIcon),
829                                    IMAGE_ICON,
830                                    GetSystemMetrics(SM_CXSMICON),
831                                    GetSystemMetrics(SM_CYSMICON),
832                                    0);
833     if (hSmallIcon)
834     {
835         SendMessageW(applet->hWnd, WM_SETICON, ICON_SMALL, (LPARAM)hSmallIcon);
836     }
837     else
838     {
839         if (applet->info[index].icon)
840         {
841             SendMessageW(applet->hWnd, WM_SETICON, ICON_SMALL, (LPARAM)applet->info[index].icon);
842         }
843     }
844 
845     /* Add button to the taskbar */
846     ShowWindow(applet->hWnd, SW_SHOWMINNOACTIVE);
847 
848     /* Activate the corresponding button in the taskbar */
849     CoInitialize(NULL);
850     if (CoCreateInstance(&CLSID_TaskbarList,
851                          NULL, CLSCTX_INPROC_SERVER,
852                          &IID_ITaskbarList,
853                          (LPVOID*)&pTaskbar) == S_OK)
854     {
855         if (ITaskbarList_HrInit(pTaskbar) == S_OK)
856         {
857             ITaskbarList_ActivateTab(pTaskbar, applet->hWnd);
858         }
859         ITaskbarList_Release(pTaskbar);
860     }
861     CoUninitialize();
862 }
863 
864 #endif /* __REACTOS__ */
865 
866 static	void	Control_DoLaunch(CPanel* panel, HWND hWnd, LPCWSTR wszCmd)
867    /* forms to parse:
868     *	foo.cpl,@sp,str
869     *	foo.cpl,@sp
870     *	foo.cpl,,str
871     *	foo.cpl @sp
872     *	foo.cpl str
873     *   "a path\foo.cpl"
874     */
875 {
876 #ifndef __REACTOS__
877     LPWSTR	buffer;
878     LPWSTR	beg = NULL;
879     LPWSTR	end;
880     WCHAR	ch;
881     LPWSTR       ptr;
882     signed 	sp = -1;
883     LPWSTR	extraPmtsBuf = NULL;
884     LPWSTR	extraPmts = NULL;
885     BOOL        quoted = FALSE;
886     CPlApplet *applet;
887 
888     buffer = HeapAlloc(GetProcessHeap(), 0, (lstrlenW(wszCmd) + 1) * sizeof(*wszCmd));
889     if (!buffer) return;
890 
891     end = lstrcpyW(buffer, wszCmd);
892 
893     for (;;) {
894         ch = *end;
895         if (ch == '"') quoted = !quoted;
896         if (!quoted && (ch == ' ' || ch == ',' || ch == '\0')) {
897             *end = '\0';
898             if (beg) {
899                 if (*beg == '@') {
900                     sp = atoiW(beg + 1);
901                 } else if (*beg == '\0') {
902                     sp = -1;
903                 } else {
904                     extraPmtsBuf = beg;
905                 }
906             }
907             if (ch == '\0') break;
908             beg = end + 1;
909             if (ch == ' ') while (end[1] == ' ') end++;
910         }
911         end++;
912     }
913     while ((ptr = StrChrW(buffer, '"')))
914 	memmove(ptr, ptr+1, lstrlenW(ptr)*sizeof(WCHAR));
915 
916     /* now check for any quotes in extraPmtsBuf and remove */
917     if (extraPmtsBuf != NULL)
918     {
919         beg = end = extraPmtsBuf;
920         quoted = FALSE;
921 
922         for (;;) {
923             ch = *end;
924             if (ch == '"') quoted = !quoted;
925             if (!quoted && (ch == ' ' || ch == ',' || ch == '\0')) {
926                 *end = '\0';
927                 if (beg) {
928                     if (*beg != '\0') {
929                         extraPmts = beg;
930                     }
931                 }
932                 if (ch == '\0') break;
933                 beg = end + 1;
934                 if (ch == ' ') while (end[1] == ' ') end++;
935             }
936             end++;
937         }
938 
939         while ((ptr = StrChrW(extraPmts, '"')))
940             memmove(ptr, ptr+1, lstrlenW(ptr)*sizeof(WCHAR));
941 
942         if (extraPmts == NULL)
943             extraPmts = extraPmtsBuf;
944     }
945 
946     /* Now check if there had been a numerical value in the extra params */
947     if ((extraPmts) && (*extraPmts == '@') && (sp == -1)) {
948         sp = atoiW(extraPmts + 1);
949     }
950 
951     TRACE("cmd %s, extra %s, sp %d\n", debugstr_w(buffer), debugstr_w(extraPmts), sp);
952 
953     applet = Control_LoadApplet(hWnd, buffer, panel);
954     if (applet)
955     {
956         /* we've been given a textual parameter (or none at all) */
957         if (sp == -1) {
958             while ((++sp) != applet->count) {
959                 TRACE("sp %d, name %s\n", sp, debugstr_w(applet->info[sp].name));
960 
961                 if (StrCmpIW(extraPmts, applet->info[sp].name) == 0)
962                     break;
963             }
964         }
965 
966         if (sp >= applet->count) {
967             WARN("Out of bounds (%u >= %u), setting to 0\n", sp, applet->count);
968             sp = 0;
969         }
970 
971         if (!applet->proc(applet->hWnd, CPL_STARTWPARMSW, sp, (LPARAM)extraPmts))
972             applet->proc(applet->hWnd, CPL_DBLCLK, sp, applet->info[sp].data);
973 
974         Control_UnloadApplet(applet);
975     }
976 
977     HeapFree(GetProcessHeap(), 0, buffer);
978 #else
979     LPWSTR	buffer;
980     LPWSTR       ptr;
981     signed 	sp = -1;
982     LPCWSTR	extraPmts = L"";
983     BOOL        quoted = FALSE;
984     CPlApplet *applet;
985     LPCWSTR pchFirstComma = NULL, pchSecondComma = NULL;
986     LPCWSTR pchLastUnquotedSpace = NULL;
987     LPWSTR wszDialogBoxName;
988     int i = 0;
989     SIZE_T nLen = lstrlenW(wszCmd);
990 
991     buffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*buffer) * (nLen + 1));
992     wszDialogBoxName = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*wszDialogBoxName) * (nLen + 1));
993     if (wszDialogBoxName == NULL || buffer == NULL)
994     {
995         if (buffer != NULL)
996             HeapFree(GetProcessHeap(), 0, buffer);
997         if (wszDialogBoxName != NULL)
998             HeapFree(GetProcessHeap(), 0, wszDialogBoxName);
999         return;
1000     }
1001 
1002     /* Search for unquoted commas and spaces. */
1003     for (i = 0; i < nLen; i++)
1004     {
1005         if (quoted && wszCmd[i] != L'"')
1006             continue;
1007         switch (wszCmd[i])
1008         {
1009             case L'"':
1010                 quoted = !quoted;
1011                 break;
1012             case L',':
1013                 if (!pchFirstComma)
1014                     pchFirstComma = &wszCmd[i];
1015                 else if (!pchSecondComma)
1016                     pchSecondComma = &wszCmd[i];
1017                 break;
1018             case L' ':
1019                 pchLastUnquotedSpace = &wszCmd[i];
1020                 break;
1021         }
1022     }
1023 
1024     /* If no unquoted commas are found, parameters are either space separated, or the entire string
1025      * is a CPL path. */
1026     if (!pchFirstComma)
1027     {
1028         /* An unquoted space was found in the string. Assume the last word is the dialog box
1029          * name/number. */
1030         if (pchLastUnquotedSpace)
1031         {
1032             int nSpaces = 0;
1033 
1034             while (pchLastUnquotedSpace[nSpaces] == L' ')
1035                 nSpaces++;
1036 
1037             StringCchCopyNW(buffer, nLen + 1, wszCmd, pchLastUnquotedSpace - wszCmd);
1038             StringCchCopyW(wszDialogBoxName, nLen + 1, pchLastUnquotedSpace + nSpaces);
1039         }
1040         /* No parameters were passed, the entire string is the CPL path. */
1041         else
1042         {
1043             StringCchCopyW(buffer, nLen + 1, wszCmd);
1044         }
1045     }
1046     /* If an unquoted comma was found, there are at least two parts of the string:
1047      * - the CPL path
1048      * - either a dialog box number preceeded by @, or a dialog box name.
1049      * If there was a second unqoted comma, there is another part of the string:
1050      * - the rest of the parameters. */
1051     else
1052     {
1053         /* If there was no second unquoted comma in the string, the CPL path ends at thes
1054           * null terminator. */
1055         if (!pchSecondComma)
1056             pchSecondComma = wszCmd + nLen;
1057 
1058         StringCchCopyNW(buffer, nLen + 1, wszCmd, pchFirstComma - wszCmd);
1059         StringCchCopyNW(wszDialogBoxName,
1060                         nLen + 1,
1061                         pchFirstComma + 1,
1062                         pchSecondComma - pchFirstComma - 1);
1063 
1064         if (pchSecondComma != wszCmd + nLen)
1065         {
1066             extraPmts = pchSecondComma + 1;
1067         }
1068     }
1069 
1070     /* Remove the quotes from both buffers. */
1071     while ((ptr = StrChrW(buffer, '"')))
1072         memmove(ptr, ptr+1, lstrlenW(ptr)*sizeof(WCHAR));
1073 
1074     while ((ptr = StrChrW(wszDialogBoxName, '"')))
1075         memmove(ptr, ptr+1, lstrlenW(ptr)*sizeof(WCHAR));
1076 
1077     if (wszDialogBoxName[0] == L'@')
1078     {
1079         sp = _wtoi(wszDialogBoxName + 1);
1080     }
1081 
1082     TRACE("cmd %s, extra %s, sp %d\n", debugstr_w(buffer), debugstr_w(extraPmts), sp);
1083 
1084     applet = Control_LoadApplet(hWnd, buffer, panel);
1085     if (applet)
1086     {
1087         ULONG_PTR cookie;
1088         BOOL bActivated;
1089         ATOM aCPLName;
1090         ATOM aCPLFlags;
1091         ATOM aCPLPath;
1092         AppDlgFindData findData;
1093 
1094         /* we've been given a textual parameter (or none at all) */
1095         if (sp == -1)
1096         {
1097             while ((++sp) != applet->count)
1098             {
1099                 TRACE("sp %d, name %s\n", sp, debugstr_w(applet->info[sp].name));
1100 
1101                 if (StrCmpIW(wszDialogBoxName, applet->info[sp].name) == 0)
1102                     break;
1103             }
1104         }
1105 
1106         if (sp >= applet->count && wszDialogBoxName[0] == L'\0')
1107         {
1108             sp = 0;
1109         }
1110 
1111         bActivated = (applet->hActCtx != INVALID_HANDLE_VALUE ? ActivateActCtx(applet->hActCtx, &cookie) : FALSE);
1112 
1113         if (sp < applet->count)
1114         {
1115             aCPLPath = GlobalFindAtomW(applet->cmd);
1116             if (!aCPLPath)
1117                 aCPLPath = GlobalAddAtomW(applet->cmd);
1118 
1119             aCPLName = GlobalFindAtomW(L"CPLName");
1120             if (!aCPLName)
1121                 aCPLName = GlobalAddAtomW(L"CPLName");
1122 
1123             aCPLFlags = GlobalFindAtomW(L"CPLFlags");
1124             if (!aCPLFlags)
1125                 aCPLFlags = GlobalAddAtomW(L"CPLFlags");
1126 
1127             findData.szAppFile = applet->cmd;
1128             findData.sAppletNo = (UINT_PTR)(sp + 1);
1129             findData.aCPLName = aCPLName;
1130             findData.aCPLFlags = aCPLFlags;
1131             findData.hRunDLL = applet->hWnd;
1132             findData.hDlgResult = NULL;
1133             // Find the dialog of this applet in the first instance.
1134             // Note: The simpler functions "FindWindow" or "FindWindowEx" does not find this type of dialogs.
1135             EnumWindows(Control_EnumWinProc, (LPARAM)&findData);
1136             if (findData.hDlgResult)
1137             {
1138                 BringWindowToTop(findData.hDlgResult);
1139             }
1140             else
1141             {
1142                 SetPropW(applet->hWnd, (LPTSTR)MAKEINTATOM(aCPLName), (HANDLE)MAKEINTATOM(aCPLPath));
1143                 SetPropW(applet->hWnd, (LPTSTR)MAKEINTATOM(aCPLFlags), UlongToHandle(sp + 1));
1144                 Control_ShowAppletInTaskbar(applet, sp);
1145 
1146                 if (extraPmts[0] == L'\0' ||
1147                     !applet->proc(applet->hWnd, CPL_STARTWPARMSW, sp, (LPARAM)extraPmts))
1148                 {
1149                     applet->proc(applet->hWnd, CPL_DBLCLK, sp, applet->info[sp].data);
1150                 }
1151 
1152                 RemovePropW(applet->hWnd, applet->cmd);
1153                 GlobalDeleteAtom(aCPLPath);
1154             }
1155         }
1156 
1157         Control_UnloadApplet(applet);
1158 
1159         if (bActivated)
1160             DeactivateActCtx(0, cookie);
1161     }
1162 
1163     HeapFree(GetProcessHeap(), 0, buffer);
1164     HeapFree(GetProcessHeap(), 0, wszDialogBoxName);
1165 #endif
1166 }
1167 
1168 /*************************************************************************
1169  * Control_RunDLLW			[SHELL32.@]
1170  *
1171  */
1172 void WINAPI Control_RunDLLW(HWND hWnd, HINSTANCE hInst, LPCWSTR cmd, DWORD nCmdShow)
1173 {
1174     CPanel	panel;
1175 
1176     TRACE("(%p, %p, %s, 0x%08x)\n",
1177 	  hWnd, hInst, debugstr_w(cmd), nCmdShow);
1178 
1179 #ifndef __REACTOS__
1180     memset(&panel, 0, sizeof(panel));
1181     list_init( &panel.applets );
1182 #endif
1183 
1184     if (!cmd || !*cmd) {
1185         Control_DoWindow(&panel, hWnd, hInst);
1186     } else {
1187         Control_DoLaunch(&panel, hWnd, cmd);
1188     }
1189 }
1190 
1191 /*************************************************************************
1192  * Control_RunDLLA			[SHELL32.@]
1193  *
1194  */
1195 void WINAPI Control_RunDLLA(HWND hWnd, HINSTANCE hInst, LPCSTR cmd, DWORD nCmdShow)
1196 {
1197     DWORD len = MultiByteToWideChar(CP_ACP, 0, cmd, -1, NULL, 0 );
1198     LPWSTR wszCmd = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1199     if (wszCmd && MultiByteToWideChar(CP_ACP, 0, cmd, -1, wszCmd, len ))
1200     {
1201         Control_RunDLLW(hWnd, hInst, wszCmd, nCmdShow);
1202     }
1203     HeapFree(GetProcessHeap(), 0, wszCmd);
1204 }
1205 
1206 /*************************************************************************
1207  * Control_FillCache_RunDLLW			[SHELL32.@]
1208  *
1209  */
1210 HRESULT WINAPI Control_FillCache_RunDLLW(HWND hWnd, HANDLE hModule, DWORD w, DWORD x)
1211 {
1212     FIXME("%p %p 0x%08x 0x%08x stub\n", hWnd, hModule, w, x);
1213     return S_OK;
1214 }
1215 
1216 /*************************************************************************
1217  * Control_FillCache_RunDLLA			[SHELL32.@]
1218  *
1219  */
1220 HRESULT WINAPI Control_FillCache_RunDLLA(HWND hWnd, HANDLE hModule, DWORD w, DWORD x)
1221 {
1222     return Control_FillCache_RunDLLW(hWnd, hModule, w, x);
1223 }
1224 
1225 
1226 #ifdef __REACTOS__
1227 /*************************************************************************
1228  * RunDll_CallEntry16                [SHELL32.122]
1229  * the name is OK (when written with Dll, and not DLL as in Wine!)
1230  */
1231 void WINAPI RunDll_CallEntry16( DWORD proc, HWND hwnd, HINSTANCE inst,
1232                                 LPCSTR cmdline, INT cmdshow )
1233 {
1234     FIXME( "proc %lx hwnd %p inst %p cmdline %s cmdshow %d\n",
1235            proc, hwnd, inst, debugstr_a(cmdline), cmdshow );
1236 }
1237 #endif
1238 
1239 /*************************************************************************
1240  * CallCPLEntry16				[SHELL32.166]
1241  *
1242  * called by desk.cpl on "Advanced" with:
1243  * hMod("DeskCp16.Dll"), pFunc("CplApplet"), 0, 1, 0xc, 0
1244  *
1245  */
1246 #ifndef __REACTOS__
1247 DWORD WINAPI CallCPLEntry16(HMODULE hMod, FARPROC pFunc, DWORD dw3, DWORD dw4, DWORD dw5, DWORD dw6)
1248 #else
1249 DECLARE_HANDLE(FARPROC16);
1250 LRESULT WINAPI CallCPLEntry16(HINSTANCE hMod, FARPROC16 pFunc, HWND dw3, UINT dw4, LPARAM dw5, LPARAM dw6)
1251 #endif
1252 {
1253     FIXME("(%p, %p, %08x, %08x, %08x, %08x): stub.\n", hMod, pFunc, dw3, dw4, dw5, dw6);
1254     return 0x0deadbee;
1255 }
1256