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 : Dependant on message
595 static BOOL 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, (DLGPROC)
685 SupportInfoDlgProc, (LPARAM) id);
688 /* Definition of column headers for AddListViewColumns function */
689 typedef struct AppWizColumn {
695 static const AppWizColumn columns[] = {
696 {200, LVCFMT_LEFT, IDS_COLUMN_NAME},
697 {150, LVCFMT_LEFT, IDS_COLUMN_PUBLISHER},
698 {100, LVCFMT_LEFT, IDS_COLUMN_VERSION},
701 /******************************************************************************
702 * Name : AddListViewColumns
703 * Description: Adds column headers to the list view control.
704 * Parameters : hWnd - Handle of the list view control.
705 * Returns : TRUE if completed successfully, FALSE otherwise.
707 static BOOL AddListViewColumns(HWND hWnd)
709 WCHAR buf[MAX_STRING_LEN];
713 lvc.mask = LVCF_FMT | LVCF_TEXT | LVCF_SUBITEM | LVCF_WIDTH;
715 /* Add the columns */
716 for (i = 0; i < sizeof(columns) / sizeof(columns[0]); i++)
721 /* set width and format */
722 lvc.cx = columns[i].width;
723 lvc.fmt = columns[i].fmt;
725 LoadStringW(hInst, columns[i].title, buf, sizeof(buf) / sizeof(buf[0]));
727 if (ListView_InsertColumnW(hWnd, i, &lvc) == -1)
734 /******************************************************************************
735 * Name : AddListViewImageList
736 * Description: Creates an ImageList for the list view control.
737 * Parameters : hWnd - Handle of the list view control.
738 * Returns : Handle of the image list.
740 static HIMAGELIST AddListViewImageList(HWND hWnd)
745 hSmall = ImageList_Create(GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON),
746 ILC_COLOR32 | ILC_MASK, 1, 1);
748 /* Add default icon to image list */
749 hDefaultIcon = LoadIconW(hInst, MAKEINTRESOURCEW(ICO_MAIN));
750 ImageList_AddIcon(hSmall, hDefaultIcon);
751 DestroyIcon(hDefaultIcon);
753 SendMessageW(hWnd, LVM_SETIMAGELIST, LVSIL_SMALL, (LPARAM)hSmall);
758 /******************************************************************************
759 * Name : ResetApplicationList
760 * Description: Empties the app list, if need be, and recreates it.
761 * Parameters : bFirstRun - TRUE if this is the first time this is run, FALSE otherwise
762 * hWnd - handle of the dialog box
763 * hImageList - handle of the image list
764 * Returns : New handle of the image list.
766 static HIMAGELIST ResetApplicationList(BOOL bFirstRun, HWND hWnd, HIMAGELIST hImageList)
768 static const BOOL is_64bit = sizeof(void *) > sizeof(int);
772 hWndListView = GetDlgItem(hWnd, IDL_PROGRAMS);
774 /* if first run, create the image list and add the listview columns */
777 if (!AddListViewColumns(hWndListView))
780 else /* we need to remove the existing things first */
782 RemoveItemsFromList(hWnd);
783 ImageList_Destroy(hImageList);
785 /* reset the list, since it's probably changed if the uninstallation was
790 /* now create the image list and add the applications to the listview */
791 hImageList = AddListViewImageList(hWndListView);
793 if (!RegOpenKeyExW(HKEY_LOCAL_MACHINE, PathUninstallW, 0, KEY_READ, &hkey))
795 ReadApplicationsFromRegistry(hkey);
799 !RegOpenKeyExW(HKEY_LOCAL_MACHINE, PathUninstallW, 0, KEY_READ|KEY_WOW64_32KEY, &hkey))
801 ReadApplicationsFromRegistry(hkey);
804 if (!RegOpenKeyExW(HKEY_CURRENT_USER, PathUninstallW, 0, KEY_READ, &hkey))
806 ReadApplicationsFromRegistry(hkey);
810 AddApplicationsToList(hWndListView, hImageList);
816 /******************************************************************************
818 * Description: Callback procedure for main tab
819 * Parameters : hWnd - hWnd of the window
820 * msg - reason for calling function
821 * wParam - additional parameter
822 * lParam - additional parameter
823 * Returns : Dependant on message
825 static BOOL CALLBACK MainDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
828 static HIMAGELIST hImageList;
835 hImageList = ResetApplicationList(TRUE, hWnd, hImageList);
843 RemoveItemsFromList(hWnd);
844 ImageList_Destroy(hImageList);
851 nmh = (LPNMHDR) lParam;
858 case LVN_ITEMCHANGED:
868 switch (LOWORD(wParam))
871 InstallProgram(hWnd);
876 selitem = SendDlgItemMessageW(hWnd, IDL_PROGRAMS,
877 LVM_GETNEXTITEM, -1, LVNI_FOCUSED|LVNI_SELECTED);
881 lvItem.iItem = selitem;
882 lvItem.mask = LVIF_PARAM;
884 if (SendDlgItemMessageW(hWnd, IDL_PROGRAMS, LVM_GETITEMW,
885 0, (LPARAM) &lvItem))
886 UninstallProgram(lvItem.lParam, LOWORD(wParam));
889 hImageList = ResetApplicationList(FALSE, hWnd, hImageList);
893 case IDC_SUPPORT_INFO:
894 selitem = SendDlgItemMessageW(hWnd, IDL_PROGRAMS,
895 LVM_GETNEXTITEM, -1, LVNI_FOCUSED | LVNI_SELECTED);
899 lvItem.iItem = selitem;
900 lvItem.mask = LVIF_PARAM;
902 if (SendDlgItemMessageW(hWnd, IDL_PROGRAMS, LVM_GETITEMW,
903 0, (LPARAM) &lvItem))
904 SupportInfo(hWnd, lvItem.lParam);
916 static int CALLBACK propsheet_callback( HWND hwnd, UINT msg, LPARAM lparam )
920 case PSCB_INITIALIZED:
921 SendMessageW( hwnd, WM_SETICON, ICON_BIG, (LPARAM)LoadIconW( hInst, MAKEINTRESOURCEW(ICO_MAIN) ));
927 /******************************************************************************
929 * Description: Main routine for applet
930 * Parameters : hWnd - hWnd of the Control Panel
932 static void StartApplet(HWND hWnd)
935 PROPSHEETHEADERW psh;
936 WCHAR tab_title[MAX_STRING_LEN], app_title[MAX_STRING_LEN];
938 /* Load the strings we will use */
939 LoadStringW(hInst, IDS_TAB1_TITLE, tab_title, sizeof(tab_title) / sizeof(tab_title[0]));
940 LoadStringW(hInst, IDS_CPL_TITLE, app_title, sizeof(app_title) / sizeof(app_title[0]));
941 LoadStringW(hInst, IDS_REMOVE, btnRemove, sizeof(btnRemove) / sizeof(btnRemove[0]));
942 LoadStringW(hInst, IDS_MODIFY_REMOVE, btnModifyRemove, sizeof(btnModifyRemove) / sizeof(btnModifyRemove[0]));
944 /* Fill out the PROPSHEETPAGE */
945 psp.dwSize = sizeof (PROPSHEETPAGEW);
946 psp.dwFlags = PSP_USETITLE;
947 psp.hInstance = hInst;
948 psp.u.pszTemplate = MAKEINTRESOURCEW (IDD_MAIN);
949 psp.u2.pszIcon = NULL;
950 psp.pfnDlgProc = (DLGPROC) MainDlgProc;
951 psp.pszTitle = tab_title;
954 /* Fill out the PROPSHEETHEADER */
955 psh.dwSize = sizeof (PROPSHEETHEADERW);
956 psh.dwFlags = PSH_PROPSHEETPAGE | PSH_USEICONID | PSH_USECALLBACK;
957 psh.hwndParent = hWnd;
958 psh.hInstance = hInst;
959 psh.u.pszIcon = MAKEINTRESOURCEW(ICO_MAIN);
960 psh.pszCaption = app_title;
963 psh.pfnCallback = propsheet_callback;
964 psh.u2.nStartPage = 0;
966 /* Display the property sheet */
967 PropertySheetW (&psh);
970 static LONG start_params(const WCHAR *params)
972 static const WCHAR install_geckoW[] = {'i','n','s','t','a','l','l','_','g','e','c','k','o',0};
977 if(!strcmpW(params, install_geckoW)) {
978 install_wine_gecko();
982 WARN("unknown param %s\n", debugstr_w(params));
986 /******************************************************************************
988 * Description: Entry point for Control Panel applets
989 * Parameters : hwndCPL - hWnd of the Control Panel
990 * message - reason for calling function
991 * lParam1 - additional parameter
992 * lParam2 - additional parameter
993 * Returns : Dependant on message
995 LONG CALLBACK CPlApplet(HWND hwndCPL, UINT message, LPARAM lParam1, LPARAM lParam2)
997 INITCOMMONCONTROLSEX iccEx;
1002 iccEx.dwSize = sizeof(iccEx);
1003 iccEx.dwICC = ICC_LISTVIEW_CLASSES | ICC_TAB_CLASSES;
1005 InitCommonControlsEx(&iccEx);
1012 case CPL_STARTWPARMSW:
1013 return start_params((const WCHAR *)lParam2);
1017 CPLINFO *appletInfo = (CPLINFO *) lParam2;
1019 appletInfo->idIcon = ICO_MAIN;
1020 appletInfo->idName = IDS_CPL_TITLE;
1021 appletInfo->idInfo = IDS_CPL_DESC;
1022 appletInfo->lData = 0;
1028 StartApplet(hwndCPL);