opengl32: Preserve the remainder of the version string when limiting the version...
[wine.git] / dlls / appwiz.cpl / appwiz.c
blob6f95c23bf281e701bfa374a779abad8444ad3cd8
1 /*
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 #include <string.h>
27 #include <stdlib.h>
28 #include <stdarg.h>
29 #include <stdio.h>
30 #include <windef.h>
31 #include <winbase.h>
32 #include <winuser.h>
33 #include <wingdi.h>
34 #include <winreg.h>
35 #include <shellapi.h>
36 #include <commctrl.h>
37 #include <commdlg.h>
38 #include <cpl.h>
40 #include "wine/list.h"
41 #include "wine/debug.h"
42 #include "appwiz.h"
43 #include "res.h"
45 WINE_DEFAULT_DEBUG_CHANNEL(appwizcpl);
47 /* define a maximum length for various buffers we use */
48 #define MAX_STRING_LEN 1024
50 typedef struct APPINFO
52 struct list entry;
53 int id;
55 LPWSTR title;
56 LPWSTR path;
57 LPWSTR path_modify;
59 LPWSTR icon;
60 int iconIdx;
62 LPWSTR publisher;
63 LPWSTR version;
64 LPWSTR contact;
65 LPWSTR helplink;
66 LPWSTR helptelephone;
67 LPWSTR readme;
68 LPWSTR urlupdateinfo;
69 LPWSTR comments;
71 HKEY regroot;
72 WCHAR regkey[MAX_STRING_LEN];
73 } APPINFO;
75 static struct list app_list = LIST_INIT( app_list );
76 HINSTANCE hInst;
78 static WCHAR btnRemove[MAX_STRING_LEN];
79 static WCHAR btnModifyRemove[MAX_STRING_LEN];
81 static const WCHAR PathUninstallW[] = L"Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall";
83 /******************************************************************************
84 * Name : DllMain
85 * Description: Entry point for DLL file
87 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason,
88 LPVOID lpvReserved)
90 TRACE("(%p, %ld, %p)\n", hinstDLL, fdwReason, lpvReserved);
92 switch (fdwReason)
94 case DLL_PROCESS_ATTACH:
95 hInst = hinstDLL;
96 break;
98 return TRUE;
101 /******************************************************************************
102 * Name : FreeAppInfo
103 * Description: Frees memory used by an AppInfo structure, and any children.
105 static void FreeAppInfo(APPINFO *info)
107 free(info->title);
108 free(info->path);
109 free(info->path_modify);
110 free(info->icon);
111 free(info->publisher);
112 free(info->version);
113 free(info->contact);
114 free(info->helplink);
115 free(info->helptelephone);
116 free(info->readme);
117 free(info->urlupdateinfo);
118 free(info->comments);
119 free(info);
122 static WCHAR *get_reg_str(HKEY hkey, const WCHAR *value)
124 DWORD len, type;
125 WCHAR *ret = NULL;
126 if (!RegQueryValueExW(hkey, value, NULL, &type, NULL, &len) && type == REG_SZ)
128 if (!(ret = malloc(len))) return NULL;
129 RegQueryValueExW(hkey, value, 0, 0, (BYTE *)ret, &len);
131 return ret;
134 /******************************************************************************
135 * Name : ReadApplicationsFromRegistry
136 * Description: Creates a linked list of uninstallable applications from the
137 * registry.
138 * Parameters : root - Which registry root to read from
139 * Returns : TRUE if successful, FALSE otherwise
141 static BOOL ReadApplicationsFromRegistry(HKEY root)
143 HKEY hkeyApp;
144 int i;
145 static int id = 0;
146 DWORD sizeOfSubKeyName, displen, uninstlen;
147 DWORD dwNoModify, dwType, value, size;
148 WCHAR subKeyName[256];
149 WCHAR *command;
150 APPINFO *info = NULL;
151 LPWSTR iconPtr;
153 sizeOfSubKeyName = ARRAY_SIZE(subKeyName);
155 for (i = 0; RegEnumKeyExW(root, i, subKeyName, &sizeOfSubKeyName, NULL,
156 NULL, NULL, NULL) != ERROR_NO_MORE_ITEMS; ++i)
158 RegOpenKeyExW(root, subKeyName, 0, KEY_READ, &hkeyApp);
159 size = sizeof(value);
160 if (!RegQueryValueExW(hkeyApp, L"SystemComponent", NULL, &dwType, (BYTE *)&value, &size)
161 && dwType == REG_DWORD && value == 1)
163 RegCloseKey(hkeyApp);
164 sizeOfSubKeyName = ARRAY_SIZE(subKeyName);
165 continue;
167 displen = 0;
168 uninstlen = 0;
169 if (!RegQueryValueExW(hkeyApp, L"DisplayName", 0, 0, NULL, &displen))
171 size = sizeof(value);
172 if (!RegQueryValueExW(hkeyApp, L"WindowsInstaller", NULL, &dwType, (BYTE *)&value, &size)
173 && dwType == REG_DWORD && value == 1)
175 int len = lstrlenW(L"msiexec /x%s") + lstrlenW(subKeyName);
177 if (!(command = malloc(len * sizeof(WCHAR)))) goto err;
178 wsprintfW(command, L"msiexec /x%s", subKeyName);
180 else if (!RegQueryValueExW(hkeyApp, L"UninstallString", 0, 0, NULL, &uninstlen))
182 if (!(command = malloc(uninstlen))) goto err;
183 RegQueryValueExW(hkeyApp, L"UninstallString", 0, 0, (BYTE *)command, &uninstlen);
185 else
187 RegCloseKey(hkeyApp);
188 sizeOfSubKeyName = ARRAY_SIZE(subKeyName);
189 continue;
192 info = calloc(1, sizeof(*info));
193 if (!info) goto err;
195 info->title = malloc(displen);
197 if (!info->title)
198 goto err;
200 RegQueryValueExW(hkeyApp, L"DisplayName", 0, 0, (BYTE *)info->title, &displen);
202 /* now get DisplayIcon */
203 displen = 0;
204 RegQueryValueExW(hkeyApp, L"DisplayIcon", 0, 0, NULL, &displen);
206 if (displen == 0)
207 info->icon = 0;
208 else
210 info->icon = malloc(displen);
212 if (!info->icon)
213 goto err;
215 RegQueryValueExW(hkeyApp, L"DisplayIcon", 0, 0, (BYTE *)info->icon, &displen);
217 /* separate the index from the icon name, if supplied */
218 iconPtr = wcschr(info->icon, ',');
220 if (iconPtr)
222 *iconPtr++ = 0;
223 info->iconIdx = wcstol(iconPtr, NULL, 10);
227 info->publisher = get_reg_str(hkeyApp, L"Publisher");
228 info->version = get_reg_str(hkeyApp, L"DisplayVersion");
229 info->contact = get_reg_str(hkeyApp, L"Contact");
230 info->helplink = get_reg_str(hkeyApp, L"HelpLink");
231 info->helptelephone = get_reg_str(hkeyApp, L"HelpTelephone");
232 info->readme = get_reg_str(hkeyApp, L"Readme");
233 info->urlupdateinfo = get_reg_str(hkeyApp, L"URLUpdateInfo");
234 info->comments = get_reg_str(hkeyApp, L"Comments");
236 /* Check if NoModify is set */
237 dwType = REG_DWORD;
238 dwNoModify = 0;
239 displen = sizeof(DWORD);
241 if (RegQueryValueExW(hkeyApp, L"NoModify", NULL, &dwType, (BYTE *)&dwNoModify, &displen)
242 != ERROR_SUCCESS)
244 dwNoModify = 0;
247 /* Some installers incorrectly create a REG_SZ instead of a REG_DWORD */
248 if (dwType == REG_SZ)
249 dwNoModify = (*(BYTE *)&dwNoModify == '1');
251 /* Fetch the modify path */
252 if (!dwNoModify)
254 size = sizeof(value);
255 if (!RegQueryValueExW(hkeyApp, L"WindowsInstaller", NULL, &dwType, (BYTE *)&value, &size)
256 && dwType == REG_DWORD && value == 1)
258 int len = lstrlenW(L"msiexec /i%s") + lstrlenW(subKeyName);
260 if (!(info->path_modify = malloc(len * sizeof(WCHAR)))) goto err;
261 wsprintfW(info->path_modify, L"msiexec /i%s", subKeyName);
263 else if (!RegQueryValueExW(hkeyApp, L"ModifyPath", 0, 0, NULL, &displen))
265 if (!(info->path_modify = malloc(displen))) goto err;
266 RegQueryValueExW(hkeyApp, L"ModifyPath", 0, 0, (BYTE *)info->path_modify, &displen);
270 /* registry key */
271 RegOpenKeyExW(root, NULL, 0, KEY_READ, &info->regroot);
272 lstrcpyW(info->regkey, subKeyName);
273 info->path = command;
275 info->id = id++;
276 list_add_tail( &app_list, &info->entry );
279 RegCloseKey(hkeyApp);
280 sizeOfSubKeyName = ARRAY_SIZE(subKeyName);
283 return TRUE;
284 err:
285 RegCloseKey(hkeyApp);
286 if (info) FreeAppInfo(info);
287 free(command);
288 return FALSE;
292 /******************************************************************************
293 * Name : AddApplicationsToList
294 * Description: Populates the list box with applications.
295 * Parameters : hWnd - Handle of the dialog box
297 static void AddApplicationsToList(HWND hWnd, HIMAGELIST hList)
299 APPINFO *iter;
300 LVITEMW lvItem;
301 HICON hIcon;
302 int index;
304 LIST_FOR_EACH_ENTRY( iter, &app_list, APPINFO, entry )
306 if (!iter->title[0]) continue;
308 /* get the icon */
309 index = 0;
311 if (iter->icon)
313 if (ExtractIconExW(iter->icon, iter->iconIdx, NULL, &hIcon, 1) == 1)
315 index = ImageList_AddIcon(hList, hIcon);
316 DestroyIcon(hIcon);
320 lvItem.mask = LVIF_IMAGE | LVIF_TEXT | LVIF_PARAM;
321 lvItem.iItem = iter->id;
322 lvItem.iSubItem = 0;
323 lvItem.pszText = iter->title;
324 lvItem.iImage = index;
325 lvItem.lParam = iter->id;
327 index = ListView_InsertItemW(hWnd, &lvItem);
329 /* now add the subitems (columns) */
330 ListView_SetItemTextW(hWnd, index, 1, iter->publisher);
331 ListView_SetItemTextW(hWnd, index, 2, iter->version);
335 /******************************************************************************
336 * Name : RemoveItemsFromList
337 * Description: Clears the application list box.
338 * Parameters : hWnd - Handle of the dialog box
340 static void RemoveItemsFromList(HWND hWnd)
342 SendDlgItemMessageW(hWnd, IDL_PROGRAMS, LVM_DELETEALLITEMS, 0, 0);
345 /******************************************************************************
346 * Name : EmptyList
347 * Description: Frees memory used by the application linked list.
349 static inline void EmptyList(void)
351 APPINFO *info, *next;
352 LIST_FOR_EACH_ENTRY_SAFE( info, next, &app_list, APPINFO, entry )
354 list_remove( &info->entry );
355 FreeAppInfo( info );
359 /******************************************************************************
360 * Name : UpdateButtons
361 * Description: Enables/disables the Add/Remove button depending on current
362 * selection in list box.
363 * Parameters : hWnd - Handle of the dialog box
365 static void UpdateButtons(HWND hWnd)
367 APPINFO *iter;
368 LVITEMW lvItem;
369 LRESULT selitem = SendDlgItemMessageW(hWnd, IDL_PROGRAMS, LVM_GETNEXTITEM, -1,
370 LVNI_FOCUSED | LVNI_SELECTED);
371 BOOL enable_modify = FALSE;
373 if (selitem != -1)
375 lvItem.iItem = selitem;
376 lvItem.mask = LVIF_PARAM;
378 if (SendDlgItemMessageW(hWnd, IDL_PROGRAMS, LVM_GETITEMW, 0, (LPARAM) &lvItem))
380 LIST_FOR_EACH_ENTRY( iter, &app_list, APPINFO, entry )
382 if (iter->id == lvItem.lParam)
384 /* Decide whether to display Modify/Remove as one button or two */
385 enable_modify = (iter->path_modify != NULL);
387 /* Update title as appropriate */
388 if (iter->path_modify == NULL)
389 SetWindowTextW(GetDlgItem(hWnd, IDC_ADDREMOVE), btnModifyRemove);
390 else
391 SetWindowTextW(GetDlgItem(hWnd, IDC_ADDREMOVE), btnRemove);
393 break;
399 /* Enable/disable other buttons if necessary */
400 EnableWindow(GetDlgItem(hWnd, IDC_ADDREMOVE), (selitem != -1));
401 EnableWindow(GetDlgItem(hWnd, IDC_SUPPORT_INFO), (selitem != -1));
402 EnableWindow(GetDlgItem(hWnd, IDC_MODIFY), enable_modify);
405 /******************************************************************************
406 * Name : InstallProgram
407 * Description: Search for potential Installer and execute it.
408 * Parameters : hWnd - Handle of the dialog box
410 static void InstallProgram(HWND hWnd)
412 OPENFILENAMEW ofn;
413 WCHAR titleW[MAX_STRING_LEN];
414 WCHAR filter_installs[MAX_STRING_LEN];
415 WCHAR filter_programs[MAX_STRING_LEN];
416 WCHAR filter_all[MAX_STRING_LEN];
417 WCHAR FilterBufferW[MAX_PATH];
418 WCHAR FileNameBufferW[MAX_PATH];
420 LoadStringW(hInst, IDS_CPL_TITLE, titleW, ARRAY_SIZE(titleW));
421 LoadStringW(hInst, IDS_FILTER_INSTALLS, filter_installs, ARRAY_SIZE(filter_installs));
422 LoadStringW(hInst, IDS_FILTER_PROGRAMS, filter_programs, ARRAY_SIZE(filter_programs));
423 LoadStringW(hInst, IDS_FILTER_ALL, filter_all, ARRAY_SIZE(filter_all));
425 swprintf( FilterBufferW, MAX_PATH, L"%s%c*instal*.exe;*setup*.exe;*.msi%c%s%c*.exe%c%s%c*.*%c",
426 filter_installs, 0, 0, filter_programs, 0, 0, filter_all, 0, 0 );
427 memset(&ofn, 0, sizeof(OPENFILENAMEW));
428 ofn.lStructSize = sizeof(OPENFILENAMEW);
429 ofn.hwndOwner = hWnd;
430 ofn.hInstance = hInst;
431 ofn.lpstrFilter = FilterBufferW;
432 ofn.nFilterIndex = 0;
433 ofn.lpstrFile = FileNameBufferW;
434 ofn.nMaxFile = MAX_PATH;
435 ofn.lpstrFileTitle = NULL;
436 ofn.nMaxFileTitle = 0;
437 ofn.lpstrTitle = titleW;
438 ofn.Flags = OFN_HIDEREADONLY | OFN_ENABLESIZING;
439 FileNameBufferW[0] = 0;
441 if (GetOpenFileNameW(&ofn))
443 SHELLEXECUTEINFOW sei;
444 memset(&sei, 0, sizeof(sei));
445 sei.cbSize = sizeof(sei);
446 sei.lpVerb = L"open";
447 sei.nShow = SW_SHOWDEFAULT;
448 sei.fMask = 0;
449 sei.lpFile = ofn.lpstrFile;
451 ShellExecuteExW(&sei);
455 static HANDLE run_uninstaller(int id, DWORD button)
457 APPINFO *iter;
458 STARTUPINFOW si;
459 PROCESS_INFORMATION info;
460 WCHAR errormsg[MAX_STRING_LEN];
461 WCHAR sUninstallFailed[MAX_STRING_LEN];
462 BOOL res;
464 LoadStringW(hInst, IDS_UNINSTALL_FAILED, sUninstallFailed,
465 ARRAY_SIZE(sUninstallFailed));
467 LIST_FOR_EACH_ENTRY( iter, &app_list, APPINFO, entry )
469 if (iter->id == id)
471 TRACE("Uninstalling %s (%s)\n", wine_dbgstr_w(iter->title),
472 wine_dbgstr_w(iter->path));
474 memset(&si, 0, sizeof(STARTUPINFOW));
475 si.cb = sizeof(STARTUPINFOW);
476 si.wShowWindow = SW_NORMAL;
478 res = CreateProcessW(NULL, (button == IDC_MODIFY) ? iter->path_modify : iter->path,
479 NULL, NULL, FALSE, 0, NULL, NULL, &si, &info);
481 if (res)
483 CloseHandle(info.hThread);
484 return info.hProcess;
486 else
488 wsprintfW(errormsg, sUninstallFailed, iter->path);
490 if (MessageBoxW(0, errormsg, iter->title, MB_YESNO |
491 MB_ICONQUESTION) == IDYES)
493 /* delete the application's uninstall entry */
494 RegDeleteKeyW(iter->regroot, iter->regkey);
495 RegCloseKey(iter->regroot);
499 break;
503 return NULL;
506 /**********************************************************************************
507 * Name : SetInfoDialogText
508 * Description: Sets the text of a label in a window, based upon a registry entry
509 * or string passed to the function.
510 * Parameters : hKey - registry entry to read from, NULL if not reading
511 * from registry
512 * lpKeyName - key to read from, or string to check if hKey is NULL
513 * lpAltMessage - alternative message if entry not found
514 * hWnd - handle of dialog box
515 * iDlgItem - ID of label in dialog box
517 static void SetInfoDialogText(HKEY hKey, LPCWSTR lpKeyName, LPCWSTR lpAltMessage,
518 HWND hWnd, int iDlgItem)
520 WCHAR buf[MAX_STRING_LEN];
521 DWORD buflen;
522 HWND hWndDlgItem;
524 hWndDlgItem = GetDlgItem(hWnd, iDlgItem);
526 /* if hKey is null, lpKeyName contains the string we want to check */
527 if (hKey == NULL)
529 if (lpKeyName && lpKeyName[0])
530 SetWindowTextW(hWndDlgItem, lpKeyName);
531 else
532 SetWindowTextW(hWndDlgItem, lpAltMessage);
534 else
536 buflen = sizeof(buf);
538 if ((RegQueryValueExW(hKey, lpKeyName, 0, 0, (LPBYTE) buf, &buflen) ==
539 ERROR_SUCCESS) && buf[0])
540 SetWindowTextW(hWndDlgItem, buf);
541 else
542 SetWindowTextW(hWndDlgItem, lpAltMessage);
546 /******************************************************************************
547 * Name : SupportInfoDlgProc
548 * Description: Callback procedure for support info dialog
549 * Parameters : hWnd - hWnd of the window
550 * msg - reason for calling function
551 * wParam - additional parameter
552 * lParam - additional parameter
553 * Returns : Depends on the message
555 static INT_PTR CALLBACK SupportInfoDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
557 APPINFO *iter;
558 HKEY hkey;
559 WCHAR oldtitle[MAX_STRING_LEN];
560 WCHAR buf[MAX_STRING_LEN];
561 WCHAR key[MAX_STRING_LEN];
562 WCHAR notfound[MAX_STRING_LEN];
564 switch(msg)
566 case WM_INITDIALOG:
567 LIST_FOR_EACH_ENTRY( iter, &app_list, APPINFO, entry )
569 if (iter->id == (int) lParam)
571 lstrcpyW(key, PathUninstallW);
572 lstrcatW(key, L"\\");
573 lstrcatW(key, iter->regkey);
575 /* check the application's registry entries */
576 RegOpenKeyExW(iter->regroot, key, 0, KEY_READ, &hkey);
578 /* Load our "not specified" string */
579 LoadStringW(hInst, IDS_NOT_SPECIFIED, notfound, ARRAY_SIZE(notfound));
581 SetInfoDialogText(NULL, iter->publisher, notfound, hWnd, IDC_INFO_PUBLISHER);
582 SetInfoDialogText(NULL, iter->version, notfound, hWnd, IDC_INFO_VERSION);
583 SetInfoDialogText(hkey, iter->contact, notfound, hWnd, IDC_INFO_CONTACT);
584 SetInfoDialogText(hkey, iter->helplink, notfound, hWnd, IDC_INFO_SUPPORT);
585 SetInfoDialogText(hkey, iter->helptelephone, notfound, hWnd, IDC_INFO_PHONE);
586 SetInfoDialogText(hkey, iter->readme, notfound, hWnd, IDC_INFO_README);
587 SetInfoDialogText(hkey, iter->urlupdateinfo, notfound, hWnd, IDC_INFO_UPDATES);
588 SetInfoDialogText(hkey, iter->comments, notfound, hWnd, IDC_INFO_COMMENTS);
590 /* Update the main label with the app name */
591 if (GetWindowTextW(GetDlgItem(hWnd, IDC_INFO_LABEL), oldtitle,
592 MAX_STRING_LEN) != 0)
594 wsprintfW(buf, oldtitle, iter->title);
595 SetWindowTextW(GetDlgItem(hWnd, IDC_INFO_LABEL), buf);
598 RegCloseKey(hkey);
600 break;
604 return TRUE;
606 case WM_DESTROY:
607 return 0;
609 case WM_CLOSE:
610 EndDialog(hWnd, TRUE);
611 return TRUE;
613 case WM_COMMAND:
614 switch (LOWORD(wParam))
616 case IDCANCEL:
617 case IDOK:
618 EndDialog(hWnd, TRUE);
619 break;
623 return TRUE;
626 return FALSE;
629 /******************************************************************************
630 * Name : SupportInfo
631 * Description: Displays the Support Information dialog
632 * Parameters : hWnd - Handle of the main dialog
633 * id - ID of the application to display information for
635 static void SupportInfo(HWND hWnd, int id)
637 DialogBoxParamW(hInst, MAKEINTRESOURCEW(IDD_INFO), hWnd, SupportInfoDlgProc, id);
640 /* Definition of column headers for AddListViewColumns function */
641 typedef struct AppWizColumn {
642 int width;
643 int fmt;
644 int title;
645 } AppWizColumn;
647 static const AppWizColumn columns[] = {
648 {200, LVCFMT_LEFT, IDS_COLUMN_NAME},
649 {150, LVCFMT_LEFT, IDS_COLUMN_PUBLISHER},
650 {100, LVCFMT_LEFT, IDS_COLUMN_VERSION},
653 /******************************************************************************
654 * Name : AddListViewColumns
655 * Description: Adds column headers to the list view control.
656 * Parameters : hWnd - Handle of the list view control.
657 * Returns : TRUE if completed successfully, FALSE otherwise.
659 static BOOL AddListViewColumns(HWND hWnd)
661 WCHAR buf[MAX_STRING_LEN];
662 LVCOLUMNW lvc;
663 UINT i;
665 lvc.mask = LVCF_FMT | LVCF_TEXT | LVCF_SUBITEM | LVCF_WIDTH;
667 /* Add the columns */
668 for (i = 0; i < ARRAY_SIZE(columns); i++)
670 lvc.iSubItem = i;
671 lvc.pszText = buf;
673 /* set width and format */
674 lvc.cx = columns[i].width;
675 lvc.fmt = columns[i].fmt;
677 LoadStringW(hInst, columns[i].title, buf, ARRAY_SIZE(buf));
679 if (ListView_InsertColumnW(hWnd, i, &lvc) == -1)
680 return FALSE;
683 return TRUE;
686 /******************************************************************************
687 * Name : AddListViewImageList
688 * Description: Creates an ImageList for the list view control.
689 * Parameters : hWnd - Handle of the list view control.
690 * Returns : Handle of the image list.
692 static HIMAGELIST AddListViewImageList(HWND hWnd)
694 HIMAGELIST hSmall;
695 HICON hDefaultIcon;
697 hSmall = ImageList_Create(GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON),
698 ILC_COLOR32 | ILC_MASK, 1, 1);
700 /* Add default icon to image list */
701 hDefaultIcon = LoadIconW(hInst, MAKEINTRESOURCEW(ICO_MAIN));
702 ImageList_AddIcon(hSmall, hDefaultIcon);
703 DestroyIcon(hDefaultIcon);
705 SendMessageW(hWnd, LVM_SETIMAGELIST, LVSIL_SMALL, (LPARAM)hSmall);
707 return hSmall;
710 /******************************************************************************
711 * Name : ResetApplicationList
712 * Description: Empties the app list, if need be, and recreates it.
713 * Parameters : bFirstRun - TRUE if this is the first time this is run, FALSE otherwise
714 * hWnd - handle of the dialog box
715 * hImageList - handle of the image list
716 * Returns : New handle of the image list.
718 static HIMAGELIST ResetApplicationList(BOOL bFirstRun, HWND hWnd, HIMAGELIST hImageList)
720 static const BOOL is_64bit = sizeof(void *) > sizeof(int);
721 HWND hWndListView;
722 HKEY hkey;
724 hWndListView = GetDlgItem(hWnd, IDL_PROGRAMS);
726 /* if first run, create the image list and add the listview columns */
727 if (bFirstRun)
729 if (!AddListViewColumns(hWndListView))
730 return NULL;
732 else /* we need to remove the existing things first */
734 RemoveItemsFromList(hWnd);
735 ImageList_Destroy(hImageList);
737 /* reset the list, since it's probably changed if the uninstallation was
738 successful */
739 EmptyList();
742 /* now create the image list and add the applications to the listview */
743 hImageList = AddListViewImageList(hWndListView);
745 if (!RegOpenKeyExW(HKEY_LOCAL_MACHINE, PathUninstallW, 0, KEY_READ, &hkey))
747 ReadApplicationsFromRegistry(hkey);
748 RegCloseKey(hkey);
750 if (is_64bit &&
751 !RegOpenKeyExW(HKEY_LOCAL_MACHINE, PathUninstallW, 0, KEY_READ|KEY_WOW64_32KEY, &hkey))
753 ReadApplicationsFromRegistry(hkey);
754 RegCloseKey(hkey);
756 if (!RegOpenKeyExW(HKEY_CURRENT_USER, PathUninstallW, 0, KEY_READ, &hkey))
758 ReadApplicationsFromRegistry(hkey);
759 RegCloseKey(hkey);
762 AddApplicationsToList(hWndListView, hImageList);
763 UpdateButtons(hWnd);
765 return(hImageList);
768 /******************************************************************************
769 * Name : MainDlgProc
770 * Description: Callback procedure for main tab
771 * Parameters : hWnd - hWnd of the window
772 * msg - reason for calling function
773 * wParam - additional parameter
774 * lParam - additional parameter
775 * Returns : Depends on the message
777 static INT_PTR CALLBACK MainDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
779 int selitem;
780 static HANDLE uninstaller = NULL;
781 static HIMAGELIST hImageList;
782 LPNMHDR nmh;
783 LVITEMW lvItem;
785 switch(msg)
787 case WM_INITDIALOG:
788 SendDlgItemMessageW(hWnd, IDL_PROGRAMS, LVM_SETEXTENDEDLISTVIEWSTYLE,
789 LVS_EX_FULLROWSELECT, LVS_EX_FULLROWSELECT);
791 hImageList = ResetApplicationList(TRUE, hWnd, hImageList);
793 if (!hImageList)
794 return FALSE;
796 return TRUE;
798 case WM_DESTROY:
799 RemoveItemsFromList(hWnd);
800 ImageList_Destroy(hImageList);
802 EmptyList();
804 return 0;
806 case WM_NOTIFY:
807 nmh = (LPNMHDR) lParam;
809 switch (nmh->idFrom)
811 case IDL_PROGRAMS:
812 switch (nmh->code)
814 case LVN_ITEMCHANGED:
815 UpdateButtons(hWnd);
816 break;
818 break;
821 return TRUE;
823 case WM_COMMAND:
824 switch (LOWORD(wParam))
826 case IDC_INSTALL:
827 InstallProgram(hWnd);
828 break;
830 case IDC_ADDREMOVE:
831 case IDC_MODIFY:
832 if (uninstaller)
834 WCHAR titleW[MAX_STRING_LEN], wait_tip[MAX_STRING_LEN];
836 LoadStringW(hInst, IDS_CPL_TITLE, titleW, ARRAY_SIZE(titleW));
837 LoadStringW(hInst, IDS_WAIT_COMPLETE, wait_tip, ARRAY_SIZE(wait_tip));
838 MessageBoxW(hWnd, wait_tip, titleW, MB_OK | MB_ICONWARNING);
839 break;
842 selitem = SendDlgItemMessageW(hWnd, IDL_PROGRAMS,
843 LVM_GETNEXTITEM, -1, LVNI_FOCUSED|LVNI_SELECTED);
845 if (selitem != -1)
847 lvItem.iItem = selitem;
848 lvItem.mask = LVIF_PARAM;
850 if (SendDlgItemMessageW(hWnd, IDL_PROGRAMS, LVM_GETITEMW, 0, (LPARAM)&lvItem))
852 uninstaller = run_uninstaller(lvItem.lParam, LOWORD(wParam));
853 while (MsgWaitForMultipleObjects(1, &uninstaller, FALSE, INFINITE, QS_ALLINPUT) == 1)
855 MSG message;
857 while (PeekMessageW(&message, 0, 0, 0, PM_REMOVE))
859 TranslateMessage(&message);
860 DispatchMessageW(&message);
863 CloseHandle(uninstaller);
864 uninstaller = NULL;
868 hImageList = ResetApplicationList(FALSE, hWnd, hImageList);
870 break;
872 case IDC_SUPPORT_INFO:
873 selitem = SendDlgItemMessageW(hWnd, IDL_PROGRAMS,
874 LVM_GETNEXTITEM, -1, LVNI_FOCUSED | LVNI_SELECTED);
876 if (selitem != -1)
878 lvItem.iItem = selitem;
879 lvItem.mask = LVIF_PARAM;
881 if (SendDlgItemMessageW(hWnd, IDL_PROGRAMS, LVM_GETITEMW,
882 0, (LPARAM) &lvItem))
883 SupportInfo(hWnd, lvItem.lParam);
886 break;
889 return TRUE;
892 return FALSE;
895 static int CALLBACK propsheet_callback( HWND hwnd, UINT msg, LPARAM lparam )
897 switch (msg)
899 case PSCB_INITIALIZED:
900 SendMessageW( hwnd, WM_SETICON, ICON_BIG, (LPARAM)LoadIconW( hInst, MAKEINTRESOURCEW(ICO_MAIN) ));
901 break;
903 return 0;
906 /******************************************************************************
907 * Name : StartApplet
908 * Description: Main routine for applet
909 * Parameters : hWnd - hWnd of the Control Panel
911 static void StartApplet(HWND hWnd)
913 PROPSHEETPAGEW psp;
914 PROPSHEETHEADERW psh;
915 WCHAR tab_title[MAX_STRING_LEN], app_title[MAX_STRING_LEN];
917 /* Load the strings we will use */
918 LoadStringW(hInst, IDS_TAB1_TITLE, tab_title, ARRAY_SIZE(tab_title));
919 LoadStringW(hInst, IDS_CPL_TITLE, app_title, ARRAY_SIZE(app_title));
920 LoadStringW(hInst, IDS_REMOVE, btnRemove, ARRAY_SIZE(btnRemove));
921 LoadStringW(hInst, IDS_MODIFY_REMOVE, btnModifyRemove, ARRAY_SIZE(btnModifyRemove));
923 /* Fill out the PROPSHEETPAGE */
924 psp.dwSize = sizeof (PROPSHEETPAGEW);
925 psp.dwFlags = PSP_USETITLE;
926 psp.hInstance = hInst;
927 psp.pszTemplate = MAKEINTRESOURCEW (IDD_MAIN);
928 psp.pszIcon = NULL;
929 psp.pfnDlgProc = MainDlgProc;
930 psp.pszTitle = tab_title;
931 psp.lParam = 0;
933 /* Fill out the PROPSHEETHEADER */
934 psh.dwSize = sizeof (PROPSHEETHEADERW);
935 psh.dwFlags = PSH_PROPSHEETPAGE | PSH_USEICONID | PSH_USECALLBACK;
936 psh.hwndParent = hWnd;
937 psh.hInstance = hInst;
938 psh.pszIcon = MAKEINTRESOURCEW(ICO_MAIN);
939 psh.pszCaption = app_title;
940 psh.nPages = 1;
941 psh.ppsp = &psp;
942 psh.pfnCallback = propsheet_callback;
943 psh.nStartPage = 0;
945 /* Display the property sheet */
946 PropertySheetW (&psh);
949 static LONG start_params(const WCHAR *params)
951 if(!params)
952 return FALSE;
954 if(!wcscmp(params, L"install_gecko")) {
955 install_addon(ADDON_GECKO);
956 return TRUE;
959 if(!wcscmp(params, L"install_mono")) {
960 install_addon(ADDON_MONO);
961 return TRUE;
964 WARN("unknown param %s\n", debugstr_w(params));
965 return FALSE;
968 /******************************************************************************
969 * Name : CPlApplet
970 * Description: Entry point for Control Panel applets
971 * Parameters : hwndCPL - hWnd of the Control Panel
972 * message - reason for calling function
973 * lParam1 - additional parameter
974 * lParam2 - additional parameter
975 * Returns : Depends on the message
977 LONG CALLBACK CPlApplet(HWND hwndCPL, UINT message, LPARAM lParam1, LPARAM lParam2)
979 INITCOMMONCONTROLSEX iccEx;
981 switch (message)
983 case CPL_INIT:
984 iccEx.dwSize = sizeof(iccEx);
985 iccEx.dwICC = ICC_LISTVIEW_CLASSES | ICC_TAB_CLASSES | ICC_LINK_CLASS;
987 InitCommonControlsEx(&iccEx);
989 return TRUE;
991 case CPL_GETCOUNT:
992 return 1;
994 case CPL_STARTWPARMSW:
995 return start_params((const WCHAR *)lParam2);
997 case CPL_INQUIRE:
999 CPLINFO *appletInfo = (CPLINFO *) lParam2;
1001 appletInfo->idIcon = ICO_MAIN;
1002 appletInfo->idName = IDS_CPL_TITLE;
1003 appletInfo->idInfo = IDS_CPL_DESC;
1004 appletInfo->lData = 0;
1006 break;
1009 case CPL_DBLCLK:
1010 StartApplet(hwndCPL);
1011 break;
1014 return FALSE;