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 PathUninstallW
[] = L
"Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall";
85 /******************************************************************************
87 * Description: Entry point for DLL file
89 BOOL WINAPI
DllMain(HINSTANCE hinstDLL
, DWORD fdwReason
,
92 TRACE("(%p, %d, %p)\n", hinstDLL
, fdwReason
, lpvReserved
);
96 case DLL_PROCESS_ATTACH
:
103 /******************************************************************************
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
)
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
);
136 /******************************************************************************
137 * Name : ReadApplicationsFromRegistry
138 * Description: Creates a linked list of uninstallable applications from the
140 * Parameters : root - Which registry root to read from
141 * Returns : TRUE if successful, FALSE otherwise
143 static BOOL
ReadApplicationsFromRegistry(HKEY root
)
148 DWORD sizeOfSubKeyName
, displen
, uninstlen
;
149 DWORD dwNoModify
, dwType
, value
, size
;
150 WCHAR subKeyName
[256];
152 APPINFO
*info
= NULL
;
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
);
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
);
189 RegCloseKey(hkeyApp
);
190 sizeOfSubKeyName
= ARRAY_SIZE(subKeyName
);
194 info
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(struct APPINFO
));
197 info
->title
= HeapAlloc(GetProcessHeap(), 0, displen
);
202 RegQueryValueExW(hkeyApp
, L
"DisplayName", 0, 0, (BYTE
*)info
->title
, &displen
);
204 /* now get DisplayIcon */
206 RegQueryValueExW(hkeyApp
, L
"DisplayIcon", 0, 0, NULL
, &displen
);
212 info
->icon
= HeapAlloc(GetProcessHeap(), 0, displen
);
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
, ',');
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 */
241 displen
= sizeof(DWORD
);
243 if (RegQueryValueExW(hkeyApp
, L
"NoModify", NULL
, &dwType
, (BYTE
*)&dwNoModify
, &displen
)
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 */
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
);
273 RegOpenKeyExW(root
, NULL
, 0, KEY_READ
, &info
->regroot
);
274 lstrcpyW(info
->regkey
, subKeyName
);
275 info
->path
= command
;
278 list_add_tail( &app_list
, &info
->entry
);
281 RegCloseKey(hkeyApp
);
282 sizeOfSubKeyName
= ARRAY_SIZE(subKeyName
);
287 RegCloseKey(hkeyApp
);
288 if (info
) FreeAppInfo(info
);
289 HeapFree(GetProcessHeap(), 0, command
);
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
)
306 LIST_FOR_EACH_ENTRY( iter
, &app_list
, APPINFO
, entry
)
308 if (!iter
->title
[0]) continue;
315 if (ExtractIconExW(iter
->icon
, iter
->iconIdx
, NULL
, &hIcon
, 1) == 1)
317 index
= ImageList_AddIcon(hList
, hIcon
);
322 lvItem
.mask
= LVIF_IMAGE
| LVIF_TEXT
| LVIF_PARAM
;
323 lvItem
.iItem
= iter
->id
;
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 /******************************************************************************
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
);
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
)
371 LRESULT selitem
= SendDlgItemMessageW(hWnd
, IDL_PROGRAMS
, LVM_GETNEXTITEM
, -1,
372 LVNI_FOCUSED
| LVNI_SELECTED
);
373 BOOL enable_modify
= FALSE
;
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
);
393 SetWindowTextW(GetDlgItem(hWnd
, IDC_ADDREMOVE
), btnRemove
);
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
)
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
;
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
)
467 PROCESS_INFORMATION info
;
468 WCHAR errormsg
[MAX_STRING_LEN
];
469 WCHAR sUninstallFailed
[MAX_STRING_LEN
];
472 LoadStringW(hInst
, IDS_UNINSTALL_FAILED
, sUninstallFailed
,
473 ARRAY_SIZE(sUninstallFailed
));
475 LIST_FOR_EACH_ENTRY( iter
, &app_list
, APPINFO
, entry
)
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
);
491 CloseHandle(info
.hThread
);
493 /* wait for the process to exit */
494 WaitForSingleObject(info
.hProcess
, INFINITE
);
495 CloseHandle(info
.hProcess
);
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
);
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
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
];
533 hWndDlgItem
= GetDlgItem(hWnd
, iDlgItem
);
535 /* if hKey is null, lpKeyName contains the string we want to check */
538 if (lpKeyName
&& lpKeyName
[0])
539 SetWindowTextW(hWndDlgItem
, lpKeyName
);
541 SetWindowTextW(hWndDlgItem
, lpAltMessage
);
545 buflen
= MAX_STRING_LEN
;
547 if ((RegQueryValueExW(hKey
, lpKeyName
, 0, 0, (LPBYTE
) buf
, &buflen
) ==
548 ERROR_SUCCESS
) && buf
[0])
549 SetWindowTextW(hWndDlgItem
, buf
);
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
)
568 WCHAR oldtitle
[MAX_STRING_LEN
];
569 WCHAR buf
[MAX_STRING_LEN
];
570 WCHAR key
[MAX_STRING_LEN
];
571 WCHAR notfound
[MAX_STRING_LEN
];
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
);
619 switch (LOWORD(wParam
))
622 EndDialog(hWnd
, TRUE
);
633 /******************************************************************************
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
{
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
];
669 lvc
.mask
= LVCF_FMT
| LVCF_TEXT
| LVCF_SUBITEM
| LVCF_WIDTH
;
671 /* Add the columns */
672 for (i
= 0; i
< ARRAY_SIZE(columns
); i
++)
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)
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
)
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
);
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);
728 hWndListView
= GetDlgItem(hWnd
, IDL_PROGRAMS
);
730 /* if first run, create the image list and add the listview columns */
733 if (!AddListViewColumns(hWndListView
))
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
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
);
755 !RegOpenKeyExW(HKEY_LOCAL_MACHINE
, PathUninstallW
, 0, KEY_READ
|KEY_WOW64_32KEY
, &hkey
))
757 ReadApplicationsFromRegistry(hkey
);
760 if (!RegOpenKeyExW(HKEY_CURRENT_USER
, PathUninstallW
, 0, KEY_READ
, &hkey
))
762 ReadApplicationsFromRegistry(hkey
);
766 AddApplicationsToList(hWndListView
, hImageList
);
772 /******************************************************************************
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
)
784 static HIMAGELIST hImageList
;
791 SendDlgItemMessageW(hWnd
, IDL_PROGRAMS
, LVM_SETEXTENDEDLISTVIEWSTYLE
,
792 LVS_EX_FULLROWSELECT
, LVS_EX_FULLROWSELECT
);
794 hImageList
= ResetApplicationList(TRUE
, hWnd
, hImageList
);
802 RemoveItemsFromList(hWnd
);
803 ImageList_Destroy(hImageList
);
810 nmh
= (LPNMHDR
) lParam
;
817 case LVN_ITEMCHANGED
:
827 switch (LOWORD(wParam
))
830 InstallProgram(hWnd
);
835 selitem
= SendDlgItemMessageW(hWnd
, IDL_PROGRAMS
,
836 LVM_GETNEXTITEM
, -1, LVNI_FOCUSED
|LVNI_SELECTED
);
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
);
852 case IDC_SUPPORT_INFO
:
853 selitem
= SendDlgItemMessageW(hWnd
, IDL_PROGRAMS
,
854 LVM_GETNEXTITEM
, -1, LVNI_FOCUSED
| LVNI_SELECTED
);
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
);
875 static int CALLBACK
propsheet_callback( HWND hwnd
, UINT msg
, LPARAM lparam
)
879 case PSCB_INITIALIZED
:
880 SendMessageW( hwnd
, WM_SETICON
, ICON_BIG
, (LPARAM
)LoadIconW( hInst
, MAKEINTRESOURCEW(ICO_MAIN
) ));
886 /******************************************************************************
888 * Description: Main routine for applet
889 * Parameters : hWnd - hWnd of the Control Panel
891 static void StartApplet(HWND hWnd
)
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
;
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
;
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
)
934 if(!wcscmp(params
, L
"install_gecko")) {
935 install_addon(ADDON_GECKO
);
939 if(!wcscmp(params
, L
"install_mono")) {
940 install_addon(ADDON_MONO
);
944 WARN("unknown param %s\n", debugstr_w(params
));
948 /******************************************************************************
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
;
964 iccEx
.dwSize
= sizeof(iccEx
);
965 iccEx
.dwICC
= ICC_LISTVIEW_CLASSES
| ICC_TAB_CLASSES
| ICC_LINK_CLASS
;
967 InitCommonControlsEx(&iccEx
);
974 case CPL_STARTWPARMSW
:
975 return start_params((const WCHAR
*)lParam2
);
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;
990 StartApplet(hwndCPL
);