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};
103 static const WCHAR SystemComponentW[] = {'S','y','s','t','e','m','C','o','m','p','o','n','e','n','t',0};
105 static const WCHAR PathUninstallW[] = {
106 'S','o','f','t','w','a','r','e','\\',
107 'M','i','c','r','o','s','o','f','t','\\',
108 'W','i','n','d','o','w','s','\\',
109 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
110 'U','n','i','n','s','t','a','l','l',0 };
112 /******************************************************************************
114 * Description: Entry point for DLL file
116 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason,
119 TRACE("(%p, %d, %p)\n", hinstDLL, fdwReason, lpvReserved);
123 case DLL_PROCESS_ATTACH:
130 /******************************************************************************
132 * Description: Frees memory used by an AppInfo structure, and any children.
134 static void FreeAppInfo(APPINFO *info)
136 HeapFree(GetProcessHeap(), 0, info->title);
137 HeapFree(GetProcessHeap(), 0, info->path);
138 HeapFree(GetProcessHeap(), 0, info->path_modify);
139 HeapFree(GetProcessHeap(), 0, info->icon);
140 HeapFree(GetProcessHeap(), 0, info->publisher);
141 HeapFree(GetProcessHeap(), 0, info->version);
142 HeapFree(GetProcessHeap(), 0, info);
145 /******************************************************************************
146 * Name : ReadApplicationsFromRegistry
147 * Description: Creates a linked list of uninstallable applications from the
149 * Parameters : root - Which registry root to read from
150 * Returns : TRUE if successful, FALSE otherwise
152 static BOOL ReadApplicationsFromRegistry(HKEY root)
156 DWORD sizeOfSubKeyName, displen, uninstlen;
157 DWORD dwNoModify, dwType, value, size;
158 WCHAR subKeyName[256];
160 APPINFO *info = NULL;
163 sizeOfSubKeyName = sizeof(subKeyName) / sizeof(subKeyName[0]);
165 for (i = 0; RegEnumKeyExW(root, i, subKeyName, &sizeOfSubKeyName, NULL,
166 NULL, NULL, NULL) != ERROR_NO_MORE_ITEMS; ++i)
168 RegOpenKeyExW(root, subKeyName, 0, KEY_READ, &hkeyApp);
169 size = sizeof(value);
170 if (!RegQueryValueExW(hkeyApp, SystemComponentW, NULL, &dwType, (LPBYTE)&value, &size)
171 && dwType == REG_DWORD && value == 1)
173 RegCloseKey(hkeyApp);
174 sizeOfSubKeyName = sizeof(subKeyName) / sizeof(subKeyName[0]);
179 if (!RegQueryValueExW(hkeyApp, DisplayNameW, 0, 0, NULL, &displen))
181 size = sizeof(value);
182 if (!RegQueryValueExW(hkeyApp, WindowsInstallerW, NULL, &dwType, (LPBYTE)&value, &size)
183 && dwType == REG_DWORD && value == 1)
185 static const WCHAR fmtW[] = {'m','s','i','e','x','e','c',' ','/','x','%','s',0};
186 int len = lstrlenW(fmtW) + lstrlenW(subKeyName);
188 if (!(command = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)))) goto err;
189 wsprintfW(command, fmtW, subKeyName);
191 else if (!RegQueryValueExW(hkeyApp, UninstallCommandlineW, 0, 0, NULL, &uninstlen))
193 if (!(command = HeapAlloc(GetProcessHeap(), 0, uninstlen))) goto err;
194 RegQueryValueExW(hkeyApp, UninstallCommandlineW, 0, 0, (LPBYTE)command, &uninstlen);
198 RegCloseKey(hkeyApp);
199 sizeOfSubKeyName = sizeof(subKeyName) / sizeof(subKeyName[0]);
203 info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(struct APPINFO));
206 info->title = HeapAlloc(GetProcessHeap(), 0, displen);
211 RegQueryValueExW(hkeyApp, DisplayNameW, 0, 0, (LPBYTE)info->title,
214 /* now get DisplayIcon */
216 RegQueryValueExW(hkeyApp, DisplayIconW, 0, 0, NULL, &displen);
222 info->icon = HeapAlloc(GetProcessHeap(), 0, displen);
227 RegQueryValueExW(hkeyApp, DisplayIconW, 0, 0, (LPBYTE)info->icon,
230 /* separate the index from the icon name, if supplied */
231 iconPtr = strchrW(info->icon, ',');
236 info->iconIdx = atoiW(iconPtr);
240 /* publisher, version */
241 if (RegQueryValueExW(hkeyApp, PublisherW, 0, 0, NULL, &displen) ==
244 info->publisher = HeapAlloc(GetProcessHeap(), 0, displen);
246 if (!info->publisher)
249 RegQueryValueExW(hkeyApp, PublisherW, 0, 0, (LPBYTE)info->publisher,
253 if (RegQueryValueExW(hkeyApp, DisplayVersionW, 0, 0, NULL, &displen) ==
256 info->version = HeapAlloc(GetProcessHeap(), 0, displen);
261 RegQueryValueExW(hkeyApp, DisplayVersionW, 0, 0, (LPBYTE)info->version,
265 /* Check if NoModify is set */
268 displen = sizeof(DWORD);
270 if (RegQueryValueExW(hkeyApp, NoModifyW, NULL, &dwType, (LPBYTE)&dwNoModify, &displen)
276 /* Some installers incorrectly create a REG_SZ instead of a REG_DWORD */
277 if (dwType == REG_SZ)
278 dwNoModify = (*(BYTE *)&dwNoModify == '1');
280 /* Fetch the modify path */
283 size = sizeof(value);
284 if (!RegQueryValueExW(hkeyApp, WindowsInstallerW, NULL, &dwType, (LPBYTE)&value, &size)
285 && dwType == REG_DWORD && value == 1)
287 static const WCHAR fmtW[] = {'m','s','i','e','x','e','c',' ','/','i','%','s',0};
288 int len = lstrlenW(fmtW) + lstrlenW(subKeyName);
290 if (!(info->path_modify = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)))) goto err;
291 wsprintfW(info->path_modify, fmtW, subKeyName);
293 else if (!RegQueryValueExW(hkeyApp, ModifyPathW, 0, 0, NULL, &displen))
295 if (!(info->path_modify = HeapAlloc(GetProcessHeap(), 0, displen))) goto err;
296 RegQueryValueExW(hkeyApp, ModifyPathW, 0, 0, (LPBYTE)info->path_modify, &displen);
301 info->regroot = root;
302 lstrcpyW(info->regkey, subKeyName);
303 info->path = command;
306 list_add_tail( &app_list, &info->entry );
309 RegCloseKey(hkeyApp);
310 sizeOfSubKeyName = sizeof(subKeyName) / sizeof(subKeyName[0]);
315 RegCloseKey(hkeyApp);
316 if (info) FreeAppInfo(info);
321 /******************************************************************************
322 * Name : AddApplicationsToList
323 * Description: Populates the list box with applications.
324 * Parameters : hWnd - Handle of the dialog box
326 static void AddApplicationsToList(HWND hWnd, HIMAGELIST hList)
333 LIST_FOR_EACH_ENTRY( iter, &app_list, APPINFO, entry )
335 if (!iter->title[0]) continue;
342 if (ExtractIconExW(iter->icon, iter->iconIdx, NULL, &hIcon, 1) == 1)
344 index = ImageList_AddIcon(hList, hIcon);
349 lvItem.mask = LVIF_IMAGE | LVIF_TEXT | LVIF_PARAM;
350 lvItem.iItem = iter->id;
352 lvItem.pszText = iter->title;
353 lvItem.iImage = index;
354 lvItem.lParam = iter->id;
356 index = ListView_InsertItemW(hWnd, &lvItem);
358 /* now add the subitems (columns) */
359 ListView_SetItemTextW(hWnd, index, 1, iter->publisher);
360 ListView_SetItemTextW(hWnd, index, 2, iter->version);
364 /******************************************************************************
365 * Name : RemoveItemsFromList
366 * Description: Clears the application list box.
367 * Parameters : hWnd - Handle of the dialog box
369 static void RemoveItemsFromList(HWND hWnd)
371 SendDlgItemMessageW(hWnd, IDL_PROGRAMS, LVM_DELETEALLITEMS, 0, 0);
374 /******************************************************************************
376 * Description: Frees memory used by the application linked list.
378 static inline void EmptyList(void)
380 APPINFO *info, *next;
381 LIST_FOR_EACH_ENTRY_SAFE( info, next, &app_list, APPINFO, entry )
383 list_remove( &info->entry );
388 /******************************************************************************
389 * Name : UpdateButtons
390 * Description: Enables/disables the Add/Remove button depending on current
391 * selection in list box.
392 * Parameters : hWnd - Handle of the dialog box
394 static void UpdateButtons(HWND hWnd)
398 LRESULT selitem = SendDlgItemMessageW(hWnd, IDL_PROGRAMS, LVM_GETNEXTITEM, -1,
399 LVNI_FOCUSED | LVNI_SELECTED);
400 BOOL enable_modify = FALSE;
404 lvItem.iItem = selitem;
405 lvItem.mask = LVIF_PARAM;
407 if (SendDlgItemMessageW(hWnd, IDL_PROGRAMS, LVM_GETITEMW, 0, (LPARAM) &lvItem))
409 LIST_FOR_EACH_ENTRY( iter, &app_list, APPINFO, entry )
411 if (iter->id == lvItem.lParam)
413 /* Decide whether to display Modify/Remove as one button or two */
414 enable_modify = (iter->path_modify != NULL);
416 /* Update title as appropriate */
417 if (iter->path_modify == NULL)
418 SetWindowTextW(GetDlgItem(hWnd, IDC_ADDREMOVE), btnModifyRemove);
420 SetWindowTextW(GetDlgItem(hWnd, IDC_ADDREMOVE), btnRemove);
428 /* Enable/disable other buttons if necessary */
429 EnableWindow(GetDlgItem(hWnd, IDC_ADDREMOVE), (selitem != -1));
430 EnableWindow(GetDlgItem(hWnd, IDC_SUPPORT_INFO), (selitem != -1));
431 EnableWindow(GetDlgItem(hWnd, IDC_MODIFY), enable_modify);
434 /******************************************************************************
435 * Name : InstallProgram
436 * Description: Search for potential Installer and execute it.
437 * Parameters : hWnd - Handle of the dialog box
439 static void InstallProgram(HWND hWnd)
441 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}
444 WCHAR titleW[MAX_STRING_LEN];
445 WCHAR filter_installs[MAX_STRING_LEN];
446 WCHAR filter_programs[MAX_STRING_LEN];
447 WCHAR filter_all[MAX_STRING_LEN];
448 WCHAR FilterBufferW[MAX_PATH];
449 WCHAR FileNameBufferW[MAX_PATH];
451 LoadStringW(hInst, IDS_CPL_TITLE, titleW, sizeof(titleW)/sizeof(WCHAR));
452 LoadStringW(hInst, IDS_FILTER_INSTALLS, filter_installs, sizeof(filter_installs)/sizeof(WCHAR));
453 LoadStringW(hInst, IDS_FILTER_PROGRAMS, filter_programs, sizeof(filter_programs)/sizeof(WCHAR));
454 LoadStringW(hInst, IDS_FILTER_ALL, filter_all, sizeof(filter_all)/sizeof(WCHAR));
456 snprintfW( FilterBufferW, MAX_PATH, filters, filter_installs, 0, 0,
457 filter_programs, 0, 0, filter_all, 0, 0 );
458 memset(&ofn, 0, sizeof(OPENFILENAMEW));
459 ofn.lStructSize = sizeof(OPENFILENAMEW);
460 ofn.hwndOwner = hWnd;
461 ofn.hInstance = hInst;
462 ofn.lpstrFilter = FilterBufferW;
463 ofn.nFilterIndex = 0;
464 ofn.lpstrFile = FileNameBufferW;
465 ofn.nMaxFile = MAX_PATH;
466 ofn.lpstrFileTitle = NULL;
467 ofn.nMaxFileTitle = 0;
468 ofn.lpstrTitle = titleW;
469 ofn.Flags = OFN_HIDEREADONLY | OFN_ENABLESIZING;
470 FileNameBufferW[0] = 0;
472 if (GetOpenFileNameW(&ofn))
474 SHELLEXECUTEINFOW sei;
475 memset(&sei, 0, sizeof(sei));
476 sei.cbSize = sizeof(sei);
478 sei.nShow = SW_SHOWDEFAULT;
479 sei.fMask = SEE_MASK_NO_CONSOLE;
480 sei.lpFile = ofn.lpstrFile;
482 ShellExecuteExW(&sei);
486 /******************************************************************************
487 * Name : UninstallProgram
488 * Description: Executes the specified program's installer.
489 * Parameters : id - the internal ID of the installer to remove
490 * Parameters : button - ID of button pressed (Modify or Remove)
492 static void UninstallProgram(int id, DWORD button)
496 PROCESS_INFORMATION info;
497 WCHAR errormsg[MAX_STRING_LEN];
498 WCHAR sUninstallFailed[MAX_STRING_LEN];
502 LoadStringW(hInst, IDS_UNINSTALL_FAILED, sUninstallFailed,
503 sizeof(sUninstallFailed) / sizeof(sUninstallFailed[0]));
505 LIST_FOR_EACH_ENTRY( iter, &app_list, APPINFO, entry )
509 TRACE("Uninstalling %s (%s)\n", wine_dbgstr_w(iter->title),
510 wine_dbgstr_w(iter->path));
512 memset(&si, 0, sizeof(STARTUPINFOW));
513 si.cb = sizeof(STARTUPINFOW);
514 si.wShowWindow = SW_NORMAL;
516 res = CreateProcessW(NULL, (button == IDC_MODIFY) ? iter->path_modify : iter->path,
517 NULL, NULL, FALSE, 0, NULL, NULL, &si, &info);
521 CloseHandle(info.hThread);
523 /* wait for the process to exit */
524 WaitForSingleObject(info.hProcess, INFINITE);
525 CloseHandle(info.hProcess);
529 wsprintfW(errormsg, sUninstallFailed, iter->path);
531 if (MessageBoxW(0, errormsg, iter->title, MB_YESNO |
532 MB_ICONQUESTION) == IDYES)
534 /* delete the application's uninstall entry */
535 RegOpenKeyExW(iter->regroot, PathUninstallW, 0, KEY_READ, &hkey);
536 RegDeleteKeyW(hkey, iter->regkey);
546 /**********************************************************************************
547 * Name : SetInfoDialogText
548 * Description: Sets the text of a label in a window, based upon a registry entry
549 * or string passed to the function.
550 * Parameters : hKey - registry entry to read from, NULL if not reading
552 * lpKeyName - key to read from, or string to check if hKey is NULL
553 * lpAltMessage - alternative message if entry not found
554 * hWnd - handle of dialog box
555 * iDlgItem - ID of label in dialog box
557 static void SetInfoDialogText(HKEY hKey, LPCWSTR lpKeyName, LPCWSTR lpAltMessage,
558 HWND hWnd, int iDlgItem)
560 WCHAR buf[MAX_STRING_LEN];
564 hWndDlgItem = GetDlgItem(hWnd, iDlgItem);
566 /* if hKey is null, lpKeyName contains the string we want to check */
569 if ((lpKeyName) && (lstrlenW(lpKeyName) > 0))
570 SetWindowTextW(hWndDlgItem, lpKeyName);
572 SetWindowTextW(hWndDlgItem, lpAltMessage);
576 buflen = MAX_STRING_LEN;
578 if ((RegQueryValueExW(hKey, lpKeyName, 0, 0, (LPBYTE) buf, &buflen) ==
579 ERROR_SUCCESS) && (lstrlenW(buf) > 0))
580 SetWindowTextW(hWndDlgItem, buf);
582 SetWindowTextW(hWndDlgItem, lpAltMessage);
586 /******************************************************************************
587 * Name : SupportInfoDlgProc
588 * Description: Callback procedure for support info dialog
589 * Parameters : hWnd - hWnd of the window
590 * msg - reason for calling function
591 * wParam - additional parameter
592 * lParam - additional parameter
593 * Returns : Depends on the message
595 static INT_PTR CALLBACK SupportInfoDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
599 WCHAR oldtitle[MAX_STRING_LEN];
600 WCHAR buf[MAX_STRING_LEN];
601 WCHAR key[MAX_STRING_LEN];
602 WCHAR notfound[MAX_STRING_LEN];
607 LIST_FOR_EACH_ENTRY( iter, &app_list, APPINFO, entry )
609 if (iter->id == (int) lParam)
611 lstrcpyW(key, PathUninstallW);
612 lstrcatW(key, BackSlashW);
613 lstrcatW(key, iter->regkey);
615 /* check the application's registry entries */
616 RegOpenKeyExW(iter->regroot, key, 0, KEY_READ, &hkey);
618 /* Load our "not specified" string */
619 LoadStringW(hInst, IDS_NOT_SPECIFIED, notfound,
620 sizeof(notfound) / sizeof(notfound[0]));
622 /* Update the data for items already read into the structure */
623 SetInfoDialogText(NULL, iter->publisher, notfound, hWnd,
625 SetInfoDialogText(NULL, iter->version, notfound, hWnd,
628 /* And now update the data for those items in the registry */
629 SetInfoDialogText(hkey, ContactW, notfound, hWnd,
631 SetInfoDialogText(hkey, HelpLinkW, notfound, hWnd,
633 SetInfoDialogText(hkey, HelpTelephoneW, notfound, hWnd,
635 SetInfoDialogText(hkey, ReadmeW, notfound, hWnd,
637 SetInfoDialogText(hkey, URLUpdateInfoW, notfound, hWnd,
639 SetInfoDialogText(hkey, CommentsW, notfound, hWnd,
642 /* Update the main label with the app name */
643 if (GetWindowTextW(GetDlgItem(hWnd, IDC_INFO_LABEL), oldtitle,
644 MAX_STRING_LEN) != 0)
646 wsprintfW(buf, oldtitle, iter->title);
647 SetWindowTextW(GetDlgItem(hWnd, IDC_INFO_LABEL), buf);
662 switch (LOWORD(wParam))
665 EndDialog(hWnd, TRUE);
676 /******************************************************************************
678 * Description: Displays the Support Information dialog
679 * Parameters : hWnd - Handle of the main dialog
680 * id - ID of the application to display information for
682 static void SupportInfo(HWND hWnd, int id)
684 DialogBoxParamW(hInst, MAKEINTRESOURCEW(IDD_INFO), hWnd, SupportInfoDlgProc, id);
687 /* Definition of column headers for AddListViewColumns function */
688 typedef struct AppWizColumn {
694 static const AppWizColumn columns[] = {
695 {200, LVCFMT_LEFT, IDS_COLUMN_NAME},
696 {150, LVCFMT_LEFT, IDS_COLUMN_PUBLISHER},
697 {100, LVCFMT_LEFT, IDS_COLUMN_VERSION},
700 /******************************************************************************
701 * Name : AddListViewColumns
702 * Description: Adds column headers to the list view control.
703 * Parameters : hWnd - Handle of the list view control.
704 * Returns : TRUE if completed successfully, FALSE otherwise.
706 static BOOL AddListViewColumns(HWND hWnd)
708 WCHAR buf[MAX_STRING_LEN];
712 lvc.mask = LVCF_FMT | LVCF_TEXT | LVCF_SUBITEM | LVCF_WIDTH;
714 /* Add the columns */
715 for (i = 0; i < sizeof(columns) / sizeof(columns[0]); i++)
720 /* set width and format */
721 lvc.cx = columns[i].width;
722 lvc.fmt = columns[i].fmt;
724 LoadStringW(hInst, columns[i].title, buf, sizeof(buf) / sizeof(buf[0]));
726 if (ListView_InsertColumnW(hWnd, i, &lvc) == -1)
733 /******************************************************************************
734 * Name : AddListViewImageList
735 * Description: Creates an ImageList for the list view control.
736 * Parameters : hWnd - Handle of the list view control.
737 * Returns : Handle of the image list.
739 static HIMAGELIST AddListViewImageList(HWND hWnd)
744 hSmall = ImageList_Create(GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON),
745 ILC_COLOR32 | ILC_MASK, 1, 1);
747 /* Add default icon to image list */
748 hDefaultIcon = LoadIconW(hInst, MAKEINTRESOURCEW(ICO_MAIN));
749 ImageList_AddIcon(hSmall, hDefaultIcon);
750 DestroyIcon(hDefaultIcon);
752 SendMessageW(hWnd, LVM_SETIMAGELIST, LVSIL_SMALL, (LPARAM)hSmall);
757 /******************************************************************************
758 * Name : ResetApplicationList
759 * Description: Empties the app list, if need be, and recreates it.
760 * Parameters : bFirstRun - TRUE if this is the first time this is run, FALSE otherwise
761 * hWnd - handle of the dialog box
762 * hImageList - handle of the image list
763 * Returns : New handle of the image list.
765 static HIMAGELIST ResetApplicationList(BOOL bFirstRun, HWND hWnd, HIMAGELIST hImageList)
767 static const BOOL is_64bit = sizeof(void *) > sizeof(int);
771 hWndListView = GetDlgItem(hWnd, IDL_PROGRAMS);
773 /* if first run, create the image list and add the listview columns */
776 if (!AddListViewColumns(hWndListView))
779 else /* we need to remove the existing things first */
781 RemoveItemsFromList(hWnd);
782 ImageList_Destroy(hImageList);
784 /* reset the list, since it's probably changed if the uninstallation was
789 /* now create the image list and add the applications to the listview */
790 hImageList = AddListViewImageList(hWndListView);
792 if (!RegOpenKeyExW(HKEY_LOCAL_MACHINE, PathUninstallW, 0, KEY_READ, &hkey))
794 ReadApplicationsFromRegistry(hkey);
798 !RegOpenKeyExW(HKEY_LOCAL_MACHINE, PathUninstallW, 0, KEY_READ|KEY_WOW64_32KEY, &hkey))
800 ReadApplicationsFromRegistry(hkey);
803 if (!RegOpenKeyExW(HKEY_CURRENT_USER, PathUninstallW, 0, KEY_READ, &hkey))
805 ReadApplicationsFromRegistry(hkey);
809 AddApplicationsToList(hWndListView, hImageList);
815 /******************************************************************************
817 * Description: Callback procedure for main tab
818 * Parameters : hWnd - hWnd of the window
819 * msg - reason for calling function
820 * wParam - additional parameter
821 * lParam - additional parameter
822 * Returns : Depends on the message
824 static INT_PTR CALLBACK MainDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
827 static HIMAGELIST hImageList;
834 hImageList = ResetApplicationList(TRUE, hWnd, hImageList);
842 RemoveItemsFromList(hWnd);
843 ImageList_Destroy(hImageList);
850 nmh = (LPNMHDR) lParam;
857 case LVN_ITEMCHANGED:
867 switch (LOWORD(wParam))
870 InstallProgram(hWnd);
875 selitem = SendDlgItemMessageW(hWnd, IDL_PROGRAMS,
876 LVM_GETNEXTITEM, -1, LVNI_FOCUSED|LVNI_SELECTED);
880 lvItem.iItem = selitem;
881 lvItem.mask = LVIF_PARAM;
883 if (SendDlgItemMessageW(hWnd, IDL_PROGRAMS, LVM_GETITEMW,
884 0, (LPARAM) &lvItem))
885 UninstallProgram(lvItem.lParam, LOWORD(wParam));
888 hImageList = ResetApplicationList(FALSE, hWnd, hImageList);
892 case IDC_SUPPORT_INFO:
893 selitem = SendDlgItemMessageW(hWnd, IDL_PROGRAMS,
894 LVM_GETNEXTITEM, -1, LVNI_FOCUSED | LVNI_SELECTED);
898 lvItem.iItem = selitem;
899 lvItem.mask = LVIF_PARAM;
901 if (SendDlgItemMessageW(hWnd, IDL_PROGRAMS, LVM_GETITEMW,
902 0, (LPARAM) &lvItem))
903 SupportInfo(hWnd, lvItem.lParam);
915 static int CALLBACK propsheet_callback( HWND hwnd, UINT msg, LPARAM lparam )
919 case PSCB_INITIALIZED:
920 SendMessageW( hwnd, WM_SETICON, ICON_BIG, (LPARAM)LoadIconW( hInst, MAKEINTRESOURCEW(ICO_MAIN) ));
926 /******************************************************************************
928 * Description: Main routine for applet
929 * Parameters : hWnd - hWnd of the Control Panel
931 static void StartApplet(HWND hWnd)
934 PROPSHEETHEADERW psh;
935 WCHAR tab_title[MAX_STRING_LEN], app_title[MAX_STRING_LEN];
937 /* Load the strings we will use */
938 LoadStringW(hInst, IDS_TAB1_TITLE, tab_title, sizeof(tab_title) / sizeof(tab_title[0]));
939 LoadStringW(hInst, IDS_CPL_TITLE, app_title, sizeof(app_title) / sizeof(app_title[0]));
940 LoadStringW(hInst, IDS_REMOVE, btnRemove, sizeof(btnRemove) / sizeof(btnRemove[0]));
941 LoadStringW(hInst, IDS_MODIFY_REMOVE, btnModifyRemove, sizeof(btnModifyRemove) / sizeof(btnModifyRemove[0]));
943 /* Fill out the PROPSHEETPAGE */
944 psp.dwSize = sizeof (PROPSHEETPAGEW);
945 psp.dwFlags = PSP_USETITLE;
946 psp.hInstance = hInst;
947 psp.u.pszTemplate = MAKEINTRESOURCEW (IDD_MAIN);
948 psp.u2.pszIcon = NULL;
949 psp.pfnDlgProc = MainDlgProc;
950 psp.pszTitle = tab_title;
953 /* Fill out the PROPSHEETHEADER */
954 psh.dwSize = sizeof (PROPSHEETHEADERW);
955 psh.dwFlags = PSH_PROPSHEETPAGE | PSH_USEICONID | PSH_USECALLBACK;
956 psh.hwndParent = hWnd;
957 psh.hInstance = hInst;
958 psh.u.pszIcon = MAKEINTRESOURCEW(ICO_MAIN);
959 psh.pszCaption = app_title;
962 psh.pfnCallback = propsheet_callback;
963 psh.u2.nStartPage = 0;
965 /* Display the property sheet */
966 PropertySheetW (&psh);
969 static LONG start_params(const WCHAR *params)
971 static const WCHAR install_geckoW[] = {'i','n','s','t','a','l','l','_','g','e','c','k','o',0};
972 static const WCHAR install_monoW[] = {'i','n','s','t','a','l','l','_','m','o','n','o',0};
977 if(!strcmpW(params, install_geckoW)) {
978 install_addon(ADDON_GECKO);
982 if(!strcmpW(params, install_monoW)) {
983 install_addon(ADDON_MONO);
987 WARN("unknown param %s\n", debugstr_w(params));
991 /******************************************************************************
993 * Description: Entry point for Control Panel applets
994 * Parameters : hwndCPL - hWnd of the Control Panel
995 * message - reason for calling function
996 * lParam1 - additional parameter
997 * lParam2 - additional parameter
998 * Returns : Depends on the message
1000 LONG CALLBACK CPlApplet(HWND hwndCPL, UINT message, LPARAM lParam1, LPARAM lParam2)
1002 INITCOMMONCONTROLSEX iccEx;
1007 iccEx.dwSize = sizeof(iccEx);
1008 iccEx.dwICC = ICC_LISTVIEW_CLASSES | ICC_TAB_CLASSES | ICC_LINK_CLASS;
1010 InitCommonControlsEx(&iccEx);
1017 case CPL_STARTWPARMSW:
1018 return start_params((const WCHAR *)lParam2);
1022 CPLINFO *appletInfo = (CPLINFO *) lParam2;
1024 appletInfo->idIcon = ICO_MAIN;
1025 appletInfo->idName = IDS_CPL_TITLE;
1026 appletInfo->idInfo = IDS_CPL_DESC;
1027 appletInfo->lData = 0;
1033 StartApplet(hwndCPL);