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
29 #include "wine/port.h"
30 #include "wine/unicode.h"
31 #include "wine/debug.h"
49 WINE_DEFAULT_DEBUG_CHANNEL(appwizcpl
);
51 /* define a maximum length for various buffers we use */
52 #define MAX_STRING_LEN 1024
54 typedef struct APPINFO
{
68 WCHAR regkey
[MAX_STRING_LEN
];
73 static struct APPINFO
*AppInfo
= NULL
;
74 static HINSTANCE hInst
;
76 static WCHAR btnRemove
[MAX_STRING_LEN
];
77 static WCHAR btnModifyRemove
[MAX_STRING_LEN
];
79 static const WCHAR openW
[] = {'o','p','e','n',0};
81 /* names of registry keys */
82 static const WCHAR BackSlashW
[] = { '\\', 0 };
83 static const WCHAR DisplayNameW
[] = {'D','i','s','p','l','a','y','N','a','m','e',0};
84 static const WCHAR DisplayIconW
[] = {'D','i','s','p','l','a','y','I','c','o','n',0};
85 static const WCHAR DisplayVersionW
[] = {'D','i','s','p','l','a','y','V','e','r',
87 static const WCHAR PublisherW
[] = {'P','u','b','l','i','s','h','e','r',0};
88 static const WCHAR ContactW
[] = {'C','o','n','t','a','c','t',0};
89 static const WCHAR HelpLinkW
[] = {'H','e','l','p','L','i','n','k',0};
90 static const WCHAR HelpTelephoneW
[] = {'H','e','l','p','T','e','l','e','p','h',
92 static const WCHAR ModifyPathW
[] = {'M','o','d','i','f','y','P','a','t','h',0};
93 static const WCHAR NoModifyW
[] = {'N','o','M','o','d','i','f','y',0};
94 static const WCHAR ReadmeW
[] = {'R','e','a','d','m','e',0};
95 static const WCHAR URLUpdateInfoW
[] = {'U','R','L','U','p','d','a','t','e','I',
97 static const WCHAR CommentsW
[] = {'C','o','m','m','e','n','t','s',0};
98 static const WCHAR UninstallCommandlineW
[] = {'U','n','i','n','s','t','a','l','l',
99 'S','t','r','i','n','g',0};
101 static const WCHAR PathUninstallW
[] = {
102 'S','o','f','t','w','a','r','e','\\',
103 'M','i','c','r','o','s','o','f','t','\\',
104 'W','i','n','d','o','w','s','\\',
105 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
106 'U','n','i','n','s','t','a','l','l',0 };
108 /******************************************************************************
110 * Description: Entry point for DLL file
112 BOOL WINAPI
DllMain(HINSTANCE hinstDLL
, DWORD fdwReason
,
115 TRACE("(%p, %d, %p)\n", hinstDLL
, fdwReason
, lpvReserved
);
119 case DLL_PROCESS_ATTACH
:
126 /******************************************************************************
128 * Description: Frees memory used by an AppInfo structure, and any children.
130 static void FreeAppInfo(APPINFO
*info
)
134 APPINFO
*next_info
= info
->next
;
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
);
147 /******************************************************************************
148 * Name : ReadApplicationsFromRegistry
149 * Description: Creates a linked list of uninstallable applications from the
151 * Parameters : root - Which registry root to read from (HKCU/HKLM)
152 * Returns : TRUE if successful, FALSE otherwise
154 static BOOL
ReadApplicationsFromRegistry(HKEY root
)
156 HKEY hkeyUninst
, hkeyApp
;
158 DWORD sizeOfSubKeyName
, displen
, uninstlen
;
159 DWORD dwNoModify
, dwType
;
160 WCHAR subKeyName
[256];
161 WCHAR key_app
[MAX_STRING_LEN
];
163 APPINFO
*iter
= AppInfo
;
167 if (RegOpenKeyExW(root
, PathUninstallW
, 0, KEY_READ
, &hkeyUninst
) !=
171 lstrcpyW(key_app
, PathUninstallW
);
172 lstrcatW(key_app
, BackSlashW
);
173 p
= key_app
+lstrlenW(PathUninstallW
)+1;
175 sizeOfSubKeyName
= sizeof(subKeyName
) / sizeof(subKeyName
[0]);
179 /* find the end of the list */
180 for (iter
= AppInfo
; iter
->next
; iter
= iter
->next
);
183 for (i
= 0; RegEnumKeyExW(hkeyUninst
, i
, subKeyName
, &sizeOfSubKeyName
, NULL
,
184 NULL
, NULL
, NULL
) != ERROR_NO_MORE_ITEMS
; ++i
)
186 lstrcpyW(p
, subKeyName
);
187 RegOpenKeyExW(root
, key_app
, 0, KEY_READ
, &hkeyApp
);
192 if ((RegQueryValueExW(hkeyApp
, DisplayNameW
, 0, 0, NULL
, &displen
) ==
193 ERROR_SUCCESS
) && (RegQueryValueExW(hkeyApp
, UninstallCommandlineW
,
194 0, 0, NULL
, &uninstlen
) == ERROR_SUCCESS
))
196 /* if we already have iter, allocate the next entry */
199 iter
->next
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
,
200 sizeof(struct APPINFO
));
209 /* if not, start the list */
210 iter
= AppInfo
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
,
211 sizeof(struct APPINFO
));
217 iter
->title
= HeapAlloc(GetProcessHeap(), 0, displen
);
222 RegQueryValueExW(hkeyApp
, DisplayNameW
, 0, 0, (LPBYTE
)iter
->title
,
225 /* now get DisplayIcon */
227 RegQueryValueExW(hkeyApp
, DisplayIconW
, 0, 0, NULL
, &displen
);
233 iter
->icon
= HeapAlloc(GetProcessHeap(), 0, displen
);
238 RegQueryValueExW(hkeyApp
, DisplayIconW
, 0, 0, (LPBYTE
)iter
->icon
,
241 /* separate the index from the icon name, if supplied */
242 iconPtr
= strchrW(iter
->icon
, ',');
247 iter
->iconIdx
= atoiW(iconPtr
);
251 iter
->path
= HeapAlloc(GetProcessHeap(), 0, uninstlen
);
256 RegQueryValueExW(hkeyApp
, UninstallCommandlineW
, 0, 0,
257 (LPBYTE
)iter
->path
, &uninstlen
);
259 /* publisher, version */
260 if (RegQueryValueExW(hkeyApp
, PublisherW
, 0, 0, NULL
, &displen
) ==
263 iter
->publisher
= HeapAlloc(GetProcessHeap(), 0, displen
);
265 if (!iter
->publisher
)
268 RegQueryValueExW(hkeyApp
, PublisherW
, 0, 0, (LPBYTE
)iter
->publisher
,
272 if (RegQueryValueExW(hkeyApp
, DisplayVersionW
, 0, 0, NULL
, &displen
) ==
275 iter
->version
= HeapAlloc(GetProcessHeap(), 0, displen
);
280 RegQueryValueExW(hkeyApp
, DisplayVersionW
, 0, 0, (LPBYTE
)iter
->version
,
284 /* Check if NoModify is set */
287 displen
= sizeof(DWORD
);
289 if (RegQueryValueExW(hkeyApp
, NoModifyW
, NULL
, &dwType
, (LPBYTE
)&dwNoModify
, &displen
)
295 /* Some installers incorrectly create a REG_SZ instead of a REG_DWORD - check for
296 ASCII 49, which equals 1 */
297 if (dwType
== REG_SZ
)
298 dwNoModify
= (dwNoModify
== 49) ? 1 : 0;
300 /* Fetch the modify path */
301 if ((dwNoModify
== 0) && (RegQueryValueExW(hkeyApp
, ModifyPathW
, 0, 0, NULL
, &displen
)
304 iter
->path_modify
= HeapAlloc(GetProcessHeap(), 0, displen
);
306 if (!iter
->path_modify
)
309 RegQueryValueExW(hkeyApp
, ModifyPathW
, 0, 0, (LPBYTE
)iter
->path_modify
, &displen
);
313 iter
->regroot
= root
;
314 lstrcpyW(iter
->regkey
, subKeyName
);
319 RegCloseKey(hkeyApp
);
320 sizeOfSubKeyName
= sizeof(subKeyName
) / sizeof(subKeyName
[0]);
327 RegCloseKey(hkeyApp
);
331 RegCloseKey(hkeyUninst
);
336 /******************************************************************************
337 * Name : AddApplicationsToList
338 * Description: Populates the list box with applications.
339 * Parameters : hWnd - Handle of the dialog box
341 static void AddApplicationsToList(HWND hWnd
, HIMAGELIST hList
)
348 for (iter
= AppInfo
; iter
; iter
= iter
->next
)
350 if (!iter
->title
[0]) continue;
357 if (ExtractIconExW(iter
->icon
, iter
->iconIdx
, NULL
, &hIcon
, 1) == 1)
359 index
= ImageList_AddIcon(hList
, hIcon
);
364 lvItem
.mask
= LVIF_IMAGE
| LVIF_TEXT
| LVIF_PARAM
;
365 lvItem
.iItem
= iter
->id
;
367 lvItem
.pszText
= iter
->title
;
368 lvItem
.iImage
= index
;
369 lvItem
.lParam
= iter
->id
;
371 index
= ListView_InsertItemW(hWnd
, &lvItem
);
373 /* now add the subitems (columns) */
374 ListView_SetItemTextW(hWnd
, index
, 1, iter
->publisher
);
375 ListView_SetItemTextW(hWnd
, index
, 2, iter
->version
);
379 /******************************************************************************
380 * Name : RemoveItemsFromList
381 * Description: Clears the application list box.
382 * Parameters : hWnd - Handle of the dialog box
384 static void RemoveItemsFromList(HWND hWnd
)
386 SendDlgItemMessageW(hWnd
, IDL_PROGRAMS
, LVM_DELETEALLITEMS
, 0, 0);
389 /******************************************************************************
391 * Description: Frees memory used by the application linked list.
393 static inline void EmptyList(void)
395 FreeAppInfo(AppInfo
);
399 /******************************************************************************
400 * Name : UpdateButtons
401 * Description: Enables/disables the Add/Remove button depending on current
402 * selection in list box.
403 * Parameters : hWnd - Handle of the dialog box
405 static void UpdateButtons(HWND hWnd
)
409 LRESULT selitem
= SendDlgItemMessageW(hWnd
, IDL_PROGRAMS
, LVM_GETNEXTITEM
, -1,
410 LVNI_FOCUSED
| LVNI_SELECTED
);
411 BOOL enable_modify
= FALSE
;
415 lvItem
.iItem
= selitem
;
416 lvItem
.mask
= LVIF_PARAM
;
418 if (SendDlgItemMessageW(hWnd
, IDL_PROGRAMS
, LVM_GETITEMW
, 0, (LPARAM
) &lvItem
))
420 for (iter
= AppInfo
; iter
; iter
= iter
->next
)
422 if (iter
->id
== lvItem
.lParam
)
424 /* Decide whether to display Modify/Remove as one button or two */
425 enable_modify
= (iter
->path_modify
!= NULL
);
427 /* Update title as appropriate */
428 if (iter
->path_modify
== NULL
)
429 SetWindowTextW(GetDlgItem(hWnd
, IDC_ADDREMOVE
), btnModifyRemove
);
431 SetWindowTextW(GetDlgItem(hWnd
, IDC_ADDREMOVE
), btnRemove
);
439 /* Enable/disable other buttons if necessary */
440 EnableWindow(GetDlgItem(hWnd
, IDC_ADDREMOVE
), (selitem
!= -1));
441 EnableWindow(GetDlgItem(hWnd
, IDC_SUPPORT_INFO
), (selitem
!= -1));
442 EnableWindow(GetDlgItem(hWnd
, IDC_MODIFY
), enable_modify
);
445 /******************************************************************************
446 * Name : InstallProgram
447 * Description: Search for potential Installer and execute it.
448 * Parameters : hWnd - Handle of the dialog box
450 static void InstallProgram(HWND hWnd
)
453 WCHAR titleW
[MAX_STRING_LEN
];
454 WCHAR FilterBufferW
[MAX_STRING_LEN
];
455 WCHAR FileNameBufferW
[MAX_PATH
];
457 LoadStringW(hInst
, IDS_CPL_TITLE
, titleW
, sizeof(titleW
)/sizeof(WCHAR
));
458 LoadStringW(hInst
, IDS_INSTALL_FILTER
, FilterBufferW
, sizeof(FilterBufferW
)/sizeof(WCHAR
));
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
;
481 sei
.fMask
= SEE_MASK_NO_CONSOLE
;
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
];
504 LoadStringW(hInst
, IDS_UNINSTALL_FAILED
, sUninstallFailed
,
505 sizeof(sUninstallFailed
) / sizeof(sUninstallFailed
[0]));
507 for (iter
= AppInfo
; iter
; iter
= iter
->next
)
511 TRACE("Uninstalling %s (%s)\n", wine_dbgstr_w(iter
->title
),
512 wine_dbgstr_w(iter
->path
));
514 memset(&si
, 0, sizeof(STARTUPINFOW
));
515 si
.cb
= sizeof(STARTUPINFOW
);
516 si
.wShowWindow
= SW_NORMAL
;
518 res
= CreateProcessW(NULL
, (button
== IDC_MODIFY
) ? iter
->path_modify
: iter
->path
,
519 NULL
, NULL
, FALSE
, 0, NULL
, NULL
, &si
, &info
);
523 CloseHandle(info
.hThread
);
525 /* wait for the process to exit */
526 WaitForSingleObject(info
.hProcess
, INFINITE
);
527 CloseHandle(info
.hProcess
);
531 wsprintfW(errormsg
, sUninstallFailed
, iter
->path
);
533 if (MessageBoxW(0, errormsg
, iter
->title
, MB_YESNO
|
534 MB_ICONQUESTION
) == IDYES
)
536 /* delete the application's uninstall entry */
537 RegOpenKeyExW(iter
->regroot
, PathUninstallW
, 0, KEY_READ
, &hkey
);
538 RegDeleteKeyW(hkey
, iter
->regkey
);
548 /**********************************************************************************
549 * Name : SetInfoDialogText
550 * Description: Sets the text of a label in a window, based upon a registry entry
551 * or string passed to the function.
552 * Parameters : hKey - registry entry to read from, NULL if not reading
554 * lpKeyName - key to read from, or string to check if hKey is NULL
555 * lpAltMessage - alternative message if entry not found
556 * hWnd - handle of dialog box
557 * iDlgItem - ID of label in dialog box
559 static void SetInfoDialogText(HKEY hKey
, LPCWSTR lpKeyName
, LPCWSTR lpAltMessage
,
560 HWND hWnd
, int iDlgItem
)
562 WCHAR buf
[MAX_STRING_LEN
];
566 hWndDlgItem
= GetDlgItem(hWnd
, iDlgItem
);
568 /* if hKey is null, lpKeyName contains the string we want to check */
571 if ((lpKeyName
) && (lstrlenW(lpKeyName
) > 0))
572 SetWindowTextW(hWndDlgItem
, lpKeyName
);
574 SetWindowTextW(hWndDlgItem
, lpAltMessage
);
578 buflen
= MAX_STRING_LEN
;
580 if ((RegQueryValueExW(hKey
, lpKeyName
, 0, 0, (LPBYTE
) buf
, &buflen
) ==
581 ERROR_SUCCESS
) && (lstrlenW(buf
) > 0))
582 SetWindowTextW(hWndDlgItem
, buf
);
584 SetWindowTextW(hWndDlgItem
, lpAltMessage
);
588 /******************************************************************************
589 * Name : SupportInfoDlgProc
590 * Description: Callback procedure for support info dialog
591 * Parameters : hWnd - hWnd of the window
592 * msg - reason for calling function
593 * wParam - additional parameter
594 * lParam - additional parameter
595 * Returns : Dependant on message
597 static BOOL CALLBACK
SupportInfoDlgProc(HWND hWnd
, UINT msg
, WPARAM wParam
, LPARAM lParam
)
601 WCHAR oldtitle
[MAX_STRING_LEN
];
602 WCHAR buf
[MAX_STRING_LEN
];
603 WCHAR key
[MAX_STRING_LEN
];
604 WCHAR notfound
[MAX_STRING_LEN
];
609 for (iter
= AppInfo
; iter
; iter
= iter
->next
)
611 if (iter
->id
== (int) lParam
)
613 lstrcpyW(key
, PathUninstallW
);
614 lstrcatW(key
, BackSlashW
);
615 lstrcatW(key
, iter
->regkey
);
617 /* check the application's registry entries */
618 RegOpenKeyExW(iter
->regroot
, key
, 0, KEY_READ
, &hkey
);
620 /* Load our "not specified" string */
621 LoadStringW(hInst
, IDS_NOT_SPECIFIED
, notfound
,
622 sizeof(notfound
) / sizeof(notfound
[0]));
624 /* Update the data for items already read into the structure */
625 SetInfoDialogText(NULL
, iter
->publisher
, notfound
, hWnd
,
627 SetInfoDialogText(NULL
, iter
->version
, notfound
, hWnd
,
630 /* And now update the data for those items in the registry */
631 SetInfoDialogText(hkey
, ContactW
, notfound
, hWnd
,
633 SetInfoDialogText(hkey
, HelpLinkW
, notfound
, hWnd
,
635 SetInfoDialogText(hkey
, HelpTelephoneW
, notfound
, hWnd
,
637 SetInfoDialogText(hkey
, ReadmeW
, notfound
, hWnd
,
639 SetInfoDialogText(hkey
, URLUpdateInfoW
, notfound
, hWnd
,
641 SetInfoDialogText(hkey
, CommentsW
, notfound
, hWnd
,
644 /* Update the main label with the app name */
645 if (GetWindowTextW(GetDlgItem(hWnd
, IDC_INFO_LABEL
), oldtitle
,
646 MAX_STRING_LEN
) != 0)
648 wsprintfW(buf
, oldtitle
, iter
->title
);
649 SetWindowTextW(GetDlgItem(hWnd
, IDC_INFO_LABEL
), buf
);
664 switch (LOWORD(wParam
))
667 EndDialog(hWnd
, TRUE
);
678 /******************************************************************************
680 * Description: Displays the Support Information dialog
681 * Parameters : hWnd - Handle of the main dialog
682 * id - ID of the application to display information for
684 static void SupportInfo(HWND hWnd
, int id
)
686 DialogBoxParamW(hInst
, MAKEINTRESOURCEW(IDD_INFO
), hWnd
, (DLGPROC
)
687 SupportInfoDlgProc
, (LPARAM
) id
);
690 /* Definition of column headers for AddListViewColumns function */
691 typedef struct AppWizColumn
{
697 static const AppWizColumn columns
[] = {
698 {200, LVCFMT_LEFT
, IDS_COLUMN_NAME
},
699 {150, LVCFMT_LEFT
, IDS_COLUMN_PUBLISHER
},
700 {100, LVCFMT_LEFT
, IDS_COLUMN_VERSION
},
703 /******************************************************************************
704 * Name : AddListViewColumns
705 * Description: Adds column headers to the list view control.
706 * Parameters : hWnd - Handle of the list view control.
707 * Returns : TRUE if completed successfully, FALSE otherwise.
709 static BOOL
AddListViewColumns(HWND hWnd
)
711 WCHAR buf
[MAX_STRING_LEN
];
715 lvc
.mask
= LVCF_FMT
| LVCF_TEXT
| LVCF_SUBITEM
| LVCF_WIDTH
;
717 /* Add the columns */
718 for (i
= 0; i
< sizeof(columns
) / sizeof(columns
[0]); i
++)
723 /* set width and format */
724 lvc
.cx
= columns
[i
].width
;
725 lvc
.fmt
= columns
[i
].fmt
;
727 LoadStringW(hInst
, columns
[i
].title
, buf
, sizeof(buf
) / sizeof(buf
[0]));
729 if (ListView_InsertColumnW(hWnd
, i
, &lvc
) == -1)
736 /******************************************************************************
737 * Name : AddListViewImageList
738 * Description: Creates an ImageList for the list view control.
739 * Parameters : hWnd - Handle of the list view control.
740 * Returns : Handle of the image list.
742 static HIMAGELIST
AddListViewImageList(HWND hWnd
)
747 hSmall
= ImageList_Create(GetSystemMetrics(SM_CXSMICON
), GetSystemMetrics(SM_CYSMICON
),
748 ILC_COLOR32
| ILC_MASK
, 1, 1);
750 /* Add default icon to image list */
751 hDefaultIcon
= LoadIconW(hInst
, MAKEINTRESOURCEW(ICO_MAIN
));
752 ImageList_AddIcon(hSmall
, hDefaultIcon
);
753 DestroyIcon(hDefaultIcon
);
755 SendMessageW(hWnd
, LVM_SETIMAGELIST
, LVSIL_SMALL
, (LPARAM
)hSmall
);
760 /******************************************************************************
761 * Name : ResetApplicationList
762 * Description: Empties the app list, if need be, and recreates it.
763 * Parameters : bFirstRun - TRUE if this is the first time this is run, FALSE otherwise
764 * hWnd - handle of the dialog box
765 * hImageList - handle of the image list
766 * Returns : New handle of the image list.
768 static HIMAGELIST
ResetApplicationList(BOOL bFirstRun
, HWND hWnd
, HIMAGELIST hImageList
)
772 hWndListView
= GetDlgItem(hWnd
, IDL_PROGRAMS
);
774 /* if first run, create the image list and add the listview columns */
777 if (!AddListViewColumns(hWndListView
))
780 else /* we need to remove the existing things first */
782 RemoveItemsFromList(hWnd
);
783 ImageList_Destroy(hImageList
);
785 /* reset the list, since it's probably changed if the uninstallation was
790 /* now create the image list and add the applications to the listview */
791 hImageList
= AddListViewImageList(hWndListView
);
793 ReadApplicationsFromRegistry(HKEY_LOCAL_MACHINE
);
794 ReadApplicationsFromRegistry(HKEY_CURRENT_USER
);
796 AddApplicationsToList(hWndListView
, hImageList
);
802 /******************************************************************************
804 * Description: Callback procedure for main tab
805 * Parameters : hWnd - hWnd of the window
806 * msg - reason for calling function
807 * wParam - additional parameter
808 * lParam - additional parameter
809 * Returns : Dependant on message
811 static BOOL CALLBACK
MainDlgProc(HWND hWnd
, UINT msg
, WPARAM wParam
, LPARAM lParam
)
814 static HIMAGELIST hImageList
;
821 hImageList
= ResetApplicationList(TRUE
, hWnd
, hImageList
);
829 RemoveItemsFromList(hWnd
);
830 ImageList_Destroy(hImageList
);
837 nmh
= (LPNMHDR
) lParam
;
844 case LVN_ITEMCHANGED
:
854 switch (LOWORD(wParam
))
857 InstallProgram(hWnd
);
862 selitem
= SendDlgItemMessageW(hWnd
, IDL_PROGRAMS
,
863 LVM_GETNEXTITEM
, -1, LVNI_FOCUSED
|LVNI_SELECTED
);
867 lvItem
.iItem
= selitem
;
868 lvItem
.mask
= LVIF_PARAM
;
870 if (SendDlgItemMessageW(hWnd
, IDL_PROGRAMS
, LVM_GETITEMW
,
871 0, (LPARAM
) &lvItem
))
872 UninstallProgram(lvItem
.lParam
, LOWORD(wParam
));
875 hImageList
= ResetApplicationList(FALSE
, hWnd
, hImageList
);
879 case IDC_SUPPORT_INFO
:
880 selitem
= SendDlgItemMessageW(hWnd
, IDL_PROGRAMS
,
881 LVM_GETNEXTITEM
, -1, LVNI_FOCUSED
| LVNI_SELECTED
);
885 lvItem
.iItem
= selitem
;
886 lvItem
.mask
= LVIF_PARAM
;
888 if (SendDlgItemMessageW(hWnd
, IDL_PROGRAMS
, LVM_GETITEMW
,
889 0, (LPARAM
) &lvItem
))
890 SupportInfo(hWnd
, lvItem
.lParam
);
902 static int CALLBACK
propsheet_callback( HWND hwnd
, UINT msg
, LPARAM lparam
)
906 case PSCB_INITIALIZED
:
907 SendMessageW( hwnd
, WM_SETICON
, ICON_BIG
, (LPARAM
)LoadIconW( hInst
, MAKEINTRESOURCEW(ICO_MAIN
) ));
913 /******************************************************************************
915 * Description: Main routine for applet
916 * Parameters : hWnd - hWnd of the Control Panel
918 static void StartApplet(HWND hWnd
)
921 PROPSHEETHEADERW psh
;
922 WCHAR tab_title
[MAX_STRING_LEN
], app_title
[MAX_STRING_LEN
];
924 /* Load the strings we will use */
925 LoadStringW(hInst
, IDS_TAB1_TITLE
, tab_title
, sizeof(tab_title
) / sizeof(tab_title
[0]));
926 LoadStringW(hInst
, IDS_CPL_TITLE
, app_title
, sizeof(app_title
) / sizeof(app_title
[0]));
927 LoadStringW(hInst
, IDS_REMOVE
, btnRemove
, sizeof(btnRemove
) / sizeof(btnRemove
[0]));
928 LoadStringW(hInst
, IDS_MODIFY_REMOVE
, btnModifyRemove
, sizeof(btnModifyRemove
) / sizeof(btnModifyRemove
[0]));
930 /* Fill out the PROPSHEETPAGE */
931 psp
.dwSize
= sizeof (PROPSHEETPAGEW
);
932 psp
.dwFlags
= PSP_USETITLE
;
933 psp
.hInstance
= hInst
;
934 psp
.u
.pszTemplate
= MAKEINTRESOURCEW (IDD_MAIN
);
935 psp
.u2
.pszIcon
= NULL
;
936 psp
.pfnDlgProc
= (DLGPROC
) MainDlgProc
;
937 psp
.pszTitle
= tab_title
;
940 /* Fill out the PROPSHEETHEADER */
941 psh
.dwSize
= sizeof (PROPSHEETHEADERW
);
942 psh
.dwFlags
= PSH_PROPSHEETPAGE
| PSH_USEICONID
| PSH_USECALLBACK
;
943 psh
.hwndParent
= hWnd
;
944 psh
.hInstance
= hInst
;
945 psh
.u
.pszIcon
= MAKEINTRESOURCEW(ICO_MAIN
);
946 psh
.pszCaption
= app_title
;
949 psh
.pfnCallback
= propsheet_callback
;
950 psh
.u2
.nStartPage
= 0;
952 /* Display the property sheet */
953 PropertySheetW (&psh
);
956 /******************************************************************************
958 * Description: Entry point for Control Panel applets
959 * Parameters : hwndCPL - hWnd of the Control Panel
960 * message - reason for calling function
961 * lParam1 - additional parameter
962 * lParam2 - additional parameter
963 * Returns : Dependant on message
965 LONG CALLBACK
CPlApplet(HWND hwndCPL
, UINT message
, LPARAM lParam1
, LPARAM lParam2
)
967 INITCOMMONCONTROLSEX iccEx
;
972 iccEx
.dwSize
= sizeof(iccEx
);
973 iccEx
.dwICC
= ICC_LISTVIEW_CLASSES
| ICC_TAB_CLASSES
;
975 InitCommonControlsEx(&iccEx
);
984 CPLINFO
*appletInfo
= (CPLINFO
*) lParam2
;
986 appletInfo
->idIcon
= ICO_MAIN
;
987 appletInfo
->idName
= IDS_CPL_TITLE
;
988 appletInfo
->idInfo
= IDS_CPL_DESC
;
989 appletInfo
->lData
= 0;
995 StartApplet(hwndCPL
);