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
42 #include "wine/list.h"
43 #include "wine/debug.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
74 WCHAR regkey
[MAX_STRING_LEN
];
77 static struct list app_list
= LIST_INIT( app_list
);
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 /******************************************************************************
112 * Description: Entry point for DLL file
114 BOOL WINAPI
DllMain(HINSTANCE hinstDLL
, DWORD fdwReason
,
117 TRACE("(%p, %d, %p)\n", hinstDLL
, fdwReason
, lpvReserved
);
121 case DLL_PROCESS_ATTACH
:
128 /******************************************************************************
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
)
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
);
161 /******************************************************************************
162 * Name : ReadApplicationsFromRegistry
163 * Description: Creates a linked list of uninstallable applications from the
165 * Parameters : root - Which registry root to read from
166 * Returns : TRUE if successful, FALSE otherwise
168 static BOOL
ReadApplicationsFromRegistry(HKEY root
)
173 DWORD sizeOfSubKeyName
, displen
, uninstlen
;
174 DWORD dwNoModify
, dwType
, value
, size
;
175 WCHAR subKeyName
[256];
177 APPINFO
*info
= NULL
;
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
);
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
);
215 RegCloseKey(hkeyApp
);
216 sizeOfSubKeyName
= ARRAY_SIZE(subKeyName
);
220 info
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(struct APPINFO
));
223 info
->title
= HeapAlloc(GetProcessHeap(), 0, displen
);
228 RegQueryValueExW(hkeyApp
, DisplayNameW
, 0, 0, (LPBYTE
)info
->title
,
231 /* now get DisplayIcon */
233 RegQueryValueExW(hkeyApp
, DisplayIconW
, 0, 0, NULL
, &displen
);
239 info
->icon
= HeapAlloc(GetProcessHeap(), 0, displen
);
244 RegQueryValueExW(hkeyApp
, DisplayIconW
, 0, 0, (LPBYTE
)info
->icon
,
247 /* separate the index from the icon name, if supplied */
248 iconPtr
= wcschr(info
->icon
, ',');
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 */
269 displen
= sizeof(DWORD
);
271 if (RegQueryValueExW(hkeyApp
, NoModifyW
, NULL
, &dwType
, (LPBYTE
)&dwNoModify
, &displen
)
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 */
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
);
302 RegOpenKeyExW(root
, NULL
, 0, KEY_READ
, &info
->regroot
);
303 lstrcpyW(info
->regkey
, subKeyName
);
304 info
->path
= command
;
307 list_add_tail( &app_list
, &info
->entry
);
310 RegCloseKey(hkeyApp
);
311 sizeOfSubKeyName
= ARRAY_SIZE(subKeyName
);
316 RegCloseKey(hkeyApp
);
317 if (info
) FreeAppInfo(info
);
318 HeapFree(GetProcessHeap(), 0, command
);
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
)
335 LIST_FOR_EACH_ENTRY( iter
, &app_list
, APPINFO
, entry
)
337 if (!iter
->title
[0]) continue;
344 if (ExtractIconExW(iter
->icon
, iter
->iconIdx
, NULL
, &hIcon
, 1) == 1)
346 index
= ImageList_AddIcon(hList
, hIcon
);
351 lvItem
.mask
= LVIF_IMAGE
| LVIF_TEXT
| LVIF_PARAM
;
352 lvItem
.iItem
= iter
->id
;
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 /******************************************************************************
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
);
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
)
400 LRESULT selitem
= SendDlgItemMessageW(hWnd
, IDL_PROGRAMS
, LVM_GETNEXTITEM
, -1,
401 LVNI_FOCUSED
| LVNI_SELECTED
);
402 BOOL enable_modify
= FALSE
;
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
);
422 SetWindowTextW(GetDlgItem(hWnd
, IDC_ADDREMOVE
), btnRemove
);
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}
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
);
480 sei
.nShow
= SW_SHOWDEFAULT
;
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
)
498 PROCESS_INFORMATION info
;
499 WCHAR errormsg
[MAX_STRING_LEN
];
500 WCHAR sUninstallFailed
[MAX_STRING_LEN
];
503 LoadStringW(hInst
, IDS_UNINSTALL_FAILED
, sUninstallFailed
,
504 ARRAY_SIZE(sUninstallFailed
));
506 LIST_FOR_EACH_ENTRY( iter
, &app_list
, APPINFO
, entry
)
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
);
522 CloseHandle(info
.hThread
);
524 /* wait for the process to exit */
525 WaitForSingleObject(info
.hProcess
, INFINITE
);
526 CloseHandle(info
.hProcess
);
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
);
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
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
];
564 hWndDlgItem
= GetDlgItem(hWnd
, iDlgItem
);
566 /* if hKey is null, lpKeyName contains the string we want to check */
569 if (lpKeyName
&& lpKeyName
[0])
570 SetWindowTextW(hWndDlgItem
, lpKeyName
);
572 SetWindowTextW(hWndDlgItem
, lpAltMessage
);
576 buflen
= MAX_STRING_LEN
;
578 if ((RegQueryValueExW(hKey
, lpKeyName
, 0, 0, (LPBYTE
) buf
, &buflen
) ==
579 ERROR_SUCCESS
) && buf
[0])
580 SetWindowTextW(hWndDlgItem
, buf
);
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
)
599 WCHAR oldtitle
[MAX_STRING_LEN
];
600 WCHAR buf
[MAX_STRING_LEN
];
601 WCHAR key
[MAX_STRING_LEN
];
602 WCHAR notfound
[MAX_STRING_LEN
];
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
);
650 switch (LOWORD(wParam
))
653 EndDialog(hWnd
, TRUE
);
664 /******************************************************************************
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
{
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
];
700 lvc
.mask
= LVCF_FMT
| LVCF_TEXT
| LVCF_SUBITEM
| LVCF_WIDTH
;
702 /* Add the columns */
703 for (i
= 0; i
< ARRAY_SIZE(columns
); i
++)
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)
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
)
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
);
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);
759 hWndListView
= GetDlgItem(hWnd
, IDL_PROGRAMS
);
761 /* if first run, create the image list and add the listview columns */
764 if (!AddListViewColumns(hWndListView
))
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
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
);
786 !RegOpenKeyExW(HKEY_LOCAL_MACHINE
, PathUninstallW
, 0, KEY_READ
|KEY_WOW64_32KEY
, &hkey
))
788 ReadApplicationsFromRegistry(hkey
);
791 if (!RegOpenKeyExW(HKEY_CURRENT_USER
, PathUninstallW
, 0, KEY_READ
, &hkey
))
793 ReadApplicationsFromRegistry(hkey
);
797 AddApplicationsToList(hWndListView
, hImageList
);
803 /******************************************************************************
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
)
815 static HIMAGELIST hImageList
;
822 SendDlgItemMessageW(hWnd
, IDL_PROGRAMS
, LVM_SETEXTENDEDLISTVIEWSTYLE
,
823 LVS_EX_FULLROWSELECT
, LVS_EX_FULLROWSELECT
);
825 hImageList
= ResetApplicationList(TRUE
, hWnd
, hImageList
);
833 RemoveItemsFromList(hWnd
);
834 ImageList_Destroy(hImageList
);
841 nmh
= (LPNMHDR
) lParam
;
848 case LVN_ITEMCHANGED
:
858 switch (LOWORD(wParam
))
861 InstallProgram(hWnd
);
866 selitem
= SendDlgItemMessageW(hWnd
, IDL_PROGRAMS
,
867 LVM_GETNEXTITEM
, -1, LVNI_FOCUSED
|LVNI_SELECTED
);
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
);
883 case IDC_SUPPORT_INFO
:
884 selitem
= SendDlgItemMessageW(hWnd
, IDL_PROGRAMS
,
885 LVM_GETNEXTITEM
, -1, LVNI_FOCUSED
| LVNI_SELECTED
);
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
);
906 static int CALLBACK
propsheet_callback( HWND hwnd
, UINT msg
, LPARAM lparam
)
910 case PSCB_INITIALIZED
:
911 SendMessageW( hwnd
, WM_SETICON
, ICON_BIG
, (LPARAM
)LoadIconW( hInst
, MAKEINTRESOURCEW(ICO_MAIN
) ));
917 /******************************************************************************
919 * Description: Main routine for applet
920 * Parameters : hWnd - hWnd of the Control Panel
922 static void StartApplet(HWND hWnd
)
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
;
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
;
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};
968 if(!wcscmp(params
, install_geckoW
)) {
969 install_addon(ADDON_GECKO
);
973 if(!wcscmp(params
, install_monoW
)) {
974 install_addon(ADDON_MONO
);
978 WARN("unknown param %s\n", debugstr_w(params
));
982 /******************************************************************************
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
;
998 iccEx
.dwSize
= sizeof(iccEx
);
999 iccEx
.dwICC
= ICC_LISTVIEW_CLASSES
| ICC_TAB_CLASSES
| ICC_LINK_CLASS
;
1001 InitCommonControlsEx(&iccEx
);
1008 case CPL_STARTWPARMSW
:
1009 return start_params((const WCHAR
*)lParam2
);
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;
1024 StartApplet(hwndCPL
);