4 * Copyright 2000 Andreas Mohr
5 * Copyright 2004 Hannu Valtonen
6 * Copyright 2005 Jonathan Ernst
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
30 #include "wine/debug.h"
32 WINE_DEFAULT_DEBUG_CHANNEL(uninstaller
);
34 extern void WINAPI
Control_RunDLL(HWND hWnd
, HINSTANCE hInst
, LPCSTR cmd
, DWORD nCmdShow
);
43 static uninst_entry
*entries
= NULL
;
44 static unsigned int numentries
= 0;
45 static int list_need_update
= 1;
46 static int oldsel
= -1;
47 static WCHAR
*sFilter
;
49 static int FetchUninstallInformation(void);
50 static void UninstallProgram(void);
51 static int cmp_by_name(const void *a
, const void *b
);
53 static const WCHAR BackSlashW
[] = { '\\', 0 };
54 static const WCHAR DisplayNameW
[] = {'D','i','s','p','l','a','y','N','a','m','e',0};
55 static const WCHAR PathUninstallW
[] = {
56 'S','o','f','t','w','a','r','e','\\',
57 'M','i','c','r','o','s','o','f','t','\\',
58 'W','i','n','d','o','w','s','\\',
59 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
60 'U','n','i','n','s','t','a','l','l',0 };
61 static const WCHAR UninstallCommandlineW
[] = {'U','n','i','n','s','t','a','l','l','S','t','r','i','n','g',0};
62 static const WCHAR WindowsInstallerW
[] = {'W','i','n','d','o','w','s','I','n','s','t','a','l','l','e','r',0};
63 static const WCHAR SystemComponentW
[] = {'S','y','s','t','e','m','C','o','m','p','o','n','e','n','t',0};
66 * Used to output program list when used with --list
68 static void ListUninstallPrograms(void)
75 FetchUninstallInformation();
77 for (i
=0; i
< numentries
; i
++)
79 lenDescr
= WideCharToMultiByte(CP_UNIXCP
, 0, entries
[i
].descr
, -1, NULL
, 0, NULL
, NULL
);
80 lenKey
= WideCharToMultiByte(CP_UNIXCP
, 0, entries
[i
].key
, -1, NULL
, 0, NULL
, NULL
);
81 descr
= HeapAlloc(GetProcessHeap(), 0, lenDescr
);
82 key
= HeapAlloc(GetProcessHeap(), 0, lenKey
);
83 WideCharToMultiByte(CP_UNIXCP
, 0, entries
[i
].descr
, -1, descr
, lenDescr
, NULL
, NULL
);
84 WideCharToMultiByte(CP_UNIXCP
, 0, entries
[i
].key
, -1, key
, lenKey
, NULL
, NULL
);
85 printf("%s|||%s\n", key
, descr
);
86 HeapFree(GetProcessHeap(), 0, descr
);
87 HeapFree(GetProcessHeap(), 0, key
);
92 static void RemoveSpecificProgram(WCHAR
*nameW
)
98 FetchUninstallInformation();
100 for (i
=0; i
< numentries
; i
++)
102 if (CompareStringW(GetThreadLocale(), NORM_IGNORECASE
, entries
[i
].key
, -1, nameW
, -1) == CSTR_EQUAL
)
113 lenName
= WideCharToMultiByte(CP_UNIXCP
, 0, nameW
, -1, NULL
, 0, NULL
, NULL
);
114 name
= HeapAlloc(GetProcessHeap(), 0, lenName
);
115 WideCharToMultiByte(CP_UNIXCP
, 0, nameW
, -1, name
, lenName
, NULL
, NULL
);
116 fprintf(stderr
, "Error: could not match application [%s]\n", name
);
117 HeapFree(GetProcessHeap(), 0, name
);
122 int wmain(int argc
, WCHAR
*argv
[])
124 LPCWSTR token
= NULL
;
125 static const WCHAR listW
[] = { '-','-','l','i','s','t',0 };
126 static const WCHAR removeW
[] = { '-','-','r','e','m','o','v','e',0 };
133 /* Handle requests just to list the applications */
134 if( !lstrcmpW( token
, listW
) )
136 ListUninstallPrograms();
139 else if( !lstrcmpW( token
, removeW
) )
143 WINE_ERR( "The remove option requires a parameter.\n");
147 RemoveSpecificProgram( argv
[i
++] );
152 WINE_ERR( "unknown option %s\n",wine_dbgstr_w(token
));
157 /* Start the GUI control panel */
158 Control_RunDLL(GetDesktopWindow(), 0, "appwiz.cpl", SW_SHOW
);
164 * Used to sort entries by name.
166 static int cmp_by_name(const void *a
, const void *b
)
168 return lstrcmpiW(((const uninst_entry
*)a
)->descr
, ((const uninst_entry
*)b
)->descr
);
173 * Fetch information from the uninstall key.
175 static int FetchFromRootKey(HKEY root
)
179 DWORD sizeOfSubKeyName
, displen
, uninstlen
, value
, type
, size
;
180 WCHAR subKeyName
[256];
182 sizeOfSubKeyName
= 255;
183 for (i
=0; RegEnumKeyExW( root
, i
, subKeyName
, &sizeOfSubKeyName
, NULL
, NULL
, NULL
, NULL
) != ERROR_NO_MORE_ITEMS
; ++i
)
185 RegOpenKeyExW(root
, subKeyName
, 0, KEY_READ
, &hkeyApp
);
186 if (!RegQueryValueExW(hkeyApp
, SystemComponentW
, NULL
, &type
, (LPBYTE
)&value
, &size
) &&
187 type
== REG_DWORD
&& value
== 1)
189 RegCloseKey(hkeyApp
);
190 sizeOfSubKeyName
= 255;
193 if (!RegQueryValueExW(hkeyApp
, DisplayNameW
, NULL
, NULL
, NULL
, &displen
))
197 size
= sizeof(value
);
198 if (!RegQueryValueExW(hkeyApp
, WindowsInstallerW
, NULL
, &type
, (LPBYTE
)&value
, &size
) &&
199 type
== REG_DWORD
&& value
== 1)
201 static const WCHAR fmtW
[] = {'m','s','i','e','x','e','c',' ','/','x','%','s',0};
202 command
= HeapAlloc(GetProcessHeap(), 0, (lstrlenW(fmtW
) + lstrlenW(subKeyName
)) * sizeof(WCHAR
));
203 wsprintfW(command
, fmtW
, subKeyName
);
205 else if (!RegQueryValueExW(hkeyApp
, UninstallCommandlineW
, NULL
, NULL
, NULL
, &uninstlen
))
207 command
= HeapAlloc(GetProcessHeap(), 0, uninstlen
);
208 RegQueryValueExW(hkeyApp
, UninstallCommandlineW
, 0, 0, (LPBYTE
)command
, &uninstlen
);
212 RegCloseKey(hkeyApp
);
213 sizeOfSubKeyName
= 255;
217 entries
= HeapReAlloc(GetProcessHeap(), 0, entries
, numentries
*sizeof(uninst_entry
));
218 entries
[numentries
-1].root
= root
;
219 entries
[numentries
-1].key
= HeapAlloc(GetProcessHeap(), 0, (lstrlenW(subKeyName
)+1)*sizeof(WCHAR
));
220 lstrcpyW(entries
[numentries
-1].key
, subKeyName
);
221 entries
[numentries
-1].descr
= HeapAlloc(GetProcessHeap(), 0, displen
);
222 RegQueryValueExW(hkeyApp
, DisplayNameW
, 0, 0, (LPBYTE
)entries
[numentries
-1].descr
, &displen
);
223 entries
[numentries
-1].command
= command
;
224 entries
[numentries
-1].active
= 0;
225 WINE_TRACE("allocated entry #%d: %s (%s), %s\n",
226 numentries
, wine_dbgstr_w(entries
[numentries
-1].key
), wine_dbgstr_w(entries
[numentries
-1].descr
), wine_dbgstr_w(entries
[numentries
-1].command
));
227 if(sFilter
!= NULL
&& StrStrIW(entries
[numentries
-1].descr
,sFilter
)==NULL
)
230 RegCloseKey(hkeyApp
);
231 sizeOfSubKeyName
= 255;
237 static int FetchUninstallInformation(void)
239 static const BOOL is_64bit
= sizeof(void *) > sizeof(int);
246 entries
= HeapAlloc(GetProcessHeap(), 0, sizeof(uninst_entry
));
248 if (!RegOpenKeyExW(HKEY_LOCAL_MACHINE
, PathUninstallW
, 0, KEY_READ
, &root
))
250 rc
|= FetchFromRootKey(root
);
254 !RegOpenKeyExW(HKEY_LOCAL_MACHINE
, PathUninstallW
, 0, KEY_READ
|KEY_WOW64_32KEY
, &root
))
256 rc
|= FetchFromRootKey(root
);
259 if (!RegOpenKeyExW(HKEY_CURRENT_USER
, PathUninstallW
, 0, KEY_READ
, &root
))
261 rc
|= FetchFromRootKey(root
);
265 qsort(entries
, numentries
, sizeof(uninst_entry
), cmp_by_name
);
269 static void UninstallProgram(void)
272 WCHAR errormsg
[1024];
275 PROCESS_INFORMATION info
;
278 for (i
=0; i
< numentries
; i
++)
280 if (!(entries
[i
].active
)) /* don't uninstall this one */
282 WINE_TRACE("uninstalling %s\n", wine_dbgstr_w(entries
[i
].descr
));
283 memset(&si
, 0, sizeof(STARTUPINFOW
));
284 si
.cb
= sizeof(STARTUPINFOW
);
285 si
.wShowWindow
= SW_NORMAL
;
286 res
= CreateProcessW(NULL
, entries
[i
].command
, NULL
, NULL
, FALSE
, 0, NULL
, NULL
, &si
, &info
);
288 { /* wait for the process to exit */
289 WaitForSingleObject(info
.hProcess
, INFINITE
);
290 res
= GetExitCodeProcess(info
.hProcess
, &exit_code
);
291 WINE_TRACE("%d: %08x\n", res
, exit_code
);
295 WCHAR sAppName
[MAX_STRING_LEN
];
296 WCHAR sUninstallFailed
[MAX_STRING_LEN
];
297 HINSTANCE hInst
= GetModuleHandleW(0);
299 LoadStringW(hInst
, IDS_APPNAME
, sAppName
, sizeof(sAppName
)/sizeof(WCHAR
));
300 LoadStringW(hInst
, IDS_UNINSTALLFAILED
, sUninstallFailed
, sizeof(sUninstallFailed
)/sizeof(WCHAR
));
301 wsprintfW(errormsg
, sUninstallFailed
, entries
[i
].command
);
302 if(MessageBoxW(0, errormsg
, sAppName
, MB_YESNO
| MB_ICONQUESTION
)==IDYES
)
304 /* delete the application's uninstall entry */
305 RegOpenKeyExW(entries
[i
].root
, PathUninstallW
, 0, KEY_READ
, &hkey
);
306 RegDeleteKeyW(hkey
, entries
[i
].key
);
311 WINE_TRACE("finished uninstall phase.\n");
312 list_need_update
= 1;