kernelbase/tests: Use win_skip() for missing APIs.
[wine.git] / dlls / appwiz.cpl / appwiz.c
blob3359d5c4a2bd517aa1a6224c4e57b37a4076d3a6
1 /*
2 * Add/Remove Programs applet
3 * Partially based on Wine Uninstaller
5 * Copyright 2000 Andreas Mohr
6 * Copyright 2004 Hannu Valtonen
7 * Copyright 2005 Jonathan Ernst
8 * Copyright 2001-2002, 2008 Owen Rudge
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.
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.
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
26 #define NONAMELESSUNION
28 #include <string.h>
29 #include <stdlib.h>
30 #include <stdarg.h>
31 #include <stdio.h>
32 #include <windef.h>
33 #include <winbase.h>
34 #include <winuser.h>
35 #include <wingdi.h>
36 #include <winreg.h>
37 #include <shellapi.h>
38 #include <commctrl.h>
39 #include <commdlg.h>
40 #include <cpl.h>
42 #include "wine/list.h"
43 #include "wine/debug.h"
44 #include "appwiz.h"
45 #include "res.h"
47 WINE_DEFAULT_DEBUG_CHANNEL(appwizcpl);
49 /* define a maximum length for various buffers we use */
50 #define MAX_STRING_LEN 1024
52 typedef struct APPINFO
54 struct list entry;
55 int id;
57 LPWSTR title;
58 LPWSTR path;
59 LPWSTR path_modify;
61 LPWSTR icon;
62 int iconIdx;
64 LPWSTR publisher;
65 LPWSTR version;
66 LPWSTR contact;
67 LPWSTR helplink;
68 LPWSTR helptelephone;
69 LPWSTR readme;
70 LPWSTR urlupdateinfo;
71 LPWSTR comments;
73 HKEY regroot;
74 WCHAR regkey[MAX_STRING_LEN];
75 } APPINFO;
77 static struct list app_list = LIST_INIT( app_list );
78 HINSTANCE hInst;
80 static WCHAR btnRemove[MAX_STRING_LEN];
81 static WCHAR btnModifyRemove[MAX_STRING_LEN];
83 static const WCHAR PathUninstallW[] = L"Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall";
85 /******************************************************************************
86 * Name : DllMain
87 * Description: Entry point for DLL file
89 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason,
90 LPVOID lpvReserved)
92 TRACE("(%p, %ld, %p)\n", hinstDLL, fdwReason, lpvReserved);
94 switch (fdwReason)
96 case DLL_PROCESS_ATTACH:
97 hInst = hinstDLL;
98 break;
100 return TRUE;
103 /******************************************************************************
104 * Name : FreeAppInfo
105 * Description: Frees memory used by an AppInfo structure, and any children.
107 static void FreeAppInfo(APPINFO *info)
109 free(info->title);
110 free(info->path);
111 free(info->path_modify);
112 free(info->icon);
113 free(info->publisher);
114 free(info->version);
115 free(info->contact);
116 free(info->helplink);
117 free(info->helptelephone);
118 free(info->readme);
119 free(info->urlupdateinfo);
120 free(info->comments);
121 free(info);
124 static WCHAR *get_reg_str(HKEY hkey, const WCHAR *value)
126 DWORD len, type;
127 WCHAR *ret = NULL;
128 if (!RegQueryValueExW(hkey, value, NULL, &type, NULL, &len) && type == REG_SZ)
130 if (!(ret = malloc(len))) return NULL;
131 RegQueryValueExW(hkey, value, 0, 0, (BYTE *)ret, &len);
133 return ret;
136 /******************************************************************************
137 * Name : ReadApplicationsFromRegistry
138 * Description: Creates a linked list of uninstallable applications from the
139 * registry.
140 * Parameters : root - Which registry root to read from
141 * Returns : TRUE if successful, FALSE otherwise
143 static BOOL ReadApplicationsFromRegistry(HKEY root)
145 HKEY hkeyApp;
146 int i;
147 static int id = 0;
148 DWORD sizeOfSubKeyName, displen, uninstlen;
149 DWORD dwNoModify, dwType, value, size;
150 WCHAR subKeyName[256];
151 WCHAR *command;
152 APPINFO *info = NULL;
153 LPWSTR iconPtr;
155 sizeOfSubKeyName = ARRAY_SIZE(subKeyName);
157 for (i = 0; RegEnumKeyExW(root, i, subKeyName, &sizeOfSubKeyName, NULL,
158 NULL, NULL, NULL) != ERROR_NO_MORE_ITEMS; ++i)
160 RegOpenKeyExW(root, subKeyName, 0, KEY_READ, &hkeyApp);
161 size = sizeof(value);
162 if (!RegQueryValueExW(hkeyApp, L"SystemComponent", NULL, &dwType, (BYTE *)&value, &size)
163 && dwType == REG_DWORD && value == 1)
165 RegCloseKey(hkeyApp);
166 sizeOfSubKeyName = ARRAY_SIZE(subKeyName);
167 continue;
169 displen = 0;
170 uninstlen = 0;
171 if (!RegQueryValueExW(hkeyApp, L"DisplayName", 0, 0, NULL, &displen))
173 size = sizeof(value);
174 if (!RegQueryValueExW(hkeyApp, L"WindowsInstaller", NULL, &dwType, (BYTE *)&value, &size)
175 && dwType == REG_DWORD && value == 1)
177 int len = lstrlenW(L"msiexec /x%s") + lstrlenW(subKeyName);
179 if (!(command = malloc(len * sizeof(WCHAR)))) goto err;
180 wsprintfW(command, L"msiexec /x%s", subKeyName);
182 else if (!RegQueryValueExW(hkeyApp, L"UninstallString", 0, 0, NULL, &uninstlen))
184 if (!(command = malloc(uninstlen))) goto err;
185 RegQueryValueExW(hkeyApp, L"UninstallString", 0, 0, (BYTE *)command, &uninstlen);
187 else
189 RegCloseKey(hkeyApp);
190 sizeOfSubKeyName = ARRAY_SIZE(subKeyName);
191 continue;
194 info = calloc(1, sizeof(*info));
195 if (!info) goto err;
197 info->title = malloc(displen);
199 if (!info->title)
200 goto err;
202 RegQueryValueExW(hkeyApp, L"DisplayName", 0, 0, (BYTE *)info->title, &displen);
204 /* now get DisplayIcon */
205 displen = 0;
206 RegQueryValueExW(hkeyApp, L"DisplayIcon", 0, 0, NULL, &displen);
208 if (displen == 0)
209 info->icon = 0;
210 else
212 info->icon = malloc(displen);
214 if (!info->icon)
215 goto err;
217 RegQueryValueExW(hkeyApp, L"DisplayIcon", 0, 0, (BYTE *)info->icon, &displen);
219 /* separate the index from the icon name, if supplied */
220 iconPtr = wcschr(info->icon, ',');
222 if (iconPtr)
224 *iconPtr++ = 0;
225 info->iconIdx = wcstol(iconPtr, NULL, 10);
229 info->publisher = get_reg_str(hkeyApp, L"Publisher");
230 info->version = get_reg_str(hkeyApp, L"DisplayVersion");
231 info->contact = get_reg_str(hkeyApp, L"Contact");
232 info->helplink = get_reg_str(hkeyApp, L"HelpLink");
233 info->helptelephone = get_reg_str(hkeyApp, L"HelpTelephone");
234 info->readme = get_reg_str(hkeyApp, L"Readme");
235 info->urlupdateinfo = get_reg_str(hkeyApp, L"URLUpdateInfo");
236 info->comments = get_reg_str(hkeyApp, L"Comments");
238 /* Check if NoModify is set */
239 dwType = REG_DWORD;
240 dwNoModify = 0;
241 displen = sizeof(DWORD);
243 if (RegQueryValueExW(hkeyApp, L"NoModify", NULL, &dwType, (BYTE *)&dwNoModify, &displen)
244 != ERROR_SUCCESS)
246 dwNoModify = 0;
249 /* Some installers incorrectly create a REG_SZ instead of a REG_DWORD */
250 if (dwType == REG_SZ)
251 dwNoModify = (*(BYTE *)&dwNoModify == '1');
253 /* Fetch the modify path */
254 if (!dwNoModify)
256 size = sizeof(value);
257 if (!RegQueryValueExW(hkeyApp, L"WindowsInstaller", NULL, &dwType, (BYTE *)&value, &size)
258 && dwType == REG_DWORD && value == 1)
260 int len = lstrlenW(L"msiexec /i%s") + lstrlenW(subKeyName);
262 if (!(info->path_modify = malloc(len * sizeof(WCHAR)))) goto err;
263 wsprintfW(info->path_modify, L"msiexec /i%s", subKeyName);
265 else if (!RegQueryValueExW(hkeyApp, L"ModifyPath", 0, 0, NULL, &displen))
267 if (!(info->path_modify = malloc(displen))) goto err;
268 RegQueryValueExW(hkeyApp, L"ModifyPath", 0, 0, (BYTE *)info->path_modify, &displen);
272 /* registry key */
273 RegOpenKeyExW(root, NULL, 0, KEY_READ, &info->regroot);
274 lstrcpyW(info->regkey, subKeyName);
275 info->path = command;
277 info->id = id++;
278 list_add_tail( &app_list, &info->entry );
281 RegCloseKey(hkeyApp);
282 sizeOfSubKeyName = ARRAY_SIZE(subKeyName);
285 return TRUE;
286 err:
287 RegCloseKey(hkeyApp);
288 if (info) FreeAppInfo(info);
289 free(command);
290 return FALSE;
294 /******************************************************************************
295 * Name : AddApplicationsToList
296 * Description: Populates the list box with applications.
297 * Parameters : hWnd - Handle of the dialog box
299 static void AddApplicationsToList(HWND hWnd, HIMAGELIST hList)
301 APPINFO *iter;
302 LVITEMW lvItem;
303 HICON hIcon;
304 int index;
306 LIST_FOR_EACH_ENTRY( iter, &app_list, APPINFO, entry )
308 if (!iter->title[0]) continue;
310 /* get the icon */
311 index = 0;
313 if (iter->icon)
315 if (ExtractIconExW(iter->icon, iter->iconIdx, NULL, &hIcon, 1) == 1)
317 index = ImageList_AddIcon(hList, hIcon);
318 DestroyIcon(hIcon);
322 lvItem.mask = LVIF_IMAGE | LVIF_TEXT | LVIF_PARAM;
323 lvItem.iItem = iter->id;
324 lvItem.iSubItem = 0;
325 lvItem.pszText = iter->title;
326 lvItem.iImage = index;
327 lvItem.lParam = iter->id;
329 index = ListView_InsertItemW(hWnd, &lvItem);
331 /* now add the subitems (columns) */
332 ListView_SetItemTextW(hWnd, index, 1, iter->publisher);
333 ListView_SetItemTextW(hWnd, index, 2, iter->version);
337 /******************************************************************************
338 * Name : RemoveItemsFromList
339 * Description: Clears the application list box.
340 * Parameters : hWnd - Handle of the dialog box
342 static void RemoveItemsFromList(HWND hWnd)
344 SendDlgItemMessageW(hWnd, IDL_PROGRAMS, LVM_DELETEALLITEMS, 0, 0);
347 /******************************************************************************
348 * Name : EmptyList
349 * Description: Frees memory used by the application linked list.
351 static inline void EmptyList(void)
353 APPINFO *info, *next;
354 LIST_FOR_EACH_ENTRY_SAFE( info, next, &app_list, APPINFO, entry )
356 list_remove( &info->entry );
357 FreeAppInfo( info );
361 /******************************************************************************
362 * Name : UpdateButtons
363 * Description: Enables/disables the Add/Remove button depending on current
364 * selection in list box.
365 * Parameters : hWnd - Handle of the dialog box
367 static void UpdateButtons(HWND hWnd)
369 APPINFO *iter;
370 LVITEMW lvItem;
371 LRESULT selitem = SendDlgItemMessageW(hWnd, IDL_PROGRAMS, LVM_GETNEXTITEM, -1,
372 LVNI_FOCUSED | LVNI_SELECTED);
373 BOOL enable_modify = FALSE;
375 if (selitem != -1)
377 lvItem.iItem = selitem;
378 lvItem.mask = LVIF_PARAM;
380 if (SendDlgItemMessageW(hWnd, IDL_PROGRAMS, LVM_GETITEMW, 0, (LPARAM) &lvItem))
382 LIST_FOR_EACH_ENTRY( iter, &app_list, APPINFO, entry )
384 if (iter->id == lvItem.lParam)
386 /* Decide whether to display Modify/Remove as one button or two */
387 enable_modify = (iter->path_modify != NULL);
389 /* Update title as appropriate */
390 if (iter->path_modify == NULL)
391 SetWindowTextW(GetDlgItem(hWnd, IDC_ADDREMOVE), btnModifyRemove);
392 else
393 SetWindowTextW(GetDlgItem(hWnd, IDC_ADDREMOVE), btnRemove);
395 break;
401 /* Enable/disable other buttons if necessary */
402 EnableWindow(GetDlgItem(hWnd, IDC_ADDREMOVE), (selitem != -1));
403 EnableWindow(GetDlgItem(hWnd, IDC_SUPPORT_INFO), (selitem != -1));
404 EnableWindow(GetDlgItem(hWnd, IDC_MODIFY), enable_modify);
407 /******************************************************************************
408 * Name : InstallProgram
409 * Description: Search for potential Installer and execute it.
410 * Parameters : hWnd - Handle of the dialog box
412 static void InstallProgram(HWND hWnd)
414 OPENFILENAMEW ofn;
415 WCHAR titleW[MAX_STRING_LEN];
416 WCHAR filter_installs[MAX_STRING_LEN];
417 WCHAR filter_programs[MAX_STRING_LEN];
418 WCHAR filter_all[MAX_STRING_LEN];
419 WCHAR FilterBufferW[MAX_PATH];
420 WCHAR FileNameBufferW[MAX_PATH];
422 LoadStringW(hInst, IDS_CPL_TITLE, titleW, ARRAY_SIZE(titleW));
423 LoadStringW(hInst, IDS_FILTER_INSTALLS, filter_installs, ARRAY_SIZE(filter_installs));
424 LoadStringW(hInst, IDS_FILTER_PROGRAMS, filter_programs, ARRAY_SIZE(filter_programs));
425 LoadStringW(hInst, IDS_FILTER_ALL, filter_all, ARRAY_SIZE(filter_all));
427 swprintf( FilterBufferW, MAX_PATH, L"%s%c*instal*.exe;*setup*.exe;*.msi%c%s%c*.exe%c%s%c*.*%c",
428 filter_installs, 0, 0, filter_programs, 0, 0, filter_all, 0, 0 );
429 memset(&ofn, 0, sizeof(OPENFILENAMEW));
430 ofn.lStructSize = sizeof(OPENFILENAMEW);
431 ofn.hwndOwner = hWnd;
432 ofn.hInstance = hInst;
433 ofn.lpstrFilter = FilterBufferW;
434 ofn.nFilterIndex = 0;
435 ofn.lpstrFile = FileNameBufferW;
436 ofn.nMaxFile = MAX_PATH;
437 ofn.lpstrFileTitle = NULL;
438 ofn.nMaxFileTitle = 0;
439 ofn.lpstrTitle = titleW;
440 ofn.Flags = OFN_HIDEREADONLY | OFN_ENABLESIZING;
441 FileNameBufferW[0] = 0;
443 if (GetOpenFileNameW(&ofn))
445 SHELLEXECUTEINFOW sei;
446 memset(&sei, 0, sizeof(sei));
447 sei.cbSize = sizeof(sei);
448 sei.lpVerb = L"open";
449 sei.nShow = SW_SHOWDEFAULT;
450 sei.fMask = 0;
451 sei.lpFile = ofn.lpstrFile;
453 ShellExecuteExW(&sei);
457 static HANDLE run_uninstaller(int id, DWORD button)
459 APPINFO *iter;
460 STARTUPINFOW si;
461 PROCESS_INFORMATION info;
462 WCHAR errormsg[MAX_STRING_LEN];
463 WCHAR sUninstallFailed[MAX_STRING_LEN];
464 BOOL res;
466 LoadStringW(hInst, IDS_UNINSTALL_FAILED, sUninstallFailed,
467 ARRAY_SIZE(sUninstallFailed));
469 LIST_FOR_EACH_ENTRY( iter, &app_list, APPINFO, entry )
471 if (iter->id == id)
473 TRACE("Uninstalling %s (%s)\n", wine_dbgstr_w(iter->title),
474 wine_dbgstr_w(iter->path));
476 memset(&si, 0, sizeof(STARTUPINFOW));
477 si.cb = sizeof(STARTUPINFOW);
478 si.wShowWindow = SW_NORMAL;
480 res = CreateProcessW(NULL, (button == IDC_MODIFY) ? iter->path_modify : iter->path,
481 NULL, NULL, FALSE, 0, NULL, NULL, &si, &info);
483 if (res)
485 CloseHandle(info.hThread);
486 return info.hProcess;
488 else
490 wsprintfW(errormsg, sUninstallFailed, iter->path);
492 if (MessageBoxW(0, errormsg, iter->title, MB_YESNO |
493 MB_ICONQUESTION) == IDYES)
495 /* delete the application's uninstall entry */
496 RegDeleteKeyW(iter->regroot, iter->regkey);
497 RegCloseKey(iter->regroot);
501 break;
505 return NULL;
508 /**********************************************************************************
509 * Name : SetInfoDialogText
510 * Description: Sets the text of a label in a window, based upon a registry entry
511 * or string passed to the function.
512 * Parameters : hKey - registry entry to read from, NULL if not reading
513 * from registry
514 * lpKeyName - key to read from, or string to check if hKey is NULL
515 * lpAltMessage - alternative message if entry not found
516 * hWnd - handle of dialog box
517 * iDlgItem - ID of label in dialog box
519 static void SetInfoDialogText(HKEY hKey, LPCWSTR lpKeyName, LPCWSTR lpAltMessage,
520 HWND hWnd, int iDlgItem)
522 WCHAR buf[MAX_STRING_LEN];
523 DWORD buflen;
524 HWND hWndDlgItem;
526 hWndDlgItem = GetDlgItem(hWnd, iDlgItem);
528 /* if hKey is null, lpKeyName contains the string we want to check */
529 if (hKey == NULL)
531 if (lpKeyName && lpKeyName[0])
532 SetWindowTextW(hWndDlgItem, lpKeyName);
533 else
534 SetWindowTextW(hWndDlgItem, lpAltMessage);
536 else
538 buflen = sizeof(buf);
540 if ((RegQueryValueExW(hKey, lpKeyName, 0, 0, (LPBYTE) buf, &buflen) ==
541 ERROR_SUCCESS) && buf[0])
542 SetWindowTextW(hWndDlgItem, buf);
543 else
544 SetWindowTextW(hWndDlgItem, lpAltMessage);
548 /******************************************************************************
549 * Name : SupportInfoDlgProc
550 * Description: Callback procedure for support info dialog
551 * Parameters : hWnd - hWnd of the window
552 * msg - reason for calling function
553 * wParam - additional parameter
554 * lParam - additional parameter
555 * Returns : Depends on the message
557 static INT_PTR CALLBACK SupportInfoDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
559 APPINFO *iter;
560 HKEY hkey;
561 WCHAR oldtitle[MAX_STRING_LEN];
562 WCHAR buf[MAX_STRING_LEN];
563 WCHAR key[MAX_STRING_LEN];
564 WCHAR notfound[MAX_STRING_LEN];
566 switch(msg)
568 case WM_INITDIALOG:
569 LIST_FOR_EACH_ENTRY( iter, &app_list, APPINFO, entry )
571 if (iter->id == (int) lParam)
573 lstrcpyW(key, PathUninstallW);
574 lstrcatW(key, L"\\");
575 lstrcatW(key, iter->regkey);
577 /* check the application's registry entries */
578 RegOpenKeyExW(iter->regroot, key, 0, KEY_READ, &hkey);
580 /* Load our "not specified" string */
581 LoadStringW(hInst, IDS_NOT_SPECIFIED, notfound, ARRAY_SIZE(notfound));
583 SetInfoDialogText(NULL, iter->publisher, notfound, hWnd, IDC_INFO_PUBLISHER);
584 SetInfoDialogText(NULL, iter->version, notfound, hWnd, IDC_INFO_VERSION);
585 SetInfoDialogText(hkey, iter->contact, notfound, hWnd, IDC_INFO_CONTACT);
586 SetInfoDialogText(hkey, iter->helplink, notfound, hWnd, IDC_INFO_SUPPORT);
587 SetInfoDialogText(hkey, iter->helptelephone, notfound, hWnd, IDC_INFO_PHONE);
588 SetInfoDialogText(hkey, iter->readme, notfound, hWnd, IDC_INFO_README);
589 SetInfoDialogText(hkey, iter->urlupdateinfo, notfound, hWnd, IDC_INFO_UPDATES);
590 SetInfoDialogText(hkey, iter->comments, notfound, hWnd, IDC_INFO_COMMENTS);
592 /* Update the main label with the app name */
593 if (GetWindowTextW(GetDlgItem(hWnd, IDC_INFO_LABEL), oldtitle,
594 MAX_STRING_LEN) != 0)
596 wsprintfW(buf, oldtitle, iter->title);
597 SetWindowTextW(GetDlgItem(hWnd, IDC_INFO_LABEL), buf);
600 RegCloseKey(hkey);
602 break;
606 return TRUE;
608 case WM_DESTROY:
609 return 0;
611 case WM_CLOSE:
612 EndDialog(hWnd, TRUE);
613 return TRUE;
615 case WM_COMMAND:
616 switch (LOWORD(wParam))
618 case IDCANCEL:
619 case IDOK:
620 EndDialog(hWnd, TRUE);
621 break;
625 return TRUE;
628 return FALSE;
631 /******************************************************************************
632 * Name : SupportInfo
633 * Description: Displays the Support Information dialog
634 * Parameters : hWnd - Handle of the main dialog
635 * id - ID of the application to display information for
637 static void SupportInfo(HWND hWnd, int id)
639 DialogBoxParamW(hInst, MAKEINTRESOURCEW(IDD_INFO), hWnd, SupportInfoDlgProc, id);
642 /* Definition of column headers for AddListViewColumns function */
643 typedef struct AppWizColumn {
644 int width;
645 int fmt;
646 int title;
647 } AppWizColumn;
649 static const AppWizColumn columns[] = {
650 {200, LVCFMT_LEFT, IDS_COLUMN_NAME},
651 {150, LVCFMT_LEFT, IDS_COLUMN_PUBLISHER},
652 {100, LVCFMT_LEFT, IDS_COLUMN_VERSION},
655 /******************************************************************************
656 * Name : AddListViewColumns
657 * Description: Adds column headers to the list view control.
658 * Parameters : hWnd - Handle of the list view control.
659 * Returns : TRUE if completed successfully, FALSE otherwise.
661 static BOOL AddListViewColumns(HWND hWnd)
663 WCHAR buf[MAX_STRING_LEN];
664 LVCOLUMNW lvc;
665 UINT i;
667 lvc.mask = LVCF_FMT | LVCF_TEXT | LVCF_SUBITEM | LVCF_WIDTH;
669 /* Add the columns */
670 for (i = 0; i < ARRAY_SIZE(columns); i++)
672 lvc.iSubItem = i;
673 lvc.pszText = buf;
675 /* set width and format */
676 lvc.cx = columns[i].width;
677 lvc.fmt = columns[i].fmt;
679 LoadStringW(hInst, columns[i].title, buf, ARRAY_SIZE(buf));
681 if (ListView_InsertColumnW(hWnd, i, &lvc) == -1)
682 return FALSE;
685 return TRUE;
688 /******************************************************************************
689 * Name : AddListViewImageList
690 * Description: Creates an ImageList for the list view control.
691 * Parameters : hWnd - Handle of the list view control.
692 * Returns : Handle of the image list.
694 static HIMAGELIST AddListViewImageList(HWND hWnd)
696 HIMAGELIST hSmall;
697 HICON hDefaultIcon;
699 hSmall = ImageList_Create(GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON),
700 ILC_COLOR32 | ILC_MASK, 1, 1);
702 /* Add default icon to image list */
703 hDefaultIcon = LoadIconW(hInst, MAKEINTRESOURCEW(ICO_MAIN));
704 ImageList_AddIcon(hSmall, hDefaultIcon);
705 DestroyIcon(hDefaultIcon);
707 SendMessageW(hWnd, LVM_SETIMAGELIST, LVSIL_SMALL, (LPARAM)hSmall);
709 return hSmall;
712 /******************************************************************************
713 * Name : ResetApplicationList
714 * Description: Empties the app list, if need be, and recreates it.
715 * Parameters : bFirstRun - TRUE if this is the first time this is run, FALSE otherwise
716 * hWnd - handle of the dialog box
717 * hImageList - handle of the image list
718 * Returns : New handle of the image list.
720 static HIMAGELIST ResetApplicationList(BOOL bFirstRun, HWND hWnd, HIMAGELIST hImageList)
722 static const BOOL is_64bit = sizeof(void *) > sizeof(int);
723 HWND hWndListView;
724 HKEY hkey;
726 hWndListView = GetDlgItem(hWnd, IDL_PROGRAMS);
728 /* if first run, create the image list and add the listview columns */
729 if (bFirstRun)
731 if (!AddListViewColumns(hWndListView))
732 return NULL;
734 else /* we need to remove the existing things first */
736 RemoveItemsFromList(hWnd);
737 ImageList_Destroy(hImageList);
739 /* reset the list, since it's probably changed if the uninstallation was
740 successful */
741 EmptyList();
744 /* now create the image list and add the applications to the listview */
745 hImageList = AddListViewImageList(hWndListView);
747 if (!RegOpenKeyExW(HKEY_LOCAL_MACHINE, PathUninstallW, 0, KEY_READ, &hkey))
749 ReadApplicationsFromRegistry(hkey);
750 RegCloseKey(hkey);
752 if (is_64bit &&
753 !RegOpenKeyExW(HKEY_LOCAL_MACHINE, PathUninstallW, 0, KEY_READ|KEY_WOW64_32KEY, &hkey))
755 ReadApplicationsFromRegistry(hkey);
756 RegCloseKey(hkey);
758 if (!RegOpenKeyExW(HKEY_CURRENT_USER, PathUninstallW, 0, KEY_READ, &hkey))
760 ReadApplicationsFromRegistry(hkey);
761 RegCloseKey(hkey);
764 AddApplicationsToList(hWndListView, hImageList);
765 UpdateButtons(hWnd);
767 return(hImageList);
770 /******************************************************************************
771 * Name : MainDlgProc
772 * Description: Callback procedure for main tab
773 * Parameters : hWnd - hWnd of the window
774 * msg - reason for calling function
775 * wParam - additional parameter
776 * lParam - additional parameter
777 * Returns : Depends on the message
779 static INT_PTR CALLBACK MainDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
781 int selitem;
782 static HANDLE uninstaller = NULL;
783 static HIMAGELIST hImageList;
784 LPNMHDR nmh;
785 LVITEMW lvItem;
787 switch(msg)
789 case WM_INITDIALOG:
790 SendDlgItemMessageW(hWnd, IDL_PROGRAMS, LVM_SETEXTENDEDLISTVIEWSTYLE,
791 LVS_EX_FULLROWSELECT, LVS_EX_FULLROWSELECT);
793 hImageList = ResetApplicationList(TRUE, hWnd, hImageList);
795 if (!hImageList)
796 return FALSE;
798 return TRUE;
800 case WM_DESTROY:
801 RemoveItemsFromList(hWnd);
802 ImageList_Destroy(hImageList);
804 EmptyList();
806 return 0;
808 case WM_NOTIFY:
809 nmh = (LPNMHDR) lParam;
811 switch (nmh->idFrom)
813 case IDL_PROGRAMS:
814 switch (nmh->code)
816 case LVN_ITEMCHANGED:
817 UpdateButtons(hWnd);
818 break;
820 break;
823 return TRUE;
825 case WM_COMMAND:
826 switch (LOWORD(wParam))
828 case IDC_INSTALL:
829 InstallProgram(hWnd);
830 break;
832 case IDC_ADDREMOVE:
833 case IDC_MODIFY:
834 if (uninstaller)
836 WCHAR titleW[MAX_STRING_LEN], wait_tip[MAX_STRING_LEN];
838 LoadStringW(hInst, IDS_CPL_TITLE, titleW, ARRAY_SIZE(titleW));
839 LoadStringW(hInst, IDS_WAIT_COMPLETE, wait_tip, ARRAY_SIZE(wait_tip));
840 MessageBoxW(hWnd, wait_tip, titleW, MB_OK | MB_ICONWARNING);
841 break;
844 selitem = SendDlgItemMessageW(hWnd, IDL_PROGRAMS,
845 LVM_GETNEXTITEM, -1, LVNI_FOCUSED|LVNI_SELECTED);
847 if (selitem != -1)
849 lvItem.iItem = selitem;
850 lvItem.mask = LVIF_PARAM;
852 if (SendDlgItemMessageW(hWnd, IDL_PROGRAMS, LVM_GETITEMW, 0, (LPARAM)&lvItem))
854 uninstaller = run_uninstaller(lvItem.lParam, LOWORD(wParam));
855 while (MsgWaitForMultipleObjects(1, &uninstaller, FALSE, INFINITE, QS_ALLINPUT) == 1)
857 MSG message;
859 while (PeekMessageW(&message, 0, 0, 0, PM_REMOVE))
861 TranslateMessage(&message);
862 DispatchMessageW(&message);
865 CloseHandle(uninstaller);
866 uninstaller = NULL;
870 hImageList = ResetApplicationList(FALSE, hWnd, hImageList);
872 break;
874 case IDC_SUPPORT_INFO:
875 selitem = SendDlgItemMessageW(hWnd, IDL_PROGRAMS,
876 LVM_GETNEXTITEM, -1, LVNI_FOCUSED | LVNI_SELECTED);
878 if (selitem != -1)
880 lvItem.iItem = selitem;
881 lvItem.mask = LVIF_PARAM;
883 if (SendDlgItemMessageW(hWnd, IDL_PROGRAMS, LVM_GETITEMW,
884 0, (LPARAM) &lvItem))
885 SupportInfo(hWnd, lvItem.lParam);
888 break;
891 return TRUE;
894 return FALSE;
897 static int CALLBACK propsheet_callback( HWND hwnd, UINT msg, LPARAM lparam )
899 switch (msg)
901 case PSCB_INITIALIZED:
902 SendMessageW( hwnd, WM_SETICON, ICON_BIG, (LPARAM)LoadIconW( hInst, MAKEINTRESOURCEW(ICO_MAIN) ));
903 break;
905 return 0;
908 /******************************************************************************
909 * Name : StartApplet
910 * Description: Main routine for applet
911 * Parameters : hWnd - hWnd of the Control Panel
913 static void StartApplet(HWND hWnd)
915 PROPSHEETPAGEW psp;
916 PROPSHEETHEADERW psh;
917 WCHAR tab_title[MAX_STRING_LEN], app_title[MAX_STRING_LEN];
919 /* Load the strings we will use */
920 LoadStringW(hInst, IDS_TAB1_TITLE, tab_title, ARRAY_SIZE(tab_title));
921 LoadStringW(hInst, IDS_CPL_TITLE, app_title, ARRAY_SIZE(app_title));
922 LoadStringW(hInst, IDS_REMOVE, btnRemove, ARRAY_SIZE(btnRemove));
923 LoadStringW(hInst, IDS_MODIFY_REMOVE, btnModifyRemove, ARRAY_SIZE(btnModifyRemove));
925 /* Fill out the PROPSHEETPAGE */
926 psp.dwSize = sizeof (PROPSHEETPAGEW);
927 psp.dwFlags = PSP_USETITLE;
928 psp.hInstance = hInst;
929 psp.u.pszTemplate = MAKEINTRESOURCEW (IDD_MAIN);
930 psp.u2.pszIcon = NULL;
931 psp.pfnDlgProc = MainDlgProc;
932 psp.pszTitle = tab_title;
933 psp.lParam = 0;
935 /* Fill out the PROPSHEETHEADER */
936 psh.dwSize = sizeof (PROPSHEETHEADERW);
937 psh.dwFlags = PSH_PROPSHEETPAGE | PSH_USEICONID | PSH_USECALLBACK;
938 psh.hwndParent = hWnd;
939 psh.hInstance = hInst;
940 psh.u.pszIcon = MAKEINTRESOURCEW(ICO_MAIN);
941 psh.pszCaption = app_title;
942 psh.nPages = 1;
943 psh.u3.ppsp = &psp;
944 psh.pfnCallback = propsheet_callback;
945 psh.u2.nStartPage = 0;
947 /* Display the property sheet */
948 PropertySheetW (&psh);
951 static LONG start_params(const WCHAR *params)
953 if(!params)
954 return FALSE;
956 if(!wcscmp(params, L"install_gecko")) {
957 install_addon(ADDON_GECKO);
958 return TRUE;
961 if(!wcscmp(params, L"install_mono")) {
962 install_addon(ADDON_MONO);
963 return TRUE;
966 WARN("unknown param %s\n", debugstr_w(params));
967 return FALSE;
970 /******************************************************************************
971 * Name : CPlApplet
972 * Description: Entry point for Control Panel applets
973 * Parameters : hwndCPL - hWnd of the Control Panel
974 * message - reason for calling function
975 * lParam1 - additional parameter
976 * lParam2 - additional parameter
977 * Returns : Depends on the message
979 LONG CALLBACK CPlApplet(HWND hwndCPL, UINT message, LPARAM lParam1, LPARAM lParam2)
981 INITCOMMONCONTROLSEX iccEx;
983 switch (message)
985 case CPL_INIT:
986 iccEx.dwSize = sizeof(iccEx);
987 iccEx.dwICC = ICC_LISTVIEW_CLASSES | ICC_TAB_CLASSES | ICC_LINK_CLASS;
989 InitCommonControlsEx(&iccEx);
991 return TRUE;
993 case CPL_GETCOUNT:
994 return 1;
996 case CPL_STARTWPARMSW:
997 return start_params((const WCHAR *)lParam2);
999 case CPL_INQUIRE:
1001 CPLINFO *appletInfo = (CPLINFO *) lParam2;
1003 appletInfo->idIcon = ICO_MAIN;
1004 appletInfo->idName = IDS_CPL_TITLE;
1005 appletInfo->idInfo = IDS_CPL_DESC;
1006 appletInfo->lData = 0;
1008 break;
1011 case CPL_DBLCLK:
1012 StartApplet(hwndCPL);
1013 break;
1016 return FALSE;