mf: Avoid unnecessary prerolling calls in SAR.
[wine.git] / dlls / appwiz.cpl / appwiz.c
blobb295e40b2f4aa5f1d07d838ce8eaaa11b7fbdc74
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 #define NONAMELESSUNION
28 #include <string.h>
29 #include <stdlib.h>
30 #include <stdarg.h>
31 #include <stdio.h>
32 #include <windef.h>
33 #include <winbase.h>
34 #include <winuser.h>
35 #include <wingdi.h>
36 #include <winreg.h>
37 #include <shellapi.h>
38 #include <commctrl.h>
39 #include <commdlg.h>
40 #include <cpl.h>
42 #include "wine/list.h"
43 #include "wine/debug.h"
44 #include "appwiz.h"
45 #include "res.h"
47 WINE_DEFAULT_DEBUG_CHANNEL(appwizcpl);
49 /* define a maximum length for various buffers we use */
50 #define MAX_STRING_LEN 1024
52 typedef struct APPINFO
54 struct list entry;
55 int id;
57 LPWSTR title;
58 LPWSTR path;
59 LPWSTR path_modify;
61 LPWSTR icon;
62 int iconIdx;
64 LPWSTR publisher;
65 LPWSTR version;
66 LPWSTR contact;
67 LPWSTR helplink;
68 LPWSTR helptelephone;
69 LPWSTR readme;
70 LPWSTR urlupdateinfo;
71 LPWSTR comments;
73 HKEY regroot;
74 WCHAR regkey[MAX_STRING_LEN];
75 } APPINFO;
77 static struct list app_list = LIST_INIT( app_list );
78 HINSTANCE hInst;
80 static WCHAR btnRemove[MAX_STRING_LEN];
81 static WCHAR btnModifyRemove[MAX_STRING_LEN];
83 static const WCHAR openW[] = {'o','p','e','n',0};
85 /* names of registry keys */
86 static const WCHAR BackSlashW[] = { '\\', 0 };
87 static const WCHAR DisplayNameW[] = {'D','i','s','p','l','a','y','N','a','m','e',0};
88 static const WCHAR DisplayIconW[] = {'D','i','s','p','l','a','y','I','c','o','n',0};
89 static const WCHAR DisplayVersionW[] = {'D','i','s','p','l','a','y','V','e','r','s','i','o','n',0};
90 static const WCHAR PublisherW[] = {'P','u','b','l','i','s','h','e','r',0};
91 static const WCHAR ContactW[] = {'C','o','n','t','a','c','t',0};
92 static const WCHAR HelpLinkW[] = {'H','e','l','p','L','i','n','k',0};
93 static const WCHAR HelpTelephoneW[] = {'H','e','l','p','T','e','l','e','p','h','o','n','e',0};
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','n','f','o',0};
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','S','t','r','i','n','g',0};
100 static const WCHAR WindowsInstallerW[] = {'W','i','n','d','o','w','s','I','n','s','t','a','l','l','e','r',0};
101 static const WCHAR SystemComponentW[] = {'S','y','s','t','e','m','C','o','m','p','o','n','e','n','t',0};
103 static const WCHAR PathUninstallW[] = {
104 'S','o','f','t','w','a','r','e','\\',
105 'M','i','c','r','o','s','o','f','t','\\',
106 'W','i','n','d','o','w','s','\\',
107 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
108 'U','n','i','n','s','t','a','l','l',0 };
110 /******************************************************************************
111 * Name : DllMain
112 * Description: Entry point for DLL file
114 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason,
115 LPVOID lpvReserved)
117 TRACE("(%p, %d, %p)\n", hinstDLL, fdwReason, lpvReserved);
119 switch (fdwReason)
121 case DLL_PROCESS_ATTACH:
122 hInst = hinstDLL;
123 break;
125 return TRUE;
128 /******************************************************************************
129 * Name : FreeAppInfo
130 * Description: Frees memory used by an AppInfo structure, and any children.
132 static void FreeAppInfo(APPINFO *info)
134 HeapFree(GetProcessHeap(), 0, info->title);
135 HeapFree(GetProcessHeap(), 0, info->path);
136 HeapFree(GetProcessHeap(), 0, info->path_modify);
137 HeapFree(GetProcessHeap(), 0, info->icon);
138 HeapFree(GetProcessHeap(), 0, info->publisher);
139 HeapFree(GetProcessHeap(), 0, info->version);
140 HeapFree(GetProcessHeap(), 0, info->contact);
141 HeapFree(GetProcessHeap(), 0, info->helplink);
142 HeapFree(GetProcessHeap(), 0, info->helptelephone);
143 HeapFree(GetProcessHeap(), 0, info->readme);
144 HeapFree(GetProcessHeap(), 0, info->urlupdateinfo);
145 HeapFree(GetProcessHeap(), 0, info->comments);
146 HeapFree(GetProcessHeap(), 0, info);
149 static WCHAR *get_reg_str(HKEY hkey, const WCHAR *value)
151 DWORD len, type;
152 WCHAR *ret = NULL;
153 if (!RegQueryValueExW(hkey, value, NULL, &type, NULL, &len) && type == REG_SZ)
155 if (!(ret = HeapAlloc(GetProcessHeap(), 0, len))) return NULL;
156 RegQueryValueExW(hkey, value, 0, 0, (BYTE *)ret, &len);
158 return ret;
161 /******************************************************************************
162 * Name : ReadApplicationsFromRegistry
163 * Description: Creates a linked list of uninstallable applications from the
164 * registry.
165 * Parameters : root - Which registry root to read from
166 * Returns : TRUE if successful, FALSE otherwise
168 static BOOL ReadApplicationsFromRegistry(HKEY root)
170 HKEY hkeyApp;
171 int i;
172 static int id = 0;
173 DWORD sizeOfSubKeyName, displen, uninstlen;
174 DWORD dwNoModify, dwType, value, size;
175 WCHAR subKeyName[256];
176 WCHAR *command;
177 APPINFO *info = NULL;
178 LPWSTR iconPtr;
180 sizeOfSubKeyName = ARRAY_SIZE(subKeyName);
182 for (i = 0; RegEnumKeyExW(root, i, subKeyName, &sizeOfSubKeyName, NULL,
183 NULL, NULL, NULL) != ERROR_NO_MORE_ITEMS; ++i)
185 RegOpenKeyExW(root, subKeyName, 0, KEY_READ, &hkeyApp);
186 size = sizeof(value);
187 if (!RegQueryValueExW(hkeyApp, SystemComponentW, NULL, &dwType, (LPBYTE)&value, &size)
188 && dwType == REG_DWORD && value == 1)
190 RegCloseKey(hkeyApp);
191 sizeOfSubKeyName = ARRAY_SIZE(subKeyName);
192 continue;
194 displen = 0;
195 uninstlen = 0;
196 if (!RegQueryValueExW(hkeyApp, DisplayNameW, 0, 0, NULL, &displen))
198 size = sizeof(value);
199 if (!RegQueryValueExW(hkeyApp, WindowsInstallerW, NULL, &dwType, (LPBYTE)&value, &size)
200 && dwType == REG_DWORD && value == 1)
202 static const WCHAR fmtW[] = {'m','s','i','e','x','e','c',' ','/','x','%','s',0};
203 int len = lstrlenW(fmtW) + lstrlenW(subKeyName);
205 if (!(command = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)))) goto err;
206 wsprintfW(command, fmtW, subKeyName);
208 else if (!RegQueryValueExW(hkeyApp, UninstallCommandlineW, 0, 0, NULL, &uninstlen))
210 if (!(command = HeapAlloc(GetProcessHeap(), 0, uninstlen))) goto err;
211 RegQueryValueExW(hkeyApp, UninstallCommandlineW, 0, 0, (LPBYTE)command, &uninstlen);
213 else
215 RegCloseKey(hkeyApp);
216 sizeOfSubKeyName = ARRAY_SIZE(subKeyName);
217 continue;
220 info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(struct APPINFO));
221 if (!info) goto err;
223 info->title = HeapAlloc(GetProcessHeap(), 0, displen);
225 if (!info->title)
226 goto err;
228 RegQueryValueExW(hkeyApp, DisplayNameW, 0, 0, (LPBYTE)info->title,
229 &displen);
231 /* now get DisplayIcon */
232 displen = 0;
233 RegQueryValueExW(hkeyApp, DisplayIconW, 0, 0, NULL, &displen);
235 if (displen == 0)
236 info->icon = 0;
237 else
239 info->icon = HeapAlloc(GetProcessHeap(), 0, displen);
241 if (!info->icon)
242 goto err;
244 RegQueryValueExW(hkeyApp, DisplayIconW, 0, 0, (LPBYTE)info->icon,
245 &displen);
247 /* separate the index from the icon name, if supplied */
248 iconPtr = wcschr(info->icon, ',');
250 if (iconPtr)
252 *iconPtr++ = 0;
253 info->iconIdx = wcstol(iconPtr, NULL, 10);
257 info->publisher = get_reg_str(hkeyApp, PublisherW);
258 info->version = get_reg_str(hkeyApp, DisplayVersionW);
259 info->contact = get_reg_str(hkeyApp, ContactW);
260 info->helplink = get_reg_str(hkeyApp, HelpLinkW);
261 info->helptelephone = get_reg_str(hkeyApp, HelpTelephoneW);
262 info->readme = get_reg_str(hkeyApp, ReadmeW);
263 info->urlupdateinfo = get_reg_str(hkeyApp, URLUpdateInfoW);
264 info->comments = get_reg_str(hkeyApp, CommentsW);
266 /* Check if NoModify is set */
267 dwType = REG_DWORD;
268 dwNoModify = 0;
269 displen = sizeof(DWORD);
271 if (RegQueryValueExW(hkeyApp, NoModifyW, NULL, &dwType, (LPBYTE)&dwNoModify, &displen)
272 != ERROR_SUCCESS)
274 dwNoModify = 0;
277 /* Some installers incorrectly create a REG_SZ instead of a REG_DWORD */
278 if (dwType == REG_SZ)
279 dwNoModify = (*(BYTE *)&dwNoModify == '1');
281 /* Fetch the modify path */
282 if (!dwNoModify)
284 size = sizeof(value);
285 if (!RegQueryValueExW(hkeyApp, WindowsInstallerW, NULL, &dwType, (LPBYTE)&value, &size)
286 && dwType == REG_DWORD && value == 1)
288 static const WCHAR fmtW[] = {'m','s','i','e','x','e','c',' ','/','i','%','s',0};
289 int len = lstrlenW(fmtW) + lstrlenW(subKeyName);
291 if (!(info->path_modify = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)))) goto err;
292 wsprintfW(info->path_modify, fmtW, subKeyName);
294 else if (!RegQueryValueExW(hkeyApp, ModifyPathW, 0, 0, NULL, &displen))
296 if (!(info->path_modify = HeapAlloc(GetProcessHeap(), 0, displen))) goto err;
297 RegQueryValueExW(hkeyApp, ModifyPathW, 0, 0, (LPBYTE)info->path_modify, &displen);
301 /* registry key */
302 RegOpenKeyExW(root, NULL, 0, KEY_READ, &info->regroot);
303 lstrcpyW(info->regkey, subKeyName);
304 info->path = command;
306 info->id = id++;
307 list_add_tail( &app_list, &info->entry );
310 RegCloseKey(hkeyApp);
311 sizeOfSubKeyName = ARRAY_SIZE(subKeyName);
314 return TRUE;
315 err:
316 RegCloseKey(hkeyApp);
317 if (info) FreeAppInfo(info);
318 HeapFree(GetProcessHeap(), 0, command);
319 return FALSE;
323 /******************************************************************************
324 * Name : AddApplicationsToList
325 * Description: Populates the list box with applications.
326 * Parameters : hWnd - Handle of the dialog box
328 static void AddApplicationsToList(HWND hWnd, HIMAGELIST hList)
330 APPINFO *iter;
331 LVITEMW lvItem;
332 HICON hIcon;
333 int index;
335 LIST_FOR_EACH_ENTRY( iter, &app_list, APPINFO, entry )
337 if (!iter->title[0]) continue;
339 /* get the icon */
340 index = 0;
342 if (iter->icon)
344 if (ExtractIconExW(iter->icon, iter->iconIdx, NULL, &hIcon, 1) == 1)
346 index = ImageList_AddIcon(hList, hIcon);
347 DestroyIcon(hIcon);
351 lvItem.mask = LVIF_IMAGE | LVIF_TEXT | LVIF_PARAM;
352 lvItem.iItem = iter->id;
353 lvItem.iSubItem = 0;
354 lvItem.pszText = iter->title;
355 lvItem.iImage = index;
356 lvItem.lParam = iter->id;
358 index = ListView_InsertItemW(hWnd, &lvItem);
360 /* now add the subitems (columns) */
361 ListView_SetItemTextW(hWnd, index, 1, iter->publisher);
362 ListView_SetItemTextW(hWnd, index, 2, iter->version);
366 /******************************************************************************
367 * Name : RemoveItemsFromList
368 * Description: Clears the application list box.
369 * Parameters : hWnd - Handle of the dialog box
371 static void RemoveItemsFromList(HWND hWnd)
373 SendDlgItemMessageW(hWnd, IDL_PROGRAMS, LVM_DELETEALLITEMS, 0, 0);
376 /******************************************************************************
377 * Name : EmptyList
378 * Description: Frees memory used by the application linked list.
380 static inline void EmptyList(void)
382 APPINFO *info, *next;
383 LIST_FOR_EACH_ENTRY_SAFE( info, next, &app_list, APPINFO, entry )
385 list_remove( &info->entry );
386 FreeAppInfo( info );
390 /******************************************************************************
391 * Name : UpdateButtons
392 * Description: Enables/disables the Add/Remove button depending on current
393 * selection in list box.
394 * Parameters : hWnd - Handle of the dialog box
396 static void UpdateButtons(HWND hWnd)
398 APPINFO *iter;
399 LVITEMW lvItem;
400 LRESULT selitem = SendDlgItemMessageW(hWnd, IDL_PROGRAMS, LVM_GETNEXTITEM, -1,
401 LVNI_FOCUSED | LVNI_SELECTED);
402 BOOL enable_modify = FALSE;
404 if (selitem != -1)
406 lvItem.iItem = selitem;
407 lvItem.mask = LVIF_PARAM;
409 if (SendDlgItemMessageW(hWnd, IDL_PROGRAMS, LVM_GETITEMW, 0, (LPARAM) &lvItem))
411 LIST_FOR_EACH_ENTRY( iter, &app_list, APPINFO, entry )
413 if (iter->id == lvItem.lParam)
415 /* Decide whether to display Modify/Remove as one button or two */
416 enable_modify = (iter->path_modify != NULL);
418 /* Update title as appropriate */
419 if (iter->path_modify == NULL)
420 SetWindowTextW(GetDlgItem(hWnd, IDC_ADDREMOVE), btnModifyRemove);
421 else
422 SetWindowTextW(GetDlgItem(hWnd, IDC_ADDREMOVE), btnRemove);
424 break;
430 /* Enable/disable other buttons if necessary */
431 EnableWindow(GetDlgItem(hWnd, IDC_ADDREMOVE), (selitem != -1));
432 EnableWindow(GetDlgItem(hWnd, IDC_SUPPORT_INFO), (selitem != -1));
433 EnableWindow(GetDlgItem(hWnd, IDC_MODIFY), enable_modify);
436 /******************************************************************************
437 * Name : InstallProgram
438 * Description: Search for potential Installer and execute it.
439 * Parameters : hWnd - Handle of the dialog box
441 static void InstallProgram(HWND hWnd)
443 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}
445 OPENFILENAMEW ofn;
446 WCHAR titleW[MAX_STRING_LEN];
447 WCHAR filter_installs[MAX_STRING_LEN];
448 WCHAR filter_programs[MAX_STRING_LEN];
449 WCHAR filter_all[MAX_STRING_LEN];
450 WCHAR FilterBufferW[MAX_PATH];
451 WCHAR FileNameBufferW[MAX_PATH];
453 LoadStringW(hInst, IDS_CPL_TITLE, titleW, ARRAY_SIZE(titleW));
454 LoadStringW(hInst, IDS_FILTER_INSTALLS, filter_installs, ARRAY_SIZE(filter_installs));
455 LoadStringW(hInst, IDS_FILTER_PROGRAMS, filter_programs, ARRAY_SIZE(filter_programs));
456 LoadStringW(hInst, IDS_FILTER_ALL, filter_all, ARRAY_SIZE(filter_all));
458 swprintf( FilterBufferW, MAX_PATH, filters, filter_installs, 0, 0,
459 filter_programs, 0, 0, filter_all, 0, 0 );
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);
479 sei.lpVerb = openW;
480 sei.nShow = SW_SHOWDEFAULT;
481 sei.fMask = 0;
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)
496 APPINFO *iter;
497 STARTUPINFOW si;
498 PROCESS_INFORMATION info;
499 WCHAR errormsg[MAX_STRING_LEN];
500 WCHAR sUninstallFailed[MAX_STRING_LEN];
501 BOOL res;
503 LoadStringW(hInst, IDS_UNINSTALL_FAILED, sUninstallFailed,
504 ARRAY_SIZE(sUninstallFailed));
506 LIST_FOR_EACH_ENTRY( iter, &app_list, APPINFO, entry )
508 if (iter->id == id)
510 TRACE("Uninstalling %s (%s)\n", wine_dbgstr_w(iter->title),
511 wine_dbgstr_w(iter->path));
513 memset(&si, 0, sizeof(STARTUPINFOW));
514 si.cb = sizeof(STARTUPINFOW);
515 si.wShowWindow = SW_NORMAL;
517 res = CreateProcessW(NULL, (button == IDC_MODIFY) ? iter->path_modify : iter->path,
518 NULL, NULL, FALSE, 0, NULL, NULL, &si, &info);
520 if (res)
522 CloseHandle(info.hThread);
524 /* wait for the process to exit */
525 WaitForSingleObject(info.hProcess, INFINITE);
526 CloseHandle(info.hProcess);
528 else
530 wsprintfW(errormsg, sUninstallFailed, iter->path);
532 if (MessageBoxW(0, errormsg, iter->title, MB_YESNO |
533 MB_ICONQUESTION) == IDYES)
535 /* delete the application's uninstall entry */
536 RegDeleteKeyW(iter->regroot, iter->regkey);
537 RegCloseKey(iter->regroot);
541 break;
546 /**********************************************************************************
547 * Name : SetInfoDialogText
548 * Description: Sets the text of a label in a window, based upon a registry entry
549 * or string passed to the function.
550 * Parameters : hKey - registry entry to read from, NULL if not reading
551 * from registry
552 * lpKeyName - key to read from, or string to check if hKey is NULL
553 * lpAltMessage - alternative message if entry not found
554 * hWnd - handle of dialog box
555 * iDlgItem - ID of label in dialog box
557 static void SetInfoDialogText(HKEY hKey, LPCWSTR lpKeyName, LPCWSTR lpAltMessage,
558 HWND hWnd, int iDlgItem)
560 WCHAR buf[MAX_STRING_LEN];
561 DWORD buflen;
562 HWND hWndDlgItem;
564 hWndDlgItem = GetDlgItem(hWnd, iDlgItem);
566 /* if hKey is null, lpKeyName contains the string we want to check */
567 if (hKey == NULL)
569 if (lpKeyName && lpKeyName[0])
570 SetWindowTextW(hWndDlgItem, lpKeyName);
571 else
572 SetWindowTextW(hWndDlgItem, lpAltMessage);
574 else
576 buflen = MAX_STRING_LEN;
578 if ((RegQueryValueExW(hKey, lpKeyName, 0, 0, (LPBYTE) buf, &buflen) ==
579 ERROR_SUCCESS) && buf[0])
580 SetWindowTextW(hWndDlgItem, buf);
581 else
582 SetWindowTextW(hWndDlgItem, lpAltMessage);
586 /******************************************************************************
587 * Name : SupportInfoDlgProc
588 * Description: Callback procedure for support info dialog
589 * Parameters : hWnd - hWnd of the window
590 * msg - reason for calling function
591 * wParam - additional parameter
592 * lParam - additional parameter
593 * Returns : Depends on the message
595 static INT_PTR CALLBACK SupportInfoDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
597 APPINFO *iter;
598 HKEY hkey;
599 WCHAR oldtitle[MAX_STRING_LEN];
600 WCHAR buf[MAX_STRING_LEN];
601 WCHAR key[MAX_STRING_LEN];
602 WCHAR notfound[MAX_STRING_LEN];
604 switch(msg)
606 case WM_INITDIALOG:
607 LIST_FOR_EACH_ENTRY( iter, &app_list, APPINFO, entry )
609 if (iter->id == (int) lParam)
611 lstrcpyW(key, PathUninstallW);
612 lstrcatW(key, BackSlashW);
613 lstrcatW(key, iter->regkey);
615 /* check the application's registry entries */
616 RegOpenKeyExW(iter->regroot, key, 0, KEY_READ, &hkey);
618 /* Load our "not specified" string */
619 LoadStringW(hInst, IDS_NOT_SPECIFIED, notfound, ARRAY_SIZE(notfound));
621 SetInfoDialogText(NULL, iter->publisher, notfound, hWnd, IDC_INFO_PUBLISHER);
622 SetInfoDialogText(NULL, iter->version, notfound, hWnd, IDC_INFO_VERSION);
623 SetInfoDialogText(hkey, iter->contact, notfound, hWnd, IDC_INFO_CONTACT);
624 SetInfoDialogText(hkey, iter->helplink, notfound, hWnd, IDC_INFO_SUPPORT);
625 SetInfoDialogText(hkey, iter->helptelephone, notfound, hWnd, IDC_INFO_PHONE);
626 SetInfoDialogText(hkey, iter->readme, notfound, hWnd, IDC_INFO_README);
627 SetInfoDialogText(hkey, iter->urlupdateinfo, notfound, hWnd, IDC_INFO_UPDATES);
628 SetInfoDialogText(hkey, iter->comments, notfound, hWnd, IDC_INFO_COMMENTS);
630 /* Update the main label with the app name */
631 if (GetWindowTextW(GetDlgItem(hWnd, IDC_INFO_LABEL), oldtitle,
632 MAX_STRING_LEN) != 0)
634 wsprintfW(buf, oldtitle, iter->title);
635 SetWindowTextW(GetDlgItem(hWnd, IDC_INFO_LABEL), buf);
638 RegCloseKey(hkey);
640 break;
644 return TRUE;
646 case WM_DESTROY:
647 return 0;
649 case WM_COMMAND:
650 switch (LOWORD(wParam))
652 case IDOK:
653 EndDialog(hWnd, TRUE);
654 break;
658 return TRUE;
661 return FALSE;
664 /******************************************************************************
665 * Name : SupportInfo
666 * Description: Displays the Support Information dialog
667 * Parameters : hWnd - Handle of the main dialog
668 * id - ID of the application to display information for
670 static void SupportInfo(HWND hWnd, int id)
672 DialogBoxParamW(hInst, MAKEINTRESOURCEW(IDD_INFO), hWnd, SupportInfoDlgProc, id);
675 /* Definition of column headers for AddListViewColumns function */
676 typedef struct AppWizColumn {
677 int width;
678 int fmt;
679 int title;
680 } AppWizColumn;
682 static const AppWizColumn columns[] = {
683 {200, LVCFMT_LEFT, IDS_COLUMN_NAME},
684 {150, LVCFMT_LEFT, IDS_COLUMN_PUBLISHER},
685 {100, LVCFMT_LEFT, IDS_COLUMN_VERSION},
688 /******************************************************************************
689 * Name : AddListViewColumns
690 * Description: Adds column headers to the list view control.
691 * Parameters : hWnd - Handle of the list view control.
692 * Returns : TRUE if completed successfully, FALSE otherwise.
694 static BOOL AddListViewColumns(HWND hWnd)
696 WCHAR buf[MAX_STRING_LEN];
697 LVCOLUMNW lvc;
698 UINT i;
700 lvc.mask = LVCF_FMT | LVCF_TEXT | LVCF_SUBITEM | LVCF_WIDTH;
702 /* Add the columns */
703 for (i = 0; i < ARRAY_SIZE(columns); i++)
705 lvc.iSubItem = i;
706 lvc.pszText = buf;
708 /* set width and format */
709 lvc.cx = columns[i].width;
710 lvc.fmt = columns[i].fmt;
712 LoadStringW(hInst, columns[i].title, buf, ARRAY_SIZE(buf));
714 if (ListView_InsertColumnW(hWnd, i, &lvc) == -1)
715 return FALSE;
718 return TRUE;
721 /******************************************************************************
722 * Name : AddListViewImageList
723 * Description: Creates an ImageList for the list view control.
724 * Parameters : hWnd - Handle of the list view control.
725 * Returns : Handle of the image list.
727 static HIMAGELIST AddListViewImageList(HWND hWnd)
729 HIMAGELIST hSmall;
730 HICON hDefaultIcon;
732 hSmall = ImageList_Create(GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON),
733 ILC_COLOR32 | ILC_MASK, 1, 1);
735 /* Add default icon to image list */
736 hDefaultIcon = LoadIconW(hInst, MAKEINTRESOURCEW(ICO_MAIN));
737 ImageList_AddIcon(hSmall, hDefaultIcon);
738 DestroyIcon(hDefaultIcon);
740 SendMessageW(hWnd, LVM_SETIMAGELIST, LVSIL_SMALL, (LPARAM)hSmall);
742 return hSmall;
745 /******************************************************************************
746 * Name : ResetApplicationList
747 * Description: Empties the app list, if need be, and recreates it.
748 * Parameters : bFirstRun - TRUE if this is the first time this is run, FALSE otherwise
749 * hWnd - handle of the dialog box
750 * hImageList - handle of the image list
751 * Returns : New handle of the image list.
753 static HIMAGELIST ResetApplicationList(BOOL bFirstRun, HWND hWnd, HIMAGELIST hImageList)
755 static const BOOL is_64bit = sizeof(void *) > sizeof(int);
756 HWND hWndListView;
757 HKEY hkey;
759 hWndListView = GetDlgItem(hWnd, IDL_PROGRAMS);
761 /* if first run, create the image list and add the listview columns */
762 if (bFirstRun)
764 if (!AddListViewColumns(hWndListView))
765 return NULL;
767 else /* we need to remove the existing things first */
769 RemoveItemsFromList(hWnd);
770 ImageList_Destroy(hImageList);
772 /* reset the list, since it's probably changed if the uninstallation was
773 successful */
774 EmptyList();
777 /* now create the image list and add the applications to the listview */
778 hImageList = AddListViewImageList(hWndListView);
780 if (!RegOpenKeyExW(HKEY_LOCAL_MACHINE, PathUninstallW, 0, KEY_READ, &hkey))
782 ReadApplicationsFromRegistry(hkey);
783 RegCloseKey(hkey);
785 if (is_64bit &&
786 !RegOpenKeyExW(HKEY_LOCAL_MACHINE, PathUninstallW, 0, KEY_READ|KEY_WOW64_32KEY, &hkey))
788 ReadApplicationsFromRegistry(hkey);
789 RegCloseKey(hkey);
791 if (!RegOpenKeyExW(HKEY_CURRENT_USER, PathUninstallW, 0, KEY_READ, &hkey))
793 ReadApplicationsFromRegistry(hkey);
794 RegCloseKey(hkey);
797 AddApplicationsToList(hWndListView, hImageList);
798 UpdateButtons(hWnd);
800 return(hImageList);
803 /******************************************************************************
804 * Name : MainDlgProc
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 : Depends on the message
812 static INT_PTR CALLBACK MainDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
814 int selitem;
815 static HIMAGELIST hImageList;
816 LPNMHDR nmh;
817 LVITEMW lvItem;
819 switch(msg)
821 case WM_INITDIALOG:
822 SendDlgItemMessageW(hWnd, IDL_PROGRAMS, LVM_SETEXTENDEDLISTVIEWSTYLE,
823 LVS_EX_FULLROWSELECT, LVS_EX_FULLROWSELECT);
825 hImageList = ResetApplicationList(TRUE, hWnd, hImageList);
827 if (!hImageList)
828 return FALSE;
830 return TRUE;
832 case WM_DESTROY:
833 RemoveItemsFromList(hWnd);
834 ImageList_Destroy(hImageList);
836 EmptyList();
838 return 0;
840 case WM_NOTIFY:
841 nmh = (LPNMHDR) lParam;
843 switch (nmh->idFrom)
845 case IDL_PROGRAMS:
846 switch (nmh->code)
848 case LVN_ITEMCHANGED:
849 UpdateButtons(hWnd);
850 break;
852 break;
855 return TRUE;
857 case WM_COMMAND:
858 switch (LOWORD(wParam))
860 case IDC_INSTALL:
861 InstallProgram(hWnd);
862 break;
864 case IDC_ADDREMOVE:
865 case IDC_MODIFY:
866 selitem = SendDlgItemMessageW(hWnd, IDL_PROGRAMS,
867 LVM_GETNEXTITEM, -1, LVNI_FOCUSED|LVNI_SELECTED);
869 if (selitem != -1)
871 lvItem.iItem = selitem;
872 lvItem.mask = LVIF_PARAM;
874 if (SendDlgItemMessageW(hWnd, IDL_PROGRAMS, LVM_GETITEMW,
875 0, (LPARAM) &lvItem))
876 UninstallProgram(lvItem.lParam, LOWORD(wParam));
879 hImageList = ResetApplicationList(FALSE, hWnd, hImageList);
881 break;
883 case IDC_SUPPORT_INFO:
884 selitem = SendDlgItemMessageW(hWnd, IDL_PROGRAMS,
885 LVM_GETNEXTITEM, -1, LVNI_FOCUSED | LVNI_SELECTED);
887 if (selitem != -1)
889 lvItem.iItem = selitem;
890 lvItem.mask = LVIF_PARAM;
892 if (SendDlgItemMessageW(hWnd, IDL_PROGRAMS, LVM_GETITEMW,
893 0, (LPARAM) &lvItem))
894 SupportInfo(hWnd, lvItem.lParam);
897 break;
900 return TRUE;
903 return FALSE;
906 static int CALLBACK propsheet_callback( HWND hwnd, UINT msg, LPARAM lparam )
908 switch (msg)
910 case PSCB_INITIALIZED:
911 SendMessageW( hwnd, WM_SETICON, ICON_BIG, (LPARAM)LoadIconW( hInst, MAKEINTRESOURCEW(ICO_MAIN) ));
912 break;
914 return 0;
917 /******************************************************************************
918 * Name : StartApplet
919 * Description: Main routine for applet
920 * Parameters : hWnd - hWnd of the Control Panel
922 static void StartApplet(HWND hWnd)
924 PROPSHEETPAGEW psp;
925 PROPSHEETHEADERW psh;
926 WCHAR tab_title[MAX_STRING_LEN], app_title[MAX_STRING_LEN];
928 /* Load the strings we will use */
929 LoadStringW(hInst, IDS_TAB1_TITLE, tab_title, ARRAY_SIZE(tab_title));
930 LoadStringW(hInst, IDS_CPL_TITLE, app_title, ARRAY_SIZE(app_title));
931 LoadStringW(hInst, IDS_REMOVE, btnRemove, ARRAY_SIZE(btnRemove));
932 LoadStringW(hInst, IDS_MODIFY_REMOVE, btnModifyRemove, ARRAY_SIZE(btnModifyRemove));
934 /* Fill out the PROPSHEETPAGE */
935 psp.dwSize = sizeof (PROPSHEETPAGEW);
936 psp.dwFlags = PSP_USETITLE;
937 psp.hInstance = hInst;
938 psp.u.pszTemplate = MAKEINTRESOURCEW (IDD_MAIN);
939 psp.u2.pszIcon = NULL;
940 psp.pfnDlgProc = MainDlgProc;
941 psp.pszTitle = tab_title;
942 psp.lParam = 0;
944 /* Fill out the PROPSHEETHEADER */
945 psh.dwSize = sizeof (PROPSHEETHEADERW);
946 psh.dwFlags = PSH_PROPSHEETPAGE | PSH_USEICONID | PSH_USECALLBACK;
947 psh.hwndParent = hWnd;
948 psh.hInstance = hInst;
949 psh.u.pszIcon = MAKEINTRESOURCEW(ICO_MAIN);
950 psh.pszCaption = app_title;
951 psh.nPages = 1;
952 psh.u3.ppsp = &psp;
953 psh.pfnCallback = propsheet_callback;
954 psh.u2.nStartPage = 0;
956 /* Display the property sheet */
957 PropertySheetW (&psh);
960 static LONG start_params(const WCHAR *params)
962 static const WCHAR install_geckoW[] = {'i','n','s','t','a','l','l','_','g','e','c','k','o',0};
963 static const WCHAR install_monoW[] = {'i','n','s','t','a','l','l','_','m','o','n','o',0};
965 if(!params)
966 return FALSE;
968 if(!wcscmp(params, install_geckoW)) {
969 install_addon(ADDON_GECKO);
970 return TRUE;
973 if(!wcscmp(params, install_monoW)) {
974 install_addon(ADDON_MONO);
975 return TRUE;
978 WARN("unknown param %s\n", debugstr_w(params));
979 return FALSE;
982 /******************************************************************************
983 * Name : CPlApplet
984 * Description: Entry point for Control Panel applets
985 * Parameters : hwndCPL - hWnd of the Control Panel
986 * message - reason for calling function
987 * lParam1 - additional parameter
988 * lParam2 - additional parameter
989 * Returns : Depends on the message
991 LONG CALLBACK CPlApplet(HWND hwndCPL, UINT message, LPARAM lParam1, LPARAM lParam2)
993 INITCOMMONCONTROLSEX iccEx;
995 switch (message)
997 case CPL_INIT:
998 iccEx.dwSize = sizeof(iccEx);
999 iccEx.dwICC = ICC_LISTVIEW_CLASSES | ICC_TAB_CLASSES | ICC_LINK_CLASS;
1001 InitCommonControlsEx(&iccEx);
1003 return TRUE;
1005 case CPL_GETCOUNT:
1006 return 1;
1008 case CPL_STARTWPARMSW:
1009 return start_params((const WCHAR *)lParam2);
1011 case CPL_INQUIRE:
1013 CPLINFO *appletInfo = (CPLINFO *) lParam2;
1015 appletInfo->idIcon = ICO_MAIN;
1016 appletInfo->idName = IDS_CPL_TITLE;
1017 appletInfo->idInfo = IDS_CPL_DESC;
1018 appletInfo->lData = 0;
1020 break;
1023 case CPL_DBLCLK:
1024 StartApplet(hwndCPL);
1025 break;
1028 return FALSE;