mfplat: Read queue subscriber within the critical section.
[wine/zf.git] / dlls / appwiz.cpl / appwiz.c
blob2bc108b63c63934682d7d9f678780e53df25b11b
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 PathUninstallW[] = L"Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall";
85 /******************************************************************************
86 * Name : DllMain
87 * Description: Entry point for DLL file
89 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason,
90 LPVOID lpvReserved)
92 TRACE("(%p, %d, %p)\n", hinstDLL, fdwReason, lpvReserved);
94 switch (fdwReason)
96 case DLL_PROCESS_ATTACH:
97 hInst = hinstDLL;
98 break;
100 return TRUE;
103 /******************************************************************************
104 * Name : FreeAppInfo
105 * Description: Frees memory used by an AppInfo structure, and any children.
107 static void FreeAppInfo(APPINFO *info)
109 HeapFree(GetProcessHeap(), 0, info->title);
110 HeapFree(GetProcessHeap(), 0, info->path);
111 HeapFree(GetProcessHeap(), 0, info->path_modify);
112 HeapFree(GetProcessHeap(), 0, info->icon);
113 HeapFree(GetProcessHeap(), 0, info->publisher);
114 HeapFree(GetProcessHeap(), 0, info->version);
115 HeapFree(GetProcessHeap(), 0, info->contact);
116 HeapFree(GetProcessHeap(), 0, info->helplink);
117 HeapFree(GetProcessHeap(), 0, info->helptelephone);
118 HeapFree(GetProcessHeap(), 0, info->readme);
119 HeapFree(GetProcessHeap(), 0, info->urlupdateinfo);
120 HeapFree(GetProcessHeap(), 0, info->comments);
121 HeapFree(GetProcessHeap(), 0, info);
124 static WCHAR *get_reg_str(HKEY hkey, const WCHAR *value)
126 DWORD len, type;
127 WCHAR *ret = NULL;
128 if (!RegQueryValueExW(hkey, value, NULL, &type, NULL, &len) && type == REG_SZ)
130 if (!(ret = HeapAlloc(GetProcessHeap(), 0, len))) return NULL;
131 RegQueryValueExW(hkey, value, 0, 0, (BYTE *)ret, &len);
133 return ret;
136 /******************************************************************************
137 * Name : ReadApplicationsFromRegistry
138 * Description: Creates a linked list of uninstallable applications from the
139 * registry.
140 * Parameters : root - Which registry root to read from
141 * Returns : TRUE if successful, FALSE otherwise
143 static BOOL ReadApplicationsFromRegistry(HKEY root)
145 HKEY hkeyApp;
146 int i;
147 static int id = 0;
148 DWORD sizeOfSubKeyName, displen, uninstlen;
149 DWORD dwNoModify, dwType, value, size;
150 WCHAR subKeyName[256];
151 WCHAR *command;
152 APPINFO *info = NULL;
153 LPWSTR iconPtr;
155 sizeOfSubKeyName = ARRAY_SIZE(subKeyName);
157 for (i = 0; RegEnumKeyExW(root, i, subKeyName, &sizeOfSubKeyName, NULL,
158 NULL, NULL, NULL) != ERROR_NO_MORE_ITEMS; ++i)
160 RegOpenKeyExW(root, subKeyName, 0, KEY_READ, &hkeyApp);
161 size = sizeof(value);
162 if (!RegQueryValueExW(hkeyApp, L"SystemComponent", NULL, &dwType, (BYTE *)&value, &size)
163 && dwType == REG_DWORD && value == 1)
165 RegCloseKey(hkeyApp);
166 sizeOfSubKeyName = ARRAY_SIZE(subKeyName);
167 continue;
169 displen = 0;
170 uninstlen = 0;
171 if (!RegQueryValueExW(hkeyApp, L"DisplayName", 0, 0, NULL, &displen))
173 size = sizeof(value);
174 if (!RegQueryValueExW(hkeyApp, L"WindowsInstaller", NULL, &dwType, (BYTE *)&value, &size)
175 && dwType == REG_DWORD && value == 1)
177 int len = lstrlenW(L"msiexec /x%s") + lstrlenW(subKeyName);
179 if (!(command = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)))) goto err;
180 wsprintfW(command, L"msiexec /x%s", subKeyName);
182 else if (!RegQueryValueExW(hkeyApp, L"UninstallString", 0, 0, NULL, &uninstlen))
184 if (!(command = HeapAlloc(GetProcessHeap(), 0, uninstlen))) goto err;
185 RegQueryValueExW(hkeyApp, L"UninstallString", 0, 0, (BYTE *)command, &uninstlen);
187 else
189 RegCloseKey(hkeyApp);
190 sizeOfSubKeyName = ARRAY_SIZE(subKeyName);
191 continue;
194 info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(struct APPINFO));
195 if (!info) goto err;
197 info->title = HeapAlloc(GetProcessHeap(), 0, displen);
199 if (!info->title)
200 goto err;
202 RegQueryValueExW(hkeyApp, L"DisplayName", 0, 0, (BYTE *)info->title, &displen);
204 /* now get DisplayIcon */
205 displen = 0;
206 RegQueryValueExW(hkeyApp, L"DisplayIcon", 0, 0, NULL, &displen);
208 if (displen == 0)
209 info->icon = 0;
210 else
212 info->icon = HeapAlloc(GetProcessHeap(), 0, displen);
214 if (!info->icon)
215 goto err;
217 RegQueryValueExW(hkeyApp, L"DisplayIcon", 0, 0, (BYTE *)info->icon, &displen);
219 /* separate the index from the icon name, if supplied */
220 iconPtr = wcschr(info->icon, ',');
222 if (iconPtr)
224 *iconPtr++ = 0;
225 info->iconIdx = wcstol(iconPtr, NULL, 10);
229 info->publisher = get_reg_str(hkeyApp, L"Publisher");
230 info->version = get_reg_str(hkeyApp, L"DisplayVersion");
231 info->contact = get_reg_str(hkeyApp, L"Contact");
232 info->helplink = get_reg_str(hkeyApp, L"HelpLink");
233 info->helptelephone = get_reg_str(hkeyApp, L"HelpTelephone");
234 info->readme = get_reg_str(hkeyApp, L"Readme");
235 info->urlupdateinfo = get_reg_str(hkeyApp, L"URLUpdateInfo");
236 info->comments = get_reg_str(hkeyApp, L"Comments");
238 /* Check if NoModify is set */
239 dwType = REG_DWORD;
240 dwNoModify = 0;
241 displen = sizeof(DWORD);
243 if (RegQueryValueExW(hkeyApp, L"NoModify", NULL, &dwType, (BYTE *)&dwNoModify, &displen)
244 != ERROR_SUCCESS)
246 dwNoModify = 0;
249 /* Some installers incorrectly create a REG_SZ instead of a REG_DWORD */
250 if (dwType == REG_SZ)
251 dwNoModify = (*(BYTE *)&dwNoModify == '1');
253 /* Fetch the modify path */
254 if (!dwNoModify)
256 size = sizeof(value);
257 if (!RegQueryValueExW(hkeyApp, L"WindowsInstaller", NULL, &dwType, (BYTE *)&value, &size)
258 && dwType == REG_DWORD && value == 1)
260 int len = lstrlenW(L"msiexec /i%s") + lstrlenW(subKeyName);
262 if (!(info->path_modify = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)))) goto err;
263 wsprintfW(info->path_modify, L"msiexec /i%s", subKeyName);
265 else if (!RegQueryValueExW(hkeyApp, L"ModifyPath", 0, 0, NULL, &displen))
267 if (!(info->path_modify = HeapAlloc(GetProcessHeap(), 0, displen))) goto err;
268 RegQueryValueExW(hkeyApp, L"ModifyPath", 0, 0, (BYTE *)info->path_modify, &displen);
272 /* registry key */
273 RegOpenKeyExW(root, NULL, 0, KEY_READ, &info->regroot);
274 lstrcpyW(info->regkey, subKeyName);
275 info->path = command;
277 info->id = id++;
278 list_add_tail( &app_list, &info->entry );
281 RegCloseKey(hkeyApp);
282 sizeOfSubKeyName = ARRAY_SIZE(subKeyName);
285 return TRUE;
286 err:
287 RegCloseKey(hkeyApp);
288 if (info) FreeAppInfo(info);
289 HeapFree(GetProcessHeap(), 0, command);
290 return FALSE;
294 /******************************************************************************
295 * Name : AddApplicationsToList
296 * Description: Populates the list box with applications.
297 * Parameters : hWnd - Handle of the dialog box
299 static void AddApplicationsToList(HWND hWnd, HIMAGELIST hList)
301 APPINFO *iter;
302 LVITEMW lvItem;
303 HICON hIcon;
304 int index;
306 LIST_FOR_EACH_ENTRY( iter, &app_list, APPINFO, entry )
308 if (!iter->title[0]) continue;
310 /* get the icon */
311 index = 0;
313 if (iter->icon)
315 if (ExtractIconExW(iter->icon, iter->iconIdx, NULL, &hIcon, 1) == 1)
317 index = ImageList_AddIcon(hList, hIcon);
318 DestroyIcon(hIcon);
322 lvItem.mask = LVIF_IMAGE | LVIF_TEXT | LVIF_PARAM;
323 lvItem.iItem = iter->id;
324 lvItem.iSubItem = 0;
325 lvItem.pszText = iter->title;
326 lvItem.iImage = index;
327 lvItem.lParam = iter->id;
329 index = ListView_InsertItemW(hWnd, &lvItem);
331 /* now add the subitems (columns) */
332 ListView_SetItemTextW(hWnd, index, 1, iter->publisher);
333 ListView_SetItemTextW(hWnd, index, 2, iter->version);
337 /******************************************************************************
338 * Name : RemoveItemsFromList
339 * Description: Clears the application list box.
340 * Parameters : hWnd - Handle of the dialog box
342 static void RemoveItemsFromList(HWND hWnd)
344 SendDlgItemMessageW(hWnd, IDL_PROGRAMS, LVM_DELETEALLITEMS, 0, 0);
347 /******************************************************************************
348 * Name : EmptyList
349 * Description: Frees memory used by the application linked list.
351 static inline void EmptyList(void)
353 APPINFO *info, *next;
354 LIST_FOR_EACH_ENTRY_SAFE( info, next, &app_list, APPINFO, entry )
356 list_remove( &info->entry );
357 FreeAppInfo( info );
361 /******************************************************************************
362 * Name : UpdateButtons
363 * Description: Enables/disables the Add/Remove button depending on current
364 * selection in list box.
365 * Parameters : hWnd - Handle of the dialog box
367 static void UpdateButtons(HWND hWnd)
369 APPINFO *iter;
370 LVITEMW lvItem;
371 LRESULT selitem = SendDlgItemMessageW(hWnd, IDL_PROGRAMS, LVM_GETNEXTITEM, -1,
372 LVNI_FOCUSED | LVNI_SELECTED);
373 BOOL enable_modify = FALSE;
375 if (selitem != -1)
377 lvItem.iItem = selitem;
378 lvItem.mask = LVIF_PARAM;
380 if (SendDlgItemMessageW(hWnd, IDL_PROGRAMS, LVM_GETITEMW, 0, (LPARAM) &lvItem))
382 LIST_FOR_EACH_ENTRY( iter, &app_list, APPINFO, entry )
384 if (iter->id == lvItem.lParam)
386 /* Decide whether to display Modify/Remove as one button or two */
387 enable_modify = (iter->path_modify != NULL);
389 /* Update title as appropriate */
390 if (iter->path_modify == NULL)
391 SetWindowTextW(GetDlgItem(hWnd, IDC_ADDREMOVE), btnModifyRemove);
392 else
393 SetWindowTextW(GetDlgItem(hWnd, IDC_ADDREMOVE), btnRemove);
395 break;
401 /* Enable/disable other buttons if necessary */
402 EnableWindow(GetDlgItem(hWnd, IDC_ADDREMOVE), (selitem != -1));
403 EnableWindow(GetDlgItem(hWnd, IDC_SUPPORT_INFO), (selitem != -1));
404 EnableWindow(GetDlgItem(hWnd, IDC_MODIFY), enable_modify);
407 /******************************************************************************
408 * Name : InstallProgram
409 * Description: Search for potential Installer and execute it.
410 * Parameters : hWnd - Handle of the dialog box
412 static void InstallProgram(HWND hWnd)
414 OPENFILENAMEW ofn;
415 WCHAR titleW[MAX_STRING_LEN];
416 WCHAR filter_installs[MAX_STRING_LEN];
417 WCHAR filter_programs[MAX_STRING_LEN];
418 WCHAR filter_all[MAX_STRING_LEN];
419 WCHAR FilterBufferW[MAX_PATH];
420 WCHAR FileNameBufferW[MAX_PATH];
422 LoadStringW(hInst, IDS_CPL_TITLE, titleW, ARRAY_SIZE(titleW));
423 LoadStringW(hInst, IDS_FILTER_INSTALLS, filter_installs, ARRAY_SIZE(filter_installs));
424 LoadStringW(hInst, IDS_FILTER_PROGRAMS, filter_programs, ARRAY_SIZE(filter_programs));
425 LoadStringW(hInst, IDS_FILTER_ALL, filter_all, ARRAY_SIZE(filter_all));
427 swprintf( FilterBufferW, MAX_PATH, L"%s%c*instal*.exe;*setup*.exe;*.msi%c%s%c*.exe%c%s%c*.*%c",
428 filter_installs, 0, 0, filter_programs, 0, 0, filter_all, 0, 0 );
429 memset(&ofn, 0, sizeof(OPENFILENAMEW));
430 ofn.lStructSize = sizeof(OPENFILENAMEW);
431 ofn.hwndOwner = hWnd;
432 ofn.hInstance = hInst;
433 ofn.lpstrFilter = FilterBufferW;
434 ofn.nFilterIndex = 0;
435 ofn.lpstrFile = FileNameBufferW;
436 ofn.nMaxFile = MAX_PATH;
437 ofn.lpstrFileTitle = NULL;
438 ofn.nMaxFileTitle = 0;
439 ofn.lpstrTitle = titleW;
440 ofn.Flags = OFN_HIDEREADONLY | OFN_ENABLESIZING;
441 FileNameBufferW[0] = 0;
443 if (GetOpenFileNameW(&ofn))
445 SHELLEXECUTEINFOW sei;
446 memset(&sei, 0, sizeof(sei));
447 sei.cbSize = sizeof(sei);
448 sei.lpVerb = L"open";
449 sei.nShow = SW_SHOWDEFAULT;
450 sei.fMask = 0;
451 sei.lpFile = ofn.lpstrFile;
453 ShellExecuteExW(&sei);
457 /******************************************************************************
458 * Name : UninstallProgram
459 * Description: Executes the specified program's installer.
460 * Parameters : id - the internal ID of the installer to remove
461 * Parameters : button - ID of button pressed (Modify or Remove)
463 static void UninstallProgram(int id, DWORD button)
465 APPINFO *iter;
466 STARTUPINFOW si;
467 PROCESS_INFORMATION info;
468 WCHAR errormsg[MAX_STRING_LEN];
469 WCHAR sUninstallFailed[MAX_STRING_LEN];
470 BOOL res;
472 LoadStringW(hInst, IDS_UNINSTALL_FAILED, sUninstallFailed,
473 ARRAY_SIZE(sUninstallFailed));
475 LIST_FOR_EACH_ENTRY( iter, &app_list, APPINFO, entry )
477 if (iter->id == id)
479 TRACE("Uninstalling %s (%s)\n", wine_dbgstr_w(iter->title),
480 wine_dbgstr_w(iter->path));
482 memset(&si, 0, sizeof(STARTUPINFOW));
483 si.cb = sizeof(STARTUPINFOW);
484 si.wShowWindow = SW_NORMAL;
486 res = CreateProcessW(NULL, (button == IDC_MODIFY) ? iter->path_modify : iter->path,
487 NULL, NULL, FALSE, 0, NULL, NULL, &si, &info);
489 if (res)
491 CloseHandle(info.hThread);
493 /* wait for the process to exit */
494 WaitForSingleObject(info.hProcess, INFINITE);
495 CloseHandle(info.hProcess);
497 else
499 wsprintfW(errormsg, sUninstallFailed, iter->path);
501 if (MessageBoxW(0, errormsg, iter->title, MB_YESNO |
502 MB_ICONQUESTION) == IDYES)
504 /* delete the application's uninstall entry */
505 RegDeleteKeyW(iter->regroot, iter->regkey);
506 RegCloseKey(iter->regroot);
510 break;
515 /**********************************************************************************
516 * Name : SetInfoDialogText
517 * Description: Sets the text of a label in a window, based upon a registry entry
518 * or string passed to the function.
519 * Parameters : hKey - registry entry to read from, NULL if not reading
520 * from registry
521 * lpKeyName - key to read from, or string to check if hKey is NULL
522 * lpAltMessage - alternative message if entry not found
523 * hWnd - handle of dialog box
524 * iDlgItem - ID of label in dialog box
526 static void SetInfoDialogText(HKEY hKey, LPCWSTR lpKeyName, LPCWSTR lpAltMessage,
527 HWND hWnd, int iDlgItem)
529 WCHAR buf[MAX_STRING_LEN];
530 DWORD buflen;
531 HWND hWndDlgItem;
533 hWndDlgItem = GetDlgItem(hWnd, iDlgItem);
535 /* if hKey is null, lpKeyName contains the string we want to check */
536 if (hKey == NULL)
538 if (lpKeyName && lpKeyName[0])
539 SetWindowTextW(hWndDlgItem, lpKeyName);
540 else
541 SetWindowTextW(hWndDlgItem, lpAltMessage);
543 else
545 buflen = MAX_STRING_LEN;
547 if ((RegQueryValueExW(hKey, lpKeyName, 0, 0, (LPBYTE) buf, &buflen) ==
548 ERROR_SUCCESS) && buf[0])
549 SetWindowTextW(hWndDlgItem, buf);
550 else
551 SetWindowTextW(hWndDlgItem, lpAltMessage);
555 /******************************************************************************
556 * Name : SupportInfoDlgProc
557 * Description: Callback procedure for support info dialog
558 * Parameters : hWnd - hWnd of the window
559 * msg - reason for calling function
560 * wParam - additional parameter
561 * lParam - additional parameter
562 * Returns : Depends on the message
564 static INT_PTR CALLBACK SupportInfoDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
566 APPINFO *iter;
567 HKEY hkey;
568 WCHAR oldtitle[MAX_STRING_LEN];
569 WCHAR buf[MAX_STRING_LEN];
570 WCHAR key[MAX_STRING_LEN];
571 WCHAR notfound[MAX_STRING_LEN];
573 switch(msg)
575 case WM_INITDIALOG:
576 LIST_FOR_EACH_ENTRY( iter, &app_list, APPINFO, entry )
578 if (iter->id == (int) lParam)
580 lstrcpyW(key, PathUninstallW);
581 lstrcatW(key, L"\\");
582 lstrcatW(key, iter->regkey);
584 /* check the application's registry entries */
585 RegOpenKeyExW(iter->regroot, key, 0, KEY_READ, &hkey);
587 /* Load our "not specified" string */
588 LoadStringW(hInst, IDS_NOT_SPECIFIED, notfound, ARRAY_SIZE(notfound));
590 SetInfoDialogText(NULL, iter->publisher, notfound, hWnd, IDC_INFO_PUBLISHER);
591 SetInfoDialogText(NULL, iter->version, notfound, hWnd, IDC_INFO_VERSION);
592 SetInfoDialogText(hkey, iter->contact, notfound, hWnd, IDC_INFO_CONTACT);
593 SetInfoDialogText(hkey, iter->helplink, notfound, hWnd, IDC_INFO_SUPPORT);
594 SetInfoDialogText(hkey, iter->helptelephone, notfound, hWnd, IDC_INFO_PHONE);
595 SetInfoDialogText(hkey, iter->readme, notfound, hWnd, IDC_INFO_README);
596 SetInfoDialogText(hkey, iter->urlupdateinfo, notfound, hWnd, IDC_INFO_UPDATES);
597 SetInfoDialogText(hkey, iter->comments, notfound, hWnd, IDC_INFO_COMMENTS);
599 /* Update the main label with the app name */
600 if (GetWindowTextW(GetDlgItem(hWnd, IDC_INFO_LABEL), oldtitle,
601 MAX_STRING_LEN) != 0)
603 wsprintfW(buf, oldtitle, iter->title);
604 SetWindowTextW(GetDlgItem(hWnd, IDC_INFO_LABEL), buf);
607 RegCloseKey(hkey);
609 break;
613 return TRUE;
615 case WM_DESTROY:
616 return 0;
618 case WM_COMMAND:
619 switch (LOWORD(wParam))
621 case IDOK:
622 EndDialog(hWnd, TRUE);
623 break;
627 return TRUE;
630 return FALSE;
633 /******************************************************************************
634 * Name : SupportInfo
635 * Description: Displays the Support Information dialog
636 * Parameters : hWnd - Handle of the main dialog
637 * id - ID of the application to display information for
639 static void SupportInfo(HWND hWnd, int id)
641 DialogBoxParamW(hInst, MAKEINTRESOURCEW(IDD_INFO), hWnd, SupportInfoDlgProc, id);
644 /* Definition of column headers for AddListViewColumns function */
645 typedef struct AppWizColumn {
646 int width;
647 int fmt;
648 int title;
649 } AppWizColumn;
651 static const AppWizColumn columns[] = {
652 {200, LVCFMT_LEFT, IDS_COLUMN_NAME},
653 {150, LVCFMT_LEFT, IDS_COLUMN_PUBLISHER},
654 {100, LVCFMT_LEFT, IDS_COLUMN_VERSION},
657 /******************************************************************************
658 * Name : AddListViewColumns
659 * Description: Adds column headers to the list view control.
660 * Parameters : hWnd - Handle of the list view control.
661 * Returns : TRUE if completed successfully, FALSE otherwise.
663 static BOOL AddListViewColumns(HWND hWnd)
665 WCHAR buf[MAX_STRING_LEN];
666 LVCOLUMNW lvc;
667 UINT i;
669 lvc.mask = LVCF_FMT | LVCF_TEXT | LVCF_SUBITEM | LVCF_WIDTH;
671 /* Add the columns */
672 for (i = 0; i < ARRAY_SIZE(columns); i++)
674 lvc.iSubItem = i;
675 lvc.pszText = buf;
677 /* set width and format */
678 lvc.cx = columns[i].width;
679 lvc.fmt = columns[i].fmt;
681 LoadStringW(hInst, columns[i].title, buf, ARRAY_SIZE(buf));
683 if (ListView_InsertColumnW(hWnd, i, &lvc) == -1)
684 return FALSE;
687 return TRUE;
690 /******************************************************************************
691 * Name : AddListViewImageList
692 * Description: Creates an ImageList for the list view control.
693 * Parameters : hWnd - Handle of the list view control.
694 * Returns : Handle of the image list.
696 static HIMAGELIST AddListViewImageList(HWND hWnd)
698 HIMAGELIST hSmall;
699 HICON hDefaultIcon;
701 hSmall = ImageList_Create(GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON),
702 ILC_COLOR32 | ILC_MASK, 1, 1);
704 /* Add default icon to image list */
705 hDefaultIcon = LoadIconW(hInst, MAKEINTRESOURCEW(ICO_MAIN));
706 ImageList_AddIcon(hSmall, hDefaultIcon);
707 DestroyIcon(hDefaultIcon);
709 SendMessageW(hWnd, LVM_SETIMAGELIST, LVSIL_SMALL, (LPARAM)hSmall);
711 return hSmall;
714 /******************************************************************************
715 * Name : ResetApplicationList
716 * Description: Empties the app list, if need be, and recreates it.
717 * Parameters : bFirstRun - TRUE if this is the first time this is run, FALSE otherwise
718 * hWnd - handle of the dialog box
719 * hImageList - handle of the image list
720 * Returns : New handle of the image list.
722 static HIMAGELIST ResetApplicationList(BOOL bFirstRun, HWND hWnd, HIMAGELIST hImageList)
724 static const BOOL is_64bit = sizeof(void *) > sizeof(int);
725 HWND hWndListView;
726 HKEY hkey;
728 hWndListView = GetDlgItem(hWnd, IDL_PROGRAMS);
730 /* if first run, create the image list and add the listview columns */
731 if (bFirstRun)
733 if (!AddListViewColumns(hWndListView))
734 return NULL;
736 else /* we need to remove the existing things first */
738 RemoveItemsFromList(hWnd);
739 ImageList_Destroy(hImageList);
741 /* reset the list, since it's probably changed if the uninstallation was
742 successful */
743 EmptyList();
746 /* now create the image list and add the applications to the listview */
747 hImageList = AddListViewImageList(hWndListView);
749 if (!RegOpenKeyExW(HKEY_LOCAL_MACHINE, PathUninstallW, 0, KEY_READ, &hkey))
751 ReadApplicationsFromRegistry(hkey);
752 RegCloseKey(hkey);
754 if (is_64bit &&
755 !RegOpenKeyExW(HKEY_LOCAL_MACHINE, PathUninstallW, 0, KEY_READ|KEY_WOW64_32KEY, &hkey))
757 ReadApplicationsFromRegistry(hkey);
758 RegCloseKey(hkey);
760 if (!RegOpenKeyExW(HKEY_CURRENT_USER, PathUninstallW, 0, KEY_READ, &hkey))
762 ReadApplicationsFromRegistry(hkey);
763 RegCloseKey(hkey);
766 AddApplicationsToList(hWndListView, hImageList);
767 UpdateButtons(hWnd);
769 return(hImageList);
772 /******************************************************************************
773 * Name : MainDlgProc
774 * Description: Callback procedure for main tab
775 * Parameters : hWnd - hWnd of the window
776 * msg - reason for calling function
777 * wParam - additional parameter
778 * lParam - additional parameter
779 * Returns : Depends on the message
781 static INT_PTR CALLBACK MainDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
783 int selitem;
784 static HIMAGELIST hImageList;
785 LPNMHDR nmh;
786 LVITEMW lvItem;
788 switch(msg)
790 case WM_INITDIALOG:
791 SendDlgItemMessageW(hWnd, IDL_PROGRAMS, LVM_SETEXTENDEDLISTVIEWSTYLE,
792 LVS_EX_FULLROWSELECT, LVS_EX_FULLROWSELECT);
794 hImageList = ResetApplicationList(TRUE, hWnd, hImageList);
796 if (!hImageList)
797 return FALSE;
799 return TRUE;
801 case WM_DESTROY:
802 RemoveItemsFromList(hWnd);
803 ImageList_Destroy(hImageList);
805 EmptyList();
807 return 0;
809 case WM_NOTIFY:
810 nmh = (LPNMHDR) lParam;
812 switch (nmh->idFrom)
814 case IDL_PROGRAMS:
815 switch (nmh->code)
817 case LVN_ITEMCHANGED:
818 UpdateButtons(hWnd);
819 break;
821 break;
824 return TRUE;
826 case WM_COMMAND:
827 switch (LOWORD(wParam))
829 case IDC_INSTALL:
830 InstallProgram(hWnd);
831 break;
833 case IDC_ADDREMOVE:
834 case IDC_MODIFY:
835 selitem = SendDlgItemMessageW(hWnd, IDL_PROGRAMS,
836 LVM_GETNEXTITEM, -1, LVNI_FOCUSED|LVNI_SELECTED);
838 if (selitem != -1)
840 lvItem.iItem = selitem;
841 lvItem.mask = LVIF_PARAM;
843 if (SendDlgItemMessageW(hWnd, IDL_PROGRAMS, LVM_GETITEMW,
844 0, (LPARAM) &lvItem))
845 UninstallProgram(lvItem.lParam, LOWORD(wParam));
848 hImageList = ResetApplicationList(FALSE, hWnd, hImageList);
850 break;
852 case IDC_SUPPORT_INFO:
853 selitem = SendDlgItemMessageW(hWnd, IDL_PROGRAMS,
854 LVM_GETNEXTITEM, -1, LVNI_FOCUSED | LVNI_SELECTED);
856 if (selitem != -1)
858 lvItem.iItem = selitem;
859 lvItem.mask = LVIF_PARAM;
861 if (SendDlgItemMessageW(hWnd, IDL_PROGRAMS, LVM_GETITEMW,
862 0, (LPARAM) &lvItem))
863 SupportInfo(hWnd, lvItem.lParam);
866 break;
869 return TRUE;
872 return FALSE;
875 static int CALLBACK propsheet_callback( HWND hwnd, UINT msg, LPARAM lparam )
877 switch (msg)
879 case PSCB_INITIALIZED:
880 SendMessageW( hwnd, WM_SETICON, ICON_BIG, (LPARAM)LoadIconW( hInst, MAKEINTRESOURCEW(ICO_MAIN) ));
881 break;
883 return 0;
886 /******************************************************************************
887 * Name : StartApplet
888 * Description: Main routine for applet
889 * Parameters : hWnd - hWnd of the Control Panel
891 static void StartApplet(HWND hWnd)
893 PROPSHEETPAGEW psp;
894 PROPSHEETHEADERW psh;
895 WCHAR tab_title[MAX_STRING_LEN], app_title[MAX_STRING_LEN];
897 /* Load the strings we will use */
898 LoadStringW(hInst, IDS_TAB1_TITLE, tab_title, ARRAY_SIZE(tab_title));
899 LoadStringW(hInst, IDS_CPL_TITLE, app_title, ARRAY_SIZE(app_title));
900 LoadStringW(hInst, IDS_REMOVE, btnRemove, ARRAY_SIZE(btnRemove));
901 LoadStringW(hInst, IDS_MODIFY_REMOVE, btnModifyRemove, ARRAY_SIZE(btnModifyRemove));
903 /* Fill out the PROPSHEETPAGE */
904 psp.dwSize = sizeof (PROPSHEETPAGEW);
905 psp.dwFlags = PSP_USETITLE;
906 psp.hInstance = hInst;
907 psp.u.pszTemplate = MAKEINTRESOURCEW (IDD_MAIN);
908 psp.u2.pszIcon = NULL;
909 psp.pfnDlgProc = MainDlgProc;
910 psp.pszTitle = tab_title;
911 psp.lParam = 0;
913 /* Fill out the PROPSHEETHEADER */
914 psh.dwSize = sizeof (PROPSHEETHEADERW);
915 psh.dwFlags = PSH_PROPSHEETPAGE | PSH_USEICONID | PSH_USECALLBACK;
916 psh.hwndParent = hWnd;
917 psh.hInstance = hInst;
918 psh.u.pszIcon = MAKEINTRESOURCEW(ICO_MAIN);
919 psh.pszCaption = app_title;
920 psh.nPages = 1;
921 psh.u3.ppsp = &psp;
922 psh.pfnCallback = propsheet_callback;
923 psh.u2.nStartPage = 0;
925 /* Display the property sheet */
926 PropertySheetW (&psh);
929 static LONG start_params(const WCHAR *params)
931 if(!params)
932 return FALSE;
934 if(!wcscmp(params, L"install_gecko")) {
935 install_addon(ADDON_GECKO);
936 return TRUE;
939 if(!wcscmp(params, L"install_mono")) {
940 install_addon(ADDON_MONO);
941 return TRUE;
944 WARN("unknown param %s\n", debugstr_w(params));
945 return FALSE;
948 /******************************************************************************
949 * Name : CPlApplet
950 * Description: Entry point for Control Panel applets
951 * Parameters : hwndCPL - hWnd of the Control Panel
952 * message - reason for calling function
953 * lParam1 - additional parameter
954 * lParam2 - additional parameter
955 * Returns : Depends on the message
957 LONG CALLBACK CPlApplet(HWND hwndCPL, UINT message, LPARAM lParam1, LPARAM lParam2)
959 INITCOMMONCONTROLSEX iccEx;
961 switch (message)
963 case CPL_INIT:
964 iccEx.dwSize = sizeof(iccEx);
965 iccEx.dwICC = ICC_LISTVIEW_CLASSES | ICC_TAB_CLASSES | ICC_LINK_CLASS;
967 InitCommonControlsEx(&iccEx);
969 return TRUE;
971 case CPL_GETCOUNT:
972 return 1;
974 case CPL_STARTWPARMSW:
975 return start_params((const WCHAR *)lParam2);
977 case CPL_INQUIRE:
979 CPLINFO *appletInfo = (CPLINFO *) lParam2;
981 appletInfo->idIcon = ICO_MAIN;
982 appletInfo->idName = IDS_CPL_TITLE;
983 appletInfo->idInfo = IDS_CPL_DESC;
984 appletInfo->lData = 0;
986 break;
989 case CPL_DBLCLK:
990 StartApplet(hwndCPL);
991 break;
994 return FALSE;