setupapi: Set LastError on success in SetupInstallFromInfSectionW.
[wine.git] / dlls / appwiz.cpl / appwiz.c
blobaf893b8391d93c45d75cfcd927fcc9173da16af5
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 "config.h"
29 #include "wine/port.h"
31 #include <string.h>
32 #include <stdlib.h>
33 #include <stdarg.h>
34 #include <stdio.h>
35 #include <windef.h>
36 #include <winbase.h>
37 #include <winuser.h>
38 #include <wingdi.h>
39 #include <winreg.h>
40 #include <shellapi.h>
41 #include <commctrl.h>
42 #include <commdlg.h>
43 #include <cpl.h>
45 #include "wine/unicode.h"
46 #include "wine/list.h"
47 #include "wine/debug.h"
48 #include "appwiz.h"
49 #include "res.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
58 struct list entry;
59 int id;
61 LPWSTR title;
62 LPWSTR path;
63 LPWSTR path_modify;
65 LPWSTR icon;
66 int iconIdx;
68 LPWSTR publisher;
69 LPWSTR version;
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 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',
88 's','i','o','n',0};
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',
93 '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',
98 'n','f','o',0};
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};
103 static const WCHAR SystemComponentW[] = {'S','y','s','t','e','m','C','o','m','p','o','n','e','n','t',0};
105 static const WCHAR PathUninstallW[] = {
106 'S','o','f','t','w','a','r','e','\\',
107 'M','i','c','r','o','s','o','f','t','\\',
108 'W','i','n','d','o','w','s','\\',
109 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
110 'U','n','i','n','s','t','a','l','l',0 };
112 /******************************************************************************
113 * Name : DllMain
114 * Description: Entry point for DLL file
116 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason,
117 LPVOID lpvReserved)
119 TRACE("(%p, %d, %p)\n", hinstDLL, fdwReason, lpvReserved);
121 switch (fdwReason)
123 case DLL_PROCESS_ATTACH:
124 hInst = hinstDLL;
125 break;
127 return TRUE;
130 /******************************************************************************
131 * Name : FreeAppInfo
132 * Description: Frees memory used by an AppInfo structure, and any children.
134 static void FreeAppInfo(APPINFO *info)
136 HeapFree(GetProcessHeap(), 0, info->title);
137 HeapFree(GetProcessHeap(), 0, info->path);
138 HeapFree(GetProcessHeap(), 0, info->path_modify);
139 HeapFree(GetProcessHeap(), 0, info->icon);
140 HeapFree(GetProcessHeap(), 0, info->publisher);
141 HeapFree(GetProcessHeap(), 0, info->version);
142 HeapFree(GetProcessHeap(), 0, info);
145 /******************************************************************************
146 * Name : ReadApplicationsFromRegistry
147 * Description: Creates a linked list of uninstallable applications from the
148 * registry.
149 * Parameters : root - Which registry root to read from
150 * Returns : TRUE if successful, FALSE otherwise
152 static BOOL ReadApplicationsFromRegistry(HKEY root)
154 HKEY hkeyApp;
155 int i;
156 static int id = 0;
157 DWORD sizeOfSubKeyName, displen, uninstlen;
158 DWORD dwNoModify, dwType, value, size;
159 WCHAR subKeyName[256];
160 WCHAR *command;
161 APPINFO *info = NULL;
162 LPWSTR iconPtr;
164 sizeOfSubKeyName = ARRAY_SIZE(subKeyName);
166 for (i = 0; RegEnumKeyExW(root, i, subKeyName, &sizeOfSubKeyName, NULL,
167 NULL, NULL, NULL) != ERROR_NO_MORE_ITEMS; ++i)
169 RegOpenKeyExW(root, subKeyName, 0, KEY_READ, &hkeyApp);
170 size = sizeof(value);
171 if (!RegQueryValueExW(hkeyApp, SystemComponentW, NULL, &dwType, (LPBYTE)&value, &size)
172 && dwType == REG_DWORD && value == 1)
174 RegCloseKey(hkeyApp);
175 sizeOfSubKeyName = ARRAY_SIZE(subKeyName);
176 continue;
178 displen = 0;
179 uninstlen = 0;
180 if (!RegQueryValueExW(hkeyApp, DisplayNameW, 0, 0, NULL, &displen))
182 size = sizeof(value);
183 if (!RegQueryValueExW(hkeyApp, WindowsInstallerW, NULL, &dwType, (LPBYTE)&value, &size)
184 && dwType == REG_DWORD && value == 1)
186 static const WCHAR fmtW[] = {'m','s','i','e','x','e','c',' ','/','x','%','s',0};
187 int len = lstrlenW(fmtW) + lstrlenW(subKeyName);
189 if (!(command = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)))) goto err;
190 wsprintfW(command, fmtW, subKeyName);
192 else if (!RegQueryValueExW(hkeyApp, UninstallCommandlineW, 0, 0, NULL, &uninstlen))
194 if (!(command = HeapAlloc(GetProcessHeap(), 0, uninstlen))) goto err;
195 RegQueryValueExW(hkeyApp, UninstallCommandlineW, 0, 0, (LPBYTE)command, &uninstlen);
197 else
199 RegCloseKey(hkeyApp);
200 sizeOfSubKeyName = ARRAY_SIZE(subKeyName);
201 continue;
204 info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(struct APPINFO));
205 if (!info) goto err;
207 info->title = HeapAlloc(GetProcessHeap(), 0, displen);
209 if (!info->title)
210 goto err;
212 RegQueryValueExW(hkeyApp, DisplayNameW, 0, 0, (LPBYTE)info->title,
213 &displen);
215 /* now get DisplayIcon */
216 displen = 0;
217 RegQueryValueExW(hkeyApp, DisplayIconW, 0, 0, NULL, &displen);
219 if (displen == 0)
220 info->icon = 0;
221 else
223 info->icon = HeapAlloc(GetProcessHeap(), 0, displen);
225 if (!info->icon)
226 goto err;
228 RegQueryValueExW(hkeyApp, DisplayIconW, 0, 0, (LPBYTE)info->icon,
229 &displen);
231 /* separate the index from the icon name, if supplied */
232 iconPtr = strchrW(info->icon, ',');
234 if (iconPtr)
236 *iconPtr++ = 0;
237 info->iconIdx = atoiW(iconPtr);
241 /* publisher, version */
242 if (RegQueryValueExW(hkeyApp, PublisherW, 0, 0, NULL, &displen) ==
243 ERROR_SUCCESS)
245 info->publisher = HeapAlloc(GetProcessHeap(), 0, displen);
247 if (!info->publisher)
248 goto err;
250 RegQueryValueExW(hkeyApp, PublisherW, 0, 0, (LPBYTE)info->publisher,
251 &displen);
254 if (RegQueryValueExW(hkeyApp, DisplayVersionW, 0, 0, NULL, &displen) ==
255 ERROR_SUCCESS)
257 info->version = HeapAlloc(GetProcessHeap(), 0, displen);
259 if (!info->version)
260 goto err;
262 RegQueryValueExW(hkeyApp, DisplayVersionW, 0, 0, (LPBYTE)info->version,
263 &displen);
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 snprintfW( 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,
620 ARRAY_SIZE(notfound));
622 /* Update the data for items already read into the structure */
623 SetInfoDialogText(NULL, iter->publisher, notfound, hWnd,
624 IDC_INFO_PUBLISHER);
625 SetInfoDialogText(NULL, iter->version, notfound, hWnd,
626 IDC_INFO_VERSION);
628 /* And now update the data for those items in the registry */
629 SetInfoDialogText(hkey, ContactW, notfound, hWnd,
630 IDC_INFO_CONTACT);
631 SetInfoDialogText(hkey, HelpLinkW, notfound, hWnd,
632 IDC_INFO_SUPPORT);
633 SetInfoDialogText(hkey, HelpTelephoneW, notfound, hWnd,
634 IDC_INFO_PHONE);
635 SetInfoDialogText(hkey, ReadmeW, notfound, hWnd,
636 IDC_INFO_README);
637 SetInfoDialogText(hkey, URLUpdateInfoW, notfound, hWnd,
638 IDC_INFO_UPDATES);
639 SetInfoDialogText(hkey, CommentsW, notfound, hWnd,
640 IDC_INFO_COMMENTS);
642 /* Update the main label with the app name */
643 if (GetWindowTextW(GetDlgItem(hWnd, IDC_INFO_LABEL), oldtitle,
644 MAX_STRING_LEN) != 0)
646 wsprintfW(buf, oldtitle, iter->title);
647 SetWindowTextW(GetDlgItem(hWnd, IDC_INFO_LABEL), buf);
650 RegCloseKey(hkey);
652 break;
656 return TRUE;
658 case WM_DESTROY:
659 return 0;
661 case WM_COMMAND:
662 switch (LOWORD(wParam))
664 case IDOK:
665 EndDialog(hWnd, TRUE);
666 break;
670 return TRUE;
673 return FALSE;
676 /******************************************************************************
677 * Name : SupportInfo
678 * Description: Displays the Support Information dialog
679 * Parameters : hWnd - Handle of the main dialog
680 * id - ID of the application to display information for
682 static void SupportInfo(HWND hWnd, int id)
684 DialogBoxParamW(hInst, MAKEINTRESOURCEW(IDD_INFO), hWnd, SupportInfoDlgProc, id);
687 /* Definition of column headers for AddListViewColumns function */
688 typedef struct AppWizColumn {
689 int width;
690 int fmt;
691 int title;
692 } AppWizColumn;
694 static const AppWizColumn columns[] = {
695 {200, LVCFMT_LEFT, IDS_COLUMN_NAME},
696 {150, LVCFMT_LEFT, IDS_COLUMN_PUBLISHER},
697 {100, LVCFMT_LEFT, IDS_COLUMN_VERSION},
700 /******************************************************************************
701 * Name : AddListViewColumns
702 * Description: Adds column headers to the list view control.
703 * Parameters : hWnd - Handle of the list view control.
704 * Returns : TRUE if completed successfully, FALSE otherwise.
706 static BOOL AddListViewColumns(HWND hWnd)
708 WCHAR buf[MAX_STRING_LEN];
709 LVCOLUMNW lvc;
710 UINT i;
712 lvc.mask = LVCF_FMT | LVCF_TEXT | LVCF_SUBITEM | LVCF_WIDTH;
714 /* Add the columns */
715 for (i = 0; i < ARRAY_SIZE(columns); i++)
717 lvc.iSubItem = i;
718 lvc.pszText = buf;
720 /* set width and format */
721 lvc.cx = columns[i].width;
722 lvc.fmt = columns[i].fmt;
724 LoadStringW(hInst, columns[i].title, buf, ARRAY_SIZE(buf));
726 if (ListView_InsertColumnW(hWnd, i, &lvc) == -1)
727 return FALSE;
730 return TRUE;
733 /******************************************************************************
734 * Name : AddListViewImageList
735 * Description: Creates an ImageList for the list view control.
736 * Parameters : hWnd - Handle of the list view control.
737 * Returns : Handle of the image list.
739 static HIMAGELIST AddListViewImageList(HWND hWnd)
741 HIMAGELIST hSmall;
742 HICON hDefaultIcon;
744 hSmall = ImageList_Create(GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON),
745 ILC_COLOR32 | ILC_MASK, 1, 1);
747 /* Add default icon to image list */
748 hDefaultIcon = LoadIconW(hInst, MAKEINTRESOURCEW(ICO_MAIN));
749 ImageList_AddIcon(hSmall, hDefaultIcon);
750 DestroyIcon(hDefaultIcon);
752 SendMessageW(hWnd, LVM_SETIMAGELIST, LVSIL_SMALL, (LPARAM)hSmall);
754 return hSmall;
757 /******************************************************************************
758 * Name : ResetApplicationList
759 * Description: Empties the app list, if need be, and recreates it.
760 * Parameters : bFirstRun - TRUE if this is the first time this is run, FALSE otherwise
761 * hWnd - handle of the dialog box
762 * hImageList - handle of the image list
763 * Returns : New handle of the image list.
765 static HIMAGELIST ResetApplicationList(BOOL bFirstRun, HWND hWnd, HIMAGELIST hImageList)
767 static const BOOL is_64bit = sizeof(void *) > sizeof(int);
768 HWND hWndListView;
769 HKEY hkey;
771 hWndListView = GetDlgItem(hWnd, IDL_PROGRAMS);
773 /* if first run, create the image list and add the listview columns */
774 if (bFirstRun)
776 if (!AddListViewColumns(hWndListView))
777 return NULL;
779 else /* we need to remove the existing things first */
781 RemoveItemsFromList(hWnd);
782 ImageList_Destroy(hImageList);
784 /* reset the list, since it's probably changed if the uninstallation was
785 successful */
786 EmptyList();
789 /* now create the image list and add the applications to the listview */
790 hImageList = AddListViewImageList(hWndListView);
792 if (!RegOpenKeyExW(HKEY_LOCAL_MACHINE, PathUninstallW, 0, KEY_READ, &hkey))
794 ReadApplicationsFromRegistry(hkey);
795 RegCloseKey(hkey);
797 if (is_64bit &&
798 !RegOpenKeyExW(HKEY_LOCAL_MACHINE, PathUninstallW, 0, KEY_READ|KEY_WOW64_32KEY, &hkey))
800 ReadApplicationsFromRegistry(hkey);
801 RegCloseKey(hkey);
803 if (!RegOpenKeyExW(HKEY_CURRENT_USER, PathUninstallW, 0, KEY_READ, &hkey))
805 ReadApplicationsFromRegistry(hkey);
806 RegCloseKey(hkey);
809 AddApplicationsToList(hWndListView, hImageList);
810 UpdateButtons(hWnd);
812 return(hImageList);
815 /******************************************************************************
816 * Name : MainDlgProc
817 * Description: Callback procedure for main tab
818 * Parameters : hWnd - hWnd of the window
819 * msg - reason for calling function
820 * wParam - additional parameter
821 * lParam - additional parameter
822 * Returns : Depends on the message
824 static INT_PTR CALLBACK MainDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
826 int selitem;
827 static HIMAGELIST hImageList;
828 LPNMHDR nmh;
829 LVITEMW lvItem;
831 switch(msg)
833 case WM_INITDIALOG:
834 SendDlgItemMessageW(hWnd, IDL_PROGRAMS, LVM_SETEXTENDEDLISTVIEWSTYLE,
835 LVS_EX_FULLROWSELECT, LVS_EX_FULLROWSELECT);
837 hImageList = ResetApplicationList(TRUE, hWnd, hImageList);
839 if (!hImageList)
840 return FALSE;
842 return TRUE;
844 case WM_DESTROY:
845 RemoveItemsFromList(hWnd);
846 ImageList_Destroy(hImageList);
848 EmptyList();
850 return 0;
852 case WM_NOTIFY:
853 nmh = (LPNMHDR) lParam;
855 switch (nmh->idFrom)
857 case IDL_PROGRAMS:
858 switch (nmh->code)
860 case LVN_ITEMCHANGED:
861 UpdateButtons(hWnd);
862 break;
864 break;
867 return TRUE;
869 case WM_COMMAND:
870 switch (LOWORD(wParam))
872 case IDC_INSTALL:
873 InstallProgram(hWnd);
874 break;
876 case IDC_ADDREMOVE:
877 case IDC_MODIFY:
878 selitem = SendDlgItemMessageW(hWnd, IDL_PROGRAMS,
879 LVM_GETNEXTITEM, -1, LVNI_FOCUSED|LVNI_SELECTED);
881 if (selitem != -1)
883 lvItem.iItem = selitem;
884 lvItem.mask = LVIF_PARAM;
886 if (SendDlgItemMessageW(hWnd, IDL_PROGRAMS, LVM_GETITEMW,
887 0, (LPARAM) &lvItem))
888 UninstallProgram(lvItem.lParam, LOWORD(wParam));
891 hImageList = ResetApplicationList(FALSE, hWnd, hImageList);
893 break;
895 case IDC_SUPPORT_INFO:
896 selitem = SendDlgItemMessageW(hWnd, IDL_PROGRAMS,
897 LVM_GETNEXTITEM, -1, LVNI_FOCUSED | LVNI_SELECTED);
899 if (selitem != -1)
901 lvItem.iItem = selitem;
902 lvItem.mask = LVIF_PARAM;
904 if (SendDlgItemMessageW(hWnd, IDL_PROGRAMS, LVM_GETITEMW,
905 0, (LPARAM) &lvItem))
906 SupportInfo(hWnd, lvItem.lParam);
909 break;
912 return TRUE;
915 return FALSE;
918 static int CALLBACK propsheet_callback( HWND hwnd, UINT msg, LPARAM lparam )
920 switch (msg)
922 case PSCB_INITIALIZED:
923 SendMessageW( hwnd, WM_SETICON, ICON_BIG, (LPARAM)LoadIconW( hInst, MAKEINTRESOURCEW(ICO_MAIN) ));
924 break;
926 return 0;
929 /******************************************************************************
930 * Name : StartApplet
931 * Description: Main routine for applet
932 * Parameters : hWnd - hWnd of the Control Panel
934 static void StartApplet(HWND hWnd)
936 PROPSHEETPAGEW psp;
937 PROPSHEETHEADERW psh;
938 WCHAR tab_title[MAX_STRING_LEN], app_title[MAX_STRING_LEN];
940 /* Load the strings we will use */
941 LoadStringW(hInst, IDS_TAB1_TITLE, tab_title, ARRAY_SIZE(tab_title));
942 LoadStringW(hInst, IDS_CPL_TITLE, app_title, ARRAY_SIZE(app_title));
943 LoadStringW(hInst, IDS_REMOVE, btnRemove, ARRAY_SIZE(btnRemove));
944 LoadStringW(hInst, IDS_MODIFY_REMOVE, btnModifyRemove, ARRAY_SIZE(btnModifyRemove));
946 /* Fill out the PROPSHEETPAGE */
947 psp.dwSize = sizeof (PROPSHEETPAGEW);
948 psp.dwFlags = PSP_USETITLE;
949 psp.hInstance = hInst;
950 psp.u.pszTemplate = MAKEINTRESOURCEW (IDD_MAIN);
951 psp.u2.pszIcon = NULL;
952 psp.pfnDlgProc = MainDlgProc;
953 psp.pszTitle = tab_title;
954 psp.lParam = 0;
956 /* Fill out the PROPSHEETHEADER */
957 psh.dwSize = sizeof (PROPSHEETHEADERW);
958 psh.dwFlags = PSH_PROPSHEETPAGE | PSH_USEICONID | PSH_USECALLBACK;
959 psh.hwndParent = hWnd;
960 psh.hInstance = hInst;
961 psh.u.pszIcon = MAKEINTRESOURCEW(ICO_MAIN);
962 psh.pszCaption = app_title;
963 psh.nPages = 1;
964 psh.u3.ppsp = &psp;
965 psh.pfnCallback = propsheet_callback;
966 psh.u2.nStartPage = 0;
968 /* Display the property sheet */
969 PropertySheetW (&psh);
972 static LONG start_params(const WCHAR *params)
974 static const WCHAR install_geckoW[] = {'i','n','s','t','a','l','l','_','g','e','c','k','o',0};
975 static const WCHAR install_monoW[] = {'i','n','s','t','a','l','l','_','m','o','n','o',0};
977 if(!params)
978 return FALSE;
980 if(!strcmpW(params, install_geckoW)) {
981 install_addon(ADDON_GECKO);
982 return TRUE;
985 if(!strcmpW(params, install_monoW)) {
986 install_addon(ADDON_MONO);
987 return TRUE;
990 WARN("unknown param %s\n", debugstr_w(params));
991 return FALSE;
994 /******************************************************************************
995 * Name : CPlApplet
996 * Description: Entry point for Control Panel applets
997 * Parameters : hwndCPL - hWnd of the Control Panel
998 * message - reason for calling function
999 * lParam1 - additional parameter
1000 * lParam2 - additional parameter
1001 * Returns : Depends on the message
1003 LONG CALLBACK CPlApplet(HWND hwndCPL, UINT message, LPARAM lParam1, LPARAM lParam2)
1005 INITCOMMONCONTROLSEX iccEx;
1007 switch (message)
1009 case CPL_INIT:
1010 iccEx.dwSize = sizeof(iccEx);
1011 iccEx.dwICC = ICC_LISTVIEW_CLASSES | ICC_TAB_CLASSES | ICC_LINK_CLASS;
1013 InitCommonControlsEx(&iccEx);
1015 return TRUE;
1017 case CPL_GETCOUNT:
1018 return 1;
1020 case CPL_STARTWPARMSW:
1021 return start_params((const WCHAR *)lParam2);
1023 case CPL_INQUIRE:
1025 CPLINFO *appletInfo = (CPLINFO *) lParam2;
1027 appletInfo->idIcon = ICO_MAIN;
1028 appletInfo->idName = IDS_CPL_TITLE;
1029 appletInfo->idInfo = IDS_CPL_DESC;
1030 appletInfo->lData = 0;
1032 break;
1035 case CPL_DBLCLK:
1036 StartApplet(hwndCPL);
1037 break;
1040 return FALSE;