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"
30 #include "wine/unicode.h"
31 #include "wine/debug.h"
49 WINE_DEFAULT_DEBUG_CHANNEL(appwizcpl);
51 /* define a maximum length for various buffers we use */
52 #define MAX_STRING_LEN 1024
54 typedef struct APPINFO {
68 WCHAR regkey[MAX_STRING_LEN];
73 static struct APPINFO *AppInfo = NULL;
74 static HINSTANCE hInst;
76 static WCHAR btnRemove[MAX_STRING_LEN];
77 static WCHAR btnModifyRemove[MAX_STRING_LEN];
79 static const WCHAR openW[] = {'o','p','e','n',0};
81 /* names of registry keys */
82 static const WCHAR BackSlashW[] = { '\\', 0 };
83 static const WCHAR DisplayNameW[] = {'D','i','s','p','l','a','y','N','a','m','e',0};
84 static const WCHAR DisplayIconW[] = {'D','i','s','p','l','a','y','I','c','o','n',0};
85 static const WCHAR DisplayVersionW[] = {'D','i','s','p','l','a','y','V','e','r',
87 static const WCHAR PublisherW[] = {'P','u','b','l','i','s','h','e','r',0};
88 static const WCHAR ContactW[] = {'C','o','n','t','a','c','t',0};
89 static const WCHAR HelpLinkW[] = {'H','e','l','p','L','i','n','k',0};
90 static const WCHAR HelpTelephoneW[] = {'H','e','l','p','T','e','l','e','p','h',
92 static const WCHAR ModifyPathW[] = {'M','o','d','i','f','y','P','a','t','h',0};
93 static const WCHAR NoModifyW[] = {'N','o','M','o','d','i','f','y',0};
94 static const WCHAR ReadmeW[] = {'R','e','a','d','m','e',0};
95 static const WCHAR URLUpdateInfoW[] = {'U','R','L','U','p','d','a','t','e','I',
97 static const WCHAR CommentsW[] = {'C','o','m','m','e','n','t','s',0};
98 static const WCHAR UninstallCommandlineW[] = {'U','n','i','n','s','t','a','l','l',
99 'S','t','r','i','n','g',0};
101 static const WCHAR PathUninstallW[] = {
102 'S','o','f','t','w','a','r','e','\\',
103 'M','i','c','r','o','s','o','f','t','\\',
104 'W','i','n','d','o','w','s','\\',
105 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
106 'U','n','i','n','s','t','a','l','l',0 };
108 /******************************************************************************
110 * Description: Entry point for DLL file
112 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason,
115 TRACE("(%p, %d, %p)\n", hinstDLL, fdwReason, lpvReserved);
119 case DLL_PROCESS_ATTACH:
126 /******************************************************************************
128 * Description: Frees memory used by an AppInfo structure, and any children.
130 static void FreeAppInfo(APPINFO *info)
134 APPINFO *next_info = info->next;
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);
147 /******************************************************************************
148 * Name : ReadApplicationsFromRegistry
149 * Description: Creates a linked list of uninstallable applications from the
151 * Parameters : root - Which registry root to read from (HKCU/HKLM)
152 * Returns : TRUE if successful, FALSE otherwise
154 static BOOL ReadApplicationsFromRegistry(HKEY root)
156 HKEY hkeyUninst, hkeyApp;
158 DWORD sizeOfSubKeyName, displen, uninstlen;
159 DWORD dwNoModify, dwType;
160 WCHAR subKeyName[256];
161 WCHAR key_app[MAX_STRING_LEN];
163 APPINFO *iter = AppInfo;
167 if (RegOpenKeyExW(root, PathUninstallW, 0, KEY_READ, &hkeyUninst) !=
171 lstrcpyW(key_app, PathUninstallW);
172 lstrcatW(key_app, BackSlashW);
173 p = key_app+lstrlenW(PathUninstallW)+1;
175 sizeOfSubKeyName = sizeof(subKeyName) / sizeof(subKeyName[0]);
179 /* find the end of the list */
180 for (iter = AppInfo; iter->next; iter = iter->next);
183 for (i = 0; RegEnumKeyExW(hkeyUninst, i, subKeyName, &sizeOfSubKeyName, NULL,
184 NULL, NULL, NULL) != ERROR_NO_MORE_ITEMS; ++i)
186 lstrcpyW(p, subKeyName);
187 RegOpenKeyExW(root, key_app, 0, KEY_READ, &hkeyApp);
192 if ((RegQueryValueExW(hkeyApp, DisplayNameW, 0, 0, NULL, &displen) ==
193 ERROR_SUCCESS) && (RegQueryValueExW(hkeyApp, UninstallCommandlineW,
194 0, 0, NULL, &uninstlen) == ERROR_SUCCESS))
196 /* if we already have iter, allocate the next entry */
199 iter->next = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
200 sizeof(struct APPINFO));
209 /* if not, start the list */
210 iter = AppInfo = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
211 sizeof(struct APPINFO));
217 iter->title = HeapAlloc(GetProcessHeap(), 0, displen);
222 RegQueryValueExW(hkeyApp, DisplayNameW, 0, 0, (LPBYTE)iter->title,
225 /* now get DisplayIcon */
227 RegQueryValueExW(hkeyApp, DisplayIconW, 0, 0, NULL, &displen);
233 iter->icon = HeapAlloc(GetProcessHeap(), 0, displen);
238 RegQueryValueExW(hkeyApp, DisplayIconW, 0, 0, (LPBYTE)iter->icon,
241 /* separate the index from the icon name, if supplied */
242 iconPtr = strchrW(iter->icon, ',');
247 iter->iconIdx = atoiW(iconPtr);
251 iter->path = HeapAlloc(GetProcessHeap(), 0, uninstlen);
256 RegQueryValueExW(hkeyApp, UninstallCommandlineW, 0, 0,
257 (LPBYTE)iter->path, &uninstlen);
259 /* publisher, version */
260 if (RegQueryValueExW(hkeyApp, PublisherW, 0, 0, NULL, &displen) ==
263 iter->publisher = HeapAlloc(GetProcessHeap(), 0, displen);
265 if (!iter->publisher)
268 RegQueryValueExW(hkeyApp, PublisherW, 0, 0, (LPBYTE)iter->publisher,
272 if (RegQueryValueExW(hkeyApp, DisplayVersionW, 0, 0, NULL, &displen) ==
275 iter->version = HeapAlloc(GetProcessHeap(), 0, displen);
280 RegQueryValueExW(hkeyApp, DisplayVersionW, 0, 0, (LPBYTE)iter->version,
284 /* Check if NoModify is set */
287 displen = sizeof(DWORD);
289 if (RegQueryValueExW(hkeyApp, NoModifyW, NULL, &dwType, (LPBYTE)&dwNoModify, &displen)
295 /* Some installers incorrectly create a REG_SZ instead of a REG_DWORD - check for
296 ASCII 49, which equals 1 */
297 if (dwType == REG_SZ)
298 dwNoModify = (dwNoModify == 49) ? 1 : 0;
300 /* Fetch the modify path */
301 if ((dwNoModify == 0) && (RegQueryValueExW(hkeyApp, ModifyPathW, 0, 0, NULL, &displen)
304 iter->path_modify = HeapAlloc(GetProcessHeap(), 0, displen);
306 if (!iter->path_modify)
309 RegQueryValueExW(hkeyApp, ModifyPathW, 0, 0, (LPBYTE)iter->path_modify, &displen);
313 iter->regroot = root;
314 lstrcpyW(iter->regkey, subKeyName);
319 RegCloseKey(hkeyApp);
320 sizeOfSubKeyName = sizeof(subKeyName) / sizeof(subKeyName[0]);
327 RegCloseKey(hkeyApp);
331 RegCloseKey(hkeyUninst);
336 /******************************************************************************
337 * Name : AddApplicationsToList
338 * Description: Populates the list box with applications.
339 * Parameters : hWnd - Handle of the dialog box
341 static void AddApplicationsToList(HWND hWnd, HIMAGELIST hList)
348 for (iter = AppInfo; iter; iter = iter->next)
350 if (!iter->title[0]) continue;
357 if (ExtractIconExW(iter->icon, iter->iconIdx, NULL, &hIcon, 1) == 1)
359 index = ImageList_AddIcon(hList, hIcon);
364 lvItem.mask = LVIF_IMAGE | LVIF_TEXT | LVIF_PARAM;
365 lvItem.iItem = iter->id;
367 lvItem.pszText = iter->title;
368 lvItem.iImage = index;
369 lvItem.lParam = iter->id;
371 index = ListView_InsertItemW(hWnd, &lvItem);
373 /* now add the subitems (columns) */
374 ListView_SetItemTextW(hWnd, index, 1, iter->publisher);
375 ListView_SetItemTextW(hWnd, index, 2, iter->version);
379 /******************************************************************************
380 * Name : RemoveItemsFromList
381 * Description: Clears the application list box.
382 * Parameters : hWnd - Handle of the dialog box
384 static void RemoveItemsFromList(HWND hWnd)
386 SendDlgItemMessageW(hWnd, IDL_PROGRAMS, LVM_DELETEALLITEMS, 0, 0);
389 /******************************************************************************
391 * Description: Frees memory used by the application linked list.
393 static inline void EmptyList(void)
395 FreeAppInfo(AppInfo);
399 /******************************************************************************
400 * Name : UpdateButtons
401 * Description: Enables/disables the Add/Remove button depending on current
402 * selection in list box.
403 * Parameters : hWnd - Handle of the dialog box
405 static void UpdateButtons(HWND hWnd)
409 DWORD selitem = SendDlgItemMessageW(hWnd, IDL_PROGRAMS, LVM_GETNEXTITEM, -1,
410 LVNI_FOCUSED | LVNI_SELECTED);
411 BOOL enable_modify = FALSE;
415 lvItem.iItem = selitem;
416 lvItem.mask = LVIF_PARAM;
418 if (SendDlgItemMessageW(hWnd, IDL_PROGRAMS, LVM_GETITEMW, 0, (LPARAM) &lvItem))
420 for (iter = AppInfo; iter; iter = iter->next)
422 if (iter->id == lvItem.lParam)
424 /* Decide whether to display Modify/Remove as one button or two */
425 enable_modify = (iter->path_modify != NULL);
427 /* Update title as appropriate */
428 if (iter->path_modify == NULL)
429 SetWindowTextW(GetDlgItem(hWnd, IDC_ADDREMOVE), btnModifyRemove);
431 SetWindowTextW(GetDlgItem(hWnd, IDC_ADDREMOVE), btnRemove);
439 /* Enable/disable other buttons if necessary */
440 EnableWindow(GetDlgItem(hWnd, IDC_ADDREMOVE), (selitem != -1));
441 EnableWindow(GetDlgItem(hWnd, IDC_SUPPORT_INFO), (selitem != -1));
442 EnableWindow(GetDlgItem(hWnd, IDC_MODIFY), enable_modify);
445 /******************************************************************************
446 * Name : InstallProgram
447 * Description: Search for potential Installer and execute it.
448 * Parameters : hWnd - Handle of the dialog box
450 static void InstallProgram(HWND hWnd)
453 WCHAR titleW[MAX_STRING_LEN];
454 WCHAR FilterBufferW[MAX_STRING_LEN];
455 WCHAR FileNameBufferW[MAX_PATH];
457 LoadStringW(hInst, IDS_CPL_TITLE, titleW, sizeof(titleW)/sizeof(WCHAR));
458 LoadStringW(hInst, IDS_INSTALL_FILTER, FilterBufferW, sizeof(FilterBufferW)/sizeof(WCHAR));
460 memset(&ofn, 0, sizeof(OPENFILENAMEW));
461 ofn.lStructSize = sizeof(OPENFILENAMEW);
462 ofn.hwndOwner = hWnd;
463 ofn.hInstance = hInst;
464 ofn.lpstrFilter = FilterBufferW;
465 ofn.nFilterIndex = 0;
466 ofn.lpstrFile = FileNameBufferW;
467 ofn.nMaxFile = MAX_PATH;
468 ofn.lpstrFileTitle = NULL;
469 ofn.nMaxFileTitle = 0;
470 ofn.lpstrTitle = titleW;
471 ofn.Flags = OFN_HIDEREADONLY | OFN_ENABLESIZING;
472 FileNameBufferW[0] = 0;
474 if (GetOpenFileNameW(&ofn))
476 SHELLEXECUTEINFOW sei;
477 memset(&sei, 0, sizeof(sei));
478 sei.cbSize = sizeof(sei);
480 sei.nShow = SW_SHOWDEFAULT;
481 sei.fMask = SEE_MASK_NO_CONSOLE;
482 sei.lpFile = ofn.lpstrFile;
484 ShellExecuteExW(&sei);
488 /******************************************************************************
489 * Name : UninstallProgram
490 * Description: Executes the specified program's installer.
491 * Parameters : id - the internal ID of the installer to remove
492 * Parameters : button - ID of button pressed (Modify or Remove)
494 static void UninstallProgram(int id, DWORD button)
498 PROCESS_INFORMATION info;
499 WCHAR errormsg[MAX_STRING_LEN];
500 WCHAR sUninstallFailed[MAX_STRING_LEN];
504 LoadStringW(hInst, IDS_UNINSTALL_FAILED, sUninstallFailed,
505 sizeof(sUninstallFailed) / sizeof(sUninstallFailed[0]));
507 for (iter = AppInfo; iter; iter = iter->next)
511 TRACE("Uninstalling %s (%s)\n", wine_dbgstr_w(iter->title),
512 wine_dbgstr_w(iter->path));
514 memset(&si, 0, sizeof(STARTUPINFOW));
515 si.cb = sizeof(STARTUPINFOW);
516 si.wShowWindow = SW_NORMAL;
518 res = CreateProcessW(NULL, (button == IDC_MODIFY) ? iter->path_modify : iter->path,
519 NULL, NULL, FALSE, 0, NULL, NULL, &si, &info);
523 CloseHandle(info.hThread);
525 /* wait for the process to exit */
526 WaitForSingleObject(info.hProcess, INFINITE);
527 CloseHandle(info.hProcess);
531 wsprintfW(errormsg, sUninstallFailed, iter->path);
533 if (MessageBoxW(0, errormsg, iter->title, MB_YESNO |
534 MB_ICONQUESTION) == IDYES)
536 /* delete the application's uninstall entry */
537 RegOpenKeyExW(iter->regroot, PathUninstallW, 0, KEY_READ, &hkey);
538 RegDeleteKeyW(hkey, iter->regkey);
548 /**********************************************************************************
549 * Name : SetInfoDialogText
550 * Description: Sets the text of a label in a window, based upon a registry entry
551 * or string passed to the function.
552 * Parameters : hKey - registry entry to read from, NULL if not reading
554 * lpKeyName - key to read from, or string to check if hKey is NULL
555 * lpAltMessage - alternative message if entry not found
556 * hWnd - handle of dialog box
557 * iDlgItem - ID of label in dialog box
559 static void SetInfoDialogText(HKEY hKey, LPWSTR lpKeyName, LPWSTR lpAltMessage,
560 HWND hWnd, int iDlgItem)
562 WCHAR buf[MAX_STRING_LEN];
566 hWndDlgItem = GetDlgItem(hWnd, iDlgItem);
568 /* if hKey is null, lpKeyName contains the string we want to check */
571 if ((lpKeyName) && (lstrlenW(lpKeyName) > 0))
572 SetWindowTextW(hWndDlgItem, lpKeyName);
574 SetWindowTextW(hWndDlgItem, lpAltMessage);
578 buflen = MAX_STRING_LEN;
580 if ((RegQueryValueExW(hKey, lpKeyName, 0, 0, (LPBYTE) buf, &buflen) ==
581 ERROR_SUCCESS) && (lstrlenW(buf) > 0))
582 SetWindowTextW(hWndDlgItem, buf);
584 SetWindowTextW(hWndDlgItem, lpAltMessage);
588 /******************************************************************************
589 * Name : SupportInfoDlgProc
590 * Description: Callback procedure for support info dialog
591 * Parameters : hWnd - hWnd of the window
592 * msg - reason for calling function
593 * wParam - additional parameter
594 * lParam - additional parameter
595 * Returns : Dependant on message
597 static BOOL CALLBACK SupportInfoDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
601 WCHAR oldtitle[MAX_STRING_LEN];
602 WCHAR buf[MAX_STRING_LEN];
603 WCHAR key[MAX_STRING_LEN];
604 WCHAR notfound[MAX_STRING_LEN];
609 for (iter = AppInfo; iter; iter = iter->next)
611 if (iter->id == (int) lParam)
613 lstrcpyW(key, PathUninstallW);
614 lstrcatW(key, BackSlashW);
615 lstrcatW(key, iter->regkey);
617 /* check the application's registry entries */
618 RegOpenKeyExW(iter->regroot, key, 0, KEY_READ, &hkey);
620 /* Load our "not specified" string */
621 LoadStringW(hInst, IDS_NOT_SPECIFIED, notfound,
622 sizeof(notfound) / sizeof(notfound[0]));
624 /* Update the data for items already read into the structure */
625 SetInfoDialogText(NULL, iter->publisher, notfound, hWnd,
627 SetInfoDialogText(NULL, iter->version, notfound, hWnd,
630 /* And now update the data for those items in the registry */
631 SetInfoDialogText(hkey, (LPWSTR) ContactW, notfound, hWnd,
633 SetInfoDialogText(hkey, (LPWSTR) HelpLinkW, notfound, hWnd,
635 SetInfoDialogText(hkey, (LPWSTR) HelpTelephoneW, notfound, hWnd,
637 SetInfoDialogText(hkey, (LPWSTR) ReadmeW, notfound, hWnd,
639 SetInfoDialogText(hkey, (LPWSTR) URLUpdateInfoW, notfound, hWnd,
641 SetInfoDialogText(hkey, (LPWSTR) CommentsW, notfound, hWnd,
644 /* Update the main label with the app name */
645 if (GetWindowTextW(GetDlgItem(hWnd, IDC_INFO_LABEL), oldtitle,
646 MAX_STRING_LEN) != 0)
648 wsprintfW(buf, oldtitle, iter->title);
649 SetWindowTextW(GetDlgItem(hWnd, IDC_INFO_LABEL), buf);
664 switch (LOWORD(wParam))
667 EndDialog(hWnd, TRUE);
678 /******************************************************************************
680 * Description: Displays the Support Information dialog
681 * Parameters : hWnd - Handle of the main dialog
682 * id - ID of the application to display information for
684 static void SupportInfo(HWND hWnd, int id)
686 DialogBoxParamW(hInst, MAKEINTRESOURCEW(IDD_INFO), hWnd, (DLGPROC)
687 SupportInfoDlgProc, (LPARAM) id);
690 /* Definition of column headers for AddListViewColumns function */
691 typedef struct AppWizColumn {
697 static const AppWizColumn columns[] = {
698 {200, LVCFMT_LEFT, IDS_COLUMN_NAME},
699 {150, LVCFMT_LEFT, IDS_COLUMN_PUBLISHER},
700 {100, LVCFMT_LEFT, IDS_COLUMN_VERSION},
703 /******************************************************************************
704 * Name : AddListViewColumns
705 * Description: Adds column headers to the list view control.
706 * Parameters : hWnd - Handle of the list view control.
707 * Returns : TRUE if completed successfully, FALSE otherwise.
709 static BOOL AddListViewColumns(HWND hWnd)
711 WCHAR buf[MAX_STRING_LEN];
715 lvc.mask = LVCF_FMT | LVCF_TEXT | LVCF_SUBITEM | LVCF_WIDTH;
717 /* Add the columns */
718 for (i = 0; i < sizeof(columns) / sizeof(columns[0]); i++)
723 /* set width and format */
724 lvc.cx = columns[i].width;
725 lvc.fmt = columns[i].fmt;
727 LoadStringW(hInst, columns[i].title, buf, sizeof(buf) / sizeof(buf[0]));
729 if (ListView_InsertColumnW(hWnd, i, &lvc) == -1)
736 /******************************************************************************
737 * Name : AddListViewImageList
738 * Description: Creates an ImageList for the list view control.
739 * Parameters : hWnd - Handle of the list view control.
740 * Returns : Handle of the image list.
742 static HIMAGELIST AddListViewImageList(HWND hWnd)
747 hSmall = ImageList_Create(GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON),
750 /* Add default icon to image list */
751 hDefaultIcon = LoadIconW(hInst, MAKEINTRESOURCEW(ICO_MAIN));
752 ImageList_AddIcon(hSmall, hDefaultIcon);
753 DestroyIcon(hDefaultIcon);
755 SendMessageW(hWnd, LVM_SETIMAGELIST, LVSIL_SMALL, (LPARAM)hSmall);
760 /******************************************************************************
761 * Name : ResetApplicationList
762 * Description: Empties the app list, if need be, and recreates it.
763 * Parameters : bFirstRun - TRUE if this is the first time this is run, FALSE otherwise
764 * hWnd - handle of the dialog box
765 * hImageList - handle of the image list
766 * Returns : New handle of the image list.
768 static HIMAGELIST ResetApplicationList(BOOL bFirstRun, HWND hWnd, HIMAGELIST hImageList)
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 ReadApplicationsFromRegistry(HKEY_LOCAL_MACHINE);
794 ReadApplicationsFromRegistry(HKEY_CURRENT_USER);
796 AddApplicationsToList(hWndListView, hImageList);
802 /******************************************************************************
804 * Description: Callback procedure for main tab
805 * Parameters : hWnd - hWnd of the window
806 * msg - reason for calling function
807 * wParam - additional parameter
808 * lParam - additional parameter
809 * Returns : Dependant on message
811 static BOOL CALLBACK MainDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
814 static HIMAGELIST hImageList;
821 hImageList = ResetApplicationList(TRUE, hWnd, hImageList);
829 RemoveItemsFromList(hWnd);
830 ImageList_Destroy(hImageList);
837 nmh = (LPNMHDR) lParam;
844 case LVN_ITEMCHANGED:
854 switch (LOWORD(wParam))
857 InstallProgram(hWnd);
862 selitem = SendDlgItemMessageW(hWnd, IDL_PROGRAMS,
863 LVM_GETNEXTITEM, -1, LVNI_FOCUSED|LVNI_SELECTED);
867 lvItem.iItem = selitem;
868 lvItem.mask = LVIF_PARAM;
870 if (SendDlgItemMessageW(hWnd, IDL_PROGRAMS, LVM_GETITEMW,
871 0, (LPARAM) &lvItem))
872 UninstallProgram(lvItem.lParam, LOWORD(wParam));
875 hImageList = ResetApplicationList(FALSE, hWnd, hImageList);
879 case IDC_SUPPORT_INFO:
880 selitem = SendDlgItemMessageW(hWnd, IDL_PROGRAMS,
881 LVM_GETNEXTITEM, -1, LVNI_FOCUSED | LVNI_SELECTED);
885 lvItem.iItem = selitem;
886 lvItem.mask = LVIF_PARAM;
888 if (SendDlgItemMessageW(hWnd, IDL_PROGRAMS, LVM_GETITEMW,
889 0, (LPARAM) &lvItem))
890 SupportInfo(hWnd, lvItem.lParam);
902 /******************************************************************************
904 * Description: Main routine for applet
905 * Parameters : hWnd - hWnd of the Control Panel
907 static void StartApplet(HWND hWnd)
910 PROPSHEETHEADERW psh;
911 WCHAR tab_title[MAX_STRING_LEN], app_title[MAX_STRING_LEN];
913 /* Load the strings we will use */
914 LoadStringW(hInst, IDS_TAB1_TITLE, tab_title, sizeof(tab_title) / sizeof(tab_title[0]));
915 LoadStringW(hInst, IDS_CPL_TITLE, app_title, sizeof(app_title) / sizeof(app_title[0]));
916 LoadStringW(hInst, IDS_REMOVE, btnRemove, sizeof(btnRemove) / sizeof(btnRemove[0]));
917 LoadStringW(hInst, IDS_MODIFY_REMOVE, btnModifyRemove, sizeof(btnModifyRemove) / sizeof(btnModifyRemove[0]));
919 /* Fill out the PROPSHEETPAGE */
920 psp.dwSize = sizeof (PROPSHEETPAGEW);
921 psp.dwFlags = PSP_USETITLE;
922 psp.hInstance = hInst;
923 psp.u.pszTemplate = MAKEINTRESOURCEW (IDD_MAIN);
924 psp.u2.pszIcon = NULL;
925 psp.pfnDlgProc = (DLGPROC) MainDlgProc;
926 psp.pszTitle = tab_title;
929 /* Fill out the PROPSHEETHEADER */
930 psh.dwSize = sizeof (PROPSHEETHEADERW);
931 psh.dwFlags = PSH_PROPSHEETPAGE | PSH_USEICONID;
932 psh.hwndParent = hWnd;
933 psh.hInstance = hInst;
934 psh.u.pszIcon = NULL;
935 psh.pszCaption = app_title;
938 psh.pfnCallback = NULL;
939 psh.u2.nStartPage = 0;
941 /* Display the property sheet */
942 PropertySheetW (&psh);
945 /******************************************************************************
947 * Description: Entry point for Control Panel applets
948 * Parameters : hwndCPL - hWnd of the Control Panel
949 * message - reason for calling function
950 * lParam1 - additional parameter
951 * lParam2 - additional parameter
952 * Returns : Dependant on message
954 LONG CALLBACK CPlApplet(HWND hwndCPL, UINT message, LPARAM lParam1, LPARAM lParam2)
956 INITCOMMONCONTROLSEX iccEx;
961 iccEx.dwSize = sizeof(iccEx);
962 iccEx.dwICC = ICC_LISTVIEW_CLASSES | ICC_TAB_CLASSES;
964 InitCommonControlsEx(&iccEx);
973 CPLINFO *appletInfo = (CPLINFO *) lParam2;
975 appletInfo->idIcon = ICO_MAIN;
976 appletInfo->idName = IDS_CPL_TITLE;
977 appletInfo->idInfo = IDS_CPL_DESC;
978 appletInfo->lData = 0;
984 StartApplet(hwndCPL);