Use MapLS/UnMapLS instead of SEGPTR_* macros.
[wine/wine-kai.git] / programs / uninstaller / main.c
blob1d01875231bda3e572a2898200050677b62a91db
1 /*
2 * Q&D Uninstaller (main.c)
3 *
4 * Copyright 2000 Andreas Mohr <andi@lisas.de>
5 * To be distributed under the Wine License
6 */
9 #include <stdlib.h>
10 #include <stdio.h>
11 #include <string.h>
12 #include <time.h>
13 #include <windows.h>
14 #include "main.h"
15 #include "regstr.h"
17 /* Work around a Wine bug which defines handles as UINT rather than LPVOID */
18 #ifdef WINE_STRICT
19 #define NULL_HANDLE NULL
20 #else
21 #define NULL_HANDLE 0
22 #endif
24 #ifdef DUMB_DEBUG
25 #include <stdio.h>
26 #define DEBUG(x) fprintf(stderr,x)
27 #else
28 #define DEBUG(x)
29 #endif
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.
38 #undef DEL_REG_KEY
40 char appname[18];
42 static char about_string[] =
43 "Windows program uninstaller (C) 2000 by Andreas Mohr <andi@lisas.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 :-)";
47 typedef struct {
48 char *key;
49 char *descr;
50 char *command;
51 int active;
52 } uninst_entry;
54 uninst_entry *entries = NULL;
56 int numentries = 0;
58 struct {
59 DWORD style;
60 LPCSTR text;
61 HWND hwnd;
62 } button[] =
64 { BS_PUSHBUTTON, "Add/Remove", 0 },
65 { BS_PUSHBUTTON, "About", 0 },
66 { BS_PUSHBUTTON, "Exit", 0 }
69 #define NUM (sizeof button/sizeof button[0])
71 int GetUninstallStrings(void);
72 void UninstallProgram(void);
74 void ListUninstallPrograms(void)
76 int i;
78 if (! GetUninstallStrings())
79 exit(1);
81 for (i=0; i < numentries; i++)
82 printf("%s|||%s\n", entries[i].key, entries[i].descr);
86 void RemoveSpecificProgram(char *name)
88 int i;
90 if (! GetUninstallStrings())
91 exit(1);
93 for (i=0; i < numentries; i++)
95 if (strcmp(entries[i].key, name) == 0)
97 entries[i].active++;
98 break;
102 if (i < numentries)
103 UninstallProgram();
104 else
106 fprintf(stderr, "Error: could not match program [%s]\n", name);
111 int WINAPI WinMain( HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR cmdline, int cmdshow )
113 MSG msg;
114 WNDCLASS wc;
115 HWND hWnd;
117 /*------------------------------------------------------------------------
118 ** Handle requests just to list the programs
119 **----------------------------------------------------------------------*/
120 if (cmdline && strlen(cmdline) >= 6 && memcmp(cmdline, "--list", 6) == 0)
122 ListUninstallPrograms();
123 return(0);
126 /*------------------------------------------------------------------------
127 ** Handle requests to remove one program
128 **----------------------------------------------------------------------*/
129 if (cmdline && strlen(cmdline) > 9 && memcmp(cmdline, "--remove ", 9) == 0)
131 RemoveSpecificProgram(cmdline + 9);
132 return(0);
137 LoadString( hInst, IDS_APPNAME, appname, sizeof(appname));
139 wc.style = 0;
140 wc.lpfnWndProc = MainProc;
141 wc.cbClsExtra = 0;
142 wc.cbWndExtra = 0;
143 wc.hInstance = hInst;
144 wc.hIcon = LoadIcon( hInst, appname );
145 wc.hCursor = LoadCursor( NULL_HANDLE, IDI_APPLICATION );
146 wc.hbrBackground = (HBRUSH) GetStockObject( LTGRAY_BRUSH );
147 wc.lpszMenuName = NULL;
148 wc.lpszClassName = appname;
150 if (!RegisterClass(&wc)) exit(1);
151 hWnd = CreateWindow( appname, appname,
152 WS_OVERLAPPEDWINDOW & ~WS_THICKFRAME & ~WS_MAXIMIZEBOX,
153 CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
154 NULL_HANDLE, NULL_HANDLE, hInst, NULL );
156 if (!hWnd) exit(1);
158 ShowWindow( hWnd, cmdshow );
159 UpdateWindow( hWnd );
161 while( GetMessage(&msg, NULL_HANDLE, 0, 0) ) {
162 TranslateMessage( &msg );
163 DispatchMessage( &msg );
165 return msg.wParam;
168 int GetUninstallStrings(void)
170 HKEY hkeyUninst, hkeyApp;
171 int i;
172 DWORD sizeOfSubKeyName=255, displen, uninstlen;
173 char subKeyName[256];
174 char key_app[1024];
175 char *p;
178 if ( RegOpenKeyEx(HKEY_LOCAL_MACHINE, REGSTR_PATH_UNINSTALL,
179 0, KEY_READ, &hkeyUninst) != ERROR_SUCCESS )
181 MessageBox(0, "Uninstall registry key not available (yet), nothing to do !", appname, MB_OK);
182 return 0;
185 strcpy(key_app, REGSTR_PATH_UNINSTALL);
186 strcat(key_app, "\\");
187 p = key_app+strlen(REGSTR_PATH_UNINSTALL)+1;
188 for ( i=0;
189 RegEnumKeyExA( hkeyUninst, i, subKeyName, &sizeOfSubKeyName,
190 NULL, NULL, NULL, NULL ) != ERROR_NO_MORE_ITEMS;
191 ++i, sizeOfSubKeyName=255 )
193 strcpy(p, subKeyName);
194 RegOpenKeyEx(HKEY_LOCAL_MACHINE, key_app, 0, KEY_READ, &hkeyApp);
196 if ( (RegQueryValueEx(hkeyApp, REGSTR_VAL_UNINSTALLER_DISPLAYNAME,
197 0, 0, NULL, &displen) == ERROR_SUCCESS)
198 && (RegQueryValueEx(hkeyApp, REGSTR_VAL_UNINSTALLER_COMMANDLINE,
199 0, 0, NULL, &uninstlen) == ERROR_SUCCESS) )
201 numentries++;
202 entries = HeapReAlloc(GetProcessHeap(), 0, entries, numentries*sizeof(uninst_entry));
203 entries[numentries-1].key =
204 HeapAlloc(GetProcessHeap(), 0, strlen(subKeyName)+1);
205 strcpy(entries[numentries-1].key, subKeyName);
206 entries[numentries-1].descr =
207 HeapAlloc(GetProcessHeap(), 0, displen);
208 RegQueryValueEx(hkeyApp, REGSTR_VAL_UNINSTALLER_DISPLAYNAME, 0, 0,
209 entries[numentries-1].descr, &displen);
210 entries[numentries-1].command =
211 HeapAlloc(GetProcessHeap(), 0, uninstlen);
212 entries[numentries-1].active = 0;
213 RegQueryValueEx(hkeyApp, REGSTR_VAL_UNINSTALLER_COMMANDLINE, 0, 0,
214 entries[numentries-1].command, &uninstlen);
216 RegCloseKey(hkeyApp);
218 RegCloseKey(hkeyUninst);
219 return 1;
222 void UninstallProgram(void)
224 int i;
225 char errormsg[1024];
226 BOOL res;
227 STARTUPINFO si;
228 PROCESS_INFORMATION info;
229 DWORD exit_code;
230 #ifdef DEL_REG_KEY
231 HKEY hkey;
232 #endif
234 for (i=0; i < numentries; i++)
236 if (!(entries[i].active)) /* don't uninstall this one */
237 continue;
238 memset(&si, 0, sizeof(STARTUPINFO));
239 si.cb = sizeof(STARTUPINFO);
240 si.wShowWindow = SW_NORMAL;
241 res = CreateProcess(NULL, entries[i].command, NULL, NULL, FALSE, 0, NULL, NULL, &si, &info);
242 if (res == TRUE)
243 { /* wait for the process to exit */
244 WaitForSingleObject(info.hProcess, INFINITE);
245 res = GetExitCodeProcess(info.hProcess, &exit_code);
246 fprintf(stderr, "%d: %08lx\n", res, exit_code);
247 #ifdef DEL_REG_KEY
248 /* delete the program's uninstall entry */
249 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, REGSTR_PATH_UNINSTALL,
250 0, KEY_READ, &hkey) == ERROR_SUCCESS)
252 RegDeleteKey(hkey, entries[i].key);
253 RegCloseKey(hkey);
255 #endif
257 else
259 sprintf(errormsg, "Execution of uninstall command '%s' failed, perhaps due to missing executable.", entries[i].command);
260 MessageBox(0, errormsg, appname, MB_OK);
265 LRESULT WINAPI MainProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
267 HDC hdc;
268 PAINTSTRUCT ps;
269 TEXTMETRIC tm;
270 int cxChar, cyChar, i, y, bx, by, maxx, maxy, wx, wy;
271 static HWND hwndList = 0, hwndEdit = 0;
272 DWORD style;
273 RECT rect;
275 switch( msg ) {
276 case WM_CREATE:
278 if (!(GetUninstallStrings()))
280 PostQuitMessage(0);
281 return 0;
283 hdc = GetDC(hWnd);
284 GetTextMetrics(hdc, &tm);
285 cxChar = tm.tmAveCharWidth;
286 cyChar = tm.tmHeight + tm.tmExternalLeading;
287 ReleaseDC(hWnd, hdc);
288 /* FIXME: implement sorting and use LBS_SORT here ! */
289 style = (WS_CHILD|WS_VISIBLE|LBS_STANDARD) & ~LBS_SORT;
290 #ifdef USE_MULTIPLESEL
291 style |= LBS_MULTIPLESEL;
292 #endif
293 bx = maxx = cxChar * 5;
294 by = maxy = cyChar * 3;
295 hwndList = CreateWindow("listbox", NULL,
296 style,
297 maxx, maxy,
298 cxChar * 50 + GetSystemMetrics(SM_CXVSCROLL), cyChar * 20,
299 hWnd, (HMENU) 1,
300 (HINSTANCE)GetWindowLong(hWnd, GWL_HINSTANCE), NULL);
302 GetWindowRect(hwndList, &rect);
303 y = by;
304 maxx += (rect.right - rect.left)*1.1;
305 maxy += (rect.bottom - rect.top)*1.1;
306 wx = 20*cxChar;
307 wy = 7*cyChar/4;
308 for (i=0; i < NUM; i++)
310 button[i].hwnd = CreateWindow("button", button[i].text,
311 WS_CHILD|WS_VISIBLE|BS_PUSHBUTTON,
312 maxx, y,
313 wx, wy,
314 hWnd, (HMENU)i,
315 ((LPCREATESTRUCT)lParam)->hInstance, NULL);
316 if (!button[i].hwnd)
317 PostQuitMessage(0);
318 y += 2*cyChar;
320 CreateWindow("static", program_description,
321 WS_CHILD|WS_VISIBLE|SS_LEFT,
322 bx, maxy,
323 cxChar * 50, wy,
324 hWnd, (HMENU)1,
325 ((LPCREATESTRUCT)lParam)->hInstance, NULL);
326 maxx += wx + cxChar * 5; /* button + right border */
327 maxy += cyChar * 5 + cyChar * 2; /* static text + distance */
328 CreateWindow("static", "command line to be executed:",
329 WS_CHILD|WS_VISIBLE|SS_LEFT,
330 bx, maxy,
331 cxChar * 50, cyChar,
332 hWnd, (HMENU)1,
333 ((LPCREATESTRUCT)lParam)->hInstance, NULL);
334 maxy += cyChar;
335 hwndEdit = CreateWindow("edit", NULL,
336 WS_CHILD|WS_VISIBLE|WS_BORDER|ES_LEFT|ES_MULTILINE|ES_READONLY,
337 bx, maxy, maxx-(2*bx), (cyChar*6)+4,
338 hWnd, (HMENU)1,
339 ((LPCREATESTRUCT)lParam)->hInstance, NULL);
340 maxy += (cyChar*6)+4 + cyChar * 3; /* edit ctrl + bottom border */
341 SetWindowPos( hWnd, 0,
342 0, 0, maxx, maxy,
343 SWP_NOMOVE);
344 return 0;
347 case WM_PAINT:
349 SendMessage(hwndList, LB_RESETCONTENT, 0, 0);
350 SendMessage(hwndList, WM_SETREDRAW, FALSE, 0);
351 for (i=0; i < numentries; i++)
352 SendMessage(hwndList, LB_ADDSTRING, 0, (LPARAM)entries[i].descr);
353 SendMessage(hwndList, WM_SETREDRAW, TRUE, 0);
354 hdc = BeginPaint( hWnd, &ps );
355 EndPaint( hWnd, &ps );
356 return 0;
359 case WM_DESTROY:
360 PostQuitMessage( 0 );
361 return 0;
363 case WM_COMMAND:
364 if ((HWND)lParam == hwndList)
366 if (HIWORD(wParam) == LBN_SELCHANGE)
368 int sel = SendMessage(hwndList, LB_GETCURSEL, 0, 0);
370 entries[sel].active ^= 1; /* toggle */
371 SendMessage(hwndEdit, WM_SETTEXT, 0, (LPARAM)entries[sel].command);
374 else
375 if ((HWND)lParam == button[0].hwnd) /* Uninstall button */
377 UninstallProgram();
379 /* update listbox */
380 numentries = 0;
381 GetUninstallStrings();
382 InvalidateRect(hWnd, NULL, TRUE);
383 UpdateWindow(hWnd);
386 else
387 if ((HWND)lParam == button[1].hwnd) /* About button */
388 MessageBox(0, about_string, "About", MB_OK);
389 else
390 if ((HWND)lParam == button[2].hwnd) /* Exit button */
391 PostQuitMessage(0);
392 return 0;
395 return( DefWindowProc( hWnd, msg, wParam, lParam ));