123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371 |
- /*
- * Uninstaller
- *
- * Copyright 2000 Andreas Mohr
- * Copyright 2004 Hannu Valtonen
- * Copyright 2005 Jonathan Ernst
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
- *
- */
- #include <string.h>
- #include <windows.h>
- #include <commctrl.h>
- #include <shlwapi.h>
- #include "resource.h"
- #include "regstr.h"
- #include "wine/debug.h"
- WINE_DEFAULT_DEBUG_CHANNEL(uninstaller);
- extern void WINAPI Control_RunDLL(HWND hWnd, HINSTANCE hInst, LPCSTR cmd, DWORD nCmdShow);
- typedef struct {
- HKEY root;
- WCHAR *key;
- WCHAR *descr;
- WCHAR *command;
- int active;
- } uninst_entry;
- static uninst_entry *entries = NULL;
- static unsigned int numentries = 0;
- static int oldsel = -1;
- static WCHAR *sFilter;
- static int FetchUninstallInformation(void);
- static void UninstallProgram(void);
- static const WCHAR PathUninstallW[] = L"Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall";
- static void output_writeconsole(const WCHAR *str, DWORD len)
- {
- DWORD written, ret, lenA;
- char *strA;
- ret = WriteConsoleW(GetStdHandle(STD_OUTPUT_HANDLE), str, len, &written, NULL);
- if (ret) return;
- /* WriteConsole fails if its output is redirected to a file.
- * If this occurs, we should use an OEM codepage and call WriteFile.
- */
- lenA = WideCharToMultiByte(GetConsoleOutputCP(), 0, str, len, NULL, 0, NULL, NULL);
- strA = HeapAlloc(GetProcessHeap(), 0, lenA);
- if (strA)
- {
- WideCharToMultiByte(GetConsoleOutputCP(), 0, str, len, strA, lenA, NULL, NULL);
- WriteFile(GetStdHandle(STD_OUTPUT_HANDLE), strA, lenA, &written, FALSE);
- HeapFree(GetProcessHeap(), 0, strA);
- }
- }
- static void output_formatstring(const WCHAR *fmt, va_list va_args)
- {
- WCHAR *str;
- DWORD len;
- len = FormatMessageW(FORMAT_MESSAGE_FROM_STRING|FORMAT_MESSAGE_ALLOCATE_BUFFER,
- fmt, 0, 0, (LPWSTR)&str, 0, &va_args);
- if (len == 0 && GetLastError() != ERROR_NO_WORK_DONE)
- {
- WINE_FIXME("Could not format string: le=%u, fmt=%s\n", GetLastError(), wine_dbgstr_w(fmt));
- return;
- }
- output_writeconsole(str, len);
- LocalFree(str);
- }
- static void WINAPIV output_message(unsigned int id, ...)
- {
- WCHAR fmt[1024];
- va_list va_args;
- if (!LoadStringW(GetModuleHandleW(NULL), id, fmt, ARRAY_SIZE(fmt)))
- {
- WINE_FIXME("LoadString failed with %d\n", GetLastError());
- return;
- }
- va_start(va_args, id);
- output_formatstring(fmt, va_args);
- va_end(va_args);
- }
- static void WINAPIV output_array(const WCHAR *fmt, ...)
- {
- va_list va_args;
- va_start(va_args, fmt);
- output_formatstring(fmt, va_args);
- va_end(va_args);
- }
- /**
- * Used to output program list when used with --list
- */
- static void ListUninstallPrograms(void)
- {
- unsigned int i;
- FetchUninstallInformation();
- for (i=0; i < numentries; i++)
- output_array(L"%1|||%2\n", entries[i].key, entries[i].descr);
- }
- static void RemoveSpecificProgram(WCHAR *nameW)
- {
- unsigned int i;
- FetchUninstallInformation();
- for (i=0; i < numentries; i++)
- {
- if (CompareStringW(GetThreadLocale(), NORM_IGNORECASE, entries[i].key, -1, nameW, -1) == CSTR_EQUAL)
- {
- entries[i].active++;
- break;
- }
- }
- if (i < numentries)
- UninstallProgram();
- else
- output_message(STRING_NO_APP_MATCH, nameW);
- }
- int __cdecl wmain(int argc, WCHAR *argv[])
- {
- LPCWSTR token = NULL;
- int i = 1;
- BOOL is_wow64;
- if (IsWow64Process( GetCurrentProcess(), &is_wow64 ) && is_wow64)
- {
- STARTUPINFOW si;
- PROCESS_INFORMATION pi;
- WCHAR filename[MAX_PATH];
- void *redir;
- DWORD exit_code;
- memset( &si, 0, sizeof(si) );
- si.cb = sizeof(si);
- GetSystemDirectoryW( filename, MAX_PATH );
- wcscat( filename, L"\\uninstaller.exe" );
- Wow64DisableWow64FsRedirection( &redir );
- if (CreateProcessW( filename, GetCommandLineW(), NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi ))
- {
- WINE_TRACE( "restarting %s\n", wine_dbgstr_w(filename) );
- WaitForSingleObject( pi.hProcess, INFINITE );
- GetExitCodeProcess( pi.hProcess, &exit_code );
- ExitProcess( exit_code );
- }
- else WINE_ERR( "failed to restart 64-bit %s, err %d\n", wine_dbgstr_w(filename), GetLastError() );
- Wow64RevertWow64FsRedirection( redir );
- }
- InitCommonControls();
- while( i<argc )
- {
- token = argv[i++];
- if( !lstrcmpW( token, L"--help" ) )
- {
- output_message(STRING_HEADER);
- output_message(STRING_USAGE);
- return 0;
- }
- else if( !lstrcmpW( token, L"--list" ) )
- {
- ListUninstallPrograms();
- return 0;
- }
- else if( !lstrcmpW( token, L"--remove" ) )
- {
- if( i >= argc )
- {
- output_message(STRING_PARAMETER_REQUIRED);
- return 1;
- }
- RemoveSpecificProgram( argv[i++] );
- return 0;
- }
- else
- {
- output_message(STRING_INVALID_OPTION, token);
- return 1;
- }
- }
- /* Start the GUI control panel */
- Control_RunDLL(GetDesktopWindow(), 0, "appwiz.cpl", SW_SHOW);
- return 1;
- }
- /**
- * Used to sort entries by name.
- */
- static int __cdecl cmp_by_name(const void *a, const void *b)
- {
- return lstrcmpiW(((const uninst_entry *)a)->descr, ((const uninst_entry *)b)->descr);
- }
- /**
- * Fetch information from the uninstall key.
- */
- static int FetchFromRootKey(HKEY root)
- {
- HKEY hkeyApp;
- int i;
- DWORD sizeOfSubKeyName, displen, uninstlen, value, type, size;
- WCHAR subKeyName[256];
- sizeOfSubKeyName = 255;
- for (i=0; RegEnumKeyExW( root, i, subKeyName, &sizeOfSubKeyName, NULL, NULL, NULL, NULL ) != ERROR_NO_MORE_ITEMS; ++i)
- {
- RegOpenKeyExW(root, subKeyName, 0, KEY_READ, &hkeyApp);
- size = sizeof(value);
- if (!RegQueryValueExW(hkeyApp, L"SystemComponent", NULL, &type, (BYTE *)&value, &size) &&
- type == REG_DWORD && value == 1)
- {
- RegCloseKey(hkeyApp);
- sizeOfSubKeyName = 255;
- continue;
- }
- if (!RegQueryValueExW(hkeyApp, L"DisplayName", NULL, NULL, NULL, &displen))
- {
- WCHAR *command;
- size = sizeof(value);
- if (!RegQueryValueExW(hkeyApp, L"WindowsInstaller", NULL, &type, (BYTE *)&value, &size) &&
- type == REG_DWORD && value == 1)
- {
- command = HeapAlloc(GetProcessHeap(), 0,
- (lstrlenW(L"msiexec /x%s") + lstrlenW(subKeyName)) * sizeof(WCHAR));
- wsprintfW(command, L"msiexec /x%s", subKeyName);
- }
- else if (!RegQueryValueExW(hkeyApp, L"UninstallString", NULL, NULL, NULL, &uninstlen))
- {
- command = HeapAlloc(GetProcessHeap(), 0, uninstlen);
- RegQueryValueExW(hkeyApp, L"UninstallString", 0, 0, (BYTE *)command, &uninstlen);
- }
- else
- {
- RegCloseKey(hkeyApp);
- sizeOfSubKeyName = 255;
- continue;
- }
- numentries++;
- entries = HeapReAlloc(GetProcessHeap(), 0, entries, numentries*sizeof(uninst_entry));
- entries[numentries-1].root = root;
- entries[numentries-1].key = HeapAlloc(GetProcessHeap(), 0, (lstrlenW(subKeyName)+1)*sizeof(WCHAR));
- lstrcpyW(entries[numentries-1].key, subKeyName);
- entries[numentries-1].descr = HeapAlloc(GetProcessHeap(), 0, displen);
- RegQueryValueExW(hkeyApp, L"DisplayName", 0, 0, (BYTE *)entries[numentries-1].descr, &displen);
- entries[numentries-1].command = command;
- entries[numentries-1].active = 0;
- WINE_TRACE("allocated entry #%d: %s (%s), %s\n",
- numentries, wine_dbgstr_w(entries[numentries-1].key), wine_dbgstr_w(entries[numentries-1].descr), wine_dbgstr_w(entries[numentries-1].command));
- if(sFilter != NULL && StrStrIW(entries[numentries-1].descr,sFilter)==NULL)
- numentries--;
- }
- RegCloseKey(hkeyApp);
- sizeOfSubKeyName = 255;
- }
- return 1;
- }
- static int FetchUninstallInformation(void)
- {
- static const BOOL is_64bit = sizeof(void *) > sizeof(int);
- int rc = 0;
- HKEY root;
- numentries = 0;
- oldsel = -1;
- if (!entries)
- entries = HeapAlloc(GetProcessHeap(), 0, sizeof(uninst_entry));
- if (!RegOpenKeyExW(HKEY_LOCAL_MACHINE, PathUninstallW, 0, KEY_READ, &root))
- {
- rc |= FetchFromRootKey(root);
- RegCloseKey(root);
- }
- if (is_64bit &&
- !RegOpenKeyExW(HKEY_LOCAL_MACHINE, PathUninstallW, 0, KEY_READ|KEY_WOW64_32KEY, &root))
- {
- rc |= FetchFromRootKey(root);
- RegCloseKey(root);
- }
- if (!RegOpenKeyExW(HKEY_CURRENT_USER, PathUninstallW, 0, KEY_READ, &root))
- {
- rc |= FetchFromRootKey(root);
- RegCloseKey(root);
- }
- qsort(entries, numentries, sizeof(uninst_entry), cmp_by_name);
- return rc;
- }
- static void UninstallProgram(void)
- {
- unsigned int i;
- WCHAR errormsg[1024];
- BOOL res;
- STARTUPINFOW si;
- PROCESS_INFORMATION info;
- DWORD exit_code;
- HKEY hkey;
- for (i=0; i < numentries; i++)
- {
- if (!(entries[i].active)) /* don't uninstall this one */
- continue;
- WINE_TRACE("uninstalling %s\n", wine_dbgstr_w(entries[i].descr));
- memset(&si, 0, sizeof(STARTUPINFOW));
- si.cb = sizeof(STARTUPINFOW);
- si.wShowWindow = SW_NORMAL;
- res = CreateProcessW(NULL, entries[i].command, NULL, NULL, FALSE, 0, NULL, NULL, &si, &info);
- if (res)
- { /* wait for the process to exit */
- WaitForSingleObject(info.hProcess, INFINITE);
- res = GetExitCodeProcess(info.hProcess, &exit_code);
- WINE_TRACE("%d: %08x\n", res, exit_code);
- }
- else
- {
- WCHAR sAppName[MAX_STRING_LEN];
- WCHAR sUninstallFailed[MAX_STRING_LEN];
- HINSTANCE hInst = GetModuleHandleW(0);
- LoadStringW(hInst, IDS_APPNAME, sAppName, ARRAY_SIZE(sAppName));
- LoadStringW(hInst, IDS_UNINSTALLFAILED, sUninstallFailed, ARRAY_SIZE(sUninstallFailed));
- wsprintfW(errormsg, sUninstallFailed, entries[i].command);
- if(MessageBoxW(0, errormsg, sAppName, MB_YESNO | MB_ICONQUESTION)==IDYES)
- {
- /* delete the application's uninstall entry */
- RegOpenKeyExW(entries[i].root, PathUninstallW, 0, KEY_READ, &hkey);
- RegDeleteKeyW(hkey, entries[i].key);
- RegCloseKey(hkey);
- }
- }
- }
- WINE_TRACE("finished uninstall phase.\n");
- }
|