2 * Q&D Uninstaller (main.c)
4 * Copyright 2000 Andreas Mohr <a.mohr@mailto.de>
5 * To be distributed under the Wine License
17 /* Work around a Wine bug which defines handles as UINT rather than LPVOID */
19 #define NULL_HANDLE NULL
26 #define DEBUG(x) fprintf(stderr,x)
31 /* use multi-select listbox */
32 #undef USE_MULTIPLESEL
34 /* Delete uninstall registry key after execution.
35 * This is probably a bad idea, because it's the
36 * uninstall program that is supposed to do that.
42 static char about_string[] =
43 "Windows program uninstaller (C) 2000 by Andreas Mohr <a.mohr@mailto.de>";
44 static char program_description[] =
45 "Welcome to the Wine uninstaller !\n\nThe purpose of this program is to let you get rid of all those fantastic programs that somehow manage to always take way too much space on your HDD :-)";
51 #ifdef USE_MULTIPLESEL
56 uninst_entry *entries = NULL;
68 { BS_PUSHBUTTON, "Add/Remove", 0 },
69 { BS_PUSHBUTTON, "About", 0 },
70 { BS_PUSHBUTTON, "Exit", 0 }
73 #define NUM (sizeof button/sizeof button[0])
75 int WINAPI WinMain( HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR cmdline, int cmdshow )
81 LoadString( hInst, IDS_APPNAME, appname, sizeof(appname));
84 wc.lpfnWndProc = MainProc;
88 wc.hIcon = LoadIcon( hInst, appname );
89 wc.hCursor = LoadCursor( NULL_HANDLE, IDI_APPLICATION );
90 wc.hbrBackground = (HBRUSH) GetStockObject( LTGRAY_BRUSH );
91 wc.lpszMenuName = NULL;
92 wc.lpszClassName = appname;
94 if (!RegisterClass(&wc)) exit(1);
95 hWnd = CreateWindow( appname, appname,
96 WS_OVERLAPPEDWINDOW & ~WS_THICKFRAME & ~WS_MAXIMIZEBOX,
97 CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
98 NULL_HANDLE, NULL_HANDLE, hInst, NULL );
102 ShowWindow( hWnd, cmdshow );
103 UpdateWindow( hWnd );
105 while( GetMessage(&msg, NULL_HANDLE, 0, 0) ) {
106 TranslateMessage( &msg );
107 DispatchMessage( &msg );
112 int GetUninstallStrings()
114 HKEY hkeyUninst, hkeyApp;
116 DWORD sizeOfSubKeyName=255, displen, uninstlen;
117 char subKeyName[256];
122 if ( RegOpenKeyEx(HKEY_LOCAL_MACHINE, REGSTR_PATH_UNINSTALL,
123 0, KEY_READ, &hkeyUninst) != ERROR_SUCCESS )
125 MessageBox(0, "Uninstall registry key not available (yet), nothing to do !", appname, MB_OK);
129 strcpy(key_app, REGSTR_PATH_UNINSTALL);
130 strcat(key_app, "\\");
131 p = key_app+strlen(REGSTR_PATH_UNINSTALL)+1;
133 RegEnumKeyExA( hkeyUninst, i, subKeyName, &sizeOfSubKeyName,
134 NULL, NULL, NULL, NULL ) != ERROR_NO_MORE_ITEMS;
135 ++i, sizeOfSubKeyName=255 )
137 strcpy(p, subKeyName);
138 RegOpenKeyEx(HKEY_LOCAL_MACHINE, key_app, 0, KEY_READ, &hkeyApp);
140 if ( (RegQueryValueEx(hkeyApp, REGSTR_VAL_UNINSTALLER_DISPLAYNAME,
141 0, 0, NULL, &displen) == ERROR_SUCCESS)
142 && (RegQueryValueEx(hkeyApp, REGSTR_VAL_UNINSTALLER_COMMANDLINE,
143 0, 0, NULL, &uninstlen) == ERROR_SUCCESS) )
146 entries = HeapReAlloc(GetProcessHeap(), 0, entries, numentries*sizeof(uninst_entry));
147 entries[numentries-1].key =
148 HeapAlloc(GetProcessHeap(), 0, strlen(subKeyName)+1);
149 strcpy(entries[numentries-1].key, subKeyName);
150 entries[numentries-1].descr =
151 HeapAlloc(GetProcessHeap(), 0, displen);
152 RegQueryValueEx(hkeyApp, REGSTR_VAL_UNINSTALLER_DISPLAYNAME, 0, 0,
153 entries[numentries-1].descr, &displen);
154 entries[numentries-1].command =
155 HeapAlloc(GetProcessHeap(), 0, uninstlen);
156 #ifdef USE_MULTIPLESEL
157 entries[numentries-1].active = 0;
159 RegQueryValueEx(hkeyApp, REGSTR_VAL_UNINSTALLER_COMMANDLINE, 0, 0,
160 entries[numentries-1].command, &uninstlen);
162 RegCloseKey(hkeyApp);
164 RegCloseKey(hkeyUninst);
168 void UninstallProgram(HWND hWnd)
174 PROCESS_INFORMATION info;
180 #ifdef USE_MULTIPLESEL
181 for (i=0; i < numentries; i++)
183 if (!(entries[i].active)) /* don't uninstall this one */
190 memset(&si, 0, sizeof(STARTUPINFO));
191 si.cb = sizeof(STARTUPINFO);
192 si.wShowWindow = SW_NORMAL;
193 res = CreateProcess(NULL, entries[i].command, NULL, NULL, FALSE, 0, NULL, NULL, &si, &info);
195 { /* wait for the process to exit */
196 WaitForSingleObject(info.hProcess, INFINITE);
197 res = GetExitCodeProcess(info.hProcess, &exit_code);
198 fprintf(stderr, "%d: %08lx\n", res, exit_code);
200 /* delete the program's uninstall entry */
201 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, REGSTR_PATH_UNINSTALL,
202 0, KEY_READ, &hkey) == ERROR_SUCCESS)
204 RegDeleteKey(hkey, entries[i].key);
211 GetUninstallStrings();
212 InvalidateRect(hWnd, NULL, TRUE);
217 sprintf(errormsg, "Execution of uninstall command '%s' failed, perhaps due to missing executable.", entries[i].command);
218 MessageBox(0, errormsg, appname, MB_OK);
220 #ifdef USE_MULTIPLESEL
225 LRESULT WINAPI MainProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
230 int cxChar, cyChar, i, y, bx, by, maxx, maxy, wx, wy;
231 static HWND hwndList = 0, hwndEdit = 0;
238 if (!(GetUninstallStrings()))
244 GetTextMetrics(hdc, &tm);
245 cxChar = tm.tmAveCharWidth;
246 cyChar = tm.tmHeight + tm.tmExternalLeading;
247 ReleaseDC(hWnd, hdc);
248 /* FIXME: implement sorting and use LBS_SORT here ! */
249 style = (WS_CHILD|WS_VISIBLE|LBS_STANDARD) & ~LBS_SORT;
250 #ifdef USE_MULTIPLESEL
251 style |= LBS_MULTIPLESEL;
253 bx = maxx = cxChar * 5;
254 by = maxy = cyChar * 3;
255 hwndList = CreateWindow("listbox", NULL,
258 cxChar * 50 + GetSystemMetrics(SM_CXVSCROLL), cyChar * 20,
260 (HINSTANCE)GetWindowLong(hWnd, GWL_HINSTANCE), NULL);
262 GetWindowRect(hwndList, &rect);
264 maxx += (rect.right - rect.left)*1.1;
265 maxy += (rect.bottom - rect.top)*1.1;
268 for (i=0; i < NUM; i++)
270 button[i].hwnd = CreateWindow("button", button[i].text,
271 WS_CHILD|WS_VISIBLE|BS_PUSHBUTTON,
275 ((LPCREATESTRUCT)lParam)->hInstance, NULL);
280 CreateWindow("static", program_description,
281 WS_CHILD|WS_VISIBLE|SS_LEFT,
285 ((LPCREATESTRUCT)lParam)->hInstance, NULL);
286 maxx += wx + cxChar * 5; /* button + right border */
287 maxy += cyChar * 5 + cyChar * 2; /* static text + distance */
288 CreateWindow("static", "command line to be executed:",
289 WS_CHILD|WS_VISIBLE|SS_LEFT,
293 ((LPCREATESTRUCT)lParam)->hInstance, NULL);
295 hwndEdit = CreateWindow("edit", NULL,
296 WS_CHILD|WS_VISIBLE|WS_BORDER|ES_LEFT|ES_MULTILINE|ES_READONLY,
297 bx, maxy, maxx-(2*bx), (cyChar*6)+4,
299 ((LPCREATESTRUCT)lParam)->hInstance, NULL);
300 maxy += (cyChar*6)+4 + cyChar * 3; /* edit ctrl + bottom border */
301 SetWindowPos( hWnd, 0,
309 SendMessage(hwndList, LB_RESETCONTENT, 0, 0);
310 SendMessage(hwndList, WM_SETREDRAW, FALSE, 0);
311 for (i=0; i < numentries; i++)
312 SendMessage(hwndList, LB_ADDSTRING, 0, (LPARAM)entries[i].descr);
313 SendMessage(hwndList, WM_SETREDRAW, TRUE, 0);
314 hdc = BeginPaint( hWnd, &ps );
315 EndPaint( hWnd, &ps );
320 PostQuitMessage( 0 );
324 if ((HWND)lParam == hwndList)
326 if (HIWORD(wParam) == LBN_SELCHANGE)
328 int sel = SendMessage(hwndList, LB_GETCURSEL, 0, 0);
330 #ifdef USE_MULTIPLESEL
331 entries[sel].active ^= 1; /* toggle */
335 SendMessage(hwndEdit, WM_SETTEXT, 0, (LPARAM)entries[sel].command);
339 if ((HWND)lParam == button[0].hwnd) /* Uninstall button */
340 UninstallProgram(hWnd);
342 if ((HWND)lParam == button[1].hwnd) /* About button */
343 MessageBox(0, about_string, "About", MB_OK);
345 if ((HWND)lParam == button[2].hwnd) /* Exit button */
350 return( DefWindowProc( hWnd, msg, wParam, lParam ));