2 * Add/Remove Programs applet
3 * Partially based on Wine Uninstaller
5 * Copyright 2000 Andreas Mohr
6 * Copyright 2004 Hannu Valtonen
7 * Copyright 2005 Jonathan Ernst
8 * Copyright 2001-2002, 2008 Owen Rudge
10 * This library is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Lesser General Public
12 * License as published by the Free Software Foundation; either
13 * version 2.1 of the License, or (at your option) any later version.
15 * This library is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Lesser General Public License for more details.
20 * You should have received a copy of the GNU Lesser General Public
21 * License along with this library; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
26 #define NONAMELESSUNION
29 #include "wine/port.h"
45 #include "wine/unicode.h"
46 #include "wine/list.h"
47 #include "wine/debug.h"
51 WINE_DEFAULT_DEBUG_CHANNEL(appwizcpl);
53 /* define a maximum length for various buffers we use */
54 #define MAX_STRING_LEN 1024
56 typedef struct APPINFO
72 WCHAR regkey[MAX_STRING_LEN];
75 static struct list app_list = LIST_INIT( app_list );
78 static WCHAR btnRemove[MAX_STRING_LEN];
79 static WCHAR btnModifyRemove[MAX_STRING_LEN];
81 static const WCHAR openW[] = {'o','p','e','n',0};
83 /* names of registry keys */
84 static const WCHAR BackSlashW[] = { '\\', 0 };
85 static const WCHAR DisplayNameW[] = {'D','i','s','p','l','a','y','N','a','m','e',0};
86 static const WCHAR DisplayIconW[] = {'D','i','s','p','l','a','y','I','c','o','n',0};
87 static const WCHAR DisplayVersionW[] = {'D','i','s','p','l','a','y','V','e','r',
89 static const WCHAR PublisherW[] = {'P','u','b','l','i','s','h','e','r',0};
90 static const WCHAR ContactW[] = {'C','o','n','t','a','c','t',0};
91 static const WCHAR HelpLinkW[] = {'H','e','l','p','L','i','n','k',0};
92 static const WCHAR HelpTelephoneW[] = {'H','e','l','p','T','e','l','e','p','h',
94 static const WCHAR ModifyPathW[] = {'M','o','d','i','f','y','P','a','t','h',0};
95 static const WCHAR NoModifyW[] = {'N','o','M','o','d','i','f','y',0};
96 static const WCHAR ReadmeW[] = {'R','e','a','d','m','e',0};
97 static const WCHAR URLUpdateInfoW[] = {'U','R','L','U','p','d','a','t','e','I',
99 static const WCHAR CommentsW[] = {'C','o','m','m','e','n','t','s',0};
100 static const WCHAR UninstallCommandlineW[] = {'U','n','i','n','s','t','a','l','l',
101 'S','t','r','i','n','g',0};
102 static const WCHAR WindowsInstallerW[] = {'W','i','n','d','o','w','s','I','n','s','t','a','l','l','e','r',0};
104 static const WCHAR PathUninstallW[] = {
105 'S','o','f','t','w','a','r','e','\\',
106 'M','i','c','r','o','s','o','f','t','\\',
107 'W','i','n','d','o','w','s','\\',
108 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
109 'U','n','i','n','s','t','a','l','l',0 };
111 /******************************************************************************
113 * Description: Entry point for DLL file
115 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason,
118 TRACE("(%p, %d, %p)\n", hinstDLL, fdwReason, lpvReserved);
122 case DLL_PROCESS_ATTACH:
129 /******************************************************************************
131 * Description: Frees memory used by an AppInfo structure, and any children.
133 static void FreeAppInfo(APPINFO *info)
135 HeapFree(GetProcessHeap(), 0, info->title);
136 HeapFree(GetProcessHeap(), 0, info->path);
137 HeapFree(GetProcessHeap(), 0, info->path_modify);
138 HeapFree(GetProcessHeap(), 0, info->icon);
139 HeapFree(GetProcessHeap(), 0, info->publisher);
140 HeapFree(GetProcessHeap(), 0, info->version);
141 HeapFree(GetProcessHeap(), 0, info);
144 /******************************************************************************
145 * Name : ReadApplicationsFromRegistry
146 * Description: Creates a linked list of uninstallable applications from the
148 * Parameters : root - Which registry root to read from (HKCU/HKLM)
149 * Returns : TRUE if successful, FALSE otherwise
151 static BOOL ReadApplicationsFromRegistry(HKEY root)
153 HKEY hkeyUninst, hkeyApp;
155 DWORD sizeOfSubKeyName, displen, uninstlen;
156 DWORD dwNoModify, dwType, value;
157 WCHAR subKeyName[256];
158 WCHAR key_app[MAX_STRING_LEN];
160 APPINFO *info = NULL;
164 if (RegOpenKeyExW(root, PathUninstallW, 0, KEY_READ, &hkeyUninst) !=
168 lstrcpyW(key_app, PathUninstallW);
169 lstrcatW(key_app, BackSlashW);
170 p = key_app+lstrlenW(PathUninstallW)+1;
172 sizeOfSubKeyName = sizeof(subKeyName) / sizeof(subKeyName[0]);
174 for (i = 0; RegEnumKeyExW(hkeyUninst, i, subKeyName, &sizeOfSubKeyName, NULL,
175 NULL, NULL, NULL) != ERROR_NO_MORE_ITEMS; ++i)
177 lstrcpyW(p, subKeyName);
178 RegOpenKeyExW(root, key_app, 0, KEY_READ, &hkeyApp);
182 if (!RegQueryValueExW(hkeyApp, DisplayNameW, 0, 0, NULL, &displen))
184 DWORD size = sizeof(value);
185 if (!RegQueryValueExW(hkeyApp, WindowsInstallerW, NULL, &dwType, (LPBYTE)&value, &size)
186 && dwType == REG_DWORD && value == 1)
188 static const WCHAR fmtW[] = {'m','s','i','e','x','e','c',' ','/','x','%','s',0};
189 int len = lstrlenW(fmtW) + lstrlenW(subKeyName);
191 if (!(command = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)))) goto err;
192 wsprintfW(command, fmtW, subKeyName);
194 else if (!RegQueryValueExW(hkeyApp, UninstallCommandlineW, 0, 0, NULL, &uninstlen))
196 if (!(command = HeapAlloc(GetProcessHeap(), 0, uninstlen))) goto err;
197 RegQueryValueExW(hkeyApp, UninstallCommandlineW, 0, 0, (LPBYTE)command, &uninstlen);
201 RegCloseKey(hkeyApp);
202 sizeOfSubKeyName = sizeof(subKeyName) / sizeof(subKeyName[0]);
206 info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(struct APPINFO));
209 info->title = HeapAlloc(GetProcessHeap(), 0, displen);
214 RegQueryValueExW(hkeyApp, DisplayNameW, 0, 0, (LPBYTE)info->title,
217 /* now get DisplayIcon */
219 RegQueryValueExW(hkeyApp, DisplayIconW, 0, 0, NULL, &displen);
225 info->icon = HeapAlloc(GetProcessHeap(), 0, displen);
230 RegQueryValueExW(hkeyApp, DisplayIconW, 0, 0, (LPBYTE)info->icon,
233 /* separate the index from the icon name, if supplied */
234 iconPtr = strchrW(info->icon, ',');
239 info->iconIdx = atoiW(iconPtr);
243 /* publisher, version */
244 if (RegQueryValueExW(hkeyApp, PublisherW, 0, 0, NULL, &displen) ==
247 info->publisher = HeapAlloc(GetProcessHeap(), 0, displen);
249 if (!info->publisher)
252 RegQueryValueExW(hkeyApp, PublisherW, 0, 0, (LPBYTE)info->publisher,
256 if (RegQueryValueExW(hkeyApp, DisplayVersionW, 0, 0, NULL, &displen) ==
259 info->version = HeapAlloc(GetProcessHeap(), 0, displen);
264 RegQueryValueExW(hkeyApp, DisplayVersionW, 0, 0, (LPBYTE)info->version,
268 /* Check if NoModify is set */
271 displen = sizeof(DWORD);
273 if (RegQueryValueExW(hkeyApp, NoModifyW, NULL, &dwType, (LPBYTE)&dwNoModify, &displen)
279 /* Some installers incorrectly create a REG_SZ instead of a REG_DWORD */
280 if (dwType == REG_SZ)
281 dwNoModify = (*(BYTE *)&dwNoModify == '1');
283 /* Fetch the modify path */
286 size = sizeof(value);
287 if (!RegQueryValueExW(hkeyApp, WindowsInstallerW, NULL, &dwType, (LPBYTE)&value, &size)
288 && dwType == REG_DWORD && value == 1)
290 static const WCHAR fmtW[] = {'m','s','i','e','x','e','c',' ','/','i','%','s',0};
291 int len = lstrlenW(fmtW) + lstrlenW(subKeyName);
293 if (!(info->path_modify = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)))) goto err;
294 wsprintfW(info->path_modify, fmtW, subKeyName);
296 else if (!RegQueryValueExW(hkeyApp, ModifyPathW, 0, 0, NULL, &displen))
298 if (!(info->path_modify = HeapAlloc(GetProcessHeap(), 0, displen))) goto err;
299 RegQueryValueExW(hkeyApp, ModifyPathW, 0, 0, (LPBYTE)info->path_modify, &displen);
304 info->regroot = root;
305 lstrcpyW(info->regkey, subKeyName);
306 info->path = command;
309 list_add_tail( &app_list, &info->entry );
312 RegCloseKey(hkeyApp);
313 sizeOfSubKeyName = sizeof(subKeyName) / sizeof(subKeyName[0]);
320 RegCloseKey(hkeyApp);
321 if (info) FreeAppInfo(info);
324 RegCloseKey(hkeyUninst);
329 /******************************************************************************
330 * Name : AddApplicationsToList
331 * Description: Populates the list box with applications.
332 * Parameters : hWnd - Handle of the dialog box
334 static void AddApplicationsToList(HWND hWnd, HIMAGELIST hList)
341 LIST_FOR_EACH_ENTRY( iter, &app_list, APPINFO, entry )
343 if (!iter->title[0]) continue;
350 if (ExtractIconExW(iter->icon, iter->iconIdx, NULL, &hIcon, 1) == 1)
352 index = ImageList_AddIcon(hList, hIcon);
357 lvItem.mask = LVIF_IMAGE | LVIF_TEXT | LVIF_PARAM;
358 lvItem.iItem = iter->id;
360 lvItem.pszText = iter->title;
361 lvItem.iImage = index;
362 lvItem.lParam = iter->id;
364 index = ListView_InsertItemW(hWnd, &lvItem);
366 /* now add the subitems (columns) */
367 ListView_SetItemTextW(hWnd, index, 1, iter->publisher);
368 ListView_SetItemTextW(hWnd, index, 2, iter->version);
372 /******************************************************************************
373 * Name : RemoveItemsFromList
374 * Description: Clears the application list box.
375 * Parameters : hWnd - Handle of the dialog box
377 static void RemoveItemsFromList(HWND hWnd)
379 SendDlgItemMessageW(hWnd, IDL_PROGRAMS, LVM_DELETEALLITEMS, 0, 0);
382 /******************************************************************************
384 * Description: Frees memory used by the application linked list.
386 static inline void EmptyList(void)
388 APPINFO *info, *next;
389 LIST_FOR_EACH_ENTRY_SAFE( info, next, &app_list, APPINFO, entry )
391 list_remove( &info->entry );
396 /******************************************************************************
397 * Name : UpdateButtons
398 * Description: Enables/disables the Add/Remove button depending on current
399 * selection in list box.
400 * Parameters : hWnd - Handle of the dialog box
402 static void UpdateButtons(HWND hWnd)
406 LRESULT selitem = SendDlgItemMessageW(hWnd, IDL_PROGRAMS, LVM_GETNEXTITEM, -1,
407 LVNI_FOCUSED | LVNI_SELECTED);
408 BOOL enable_modify = FALSE;
412 lvItem.iItem = selitem;
413 lvItem.mask = LVIF_PARAM;
415 if (SendDlgItemMessageW(hWnd, IDL_PROGRAMS, LVM_GETITEMW, 0, (LPARAM) &lvItem))
417 LIST_FOR_EACH_ENTRY( iter, &app_list, APPINFO, entry )
419 if (iter->id == lvItem.lParam)
421 /* Decide whether to display Modify/Remove as one button or two */
422 enable_modify = (iter->path_modify != NULL);
424 /* Update title as appropriate */
425 if (iter->path_modify == NULL)
426 SetWindowTextW(GetDlgItem(hWnd, IDC_ADDREMOVE), btnModifyRemove);
428 SetWindowTextW(GetDlgItem(hWnd, IDC_ADDREMOVE), btnRemove);
436 /* Enable/disable other buttons if necessary */
437 EnableWindow(GetDlgItem(hWnd, IDC_ADDREMOVE), (selitem != -1));
438 EnableWindow(GetDlgItem(hWnd, IDC_SUPPORT_INFO), (selitem != -1));
439 EnableWindow(GetDlgItem(hWnd, IDC_MODIFY), enable_modify);
442 /******************************************************************************
443 * Name : InstallProgram
444 * Description: Search for potential Installer and execute it.
445 * Parameters : hWnd - Handle of the dialog box
447 static void InstallProgram(HWND hWnd)
449 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}
452 WCHAR titleW[MAX_STRING_LEN];
453 WCHAR filter_installs[MAX_STRING_LEN];
454 WCHAR filter_programs[MAX_STRING_LEN];
455 WCHAR filter_all[MAX_STRING_LEN];
456 WCHAR FilterBufferW[MAX_PATH];
457 WCHAR FileNameBufferW[MAX_PATH];
459 LoadStringW(hInst, IDS_CPL_TITLE, titleW, sizeof(titleW)/sizeof(WCHAR));
460 LoadStringW(hInst, IDS_FILTER_INSTALLS, filter_installs, sizeof(filter_installs)/sizeof(WCHAR));
461 LoadStringW(hInst, IDS_FILTER_PROGRAMS, filter_programs, sizeof(filter_programs)/sizeof(WCHAR));
462 LoadStringW(hInst, IDS_FILTER_ALL, filter_all, sizeof(filter_all)/sizeof(WCHAR));
464 snprintfW( FilterBufferW, MAX_PATH, filters, filter_installs, 0, 0,
465 filter_programs, 0, 0, filter_all, 0, 0 );
466 memset(&ofn, 0, sizeof(OPENFILENAMEW));
467 ofn.lStructSize = sizeof(OPENFILENAMEW);
468 ofn.hwndOwner = hWnd;
469 ofn.hInstance = hInst;
470 ofn.lpstrFilter = FilterBufferW;
471 ofn.nFilterIndex = 0;
472 ofn.lpstrFile = FileNameBufferW;
473 ofn.nMaxFile = MAX_PATH;
474 ofn.lpstrFileTitle = NULL;
475 ofn.nMaxFileTitle = 0;
476 ofn.lpstrTitle = titleW;
477 ofn.Flags = OFN_HIDEREADONLY | OFN_ENABLESIZING;
478 FileNameBufferW[0] = 0;
480 if (GetOpenFileNameW(&ofn))
482 SHELLEXECUTEINFOW sei;
483 memset(&sei, 0, sizeof(sei));
484 sei.cbSize = sizeof(sei);
486 sei.nShow = SW_SHOWDEFAULT;
487 sei.fMask = SEE_MASK_NO_CONSOLE;
488 sei.lpFile = ofn.lpstrFile;
490 ShellExecuteExW(&sei);
494 /******************************************************************************
495 * Name : UninstallProgram
496 * Description: Executes the specified program's installer.
497 * Parameters : id - the internal ID of the installer to remove
498 * Parameters : button - ID of button pressed (Modify or Remove)
500 static void UninstallProgram(int id, DWORD button)
504 PROCESS_INFORMATION info;
505 WCHAR errormsg[MAX_STRING_LEN];
506 WCHAR sUninstallFailed[MAX_STRING_LEN];
510 LoadStringW(hInst, IDS_UNINSTALL_FAILED, sUninstallFailed,
511 sizeof(sUninstallFailed) / sizeof(sUninstallFailed[0]));
513 LIST_FOR_EACH_ENTRY( iter, &app_list, APPINFO, entry )
517 TRACE("Uninstalling %s (%s)\n", wine_dbgstr_w(iter->title),
518 wine_dbgstr_w(iter->path));
520 memset(&si, 0, sizeof(STARTUPINFOW));
521 si.cb = sizeof(STARTUPINFOW);
522 si.wShowWindow = SW_NORMAL;
524 res = CreateProcessW(NULL, (button == IDC_MODIFY) ? iter->path_modify : iter->path,
525 NULL, NULL, FALSE, 0, NULL, NULL, &si, &info);
529 CloseHandle(info.hThread);
531 /* wait for the process to exit */
532 WaitForSingleObject(info.hProcess, INFINITE);
533 CloseHandle(info.hProcess);
537 wsprintfW(errormsg, sUninstallFailed, iter->path);
539 if (MessageBoxW(0, errormsg, iter->title, MB_YESNO |
540 MB_ICONQUESTION) == IDYES)
542 /* delete the application's uninstall entry */
543 RegOpenKeyExW(iter->regroot, PathUninstallW, 0, KEY_READ, &hkey);
544 RegDeleteKeyW(hkey, iter->regkey);
554 /**********************************************************************************
555 * Name : SetInfoDialogText
556 * Description: Sets the text of a label in a window, based upon a registry entry
557 * or string passed to the function.
558 * Parameters : hKey - registry entry to read from, NULL if not reading
560 * lpKeyName - key to read from, or string to check if hKey is NULL
561 * lpAltMessage - alternative message if entry not found
562 * hWnd - handle of dialog box
563 * iDlgItem - ID of label in dialog box
565 static void SetInfoDialogText(HKEY hKey, LPCWSTR lpKeyName, LPCWSTR lpAltMessage,
566 HWND hWnd, int iDlgItem)
568 WCHAR buf[MAX_STRING_LEN];
572 hWndDlgItem = GetDlgItem(hWnd, iDlgItem);
574 /* if hKey is null, lpKeyName contains the string we want to check */
577 if ((lpKeyName) && (lstrlenW(lpKeyName) > 0))
578 SetWindowTextW(hWndDlgItem, lpKeyName);
580 SetWindowTextW(hWndDlgItem, lpAltMessage);
584 buflen = MAX_STRING_LEN;
586 if ((RegQueryValueExW(hKey, lpKeyName, 0, 0, (LPBYTE) buf, &buflen) ==
587 ERROR_SUCCESS) && (lstrlenW(buf) > 0))
588 SetWindowTextW(hWndDlgItem, buf);
590 SetWindowTextW(hWndDlgItem, lpAltMessage);
594 /******************************************************************************
595 * Name : SupportInfoDlgProc
596 * Description: Callback procedure for support info dialog
597 * Parameters : hWnd - hWnd of the window
598 * msg - reason for calling function
599 * wParam - additional parameter
600 * lParam - additional parameter
601 * Returns : Dependant on message
603 static BOOL CALLBACK SupportInfoDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
607 WCHAR oldtitle[MAX_STRING_LEN];
608 WCHAR buf[MAX_STRING_LEN];
609 WCHAR key[MAX_STRING_LEN];
610 WCHAR notfound[MAX_STRING_LEN];
615 LIST_FOR_EACH_ENTRY( iter, &app_list, APPINFO, entry )
617 if (iter->id == (int) lParam)
619 lstrcpyW(key, PathUninstallW);
620 lstrcatW(key, BackSlashW);
621 lstrcatW(key, iter->regkey);
623 /* check the application's registry entries */
624 RegOpenKeyExW(iter->regroot, key, 0, KEY_READ, &hkey);
626 /* Load our "not specified" string */
627 LoadStringW(hInst, IDS_NOT_SPECIFIED, notfound,
628 sizeof(notfound) / sizeof(notfound[0]));
630 /* Update the data for items already read into the structure */
631 SetInfoDialogText(NULL, iter->publisher, notfound, hWnd,
633 SetInfoDialogText(NULL, iter->version, notfound, hWnd,
636 /* And now update the data for those items in the registry */
637 SetInfoDialogText(hkey, ContactW, notfound, hWnd,
639 SetInfoDialogText(hkey, HelpLinkW, notfound, hWnd,
641 SetInfoDialogText(hkey, HelpTelephoneW, notfound, hWnd,
643 SetInfoDialogText(hkey, ReadmeW, notfound, hWnd,
645 SetInfoDialogText(hkey, URLUpdateInfoW, notfound, hWnd,
647 SetInfoDialogText(hkey, CommentsW, notfound, hWnd,
650 /* Update the main label with the app name */
651 if (GetWindowTextW(GetDlgItem(hWnd, IDC_INFO_LABEL), oldtitle,
652 MAX_STRING_LEN) != 0)
654 wsprintfW(buf, oldtitle, iter->title);
655 SetWindowTextW(GetDlgItem(hWnd, IDC_INFO_LABEL), buf);
670 switch (LOWORD(wParam))
673 EndDialog(hWnd, TRUE);
684 /******************************************************************************
686 * Description: Displays the Support Information dialog
687 * Parameters : hWnd - Handle of the main dialog
688 * id - ID of the application to display information for
690 static void SupportInfo(HWND hWnd, int id)
692 DialogBoxParamW(hInst, MAKEINTRESOURCEW(IDD_INFO), hWnd, (DLGPROC)
693 SupportInfoDlgProc, (LPARAM) id);
696 /* Definition of column headers for AddListViewColumns function */
697 typedef struct AppWizColumn {
703 static const AppWizColumn columns[] = {
704 {200, LVCFMT_LEFT, IDS_COLUMN_NAME},
705 {150, LVCFMT_LEFT, IDS_COLUMN_PUBLISHER},
706 {100, LVCFMT_LEFT, IDS_COLUMN_VERSION},
709 /******************************************************************************
710 * Name : AddListViewColumns
711 * Description: Adds column headers to the list view control.
712 * Parameters : hWnd - Handle of the list view control.
713 * Returns : TRUE if completed successfully, FALSE otherwise.
715 static BOOL AddListViewColumns(HWND hWnd)
717 WCHAR buf[MAX_STRING_LEN];
721 lvc.mask = LVCF_FMT | LVCF_TEXT | LVCF_SUBITEM | LVCF_WIDTH;
723 /* Add the columns */
724 for (i = 0; i < sizeof(columns) / sizeof(columns[0]); i++)
729 /* set width and format */
730 lvc.cx = columns[i].width;
731 lvc.fmt = columns[i].fmt;
733 LoadStringW(hInst, columns[i].title, buf, sizeof(buf) / sizeof(buf[0]));
735 if (ListView_InsertColumnW(hWnd, i, &lvc) == -1)
742 /******************************************************************************
743 * Name : AddListViewImageList
744 * Description: Creates an ImageList for the list view control.
745 * Parameters : hWnd - Handle of the list view control.
746 * Returns : Handle of the image list.
748 static HIMAGELIST AddListViewImageList(HWND hWnd)
753 hSmall = ImageList_Create(GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON),
754 ILC_COLOR32 | ILC_MASK, 1, 1);
756 /* Add default icon to image list */
757 hDefaultIcon = LoadIconW(hInst, MAKEINTRESOURCEW(ICO_MAIN));
758 ImageList_AddIcon(hSmall, hDefaultIcon);
759 DestroyIcon(hDefaultIcon);
761 SendMessageW(hWnd, LVM_SETIMAGELIST, LVSIL_SMALL, (LPARAM)hSmall);
766 /******************************************************************************
767 * Name : ResetApplicationList
768 * Description: Empties the app list, if need be, and recreates it.
769 * Parameters : bFirstRun - TRUE if this is the first time this is run, FALSE otherwise
770 * hWnd - handle of the dialog box
771 * hImageList - handle of the image list
772 * Returns : New handle of the image list.
774 static HIMAGELIST ResetApplicationList(BOOL bFirstRun, HWND hWnd, HIMAGELIST hImageList)
778 hWndListView = GetDlgItem(hWnd, IDL_PROGRAMS);
780 /* if first run, create the image list and add the listview columns */
783 if (!AddListViewColumns(hWndListView))
786 else /* we need to remove the existing things first */
788 RemoveItemsFromList(hWnd);
789 ImageList_Destroy(hImageList);
791 /* reset the list, since it's probably changed if the uninstallation was
796 /* now create the image list and add the applications to the listview */
797 hImageList = AddListViewImageList(hWndListView);
799 ReadApplicationsFromRegistry(HKEY_LOCAL_MACHINE);
800 ReadApplicationsFromRegistry(HKEY_CURRENT_USER);
802 AddApplicationsToList(hWndListView, hImageList);
808 /******************************************************************************
810 * Description: Callback procedure for main tab
811 * Parameters : hWnd - hWnd of the window
812 * msg - reason for calling function
813 * wParam - additional parameter
814 * lParam - additional parameter
815 * Returns : Dependant on message
817 static BOOL CALLBACK MainDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
820 static HIMAGELIST hImageList;
827 hImageList = ResetApplicationList(TRUE, hWnd, hImageList);
835 RemoveItemsFromList(hWnd);
836 ImageList_Destroy(hImageList);
843 nmh = (LPNMHDR) lParam;
850 case LVN_ITEMCHANGED:
860 switch (LOWORD(wParam))
863 InstallProgram(hWnd);
868 selitem = SendDlgItemMessageW(hWnd, IDL_PROGRAMS,
869 LVM_GETNEXTITEM, -1, LVNI_FOCUSED|LVNI_SELECTED);
873 lvItem.iItem = selitem;
874 lvItem.mask = LVIF_PARAM;
876 if (SendDlgItemMessageW(hWnd, IDL_PROGRAMS, LVM_GETITEMW,
877 0, (LPARAM) &lvItem))
878 UninstallProgram(lvItem.lParam, LOWORD(wParam));
881 hImageList = ResetApplicationList(FALSE, hWnd, hImageList);
885 case IDC_SUPPORT_INFO:
886 selitem = SendDlgItemMessageW(hWnd, IDL_PROGRAMS,
887 LVM_GETNEXTITEM, -1, LVNI_FOCUSED | LVNI_SELECTED);
891 lvItem.iItem = selitem;
892 lvItem.mask = LVIF_PARAM;
894 if (SendDlgItemMessageW(hWnd, IDL_PROGRAMS, LVM_GETITEMW,
895 0, (LPARAM) &lvItem))
896 SupportInfo(hWnd, lvItem.lParam);
908 static int CALLBACK propsheet_callback( HWND hwnd, UINT msg, LPARAM lparam )
912 case PSCB_INITIALIZED:
913 SendMessageW( hwnd, WM_SETICON, ICON_BIG, (LPARAM)LoadIconW( hInst, MAKEINTRESOURCEW(ICO_MAIN) ));
919 /******************************************************************************
921 * Description: Main routine for applet
922 * Parameters : hWnd - hWnd of the Control Panel
924 static void StartApplet(HWND hWnd)
927 PROPSHEETHEADERW psh;
928 WCHAR tab_title[MAX_STRING_LEN], app_title[MAX_STRING_LEN];
930 /* Load the strings we will use */
931 LoadStringW(hInst, IDS_TAB1_TITLE, tab_title, sizeof(tab_title) / sizeof(tab_title[0]));
932 LoadStringW(hInst, IDS_CPL_TITLE, app_title, sizeof(app_title) / sizeof(app_title[0]));
933 LoadStringW(hInst, IDS_REMOVE, btnRemove, sizeof(btnRemove) / sizeof(btnRemove[0]));
934 LoadStringW(hInst, IDS_MODIFY_REMOVE, btnModifyRemove, sizeof(btnModifyRemove) / sizeof(btnModifyRemove[0]));
936 /* Fill out the PROPSHEETPAGE */
937 psp.dwSize = sizeof (PROPSHEETPAGEW);
938 psp.dwFlags = PSP_USETITLE;
939 psp.hInstance = hInst;
940 psp.u.pszTemplate = MAKEINTRESOURCEW (IDD_MAIN);
941 psp.u2.pszIcon = NULL;
942 psp.pfnDlgProc = (DLGPROC) MainDlgProc;
943 psp.pszTitle = tab_title;
946 /* Fill out the PROPSHEETHEADER */
947 psh.dwSize = sizeof (PROPSHEETHEADERW);
948 psh.dwFlags = PSH_PROPSHEETPAGE | PSH_USEICONID | PSH_USECALLBACK;
949 psh.hwndParent = hWnd;
950 psh.hInstance = hInst;
951 psh.u.pszIcon = MAKEINTRESOURCEW(ICO_MAIN);
952 psh.pszCaption = app_title;
955 psh.pfnCallback = propsheet_callback;
956 psh.u2.nStartPage = 0;
958 /* Display the property sheet */
959 PropertySheetW (&psh);
962 static LONG start_params(const WCHAR *params)
964 static const WCHAR install_geckoW[] = {'i','n','s','t','a','l','l','_','g','e','c','k','o',0};
969 if(!strcmpW(params, install_geckoW)) {
970 install_wine_gecko();
974 WARN("unknown param %s\n", debugstr_w(params));
978 /******************************************************************************
980 * Description: Entry point for Control Panel applets
981 * Parameters : hwndCPL - hWnd of the Control Panel
982 * message - reason for calling function
983 * lParam1 - additional parameter
984 * lParam2 - additional parameter
985 * Returns : Dependant on message
987 LONG CALLBACK CPlApplet(HWND hwndCPL, UINT message, LPARAM lParam1, LPARAM lParam2)
989 INITCOMMONCONTROLSEX iccEx;
994 iccEx.dwSize = sizeof(iccEx);
995 iccEx.dwICC = ICC_LISTVIEW_CLASSES | ICC_TAB_CLASSES;
997 InitCommonControlsEx(&iccEx);
1004 case CPL_STARTWPARMSW:
1005 return start_params((const WCHAR *)lParam2);
1009 CPLINFO *appletInfo = (CPLINFO *) lParam2;
1011 appletInfo->idIcon = ICO_MAIN;
1012 appletInfo->idName = IDS_CPL_TITLE;
1013 appletInfo->idInfo = IDS_CPL_DESC;
1014 appletInfo->lData = 0;
1020 StartApplet(hwndCPL);