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
29 #include "wine/port.h"
45 #include "wine/unicode.h"
46 #include "wine/list.h"
47 #include "wine/debug.h"
51 WINE_DEFAULT_DEBUG_CHANNEL(appwizcpl);
53 /* define a maximum length for various buffers we use */
54 #define MAX_STRING_LEN 1024
56 typedef struct APPINFO
72 WCHAR regkey[MAX_STRING_LEN];
75 static struct list app_list = LIST_INIT( app_list );
78 static WCHAR btnRemove[MAX_STRING_LEN];
79 static WCHAR btnModifyRemove[MAX_STRING_LEN];
81 static const WCHAR openW[] = {'o','p','e','n',0};
83 /* names of registry keys */
84 static const WCHAR BackSlashW[] = { '\\', 0 };
85 static const WCHAR DisplayNameW[] = {'D','i','s','p','l','a','y','N','a','m','e',0};
86 static const WCHAR DisplayIconW[] = {'D','i','s','p','l','a','y','I','c','o','n',0};
87 static const WCHAR DisplayVersionW[] = {'D','i','s','p','l','a','y','V','e','r',
89 static const WCHAR PublisherW[] = {'P','u','b','l','i','s','h','e','r',0};
90 static const WCHAR ContactW[] = {'C','o','n','t','a','c','t',0};
91 static const WCHAR HelpLinkW[] = {'H','e','l','p','L','i','n','k',0};
92 static const WCHAR HelpTelephoneW[] = {'H','e','l','p','T','e','l','e','p','h',
94 static const WCHAR ModifyPathW[] = {'M','o','d','i','f','y','P','a','t','h',0};
95 static const WCHAR NoModifyW[] = {'N','o','M','o','d','i','f','y',0};
96 static const WCHAR ReadmeW[] = {'R','e','a','d','m','e',0};
97 static const WCHAR URLUpdateInfoW[] = {'U','R','L','U','p','d','a','t','e','I',
99 static const WCHAR CommentsW[] = {'C','o','m','m','e','n','t','s',0};
100 static const WCHAR UninstallCommandlineW[] = {'U','n','i','n','s','t','a','l','l',
101 'S','t','r','i','n','g',0};
102 static const WCHAR WindowsInstallerW[] = {'W','i','n','d','o','w','s','I','n','s','t','a','l','l','e','r',0};
104 static const WCHAR PathUninstallW[] = {
105 'S','o','f','t','w','a','r','e','\\',
106 'M','i','c','r','o','s','o','f','t','\\',
107 'W','i','n','d','o','w','s','\\',
108 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
109 'U','n','i','n','s','t','a','l','l',0 };
111 /******************************************************************************
113 * Description: Entry point for DLL file
115 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason,
118 TRACE("(%p, %d, %p)\n", hinstDLL, fdwReason, lpvReserved);
122 case DLL_PROCESS_ATTACH:
129 /******************************************************************************
131 * Description: Frees memory used by an AppInfo structure, and any children.
133 static void FreeAppInfo(APPINFO *info)
135 HeapFree(GetProcessHeap(), 0, info->title);
136 HeapFree(GetProcessHeap(), 0, info->path);
137 HeapFree(GetProcessHeap(), 0, info->path_modify);
138 HeapFree(GetProcessHeap(), 0, info->icon);
139 HeapFree(GetProcessHeap(), 0, info->publisher);
140 HeapFree(GetProcessHeap(), 0, info->version);
141 HeapFree(GetProcessHeap(), 0, info);
144 /******************************************************************************
145 * Name : ReadApplicationsFromRegistry
146 * Description: Creates a linked list of uninstallable applications from the
148 * Parameters : root - Which registry root to read from
149 * Returns : TRUE if successful, FALSE otherwise
151 static BOOL ReadApplicationsFromRegistry(HKEY root)
155 DWORD sizeOfSubKeyName, displen, uninstlen;
156 DWORD dwNoModify, dwType, value;
157 WCHAR subKeyName[256];
159 APPINFO *info = NULL;
162 sizeOfSubKeyName = sizeof(subKeyName) / sizeof(subKeyName[0]);
164 for (i = 0; RegEnumKeyExW(root, i, subKeyName, &sizeOfSubKeyName, NULL,
165 NULL, NULL, NULL) != ERROR_NO_MORE_ITEMS; ++i)
167 RegOpenKeyExW(root, subKeyName, 0, KEY_READ, &hkeyApp);
171 if (!RegQueryValueExW(hkeyApp, DisplayNameW, 0, 0, NULL, &displen))
173 DWORD size = sizeof(value);
174 if (!RegQueryValueExW(hkeyApp, WindowsInstallerW, NULL, &dwType, (LPBYTE)&value, &size)
175 && dwType == REG_DWORD && value == 1)
177 static const WCHAR fmtW[] = {'m','s','i','e','x','e','c',' ','/','x','%','s',0};
178 int len = lstrlenW(fmtW) + lstrlenW(subKeyName);
180 if (!(command = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)))) goto err;
181 wsprintfW(command, fmtW, subKeyName);
183 else if (!RegQueryValueExW(hkeyApp, UninstallCommandlineW, 0, 0, NULL, &uninstlen))
185 if (!(command = HeapAlloc(GetProcessHeap(), 0, uninstlen))) goto err;
186 RegQueryValueExW(hkeyApp, UninstallCommandlineW, 0, 0, (LPBYTE)command, &uninstlen);
190 RegCloseKey(hkeyApp);
191 sizeOfSubKeyName = sizeof(subKeyName) / sizeof(subKeyName[0]);
195 info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(struct APPINFO));
198 info->title = HeapAlloc(GetProcessHeap(), 0, displen);
203 RegQueryValueExW(hkeyApp, DisplayNameW, 0, 0, (LPBYTE)info->title,
206 /* now get DisplayIcon */
208 RegQueryValueExW(hkeyApp, DisplayIconW, 0, 0, NULL, &displen);
214 info->icon = HeapAlloc(GetProcessHeap(), 0, displen);
219 RegQueryValueExW(hkeyApp, DisplayIconW, 0, 0, (LPBYTE)info->icon,
222 /* separate the index from the icon name, if supplied */
223 iconPtr = strchrW(info->icon, ',');
228 info->iconIdx = atoiW(iconPtr);
232 /* publisher, version */
233 if (RegQueryValueExW(hkeyApp, PublisherW, 0, 0, NULL, &displen) ==
236 info->publisher = HeapAlloc(GetProcessHeap(), 0, displen);
238 if (!info->publisher)
241 RegQueryValueExW(hkeyApp, PublisherW, 0, 0, (LPBYTE)info->publisher,
245 if (RegQueryValueExW(hkeyApp, DisplayVersionW, 0, 0, NULL, &displen) ==
248 info->version = HeapAlloc(GetProcessHeap(), 0, displen);
253 RegQueryValueExW(hkeyApp, DisplayVersionW, 0, 0, (LPBYTE)info->version,
257 /* Check if NoModify is set */
260 displen = sizeof(DWORD);
262 if (RegQueryValueExW(hkeyApp, NoModifyW, NULL, &dwType, (LPBYTE)&dwNoModify, &displen)
268 /* Some installers incorrectly create a REG_SZ instead of a REG_DWORD */
269 if (dwType == REG_SZ)
270 dwNoModify = (*(BYTE *)&dwNoModify == '1');
272 /* Fetch the modify path */
275 size = sizeof(value);
276 if (!RegQueryValueExW(hkeyApp, WindowsInstallerW, NULL, &dwType, (LPBYTE)&value, &size)
277 && dwType == REG_DWORD && value == 1)
279 static const WCHAR fmtW[] = {'m','s','i','e','x','e','c',' ','/','i','%','s',0};
280 int len = lstrlenW(fmtW) + lstrlenW(subKeyName);
282 if (!(info->path_modify = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)))) goto err;
283 wsprintfW(info->path_modify, fmtW, subKeyName);
285 else if (!RegQueryValueExW(hkeyApp, ModifyPathW, 0, 0, NULL, &displen))
287 if (!(info->path_modify = HeapAlloc(GetProcessHeap(), 0, displen))) goto err;
288 RegQueryValueExW(hkeyApp, ModifyPathW, 0, 0, (LPBYTE)info->path_modify, &displen);
293 info->regroot = root;
294 lstrcpyW(info->regkey, subKeyName);
295 info->path = command;
298 list_add_tail( &app_list, &info->entry );
301 RegCloseKey(hkeyApp);
302 sizeOfSubKeyName = sizeof(subKeyName) / sizeof(subKeyName[0]);
307 RegCloseKey(hkeyApp);
308 if (info) FreeAppInfo(info);
313 /******************************************************************************
314 * Name : AddApplicationsToList
315 * Description: Populates the list box with applications.
316 * Parameters : hWnd - Handle of the dialog box
318 static void AddApplicationsToList(HWND hWnd, HIMAGELIST hList)
325 LIST_FOR_EACH_ENTRY( iter, &app_list, APPINFO, entry )
327 if (!iter->title[0]) continue;
334 if (ExtractIconExW(iter->icon, iter->iconIdx, NULL, &hIcon, 1) == 1)
336 index = ImageList_AddIcon(hList, hIcon);
341 lvItem.mask = LVIF_IMAGE | LVIF_TEXT | LVIF_PARAM;
342 lvItem.iItem = iter->id;
344 lvItem.pszText = iter->title;
345 lvItem.iImage = index;
346 lvItem.lParam = iter->id;
348 index = ListView_InsertItemW(hWnd, &lvItem);
350 /* now add the subitems (columns) */
351 ListView_SetItemTextW(hWnd, index, 1, iter->publisher);
352 ListView_SetItemTextW(hWnd, index, 2, iter->version);
356 /******************************************************************************
357 * Name : RemoveItemsFromList
358 * Description: Clears the application list box.
359 * Parameters : hWnd - Handle of the dialog box
361 static void RemoveItemsFromList(HWND hWnd)
363 SendDlgItemMessageW(hWnd, IDL_PROGRAMS, LVM_DELETEALLITEMS, 0, 0);
366 /******************************************************************************
368 * Description: Frees memory used by the application linked list.
370 static inline void EmptyList(void)
372 APPINFO *info, *next;
373 LIST_FOR_EACH_ENTRY_SAFE( info, next, &app_list, APPINFO, entry )
375 list_remove( &info->entry );
380 /******************************************************************************
381 * Name : UpdateButtons
382 * Description: Enables/disables the Add/Remove button depending on current
383 * selection in list box.
384 * Parameters : hWnd - Handle of the dialog box
386 static void UpdateButtons(HWND hWnd)
390 LRESULT selitem = SendDlgItemMessageW(hWnd, IDL_PROGRAMS, LVM_GETNEXTITEM, -1,
391 LVNI_FOCUSED | LVNI_SELECTED);
392 BOOL enable_modify = FALSE;
396 lvItem.iItem = selitem;
397 lvItem.mask = LVIF_PARAM;
399 if (SendDlgItemMessageW(hWnd, IDL_PROGRAMS, LVM_GETITEMW, 0, (LPARAM) &lvItem))
401 LIST_FOR_EACH_ENTRY( iter, &app_list, APPINFO, entry )
403 if (iter->id == lvItem.lParam)
405 /* Decide whether to display Modify/Remove as one button or two */
406 enable_modify = (iter->path_modify != NULL);
408 /* Update title as appropriate */
409 if (iter->path_modify == NULL)
410 SetWindowTextW(GetDlgItem(hWnd, IDC_ADDREMOVE), btnModifyRemove);
412 SetWindowTextW(GetDlgItem(hWnd, IDC_ADDREMOVE), btnRemove);
420 /* Enable/disable other buttons if necessary */
421 EnableWindow(GetDlgItem(hWnd, IDC_ADDREMOVE), (selitem != -1));
422 EnableWindow(GetDlgItem(hWnd, IDC_SUPPORT_INFO), (selitem != -1));
423 EnableWindow(GetDlgItem(hWnd, IDC_MODIFY), enable_modify);
426 /******************************************************************************
427 * Name : InstallProgram
428 * Description: Search for potential Installer and execute it.
429 * Parameters : hWnd - Handle of the dialog box
431 static void InstallProgram(HWND hWnd)
433 static const WCHAR filters[] = {'%','s','%','c','*','i','n','s','t','a','l','*','.','e','x','e',';','*','s','e','t','u','p','*','.','e','x','e',';','*','.','m','s','i','%','c','%','s','%','c','*','.','e','x','e','%','c','%','s','%','c','*','.','*','%','c',0}
436 WCHAR titleW[MAX_STRING_LEN];
437 WCHAR filter_installs[MAX_STRING_LEN];
438 WCHAR filter_programs[MAX_STRING_LEN];
439 WCHAR filter_all[MAX_STRING_LEN];
440 WCHAR FilterBufferW[MAX_PATH];
441 WCHAR FileNameBufferW[MAX_PATH];
443 LoadStringW(hInst, IDS_CPL_TITLE, titleW, sizeof(titleW)/sizeof(WCHAR));
444 LoadStringW(hInst, IDS_FILTER_INSTALLS, filter_installs, sizeof(filter_installs)/sizeof(WCHAR));
445 LoadStringW(hInst, IDS_FILTER_PROGRAMS, filter_programs, sizeof(filter_programs)/sizeof(WCHAR));
446 LoadStringW(hInst, IDS_FILTER_ALL, filter_all, sizeof(filter_all)/sizeof(WCHAR));
448 snprintfW( FilterBufferW, MAX_PATH, filters, filter_installs, 0, 0,
449 filter_programs, 0, 0, filter_all, 0, 0 );
450 memset(&ofn, 0, sizeof(OPENFILENAMEW));
451 ofn.lStructSize = sizeof(OPENFILENAMEW);
452 ofn.hwndOwner = hWnd;
453 ofn.hInstance = hInst;
454 ofn.lpstrFilter = FilterBufferW;
455 ofn.nFilterIndex = 0;
456 ofn.lpstrFile = FileNameBufferW;
457 ofn.nMaxFile = MAX_PATH;
458 ofn.lpstrFileTitle = NULL;
459 ofn.nMaxFileTitle = 0;
460 ofn.lpstrTitle = titleW;
461 ofn.Flags = OFN_HIDEREADONLY | OFN_ENABLESIZING;
462 FileNameBufferW[0] = 0;
464 if (GetOpenFileNameW(&ofn))
466 SHELLEXECUTEINFOW sei;
467 memset(&sei, 0, sizeof(sei));
468 sei.cbSize = sizeof(sei);
470 sei.nShow = SW_SHOWDEFAULT;
471 sei.fMask = SEE_MASK_NO_CONSOLE;
472 sei.lpFile = ofn.lpstrFile;
474 ShellExecuteExW(&sei);
478 /******************************************************************************
479 * Name : UninstallProgram
480 * Description: Executes the specified program's installer.
481 * Parameters : id - the internal ID of the installer to remove
482 * Parameters : button - ID of button pressed (Modify or Remove)
484 static void UninstallProgram(int id, DWORD button)
488 PROCESS_INFORMATION info;
489 WCHAR errormsg[MAX_STRING_LEN];
490 WCHAR sUninstallFailed[MAX_STRING_LEN];
494 LoadStringW(hInst, IDS_UNINSTALL_FAILED, sUninstallFailed,
495 sizeof(sUninstallFailed) / sizeof(sUninstallFailed[0]));
497 LIST_FOR_EACH_ENTRY( iter, &app_list, APPINFO, entry )
501 TRACE("Uninstalling %s (%s)\n", wine_dbgstr_w(iter->title),
502 wine_dbgstr_w(iter->path));
504 memset(&si, 0, sizeof(STARTUPINFOW));
505 si.cb = sizeof(STARTUPINFOW);
506 si.wShowWindow = SW_NORMAL;
508 res = CreateProcessW(NULL, (button == IDC_MODIFY) ? iter->path_modify : iter->path,
509 NULL, NULL, FALSE, 0, NULL, NULL, &si, &info);
513 CloseHandle(info.hThread);
515 /* wait for the process to exit */
516 WaitForSingleObject(info.hProcess, INFINITE);
517 CloseHandle(info.hProcess);
521 wsprintfW(errormsg, sUninstallFailed, iter->path);
523 if (MessageBoxW(0, errormsg, iter->title, MB_YESNO |
524 MB_ICONQUESTION) == IDYES)
526 /* delete the application's uninstall entry */
527 RegOpenKeyExW(iter->regroot, PathUninstallW, 0, KEY_READ, &hkey);
528 RegDeleteKeyW(hkey, iter->regkey);
538 /**********************************************************************************
539 * Name : SetInfoDialogText
540 * Description: Sets the text of a label in a window, based upon a registry entry
541 * or string passed to the function.
542 * Parameters : hKey - registry entry to read from, NULL if not reading
544 * lpKeyName - key to read from, or string to check if hKey is NULL
545 * lpAltMessage - alternative message if entry not found
546 * hWnd - handle of dialog box
547 * iDlgItem - ID of label in dialog box
549 static void SetInfoDialogText(HKEY hKey, LPCWSTR lpKeyName, LPCWSTR lpAltMessage,
550 HWND hWnd, int iDlgItem)
552 WCHAR buf[MAX_STRING_LEN];
556 hWndDlgItem = GetDlgItem(hWnd, iDlgItem);
558 /* if hKey is null, lpKeyName contains the string we want to check */
561 if ((lpKeyName) && (lstrlenW(lpKeyName) > 0))
562 SetWindowTextW(hWndDlgItem, lpKeyName);
564 SetWindowTextW(hWndDlgItem, lpAltMessage);
568 buflen = MAX_STRING_LEN;
570 if ((RegQueryValueExW(hKey, lpKeyName, 0, 0, (LPBYTE) buf, &buflen) ==
571 ERROR_SUCCESS) && (lstrlenW(buf) > 0))
572 SetWindowTextW(hWndDlgItem, buf);
574 SetWindowTextW(hWndDlgItem, lpAltMessage);
578 /******************************************************************************
579 * Name : SupportInfoDlgProc
580 * Description: Callback procedure for support info dialog
581 * Parameters : hWnd - hWnd of the window
582 * msg - reason for calling function
583 * wParam - additional parameter
584 * lParam - additional parameter
585 * Returns : Dependant on message
587 static BOOL CALLBACK SupportInfoDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
591 WCHAR oldtitle[MAX_STRING_LEN];
592 WCHAR buf[MAX_STRING_LEN];
593 WCHAR key[MAX_STRING_LEN];
594 WCHAR notfound[MAX_STRING_LEN];
599 LIST_FOR_EACH_ENTRY( iter, &app_list, APPINFO, entry )
601 if (iter->id == (int) lParam)
603 lstrcpyW(key, PathUninstallW);
604 lstrcatW(key, BackSlashW);
605 lstrcatW(key, iter->regkey);
607 /* check the application's registry entries */
608 RegOpenKeyExW(iter->regroot, key, 0, KEY_READ, &hkey);
610 /* Load our "not specified" string */
611 LoadStringW(hInst, IDS_NOT_SPECIFIED, notfound,
612 sizeof(notfound) / sizeof(notfound[0]));
614 /* Update the data for items already read into the structure */
615 SetInfoDialogText(NULL, iter->publisher, notfound, hWnd,
617 SetInfoDialogText(NULL, iter->version, notfound, hWnd,
620 /* And now update the data for those items in the registry */
621 SetInfoDialogText(hkey, ContactW, notfound, hWnd,
623 SetInfoDialogText(hkey, HelpLinkW, notfound, hWnd,
625 SetInfoDialogText(hkey, HelpTelephoneW, notfound, hWnd,
627 SetInfoDialogText(hkey, ReadmeW, notfound, hWnd,
629 SetInfoDialogText(hkey, URLUpdateInfoW, notfound, hWnd,
631 SetInfoDialogText(hkey, CommentsW, notfound, hWnd,
634 /* Update the main label with the app name */
635 if (GetWindowTextW(GetDlgItem(hWnd, IDC_INFO_LABEL), oldtitle,
636 MAX_STRING_LEN) != 0)
638 wsprintfW(buf, oldtitle, iter->title);
639 SetWindowTextW(GetDlgItem(hWnd, IDC_INFO_LABEL), buf);
654 switch (LOWORD(wParam))
657 EndDialog(hWnd, TRUE);
668 /******************************************************************************
670 * Description: Displays the Support Information dialog
671 * Parameters : hWnd - Handle of the main dialog
672 * id - ID of the application to display information for
674 static void SupportInfo(HWND hWnd, int id)
676 DialogBoxParamW(hInst, MAKEINTRESOURCEW(IDD_INFO), hWnd, (DLGPROC)
677 SupportInfoDlgProc, (LPARAM) id);
680 /* Definition of column headers for AddListViewColumns function */
681 typedef struct AppWizColumn {
687 static const AppWizColumn columns[] = {
688 {200, LVCFMT_LEFT, IDS_COLUMN_NAME},
689 {150, LVCFMT_LEFT, IDS_COLUMN_PUBLISHER},
690 {100, LVCFMT_LEFT, IDS_COLUMN_VERSION},
693 /******************************************************************************
694 * Name : AddListViewColumns
695 * Description: Adds column headers to the list view control.
696 * Parameters : hWnd - Handle of the list view control.
697 * Returns : TRUE if completed successfully, FALSE otherwise.
699 static BOOL AddListViewColumns(HWND hWnd)
701 WCHAR buf[MAX_STRING_LEN];
705 lvc.mask = LVCF_FMT | LVCF_TEXT | LVCF_SUBITEM | LVCF_WIDTH;
707 /* Add the columns */
708 for (i = 0; i < sizeof(columns) / sizeof(columns[0]); i++)
713 /* set width and format */
714 lvc.cx = columns[i].width;
715 lvc.fmt = columns[i].fmt;
717 LoadStringW(hInst, columns[i].title, buf, sizeof(buf) / sizeof(buf[0]));
719 if (ListView_InsertColumnW(hWnd, i, &lvc) == -1)
726 /******************************************************************************
727 * Name : AddListViewImageList
728 * Description: Creates an ImageList for the list view control.
729 * Parameters : hWnd - Handle of the list view control.
730 * Returns : Handle of the image list.
732 static HIMAGELIST AddListViewImageList(HWND hWnd)
737 hSmall = ImageList_Create(GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON),
738 ILC_COLOR32 | ILC_MASK, 1, 1);
740 /* Add default icon to image list */
741 hDefaultIcon = LoadIconW(hInst, MAKEINTRESOURCEW(ICO_MAIN));
742 ImageList_AddIcon(hSmall, hDefaultIcon);
743 DestroyIcon(hDefaultIcon);
745 SendMessageW(hWnd, LVM_SETIMAGELIST, LVSIL_SMALL, (LPARAM)hSmall);
750 /******************************************************************************
751 * Name : ResetApplicationList
752 * Description: Empties the app list, if need be, and recreates it.
753 * Parameters : bFirstRun - TRUE if this is the first time this is run, FALSE otherwise
754 * hWnd - handle of the dialog box
755 * hImageList - handle of the image list
756 * Returns : New handle of the image list.
758 static HIMAGELIST ResetApplicationList(BOOL bFirstRun, HWND hWnd, HIMAGELIST hImageList)
760 static const BOOL is_64bit = sizeof(void *) > sizeof(int);
764 hWndListView = GetDlgItem(hWnd, IDL_PROGRAMS);
766 /* if first run, create the image list and add the listview columns */
769 if (!AddListViewColumns(hWndListView))
772 else /* we need to remove the existing things first */
774 RemoveItemsFromList(hWnd);
775 ImageList_Destroy(hImageList);
777 /* reset the list, since it's probably changed if the uninstallation was
782 /* now create the image list and add the applications to the listview */
783 hImageList = AddListViewImageList(hWndListView);
785 if (!RegOpenKeyExW(HKEY_LOCAL_MACHINE, PathUninstallW, 0, KEY_READ, &hkey))
787 ReadApplicationsFromRegistry(hkey);
791 !RegOpenKeyExW(HKEY_LOCAL_MACHINE, PathUninstallW, 0, KEY_READ|KEY_WOW64_32KEY, &hkey))
793 ReadApplicationsFromRegistry(hkey);
796 if (!RegOpenKeyExW(HKEY_CURRENT_USER, PathUninstallW, 0, KEY_READ, &hkey))
798 ReadApplicationsFromRegistry(hkey);
802 AddApplicationsToList(hWndListView, hImageList);
808 /******************************************************************************
810 * Description: Callback procedure for main tab
811 * Parameters : hWnd - hWnd of the window
812 * msg - reason for calling function
813 * wParam - additional parameter
814 * lParam - additional parameter
815 * Returns : Dependant on message
817 static BOOL CALLBACK MainDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
820 static HIMAGELIST hImageList;
827 hImageList = ResetApplicationList(TRUE, hWnd, hImageList);
835 RemoveItemsFromList(hWnd);
836 ImageList_Destroy(hImageList);
843 nmh = (LPNMHDR) lParam;
850 case LVN_ITEMCHANGED:
860 switch (LOWORD(wParam))
863 InstallProgram(hWnd);
868 selitem = SendDlgItemMessageW(hWnd, IDL_PROGRAMS,
869 LVM_GETNEXTITEM, -1, LVNI_FOCUSED|LVNI_SELECTED);
873 lvItem.iItem = selitem;
874 lvItem.mask = LVIF_PARAM;
876 if (SendDlgItemMessageW(hWnd, IDL_PROGRAMS, LVM_GETITEMW,
877 0, (LPARAM) &lvItem))
878 UninstallProgram(lvItem.lParam, LOWORD(wParam));
881 hImageList = ResetApplicationList(FALSE, hWnd, hImageList);
885 case IDC_SUPPORT_INFO:
886 selitem = SendDlgItemMessageW(hWnd, IDL_PROGRAMS,
887 LVM_GETNEXTITEM, -1, LVNI_FOCUSED | LVNI_SELECTED);
891 lvItem.iItem = selitem;
892 lvItem.mask = LVIF_PARAM;
894 if (SendDlgItemMessageW(hWnd, IDL_PROGRAMS, LVM_GETITEMW,
895 0, (LPARAM) &lvItem))
896 SupportInfo(hWnd, lvItem.lParam);
908 static int CALLBACK propsheet_callback( HWND hwnd, UINT msg, LPARAM lparam )
912 case PSCB_INITIALIZED:
913 SendMessageW( hwnd, WM_SETICON, ICON_BIG, (LPARAM)LoadIconW( hInst, MAKEINTRESOURCEW(ICO_MAIN) ));
919 /******************************************************************************
921 * Description: Main routine for applet
922 * Parameters : hWnd - hWnd of the Control Panel
924 static void StartApplet(HWND hWnd)
927 PROPSHEETHEADERW psh;
928 WCHAR tab_title[MAX_STRING_LEN], app_title[MAX_STRING_LEN];
930 /* Load the strings we will use */
931 LoadStringW(hInst, IDS_TAB1_TITLE, tab_title, sizeof(tab_title) / sizeof(tab_title[0]));
932 LoadStringW(hInst, IDS_CPL_TITLE, app_title, sizeof(app_title) / sizeof(app_title[0]));
933 LoadStringW(hInst, IDS_REMOVE, btnRemove, sizeof(btnRemove) / sizeof(btnRemove[0]));
934 LoadStringW(hInst, IDS_MODIFY_REMOVE, btnModifyRemove, sizeof(btnModifyRemove) / sizeof(btnModifyRemove[0]));
936 /* Fill out the PROPSHEETPAGE */
937 psp.dwSize = sizeof (PROPSHEETPAGEW);
938 psp.dwFlags = PSP_USETITLE;
939 psp.hInstance = hInst;
940 psp.u.pszTemplate = MAKEINTRESOURCEW (IDD_MAIN);
941 psp.u2.pszIcon = NULL;
942 psp.pfnDlgProc = (DLGPROC) MainDlgProc;
943 psp.pszTitle = tab_title;
946 /* Fill out the PROPSHEETHEADER */
947 psh.dwSize = sizeof (PROPSHEETHEADERW);
948 psh.dwFlags = PSH_PROPSHEETPAGE | PSH_USEICONID | PSH_USECALLBACK;
949 psh.hwndParent = hWnd;
950 psh.hInstance = hInst;
951 psh.u.pszIcon = MAKEINTRESOURCEW(ICO_MAIN);
952 psh.pszCaption = app_title;
955 psh.pfnCallback = propsheet_callback;
956 psh.u2.nStartPage = 0;
958 /* Display the property sheet */
959 PropertySheetW (&psh);
962 static LONG start_params(const WCHAR *params)
964 static const WCHAR install_geckoW[] = {'i','n','s','t','a','l','l','_','g','e','c','k','o',0};
969 if(!strcmpW(params, install_geckoW)) {
970 install_wine_gecko();
974 WARN("unknown param %s\n", debugstr_w(params));
978 /******************************************************************************
980 * Description: Entry point for Control Panel applets
981 * Parameters : hwndCPL - hWnd of the Control Panel
982 * message - reason for calling function
983 * lParam1 - additional parameter
984 * lParam2 - additional parameter
985 * Returns : Dependant on message
987 LONG CALLBACK CPlApplet(HWND hwndCPL, UINT message, LPARAM lParam1, LPARAM lParam2)
989 INITCOMMONCONTROLSEX iccEx;
994 iccEx.dwSize = sizeof(iccEx);
995 iccEx.dwICC = ICC_LISTVIEW_CLASSES | ICC_TAB_CLASSES;
997 InitCommonControlsEx(&iccEx);
1004 case CPL_STARTWPARMSW:
1005 return start_params((const WCHAR *)lParam2);
1009 CPLINFO *appletInfo = (CPLINFO *) lParam2;
1011 appletInfo->idIcon = ICO_MAIN;
1012 appletInfo->idName = IDS_CPL_TITLE;
1013 appletInfo->idInfo = IDS_CPL_DESC;
1014 appletInfo->lData = 0;
1020 StartApplet(hwndCPL);