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"
50 WINE_DEFAULT_DEBUG_CHANNEL(appwizcpl);
52 /* define a maximum length for various buffers we use */
53 #define MAX_STRING_LEN 1024
55 typedef struct APPINFO {
69 WCHAR regkey[MAX_STRING_LEN];
74 static struct APPINFO *AppInfo = NULL;
77 static WCHAR btnRemove[MAX_STRING_LEN];
78 static WCHAR btnModifyRemove[MAX_STRING_LEN];
80 static const WCHAR openW[] = {'o','p','e','n',0};
82 /* names of registry keys */
83 static const WCHAR BackSlashW[] = { '\\', 0 };
84 static const WCHAR DisplayNameW[] = {'D','i','s','p','l','a','y','N','a','m','e',0};
85 static const WCHAR DisplayIconW[] = {'D','i','s','p','l','a','y','I','c','o','n',0};
86 static const WCHAR DisplayVersionW[] = {'D','i','s','p','l','a','y','V','e','r',
88 static const WCHAR PublisherW[] = {'P','u','b','l','i','s','h','e','r',0};
89 static const WCHAR ContactW[] = {'C','o','n','t','a','c','t',0};
90 static const WCHAR HelpLinkW[] = {'H','e','l','p','L','i','n','k',0};
91 static const WCHAR HelpTelephoneW[] = {'H','e','l','p','T','e','l','e','p','h',
93 static const WCHAR ModifyPathW[] = {'M','o','d','i','f','y','P','a','t','h',0};
94 static const WCHAR NoModifyW[] = {'N','o','M','o','d','i','f','y',0};
95 static const WCHAR ReadmeW[] = {'R','e','a','d','m','e',0};
96 static const WCHAR URLUpdateInfoW[] = {'U','R','L','U','p','d','a','t','e','I',
98 static const WCHAR CommentsW[] = {'C','o','m','m','e','n','t','s',0};
99 static const WCHAR UninstallCommandlineW[] = {'U','n','i','n','s','t','a','l','l',
100 'S','t','r','i','n','g',0};
102 static const WCHAR PathUninstallW[] = {
103 'S','o','f','t','w','a','r','e','\\',
104 'M','i','c','r','o','s','o','f','t','\\',
105 'W','i','n','d','o','w','s','\\',
106 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
107 'U','n','i','n','s','t','a','l','l',0 };
109 /******************************************************************************
111 * Description: Entry point for DLL file
113 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason,
116 TRACE("(%p, %d, %p)\n", hinstDLL, fdwReason, lpvReserved);
120 case DLL_PROCESS_ATTACH:
127 /******************************************************************************
129 * Description: Frees memory used by an AppInfo structure, and any children.
131 static void FreeAppInfo(APPINFO *info)
135 APPINFO *next_info = info->next;
137 HeapFree(GetProcessHeap(), 0, info->title);
138 HeapFree(GetProcessHeap(), 0, info->path);
139 HeapFree(GetProcessHeap(), 0, info->path_modify);
140 HeapFree(GetProcessHeap(), 0, info->icon);
141 HeapFree(GetProcessHeap(), 0, info->publisher);
142 HeapFree(GetProcessHeap(), 0, info->version);
143 HeapFree(GetProcessHeap(), 0, info);
148 /******************************************************************************
149 * Name : ReadApplicationsFromRegistry
150 * Description: Creates a linked list of uninstallable applications from the
152 * Parameters : root - Which registry root to read from (HKCU/HKLM)
153 * Returns : TRUE if successful, FALSE otherwise
155 static BOOL ReadApplicationsFromRegistry(HKEY root)
157 HKEY hkeyUninst, hkeyApp;
159 DWORD sizeOfSubKeyName, displen, uninstlen;
160 DWORD dwNoModify, dwType;
161 WCHAR subKeyName[256];
162 WCHAR key_app[MAX_STRING_LEN];
164 APPINFO *iter = AppInfo;
168 if (RegOpenKeyExW(root, PathUninstallW, 0, KEY_READ, &hkeyUninst) !=
172 lstrcpyW(key_app, PathUninstallW);
173 lstrcatW(key_app, BackSlashW);
174 p = key_app+lstrlenW(PathUninstallW)+1;
176 sizeOfSubKeyName = sizeof(subKeyName) / sizeof(subKeyName[0]);
180 /* find the end of the list */
181 for (iter = AppInfo; iter->next; iter = iter->next);
184 for (i = 0; RegEnumKeyExW(hkeyUninst, i, subKeyName, &sizeOfSubKeyName, NULL,
185 NULL, NULL, NULL) != ERROR_NO_MORE_ITEMS; ++i)
187 lstrcpyW(p, subKeyName);
188 RegOpenKeyExW(root, key_app, 0, KEY_READ, &hkeyApp);
193 if ((RegQueryValueExW(hkeyApp, DisplayNameW, 0, 0, NULL, &displen) ==
194 ERROR_SUCCESS) && (RegQueryValueExW(hkeyApp, UninstallCommandlineW,
195 0, 0, NULL, &uninstlen) == ERROR_SUCCESS))
197 /* if we already have iter, allocate the next entry */
200 iter->next = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
201 sizeof(struct APPINFO));
210 /* if not, start the list */
211 iter = AppInfo = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
212 sizeof(struct APPINFO));
218 iter->title = HeapAlloc(GetProcessHeap(), 0, displen);
223 RegQueryValueExW(hkeyApp, DisplayNameW, 0, 0, (LPBYTE)iter->title,
226 /* now get DisplayIcon */
228 RegQueryValueExW(hkeyApp, DisplayIconW, 0, 0, NULL, &displen);
234 iter->icon = HeapAlloc(GetProcessHeap(), 0, displen);
239 RegQueryValueExW(hkeyApp, DisplayIconW, 0, 0, (LPBYTE)iter->icon,
242 /* separate the index from the icon name, if supplied */
243 iconPtr = strchrW(iter->icon, ',');
248 iter->iconIdx = atoiW(iconPtr);
252 iter->path = HeapAlloc(GetProcessHeap(), 0, uninstlen);
257 RegQueryValueExW(hkeyApp, UninstallCommandlineW, 0, 0,
258 (LPBYTE)iter->path, &uninstlen);
260 /* publisher, version */
261 if (RegQueryValueExW(hkeyApp, PublisherW, 0, 0, NULL, &displen) ==
264 iter->publisher = HeapAlloc(GetProcessHeap(), 0, displen);
266 if (!iter->publisher)
269 RegQueryValueExW(hkeyApp, PublisherW, 0, 0, (LPBYTE)iter->publisher,
273 if (RegQueryValueExW(hkeyApp, DisplayVersionW, 0, 0, NULL, &displen) ==
276 iter->version = HeapAlloc(GetProcessHeap(), 0, displen);
281 RegQueryValueExW(hkeyApp, DisplayVersionW, 0, 0, (LPBYTE)iter->version,
285 /* Check if NoModify is set */
288 displen = sizeof(DWORD);
290 if (RegQueryValueExW(hkeyApp, NoModifyW, NULL, &dwType, (LPBYTE)&dwNoModify, &displen)
296 /* Some installers incorrectly create a REG_SZ instead of a REG_DWORD - check for
297 ASCII 49, which equals 1 */
298 if (dwType == REG_SZ)
299 dwNoModify = (dwNoModify == 49) ? 1 : 0;
301 /* Fetch the modify path */
302 if ((dwNoModify == 0) && (RegQueryValueExW(hkeyApp, ModifyPathW, 0, 0, NULL, &displen)
305 iter->path_modify = HeapAlloc(GetProcessHeap(), 0, displen);
307 if (!iter->path_modify)
310 RegQueryValueExW(hkeyApp, ModifyPathW, 0, 0, (LPBYTE)iter->path_modify, &displen);
314 iter->regroot = root;
315 lstrcpyW(iter->regkey, subKeyName);
320 RegCloseKey(hkeyApp);
321 sizeOfSubKeyName = sizeof(subKeyName) / sizeof(subKeyName[0]);
328 RegCloseKey(hkeyApp);
332 RegCloseKey(hkeyUninst);
337 /******************************************************************************
338 * Name : AddApplicationsToList
339 * Description: Populates the list box with applications.
340 * Parameters : hWnd - Handle of the dialog box
342 static void AddApplicationsToList(HWND hWnd, HIMAGELIST hList)
349 for (iter = AppInfo; iter; iter = iter->next)
351 if (!iter->title[0]) continue;
358 if (ExtractIconExW(iter->icon, iter->iconIdx, NULL, &hIcon, 1) == 1)
360 index = ImageList_AddIcon(hList, hIcon);
365 lvItem.mask = LVIF_IMAGE | LVIF_TEXT | LVIF_PARAM;
366 lvItem.iItem = iter->id;
368 lvItem.pszText = iter->title;
369 lvItem.iImage = index;
370 lvItem.lParam = iter->id;
372 index = ListView_InsertItemW(hWnd, &lvItem);
374 /* now add the subitems (columns) */
375 ListView_SetItemTextW(hWnd, index, 1, iter->publisher);
376 ListView_SetItemTextW(hWnd, index, 2, iter->version);
380 /******************************************************************************
381 * Name : RemoveItemsFromList
382 * Description: Clears the application list box.
383 * Parameters : hWnd - Handle of the dialog box
385 static void RemoveItemsFromList(HWND hWnd)
387 SendDlgItemMessageW(hWnd, IDL_PROGRAMS, LVM_DELETEALLITEMS, 0, 0);
390 /******************************************************************************
392 * Description: Frees memory used by the application linked list.
394 static inline void EmptyList(void)
396 FreeAppInfo(AppInfo);
400 /******************************************************************************
401 * Name : UpdateButtons
402 * Description: Enables/disables the Add/Remove button depending on current
403 * selection in list box.
404 * Parameters : hWnd - Handle of the dialog box
406 static void UpdateButtons(HWND hWnd)
410 LRESULT selitem = SendDlgItemMessageW(hWnd, IDL_PROGRAMS, LVM_GETNEXTITEM, -1,
411 LVNI_FOCUSED | LVNI_SELECTED);
412 BOOL enable_modify = FALSE;
416 lvItem.iItem = selitem;
417 lvItem.mask = LVIF_PARAM;
419 if (SendDlgItemMessageW(hWnd, IDL_PROGRAMS, LVM_GETITEMW, 0, (LPARAM) &lvItem))
421 for (iter = AppInfo; iter; iter = iter->next)
423 if (iter->id == lvItem.lParam)
425 /* Decide whether to display Modify/Remove as one button or two */
426 enable_modify = (iter->path_modify != NULL);
428 /* Update title as appropriate */
429 if (iter->path_modify == NULL)
430 SetWindowTextW(GetDlgItem(hWnd, IDC_ADDREMOVE), btnModifyRemove);
432 SetWindowTextW(GetDlgItem(hWnd, IDC_ADDREMOVE), btnRemove);
440 /* Enable/disable other buttons if necessary */
441 EnableWindow(GetDlgItem(hWnd, IDC_ADDREMOVE), (selitem != -1));
442 EnableWindow(GetDlgItem(hWnd, IDC_SUPPORT_INFO), (selitem != -1));
443 EnableWindow(GetDlgItem(hWnd, IDC_MODIFY), enable_modify);
446 /******************************************************************************
447 * Name : InstallProgram
448 * Description: Search for potential Installer and execute it.
449 * Parameters : hWnd - Handle of the dialog box
451 static void InstallProgram(HWND hWnd)
454 WCHAR titleW[MAX_STRING_LEN];
455 WCHAR FilterBufferW[MAX_STRING_LEN];
456 WCHAR FileNameBufferW[MAX_PATH];
458 LoadStringW(hInst, IDS_CPL_TITLE, titleW, sizeof(titleW)/sizeof(WCHAR));
459 LoadStringW(hInst, IDS_INSTALL_FILTER, FilterBufferW, sizeof(FilterBufferW)/sizeof(WCHAR));
461 memset(&ofn, 0, sizeof(OPENFILENAMEW));
462 ofn.lStructSize = sizeof(OPENFILENAMEW);
463 ofn.hwndOwner = hWnd;
464 ofn.hInstance = hInst;
465 ofn.lpstrFilter = FilterBufferW;
466 ofn.nFilterIndex = 0;
467 ofn.lpstrFile = FileNameBufferW;
468 ofn.nMaxFile = MAX_PATH;
469 ofn.lpstrFileTitle = NULL;
470 ofn.nMaxFileTitle = 0;
471 ofn.lpstrTitle = titleW;
472 ofn.Flags = OFN_HIDEREADONLY | OFN_ENABLESIZING;
473 FileNameBufferW[0] = 0;
475 if (GetOpenFileNameW(&ofn))
477 SHELLEXECUTEINFOW sei;
478 memset(&sei, 0, sizeof(sei));
479 sei.cbSize = sizeof(sei);
481 sei.nShow = SW_SHOWDEFAULT;
482 sei.fMask = SEE_MASK_NO_CONSOLE;
483 sei.lpFile = ofn.lpstrFile;
485 ShellExecuteExW(&sei);
489 /******************************************************************************
490 * Name : UninstallProgram
491 * Description: Executes the specified program's installer.
492 * Parameters : id - the internal ID of the installer to remove
493 * Parameters : button - ID of button pressed (Modify or Remove)
495 static void UninstallProgram(int id, DWORD button)
499 PROCESS_INFORMATION info;
500 WCHAR errormsg[MAX_STRING_LEN];
501 WCHAR sUninstallFailed[MAX_STRING_LEN];
505 LoadStringW(hInst, IDS_UNINSTALL_FAILED, sUninstallFailed,
506 sizeof(sUninstallFailed) / sizeof(sUninstallFailed[0]));
508 for (iter = AppInfo; iter; iter = iter->next)
512 TRACE("Uninstalling %s (%s)\n", wine_dbgstr_w(iter->title),
513 wine_dbgstr_w(iter->path));
515 memset(&si, 0, sizeof(STARTUPINFOW));
516 si.cb = sizeof(STARTUPINFOW);
517 si.wShowWindow = SW_NORMAL;
519 res = CreateProcessW(NULL, (button == IDC_MODIFY) ? iter->path_modify : iter->path,
520 NULL, NULL, FALSE, 0, NULL, NULL, &si, &info);
524 CloseHandle(info.hThread);
526 /* wait for the process to exit */
527 WaitForSingleObject(info.hProcess, INFINITE);
528 CloseHandle(info.hProcess);
532 wsprintfW(errormsg, sUninstallFailed, iter->path);
534 if (MessageBoxW(0, errormsg, iter->title, MB_YESNO |
535 MB_ICONQUESTION) == IDYES)
537 /* delete the application's uninstall entry */
538 RegOpenKeyExW(iter->regroot, PathUninstallW, 0, KEY_READ, &hkey);
539 RegDeleteKeyW(hkey, iter->regkey);
549 /**********************************************************************************
550 * Name : SetInfoDialogText
551 * Description: Sets the text of a label in a window, based upon a registry entry
552 * or string passed to the function.
553 * Parameters : hKey - registry entry to read from, NULL if not reading
555 * lpKeyName - key to read from, or string to check if hKey is NULL
556 * lpAltMessage - alternative message if entry not found
557 * hWnd - handle of dialog box
558 * iDlgItem - ID of label in dialog box
560 static void SetInfoDialogText(HKEY hKey, LPCWSTR lpKeyName, LPCWSTR lpAltMessage,
561 HWND hWnd, int iDlgItem)
563 WCHAR buf[MAX_STRING_LEN];
567 hWndDlgItem = GetDlgItem(hWnd, iDlgItem);
569 /* if hKey is null, lpKeyName contains the string we want to check */
572 if ((lpKeyName) && (lstrlenW(lpKeyName) > 0))
573 SetWindowTextW(hWndDlgItem, lpKeyName);
575 SetWindowTextW(hWndDlgItem, lpAltMessage);
579 buflen = MAX_STRING_LEN;
581 if ((RegQueryValueExW(hKey, lpKeyName, 0, 0, (LPBYTE) buf, &buflen) ==
582 ERROR_SUCCESS) && (lstrlenW(buf) > 0))
583 SetWindowTextW(hWndDlgItem, buf);
585 SetWindowTextW(hWndDlgItem, lpAltMessage);
589 /******************************************************************************
590 * Name : SupportInfoDlgProc
591 * Description: Callback procedure for support info dialog
592 * Parameters : hWnd - hWnd of the window
593 * msg - reason for calling function
594 * wParam - additional parameter
595 * lParam - additional parameter
596 * Returns : Dependant on message
598 static BOOL CALLBACK SupportInfoDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
602 WCHAR oldtitle[MAX_STRING_LEN];
603 WCHAR buf[MAX_STRING_LEN];
604 WCHAR key[MAX_STRING_LEN];
605 WCHAR notfound[MAX_STRING_LEN];
610 for (iter = AppInfo; iter; iter = iter->next)
612 if (iter->id == (int) lParam)
614 lstrcpyW(key, PathUninstallW);
615 lstrcatW(key, BackSlashW);
616 lstrcatW(key, iter->regkey);
618 /* check the application's registry entries */
619 RegOpenKeyExW(iter->regroot, key, 0, KEY_READ, &hkey);
621 /* Load our "not specified" string */
622 LoadStringW(hInst, IDS_NOT_SPECIFIED, notfound,
623 sizeof(notfound) / sizeof(notfound[0]));
625 /* Update the data for items already read into the structure */
626 SetInfoDialogText(NULL, iter->publisher, notfound, hWnd,
628 SetInfoDialogText(NULL, iter->version, notfound, hWnd,
631 /* And now update the data for those items in the registry */
632 SetInfoDialogText(hkey, ContactW, notfound, hWnd,
634 SetInfoDialogText(hkey, HelpLinkW, notfound, hWnd,
636 SetInfoDialogText(hkey, HelpTelephoneW, notfound, hWnd,
638 SetInfoDialogText(hkey, ReadmeW, notfound, hWnd,
640 SetInfoDialogText(hkey, URLUpdateInfoW, notfound, hWnd,
642 SetInfoDialogText(hkey, CommentsW, notfound, hWnd,
645 /* Update the main label with the app name */
646 if (GetWindowTextW(GetDlgItem(hWnd, IDC_INFO_LABEL), oldtitle,
647 MAX_STRING_LEN) != 0)
649 wsprintfW(buf, oldtitle, iter->title);
650 SetWindowTextW(GetDlgItem(hWnd, IDC_INFO_LABEL), buf);
665 switch (LOWORD(wParam))
668 EndDialog(hWnd, TRUE);
679 /******************************************************************************
681 * Description: Displays the Support Information dialog
682 * Parameters : hWnd - Handle of the main dialog
683 * id - ID of the application to display information for
685 static void SupportInfo(HWND hWnd, int id)
687 DialogBoxParamW(hInst, MAKEINTRESOURCEW(IDD_INFO), hWnd, (DLGPROC)
688 SupportInfoDlgProc, (LPARAM) id);
691 /* Definition of column headers for AddListViewColumns function */
692 typedef struct AppWizColumn {
698 static const AppWizColumn columns[] = {
699 {200, LVCFMT_LEFT, IDS_COLUMN_NAME},
700 {150, LVCFMT_LEFT, IDS_COLUMN_PUBLISHER},
701 {100, LVCFMT_LEFT, IDS_COLUMN_VERSION},
704 /******************************************************************************
705 * Name : AddListViewColumns
706 * Description: Adds column headers to the list view control.
707 * Parameters : hWnd - Handle of the list view control.
708 * Returns : TRUE if completed successfully, FALSE otherwise.
710 static BOOL AddListViewColumns(HWND hWnd)
712 WCHAR buf[MAX_STRING_LEN];
716 lvc.mask = LVCF_FMT | LVCF_TEXT | LVCF_SUBITEM | LVCF_WIDTH;
718 /* Add the columns */
719 for (i = 0; i < sizeof(columns) / sizeof(columns[0]); i++)
724 /* set width and format */
725 lvc.cx = columns[i].width;
726 lvc.fmt = columns[i].fmt;
728 LoadStringW(hInst, columns[i].title, buf, sizeof(buf) / sizeof(buf[0]));
730 if (ListView_InsertColumnW(hWnd, i, &lvc) == -1)
737 /******************************************************************************
738 * Name : AddListViewImageList
739 * Description: Creates an ImageList for the list view control.
740 * Parameters : hWnd - Handle of the list view control.
741 * Returns : Handle of the image list.
743 static HIMAGELIST AddListViewImageList(HWND hWnd)
748 hSmall = ImageList_Create(GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON),
749 ILC_COLOR32 | ILC_MASK, 1, 1);
751 /* Add default icon to image list */
752 hDefaultIcon = LoadIconW(hInst, MAKEINTRESOURCEW(ICO_MAIN));
753 ImageList_AddIcon(hSmall, hDefaultIcon);
754 DestroyIcon(hDefaultIcon);
756 SendMessageW(hWnd, LVM_SETIMAGELIST, LVSIL_SMALL, (LPARAM)hSmall);
761 /******************************************************************************
762 * Name : ResetApplicationList
763 * Description: Empties the app list, if need be, and recreates it.
764 * Parameters : bFirstRun - TRUE if this is the first time this is run, FALSE otherwise
765 * hWnd - handle of the dialog box
766 * hImageList - handle of the image list
767 * Returns : New handle of the image list.
769 static HIMAGELIST ResetApplicationList(BOOL bFirstRun, HWND hWnd, HIMAGELIST hImageList)
773 hWndListView = GetDlgItem(hWnd, IDL_PROGRAMS);
775 /* if first run, create the image list and add the listview columns */
778 if (!AddListViewColumns(hWndListView))
781 else /* we need to remove the existing things first */
783 RemoveItemsFromList(hWnd);
784 ImageList_Destroy(hImageList);
786 /* reset the list, since it's probably changed if the uninstallation was
791 /* now create the image list and add the applications to the listview */
792 hImageList = AddListViewImageList(hWndListView);
794 ReadApplicationsFromRegistry(HKEY_LOCAL_MACHINE);
795 ReadApplicationsFromRegistry(HKEY_CURRENT_USER);
797 AddApplicationsToList(hWndListView, hImageList);
803 /******************************************************************************
805 * Description: Callback procedure for main tab
806 * Parameters : hWnd - hWnd of the window
807 * msg - reason for calling function
808 * wParam - additional parameter
809 * lParam - additional parameter
810 * Returns : Dependant on message
812 static BOOL CALLBACK MainDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
815 static HIMAGELIST hImageList;
822 hImageList = ResetApplicationList(TRUE, hWnd, hImageList);
830 RemoveItemsFromList(hWnd);
831 ImageList_Destroy(hImageList);
838 nmh = (LPNMHDR) lParam;
845 case LVN_ITEMCHANGED:
855 switch (LOWORD(wParam))
858 InstallProgram(hWnd);
863 selitem = SendDlgItemMessageW(hWnd, IDL_PROGRAMS,
864 LVM_GETNEXTITEM, -1, LVNI_FOCUSED|LVNI_SELECTED);
868 lvItem.iItem = selitem;
869 lvItem.mask = LVIF_PARAM;
871 if (SendDlgItemMessageW(hWnd, IDL_PROGRAMS, LVM_GETITEMW,
872 0, (LPARAM) &lvItem))
873 UninstallProgram(lvItem.lParam, LOWORD(wParam));
876 hImageList = ResetApplicationList(FALSE, hWnd, hImageList);
880 case IDC_SUPPORT_INFO:
881 selitem = SendDlgItemMessageW(hWnd, IDL_PROGRAMS,
882 LVM_GETNEXTITEM, -1, LVNI_FOCUSED | LVNI_SELECTED);
886 lvItem.iItem = selitem;
887 lvItem.mask = LVIF_PARAM;
889 if (SendDlgItemMessageW(hWnd, IDL_PROGRAMS, LVM_GETITEMW,
890 0, (LPARAM) &lvItem))
891 SupportInfo(hWnd, lvItem.lParam);
903 static int CALLBACK propsheet_callback( HWND hwnd, UINT msg, LPARAM lparam )
907 case PSCB_INITIALIZED:
908 SendMessageW( hwnd, WM_SETICON, ICON_BIG, (LPARAM)LoadIconW( hInst, MAKEINTRESOURCEW(ICO_MAIN) ));
914 /******************************************************************************
916 * Description: Main routine for applet
917 * Parameters : hWnd - hWnd of the Control Panel
919 static void StartApplet(HWND hWnd)
922 PROPSHEETHEADERW psh;
923 WCHAR tab_title[MAX_STRING_LEN], app_title[MAX_STRING_LEN];
925 /* Load the strings we will use */
926 LoadStringW(hInst, IDS_TAB1_TITLE, tab_title, sizeof(tab_title) / sizeof(tab_title[0]));
927 LoadStringW(hInst, IDS_CPL_TITLE, app_title, sizeof(app_title) / sizeof(app_title[0]));
928 LoadStringW(hInst, IDS_REMOVE, btnRemove, sizeof(btnRemove) / sizeof(btnRemove[0]));
929 LoadStringW(hInst, IDS_MODIFY_REMOVE, btnModifyRemove, sizeof(btnModifyRemove) / sizeof(btnModifyRemove[0]));
931 /* Fill out the PROPSHEETPAGE */
932 psp.dwSize = sizeof (PROPSHEETPAGEW);
933 psp.dwFlags = PSP_USETITLE;
934 psp.hInstance = hInst;
935 psp.u.pszTemplate = MAKEINTRESOURCEW (IDD_MAIN);
936 psp.u2.pszIcon = NULL;
937 psp.pfnDlgProc = (DLGPROC) MainDlgProc;
938 psp.pszTitle = tab_title;
941 /* Fill out the PROPSHEETHEADER */
942 psh.dwSize = sizeof (PROPSHEETHEADERW);
943 psh.dwFlags = PSH_PROPSHEETPAGE | PSH_USEICONID | PSH_USECALLBACK;
944 psh.hwndParent = hWnd;
945 psh.hInstance = hInst;
946 psh.u.pszIcon = MAKEINTRESOURCEW(ICO_MAIN);
947 psh.pszCaption = app_title;
950 psh.pfnCallback = propsheet_callback;
951 psh.u2.nStartPage = 0;
953 /* Display the property sheet */
954 PropertySheetW (&psh);
957 static LONG start_params(const WCHAR *params)
959 static const WCHAR install_geckoW[] = {'i','n','s','t','a','l','l','_','g','e','c','k','o',0};
964 if(!strcmpW(params, install_geckoW)) {
965 install_wine_gecko();
969 WARN("unknown param %s\n", debugstr_w(params));
973 /******************************************************************************
975 * Description: Entry point for Control Panel applets
976 * Parameters : hwndCPL - hWnd of the Control Panel
977 * message - reason for calling function
978 * lParam1 - additional parameter
979 * lParam2 - additional parameter
980 * Returns : Dependant on message
982 LONG CALLBACK CPlApplet(HWND hwndCPL, UINT message, LPARAM lParam1, LPARAM lParam2)
984 INITCOMMONCONTROLSEX iccEx;
989 iccEx.dwSize = sizeof(iccEx);
990 iccEx.dwICC = ICC_LISTVIEW_CLASSES | ICC_TAB_CLASSES;
992 InitCommonControlsEx(&iccEx);
999 case CPL_STARTWPARMSW:
1000 return start_params((const WCHAR *)lParam2);
1004 CPLINFO *appletInfo = (CPLINFO *) lParam2;
1006 appletInfo->idIcon = ICO_MAIN;
1007 appletInfo->idName = IDS_CPL_TITLE;
1008 appletInfo->idInfo = IDS_CPL_DESC;
1009 appletInfo->lData = 0;
1015 StartApplet(hwndCPL);