wined3d: Prevent a recursive ENTER_GL before calling blitter->free_private.
[wine] / dlls / appwiz.cpl / appwiz.c
1 /*
2  * Add/Remove Programs applet
3  * Partially based on Wine Uninstaller
4  *
5  * Copyright 2000 Andreas Mohr
6  * Copyright 2004 Hannu Valtonen
7  * Copyright 2005 Jonathan Ernst
8  * Copyright 2001-2002, 2008 Owen Rudge
9  *
10  * This library is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU Lesser General Public
12  * License as published by the Free Software Foundation; either
13  * version 2.1 of the License, or (at your option) any later version.
14  *
15  * This library is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18  * Lesser General Public License for more details.
19  *
20  * You should have received a copy of the GNU Lesser General Public
21  * License along with this library; if not, write to the Free Software
22  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
23  *
24  */
25
26 #define NONAMELESSUNION
27
28 #include "config.h"
29 #include "wine/port.h"
30 #include "wine/unicode.h"
31 #include "wine/debug.h"
32
33 #include <string.h>
34 #include <stdlib.h>
35 #include <stdarg.h>
36 #include <stdio.h>
37 #include <windef.h>
38 #include <winbase.h>
39 #include <winuser.h>
40 #include <wingdi.h>
41 #include <winreg.h>
42 #include <shellapi.h>
43 #include <commctrl.h>
44 #include <cpl.h>
45
46 #include "res.h"
47
48 WINE_DEFAULT_DEBUG_CHANNEL(appwizcpl);
49
50 /* define a maximum length for various buffers we use */
51 #define MAX_STRING_LEN    1024
52
53 typedef struct APPINFO {
54     int id;
55
56     LPWSTR title;
57     LPWSTR path;
58
59     LPWSTR icon;
60     int iconIdx;
61
62     LPWSTR publisher;
63     LPWSTR version;
64
65     HKEY regroot;
66     WCHAR regkey[MAX_STRING_LEN];
67
68     struct APPINFO *next;
69 } APPINFO;
70
71 static struct APPINFO *AppInfo = NULL;
72 static HINSTANCE hInst;
73
74 /* names of registry keys */
75 static const WCHAR BackSlashW[] = { '\\', 0 };
76 static const WCHAR DisplayNameW[] = {'D','i','s','p','l','a','y','N','a','m','e',0};
77 static const WCHAR DisplayIconW[] = {'D','i','s','p','l','a','y','I','c','o','n',0};
78 static const WCHAR DisplayVersionW[] = {'D','i','s','p','l','a','y','V','e','r',
79     's','i','o','n',0};
80 static const WCHAR PublisherW[] = {'P','u','b','l','i','s','h','e','r',0};
81 static const WCHAR ContactW[] = {'C','o','n','t','a','c','t',0};
82 static const WCHAR HelpLinkW[] = {'H','e','l','p','L','i','n','k',0};
83 static const WCHAR HelpTelephoneW[] = {'H','e','l','p','T','e','l','e','p','h',
84     'o','n','e',0};
85 static const WCHAR ReadmeW[] = {'R','e','a','d','m','e',0};
86 static const WCHAR URLUpdateInfoW[] = {'U','R','L','U','p','d','a','t','e','I',
87     'n','f','o',0};
88 static const WCHAR CommentsW[] = {'C','o','m','m','e','n','t','s',0};
89 static const WCHAR UninstallCommandlineW[] = {'U','n','i','n','s','t','a','l','l',
90     'S','t','r','i','n','g',0};
91
92 static const WCHAR PathUninstallW[] = {
93         'S','o','f','t','w','a','r','e','\\',
94         'M','i','c','r','o','s','o','f','t','\\',
95         'W','i','n','d','o','w','s','\\',
96         'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
97         'U','n','i','n','s','t','a','l','l',0 };
98
99 /******************************************************************************
100  * Name       : DllMain
101  * Description: Entry point for DLL file
102  */
103 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason,
104                     LPVOID lpvReserved)
105 {
106     TRACE("(%p, %d, %p)\n", hinstDLL, fdwReason, lpvReserved);
107
108     switch (fdwReason)
109     {
110         case DLL_PROCESS_ATTACH:
111             hInst = hinstDLL;
112             break;
113     }
114     return TRUE;
115 }
116
117 /******************************************************************************
118  * Name       : FreeAppInfo
119  * Description: Frees memory used by an AppInfo structure, and any children.
120  */
121 static void FreeAppInfo(APPINFO *info)
122 {
123     while (info)
124     {
125         APPINFO *next_info = info->next;
126
127         HeapFree(GetProcessHeap(), 0, info->title);
128         HeapFree(GetProcessHeap(), 0, info->path);
129         HeapFree(GetProcessHeap(), 0, info->icon);
130         HeapFree(GetProcessHeap(), 0, info->publisher);
131         HeapFree(GetProcessHeap(), 0, info->version);
132         HeapFree(GetProcessHeap(), 0, info);
133         info = next_info;
134     }
135 }
136
137 /******************************************************************************
138  * Name       : ReadApplicationsFromRegistry
139  * Description: Creates a linked list of uninstallable applications from the
140  *              registry.
141  * Parameters : root    - Which registry root to read from (HKCU/HKLM)
142  * Returns    : TRUE if successful, FALSE otherwise
143  */
144 static BOOL ReadApplicationsFromRegistry(HKEY root)
145 {
146     HKEY hkeyUninst, hkeyApp;
147     int i, id = 0;
148     DWORD sizeOfSubKeyName, displen, uninstlen;
149     WCHAR subKeyName[256];
150     WCHAR key_app[MAX_STRING_LEN];
151     WCHAR *p;
152     APPINFO *iter = AppInfo;
153     LPWSTR iconPtr;
154     BOOL ret = FALSE;
155
156     if (RegOpenKeyExW(root, PathUninstallW, 0, KEY_READ, &hkeyUninst) !=
157       ERROR_SUCCESS)
158         return FALSE;
159
160     lstrcpyW(key_app, PathUninstallW);
161     lstrcatW(key_app, BackSlashW);
162     p = key_app+lstrlenW(PathUninstallW)+1;
163
164     sizeOfSubKeyName = sizeof(subKeyName) / sizeof(subKeyName[0]);
165
166     if (iter)
167     {
168         /* find the end of the list */
169         for (iter = AppInfo; iter->next; iter = iter->next);
170     }
171
172     for (i = 0; RegEnumKeyExW(hkeyUninst, i, subKeyName, &sizeOfSubKeyName, NULL,
173         NULL, NULL, NULL) != ERROR_NO_MORE_ITEMS; ++i)
174     {
175         lstrcpyW(p, subKeyName);
176         RegOpenKeyExW(root, key_app, 0, KEY_READ, &hkeyApp);
177
178         displen = 0;
179         uninstlen = 0;
180
181         if ((RegQueryValueExW(hkeyApp, DisplayNameW, 0, 0, NULL, &displen) ==
182             ERROR_SUCCESS) && (RegQueryValueExW(hkeyApp, UninstallCommandlineW,
183             0, 0, NULL, &uninstlen) == ERROR_SUCCESS))
184         {
185             /* if we already have iter, allocate the next entry */
186             if (iter)
187             {
188                 iter->next = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
189                     sizeof(struct APPINFO));
190
191                 if (!iter->next)
192                     goto err;
193
194                 iter = iter->next;
195             }
196             else
197             {
198                 /* if not, start the list */
199                 iter = AppInfo = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
200                     sizeof(struct APPINFO));
201
202                 if (!iter)
203                     goto err;
204             }
205
206             iter->title = HeapAlloc(GetProcessHeap(), 0, displen);
207
208             if (!iter->title)
209                 goto err;
210
211             RegQueryValueExW(hkeyApp, DisplayNameW, 0, 0, (LPBYTE)iter->title,
212                 &displen);
213
214             /* now get DisplayIcon */
215             displen = 0;
216             RegQueryValueExW(hkeyApp, DisplayIconW, 0, 0, NULL, &displen);
217
218             if (displen == 0)
219                 iter->icon = 0;
220             else
221             {
222                 iter->icon = HeapAlloc(GetProcessHeap(), 0, displen);
223
224                 if (!iter->icon)
225                     goto err;
226
227                 RegQueryValueExW(hkeyApp, DisplayIconW, 0, 0, (LPBYTE)iter->icon,
228                     &displen);
229
230                 /* separate the index from the icon name, if supplied */
231                 iconPtr = strchrW(iter->icon, ',');
232
233                 if (iconPtr)
234                 {
235                     *iconPtr++ = 0;
236                     iter->iconIdx = atoiW(iconPtr);
237                 }
238             }
239
240             iter->path = HeapAlloc(GetProcessHeap(), 0, uninstlen);
241
242             if (!iter->path)
243                 goto err;
244
245             RegQueryValueExW(hkeyApp, UninstallCommandlineW, 0, 0,
246                 (LPBYTE)iter->path, &uninstlen);
247
248             /* publisher, version */
249             if (RegQueryValueExW(hkeyApp, PublisherW, 0, 0, NULL, &displen) ==
250                 ERROR_SUCCESS)
251             {
252                 iter->publisher = HeapAlloc(GetProcessHeap(), 0, displen);
253
254                 if (!iter->publisher)
255                     goto err;
256
257                 RegQueryValueExW(hkeyApp, PublisherW, 0, 0, (LPBYTE)iter->publisher,
258                     &displen);
259             }
260
261             if (RegQueryValueExW(hkeyApp, DisplayVersionW, 0, 0, NULL, &displen) ==
262                 ERROR_SUCCESS)
263             {
264                 iter->version = HeapAlloc(GetProcessHeap(), 0, displen);
265
266                 if (!iter->version)
267                     goto err;
268
269                 RegQueryValueExW(hkeyApp, DisplayVersionW, 0, 0, (LPBYTE)iter->version,
270                     &displen);
271             }
272
273             /* registry key */
274             iter->regroot = root;
275             lstrcpyW(iter->regkey, subKeyName);
276
277             iter->id = id++;
278         }
279
280         RegCloseKey(hkeyApp);
281         sizeOfSubKeyName = sizeof(subKeyName) / sizeof(subKeyName[0]);
282     }
283
284     ret = TRUE;
285     goto end;
286
287 err:
288     RegCloseKey(hkeyApp);
289     FreeAppInfo(iter);
290
291 end:
292     RegCloseKey(hkeyUninst);
293     return ret;
294 }
295
296
297 /******************************************************************************
298  * Name       : AddApplicationsToList
299  * Description: Populates the list box with applications.
300  * Parameters : hWnd    - Handle of the dialog box
301  */
302 static void AddApplicationsToList(HWND hWnd, HIMAGELIST hList)
303 {
304     APPINFO *iter = AppInfo;
305     LVITEMW lvItem;
306     HICON hIcon;
307     int index;
308
309     while (iter)
310     {
311         /* get the icon */
312         index = 0;
313
314         if (iter->icon)
315         {
316             if (ExtractIconExW(iter->icon, iter->iconIdx, NULL, &hIcon, 1) == 1)
317             {
318                 index = ImageList_AddIcon(hList, hIcon);
319                 DestroyIcon(hIcon);
320             }
321         }
322
323         lvItem.mask = LVIF_IMAGE | LVIF_TEXT | LVIF_PARAM;
324         lvItem.iItem = iter->id;
325         lvItem.iSubItem = 0;
326         lvItem.pszText = iter->title;
327         lvItem.iImage = index;
328         lvItem.lParam = iter->id;
329
330         index = ListView_InsertItemW(hWnd, &lvItem);
331
332         /* now add the subitems (columns) */
333         ListView_SetItemTextW(hWnd, index, 1, iter->publisher);
334         ListView_SetItemTextW(hWnd, index, 2, iter->version);
335
336         iter = iter->next;
337     }
338 }
339
340 /******************************************************************************
341  * Name       : RemoveItemsFromList
342  * Description: Clears the application list box.
343  * Parameters : hWnd    - Handle of the dialog box
344  */
345 static void RemoveItemsFromList(HWND hWnd)
346 {
347     SendDlgItemMessageW(hWnd, IDL_PROGRAMS, LVM_DELETEALLITEMS, 0, 0);
348 }
349
350 /******************************************************************************
351  * Name       : EmptyList
352  * Description: Frees memory used by the application linked list.
353  */
354 static inline void EmptyList(void)
355 {
356     FreeAppInfo(AppInfo);
357     AppInfo = NULL;
358 }
359
360 /******************************************************************************
361  * Name       : UpdateButtons
362  * Description: Enables/disables the Add/Remove button depending on current
363  *              selection in list box.
364  * Parameters : hWnd    - Handle of the dialog box
365  */
366 static void UpdateButtons(HWND hWnd)
367 {
368     BOOL sel = ListView_GetSelectedCount(GetDlgItem(hWnd, IDL_PROGRAMS)) != 0;
369
370     EnableWindow(GetDlgItem(hWnd, IDC_ADDREMOVE), sel);
371     EnableWindow(GetDlgItem(hWnd, IDC_SUPPORT_INFO), sel);
372 }
373
374 /******************************************************************************
375  * Name       : UninstallProgram
376  * Description: Executes the specified program's installer.
377  * Parameters : id      - the internal ID of the installer to remove
378  */
379 static void UninstallProgram(int id)
380 {
381     APPINFO *iter;
382     STARTUPINFOW si;
383     PROCESS_INFORMATION info;
384     WCHAR errormsg[MAX_STRING_LEN];
385     WCHAR sUninstallFailed[MAX_STRING_LEN];
386     HKEY hkey;
387     BOOL res;
388
389     LoadStringW(hInst, IDS_UNINSTALL_FAILED, sUninstallFailed,
390         sizeof(sUninstallFailed) / sizeof(sUninstallFailed[0]));
391
392     for (iter = AppInfo; iter; iter = iter->next)
393     {
394         if (iter->id == id)
395         {
396             TRACE("Uninstalling %s (%s)\n", wine_dbgstr_w(iter->title),
397                 wine_dbgstr_w(iter->path));
398
399             memset(&si, 0, sizeof(STARTUPINFOW));
400             si.cb = sizeof(STARTUPINFOW);
401             si.wShowWindow = SW_NORMAL;
402             res = CreateProcessW(NULL, iter->path, NULL, NULL, FALSE, 0, NULL,
403                 NULL, &si, &info);
404
405             if (res)
406             {
407                 CloseHandle(info.hThread);
408
409                 /* wait for the process to exit */
410                 WaitForSingleObject(info.hProcess, INFINITE);
411                 CloseHandle(info.hProcess);
412             }
413             else
414             {
415                 wsprintfW(errormsg, sUninstallFailed, iter->path);
416
417                 if (MessageBoxW(0, errormsg, iter->title, MB_YESNO |
418                     MB_ICONQUESTION) == IDYES)
419                 {
420                     /* delete the application's uninstall entry */
421                     RegOpenKeyExW(iter->regroot, PathUninstallW, 0, KEY_READ, &hkey);
422                     RegDeleteKeyW(hkey, iter->regkey);
423                     RegCloseKey(hkey);
424                 }
425             }
426
427             break;
428         }
429     }
430 }
431
432 /**********************************************************************************
433  * Name       : SetInfoDialogText
434  * Description: Sets the text of a label in a window, based upon a registry entry
435  *              or string passed to the function.
436  * Parameters : hKey         - registry entry to read from, NULL if not reading
437  *                             from registry
438  *              lpKeyName    - key to read from, or string to check if hKey is NULL
439  *              lpAltMessage - alternative message if entry not found
440  *              hWnd         - handle of dialog box
441  *              iDlgItem     - ID of label in dialog box
442  */
443 static void SetInfoDialogText(HKEY hKey, LPWSTR lpKeyName, LPWSTR lpAltMessage,
444   HWND hWnd, int iDlgItem)
445 {
446     WCHAR buf[MAX_STRING_LEN];
447     DWORD buflen;
448     HWND hWndDlgItem;
449
450     hWndDlgItem = GetDlgItem(hWnd, iDlgItem);
451
452     /* if hKey is null, lpKeyName contains the string we want to check */
453     if (hKey == NULL)
454     {
455         if ((lpKeyName) && (lstrlenW(lpKeyName) > 0))
456             SetWindowTextW(hWndDlgItem, lpKeyName);
457         else
458             SetWindowTextW(hWndDlgItem, lpAltMessage);
459     }
460     else
461     {
462         buflen = MAX_STRING_LEN;
463
464         if ((RegQueryValueExW(hKey, lpKeyName, 0, 0, (LPBYTE) buf, &buflen) ==
465            ERROR_SUCCESS) && (lstrlenW(buf) > 0))
466             SetWindowTextW(hWndDlgItem, buf);
467         else
468             SetWindowTextW(hWndDlgItem, lpAltMessage);
469     }
470 }
471
472 /******************************************************************************
473  * Name       : SupportInfoDlgProc
474  * Description: Callback procedure for support info dialog
475  * Parameters : hWnd    - hWnd of the window
476  *              msg     - reason for calling function
477  *              wParam  - additional parameter
478  *              lParam  - additional parameter
479  * Returns    : Dependant on message
480  */
481 static BOOL CALLBACK SupportInfoDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
482 {
483     APPINFO *iter;
484     HKEY hkey;
485     WCHAR oldtitle[MAX_STRING_LEN];
486     WCHAR buf[MAX_STRING_LEN];
487     WCHAR key[MAX_STRING_LEN];
488     WCHAR notfound[MAX_STRING_LEN];
489
490     switch(msg)
491     {
492         case WM_INITDIALOG:
493             for (iter = AppInfo; iter; iter = iter->next)
494             {
495                 if (iter->id == (int) lParam)
496                 {
497                     lstrcpyW(key, PathUninstallW);
498                     lstrcatW(key, BackSlashW);
499                     lstrcatW(key, iter->regkey);
500
501                     /* check the application's registry entries */
502                     RegOpenKeyExW(iter->regroot, key, 0, KEY_READ, &hkey);
503
504                     /* Load our "not specified" string */
505                     LoadStringW(hInst, IDS_NOT_SPECIFIED, notfound,
506                         sizeof(notfound) / sizeof(notfound[0]));
507
508                     /* Update the data for items already read into the structure */
509                     SetInfoDialogText(NULL, iter->publisher, notfound, hWnd,
510                         IDC_INFO_PUBLISHER);
511                     SetInfoDialogText(NULL, iter->version, notfound, hWnd,
512                         IDC_INFO_VERSION);
513
514                     /* And now update the data for those items in the registry */
515                     SetInfoDialogText(hkey, (LPWSTR) ContactW, notfound, hWnd,
516                         IDC_INFO_CONTACT);
517                     SetInfoDialogText(hkey, (LPWSTR) HelpLinkW, notfound, hWnd,
518                         IDC_INFO_SUPPORT);
519                     SetInfoDialogText(hkey, (LPWSTR) HelpTelephoneW, notfound, hWnd,
520                         IDC_INFO_PHONE);
521                     SetInfoDialogText(hkey, (LPWSTR) ReadmeW, notfound, hWnd,
522                         IDC_INFO_README);
523                     SetInfoDialogText(hkey, (LPWSTR) URLUpdateInfoW, notfound, hWnd,
524                         IDC_INFO_UPDATES);
525                     SetInfoDialogText(hkey, (LPWSTR) CommentsW, notfound, hWnd,
526                         IDC_INFO_COMMENTS);
527
528                     /* Update the main label with the app name */
529                     if (GetWindowTextW(GetDlgItem(hWnd, IDC_INFO_LABEL), oldtitle,
530                         MAX_STRING_LEN) != 0)
531                     {
532                         wsprintfW(buf, oldtitle, iter->title);
533                         SetWindowTextW(GetDlgItem(hWnd, IDC_INFO_LABEL), buf);
534                     }
535
536                     RegCloseKey(hkey);
537
538                     break;
539                 }
540             }
541
542             return TRUE;
543
544         case WM_DESTROY:
545             return 0;
546
547         case WM_COMMAND:
548             switch (LOWORD(wParam))
549             {
550                 case IDOK:
551                     EndDialog(hWnd, TRUE);
552                     break;
553
554             }
555
556             return TRUE;
557     }
558
559     return FALSE;
560 }
561
562 /******************************************************************************
563  * Name       : SupportInfo
564  * Description: Displays the Support Information dialog
565  * Parameters : hWnd    - Handle of the main dialog
566  *              id      - ID of the application to display information for
567  */
568 static void SupportInfo(HWND hWnd, int id)
569 {
570     DialogBoxParamW(hInst, MAKEINTRESOURCEW(IDD_INFO), hWnd, (DLGPROC)
571         SupportInfoDlgProc, (LPARAM) id);
572 }
573
574 /* Definition of column headers for AddListViewColumns function */
575 typedef struct AppWizColumn {
576    int width;
577    int fmt;
578    int title;
579 } AppWizColumn;
580
581 AppWizColumn columns[] = {
582     {200, LVCFMT_LEFT, IDS_COLUMN_NAME},
583     {150, LVCFMT_LEFT, IDS_COLUMN_PUBLISHER},
584     {100, LVCFMT_LEFT, IDS_COLUMN_VERSION},
585 };
586
587 /******************************************************************************
588  * Name       : AddListViewColumns
589  * Description: Adds column headers to the list view control.
590  * Parameters : hWnd    - Handle of the list view control.
591  * Returns    : TRUE if completed successfully, FALSE otherwise.
592  */
593 static BOOL AddListViewColumns(HWND hWnd)
594 {
595     WCHAR buf[MAX_STRING_LEN];
596     LVCOLUMNW lvc;
597     UINT i;
598
599     lvc.mask = LVCF_FMT | LVCF_TEXT | LVCF_SUBITEM | LVCF_WIDTH;
600
601     /* Add the columns */
602     for (i = 0; i < sizeof(columns) / sizeof(columns[0]); i++)
603     {
604         lvc.iSubItem = i;
605         lvc.pszText = buf;
606
607         /* set width and format */
608         lvc.cx = columns[i].width;
609         lvc.fmt = columns[i].fmt;
610
611         LoadStringW(hInst, columns[i].title, buf, sizeof(buf) / sizeof(buf[0]));
612
613         if (ListView_InsertColumnW(hWnd, i, &lvc) == -1)
614             return FALSE;
615     }
616
617     return TRUE;
618 }
619
620 /******************************************************************************
621  * Name       : AddListViewImageList
622  * Description: Creates an ImageList for the list view control.
623  * Parameters : hWnd    - Handle of the list view control.
624  * Returns    : Handle of the image list.
625  */
626 static HIMAGELIST AddListViewImageList(HWND hWnd)
627 {
628     HIMAGELIST hSmall;
629     HICON hDefaultIcon;
630
631     hSmall = ImageList_Create(GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON),
632         ILC_MASK, 1, 1);
633
634     /* Add default icon to image list */
635     hDefaultIcon = LoadIconW(hInst, MAKEINTRESOURCEW(ICO_MAIN));
636     ImageList_AddIcon(hSmall, hDefaultIcon);
637     DestroyIcon(hDefaultIcon);
638
639     (void) ListView_SetImageList(hWnd, hSmall, LVSIL_SMALL);
640
641     return hSmall;
642 }
643
644 /******************************************************************************
645  * Name       : ResetApplicationList
646  * Description: Empties the app list, if need be, and recreates it.
647  * Parameters : bFirstRun  - TRUE if this is the first time this is run, FALSE otherwise
648  *              hWnd       - handle of the dialog box
649  *              hImageList - handle of the image list
650  * Returns    : New handle of the image list.
651  */
652 static HIMAGELIST ResetApplicationList(BOOL bFirstRun, HWND hWnd, HIMAGELIST hImageList)
653 {
654     HWND hWndListView;
655
656     hWndListView = GetDlgItem(hWnd, IDL_PROGRAMS);
657
658     /* if first run, create the image list and add the listview columns */
659     if (bFirstRun)
660     {
661         if (!AddListViewColumns(hWndListView))
662             return NULL;
663     }
664     else /* we need to remove the existing things first */
665     {
666         RemoveItemsFromList(hWnd);
667         ImageList_Destroy(hImageList);
668
669         /* reset the list, since it's probably changed if the uninstallation was
670            successful */
671         EmptyList();
672     }
673
674     /* now create the image list and add the applications to the listview */
675     hImageList = AddListViewImageList(hWndListView);
676
677     ReadApplicationsFromRegistry(HKEY_LOCAL_MACHINE);
678     ReadApplicationsFromRegistry(HKEY_CURRENT_USER);
679
680     AddApplicationsToList(hWndListView, hImageList);
681     UpdateButtons(hWnd);
682
683     return(hImageList);
684 }
685
686 /******************************************************************************
687  * Name       : MainDlgProc
688  * Description: Callback procedure for main tab
689  * Parameters : hWnd    - hWnd of the window
690  *              msg     - reason for calling function
691  *              wParam  - additional parameter
692  *              lParam  - additional parameter
693  * Returns    : Dependant on message
694  */
695 static BOOL CALLBACK MainDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
696 {
697     int selitem;
698     static HIMAGELIST hImageList;
699     LPNMHDR nmh;
700     LVITEMW lvItem;
701
702     switch(msg)
703     {
704         case WM_INITDIALOG:
705             hImageList = ResetApplicationList(TRUE, hWnd, hImageList);
706
707             if (!hImageList)
708                 return FALSE;
709
710             return TRUE;
711
712         case WM_DESTROY:
713             RemoveItemsFromList(hWnd);
714             ImageList_Destroy(hImageList);
715
716             EmptyList();
717
718             return 0;
719
720         case WM_NOTIFY:
721             nmh = (LPNMHDR) lParam;
722
723             switch (nmh->idFrom)
724             {
725                 case IDL_PROGRAMS:
726                     switch (nmh->code)
727                     {
728                         case LVN_ITEMCHANGED:
729                             UpdateButtons(hWnd);
730                             break;
731                     }
732                     break;
733             }
734
735             return TRUE;
736
737         case WM_COMMAND:
738             switch (LOWORD(wParam))
739             {
740                 case IDC_ADDREMOVE:
741                     selitem = SendDlgItemMessageW(hWnd, IDL_PROGRAMS,
742                         LVM_GETNEXTITEM, -1, LVNI_FOCUSED|LVNI_SELECTED);
743
744                     if (selitem != -1)
745                     {
746                         lvItem.iItem = selitem;
747                         lvItem.mask = LVIF_PARAM;
748
749                         if (SendDlgItemMessageW(hWnd, IDL_PROGRAMS, LVM_GETITEMW,
750                           0, (LPARAM) &lvItem))
751                             UninstallProgram(lvItem.lParam);
752                     }
753
754                     hImageList = ResetApplicationList(FALSE, hWnd, hImageList);
755
756                     break;
757
758                 case IDC_SUPPORT_INFO:
759                     selitem = SendDlgItemMessageW(hWnd, IDL_PROGRAMS,
760                         LVM_GETNEXTITEM, -1, LVNI_FOCUSED | LVNI_SELECTED);
761
762                     if (selitem != -1)
763                     {
764                         lvItem.iItem = selitem;
765                         lvItem.mask = LVIF_PARAM;
766
767                         if (SendDlgItemMessageW(hWnd, IDL_PROGRAMS, LVM_GETITEMW,
768                           0, (LPARAM) &lvItem))
769                             SupportInfo(hWnd, lvItem.lParam);
770                     }
771
772                     break;
773             }
774
775             return TRUE;
776     }
777
778     return FALSE;
779 }
780
781 /******************************************************************************
782  * Name       : StartApplet
783  * Description: Main routine for applet
784  * Parameters : hWnd    - hWnd of the Control Panel
785  */
786 static void StartApplet(HWND hWnd)
787 {
788     PROPSHEETPAGEW psp;
789     PROPSHEETHEADERW psh;
790     WCHAR tab_title[MAX_STRING_LEN], app_title[MAX_STRING_LEN];
791
792     /* Load the strings we will use */
793     LoadStringW(hInst, IDS_TAB1_TITLE, tab_title, sizeof(tab_title) / sizeof(tab_title[0]));
794     LoadStringW(hInst, IDS_CPL_TITLE, app_title, sizeof(app_title) / sizeof(app_title[0]));
795
796     /* Fill out the PROPSHEETPAGE */
797     psp.dwSize = sizeof (PROPSHEETPAGEW);
798     psp.dwFlags = PSP_USETITLE;
799     psp.hInstance = hInst;
800     psp.u.pszTemplate = MAKEINTRESOURCEW (IDD_MAIN);
801     psp.u2.pszIcon = NULL;
802     psp.pfnDlgProc = (DLGPROC) MainDlgProc;
803     psp.pszTitle = tab_title;
804     psp.lParam = 0;
805
806     /* Fill out the PROPSHEETHEADER */
807     psh.dwSize = sizeof (PROPSHEETHEADERW);
808     psh.dwFlags = PSH_PROPSHEETPAGE | PSH_USEICONID;
809     psh.hwndParent = hWnd;
810     psh.hInstance = hInst;
811     psh.u.pszIcon = NULL;
812     psh.pszCaption = app_title;
813     psh.nPages = 1;
814     psh.u3.ppsp = &psp;
815     psh.pfnCallback = NULL;
816     psh.u2.nStartPage = 0;
817
818     /* Display the property sheet */
819     PropertySheetW (&psh);
820 }
821
822 /******************************************************************************
823  * Name       : CPlApplet
824  * Description: Entry point for Control Panel applets
825  * Parameters : hwndCPL - hWnd of the Control Panel
826  *              message - reason for calling function
827  *              lParam1 - additional parameter
828  *              lParam2 - additional parameter
829  * Returns    : Dependant on message
830  */
831 LONG CALLBACK CPlApplet(HWND hwndCPL, UINT message, LPARAM lParam1, LPARAM lParam2)
832 {
833     INITCOMMONCONTROLSEX iccEx;
834
835     switch (message)
836     {
837         case CPL_INIT:
838             iccEx.dwSize = sizeof(iccEx);
839             iccEx.dwICC = ICC_LISTVIEW_CLASSES | ICC_TAB_CLASSES;
840
841             InitCommonControlsEx(&iccEx);
842
843             return TRUE;
844
845         case CPL_GETCOUNT:
846             return 1;
847
848         case CPL_INQUIRE:
849         {
850             CPLINFO *appletInfo = (CPLINFO *) lParam2;
851
852             appletInfo->idIcon = ICO_MAIN;
853             appletInfo->idName = IDS_CPL_TITLE;
854             appletInfo->idInfo = IDS_CPL_DESC;
855             appletInfo->lData = 0;
856
857             break;
858         }
859
860         case CPL_DBLCLK:
861             StartApplet(hwndCPL);
862             break;
863     }
864
865     return FALSE;
866 }