Stub implementation for WSALookupServiceBeginA/W.
[wine.git] / programs / uninstaller / main.c
blob85179caf50c0ad17a9bc22efdef3493b1a945fd4
1 /*
2 * Q&D Uninstaller (main.c)
4 * Copyright 2000 Andreas Mohr <andi@lisas.de>
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 * ToDo:
21 * - add search box for locating entries quickly
25 #include <stdlib.h>
26 #include <stdio.h>
27 #include <string.h>
28 #include <time.h>
29 #include <windows.h>
30 #include "main.h"
31 #include "regstr.h"
32 #include "wine/debug.h"
34 WINE_DEFAULT_DEBUG_CHANNEL(uninstaller);
36 /* Work around a Wine bug which defines handles as UINT rather than LPVOID */
37 #ifdef WINE_STRICT
38 #define NULL_HANDLE NULL
39 #else
40 #define NULL_HANDLE 0
41 #endif
43 /* use multi-select listbox */
44 #undef USE_MULTIPLESEL
46 /* Delete uninstall registry key after execution.
47 * This is probably a bad idea, because it's the
48 * uninstall program that is supposed to do that.
50 #undef DEL_REG_KEY
52 char appname[18];
54 static char about_string[] =
55 "Wine Application Uninstaller (C) 2004 by Andreas Mohr <andi@lisas.de> and Hannu Valtonen <Hannu.Valtonen@hut.fi>";
56 static char program_description[] =
57 "Please select the application you wish to uninstall:";
59 typedef struct {
60 char *key;
61 WCHAR *descr;
62 char *command;
63 int active;
64 } uninst_entry;
66 uninst_entry *entries = NULL;
68 int numentries = 0;
69 int list_need_update = 1;
70 int oldsel = -1;
72 struct {
73 DWORD style;
74 LPCSTR text;
75 HWND hwnd;
76 } button[] =
78 { BS_PUSHBUTTON, "Add/Remove", 0 },
79 { BS_PUSHBUTTON, "About", 0 },
80 { BS_PUSHBUTTON, "Exit", 0 }
83 #define NUM (sizeof(button)/sizeof(button[0]))
85 int FetchUninstallInformation(void);
86 void UninstallProgram(void);
88 void ListUninstallPrograms(void)
90 int i, len;
91 char *descr;
93 if (! FetchUninstallInformation())
94 return;
96 for (i=0; i < numentries; i++)
98 len = WideCharToMultiByte(CP_UNIXCP, 0, entries[i].descr, -1, NULL, 0, NULL, NULL);
99 descr = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
100 WideCharToMultiByte(CP_UNIXCP, 0, entries[i].descr, -1, descr, len, NULL, NULL);
101 printf("%s|||%s\n", entries[i].key, descr);
102 HeapFree(GetProcessHeap(), 0, descr);
107 void RemoveSpecificProgram(char *name)
109 int i;
111 if (! FetchUninstallInformation())
112 return;
114 for (i=0; i < numentries; i++)
116 if (strcmp(entries[i].key, name) == 0)
118 entries[i].active++;
119 break;
123 if (i < numentries)
124 UninstallProgram();
125 else
127 fprintf(stderr, "Error: could not match application [%s]\n", name);
131 int main( int argc, char *argv[])
133 MSG msg;
134 WNDCLASS wc;
135 HWND hWnd;
136 LPSTR token = NULL;
137 int i = 1;
138 HINSTANCE hInst = NULL;
140 while( i<argc )
142 token = argv[i++];
144 /* Handle requests just to list the applications */
145 if( !lstrcmpA( token, "--list" ) )
147 ListUninstallPrograms();
148 return 0;
150 else if( !lstrcmpA( token, "--remove" ) )
152 if( i >= argc )
154 WINE_ERR( "The remove option requires a parameter.\n");
155 return 1;
158 RemoveSpecificProgram( argv[i++] );
159 return 0;
161 else
163 WINE_ERR( "unknown option %s\n",token);
164 return 1;
168 LoadString( hInst, IDS_APPNAME, appname, sizeof(appname));
170 wc.style = 0;
171 wc.lpfnWndProc = MainProc;
172 wc.cbClsExtra = 0;
173 wc.cbWndExtra = 0;
174 wc.hInstance = hInst;
175 wc.hIcon = LoadIcon( hInst, appname );
176 wc.hCursor = LoadCursor( NULL_HANDLE, IDI_APPLICATION );
177 wc.hbrBackground = (HBRUSH)(COLOR_3DFACE + 1);
178 wc.lpszMenuName = NULL;
179 wc.lpszClassName = appname;
181 if (!RegisterClass(&wc)) exit(1);
182 hWnd = CreateWindow( appname, "Wine Application Uninstaller",
183 WS_OVERLAPPEDWINDOW & ~WS_THICKFRAME & ~WS_MAXIMIZEBOX,
184 CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
185 NULL_HANDLE, NULL_HANDLE, hInst, NULL );
187 if (!hWnd) exit(1);
189 ShowWindow( hWnd, SW_SHOW );
190 UpdateWindow( hWnd );
192 while( GetMessage(&msg, NULL_HANDLE, 0, 0) ) {
193 TranslateMessage( &msg );
194 DispatchMessage( &msg );
196 return msg.wParam;
199 int cmp_by_name(const void *a, const void *b)
201 return lstrcmpiW(((uninst_entry *)a)->descr, ((uninst_entry *)b)->descr);
204 int FetchUninstallInformation(void)
206 HKEY hkeyUninst, hkeyApp;
207 int i;
208 DWORD sizeOfSubKeyName, displen, uninstlen;
209 char subKeyName[256];
210 char key_app[1024];
211 char *p;
213 numentries = 0;
214 oldsel = -1;
215 if ( RegOpenKeyExA(HKEY_LOCAL_MACHINE, REGSTR_PATH_UNINSTALL,
216 0, KEY_READ, &hkeyUninst) != ERROR_SUCCESS )
218 MessageBox(0, "Uninstall registry key not available (yet), nothing to do !", appname, MB_OK);
219 return 0;
222 if (!entries)
223 entries = HeapAlloc(GetProcessHeap(), 0, sizeof(uninst_entry));
225 strcpy(key_app, REGSTR_PATH_UNINSTALL);
226 strcat(key_app, "\\");
227 p = key_app+strlen(REGSTR_PATH_UNINSTALL)+1;
229 sizeOfSubKeyName = 255;
230 for ( i=0;
231 RegEnumKeyExA( hkeyUninst, i, subKeyName, &sizeOfSubKeyName,
232 NULL, NULL, NULL, NULL ) != ERROR_NO_MORE_ITEMS;
233 ++i )
235 static const WCHAR DisplayNameW[] = {'D','i','s','p','l','a','y','N','a','m','e',0};
237 strcpy(p, subKeyName);
238 RegOpenKeyExA(HKEY_LOCAL_MACHINE, key_app, 0, KEY_READ, &hkeyApp);
240 if ( (RegQueryValueExW(hkeyApp, DisplayNameW,
241 0, 0, NULL, &displen) == ERROR_SUCCESS)
242 && (RegQueryValueExA(hkeyApp, REGSTR_VAL_UNINSTALLER_COMMANDLINE,
243 0, 0, NULL, &uninstlen) == ERROR_SUCCESS) )
245 numentries++;
246 entries = HeapReAlloc(GetProcessHeap(), 0, entries, numentries*sizeof(uninst_entry));
247 entries[numentries-1].key =
248 HeapAlloc(GetProcessHeap(), 0, strlen(subKeyName)+1);
249 strcpy(entries[numentries-1].key, subKeyName);
250 entries[numentries-1].descr =
251 HeapAlloc(GetProcessHeap(), 0, displen);
252 RegQueryValueExW(hkeyApp, DisplayNameW, 0, 0,
253 (LPBYTE)entries[numentries-1].descr, &displen);
254 entries[numentries-1].command =
255 HeapAlloc(GetProcessHeap(), 0, uninstlen);
256 entries[numentries-1].active = 0;
257 RegQueryValueExA(hkeyApp, REGSTR_VAL_UNINSTALLER_COMMANDLINE, 0, 0,
258 entries[numentries-1].command, &uninstlen);
259 WINE_TRACE("allocated entry #%d: %s (%s), %s\n",
260 numentries, entries[numentries-1].key,
261 wine_dbgstr_w(entries[numentries-1].descr),
262 entries[numentries-1].command);
264 RegCloseKey(hkeyApp);
266 sizeOfSubKeyName = 255;
268 qsort(entries, numentries, sizeof(uninst_entry), cmp_by_name);
269 RegCloseKey(hkeyUninst);
270 return 1;
273 void UninstallProgram(void)
275 int i;
276 char errormsg[1024];
277 BOOL res;
278 STARTUPINFO si;
279 PROCESS_INFORMATION info;
280 DWORD exit_code;
281 #ifdef DEL_REG_KEY
282 HKEY hkey;
283 #endif
285 for (i=0; i < numentries; i++)
287 if (!(entries[i].active)) /* don't uninstall this one */
288 continue;
289 WINE_TRACE("uninstalling %s\n", wine_dbgstr_w(entries[i].descr));
290 memset(&si, 0, sizeof(STARTUPINFO));
291 si.cb = sizeof(STARTUPINFO);
292 si.wShowWindow = SW_NORMAL;
293 res = CreateProcess(NULL, entries[i].command, NULL, NULL, FALSE, 0, NULL, NULL, &si, &info);
294 if (res == TRUE)
295 { /* wait for the process to exit */
296 WaitForSingleObject(info.hProcess, INFINITE);
297 res = GetExitCodeProcess(info.hProcess, &exit_code);
298 WINE_TRACE("%d: %08lx\n", res, exit_code);
299 #ifdef DEL_REG_KEY
300 /* delete the application's uninstall entry */
301 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, REGSTR_PATH_UNINSTALL,
302 0, KEY_READ, &hkey) == ERROR_SUCCESS)
304 RegDeleteKey(hkey, entries[i].key);
305 RegCloseKey(hkey);
307 #endif
309 else
311 sprintf(errormsg, "Execution of uninstall command '%s' failed, perhaps due to missing executable.", entries[i].command);
312 MessageBox(0, errormsg, appname, MB_OK);
315 WINE_TRACE("finished uninstall phase.\n");
316 list_need_update = 1;
319 LRESULT WINAPI MainProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
321 HDC hdc;
322 PAINTSTRUCT ps;
323 TEXTMETRIC tm;
324 int cxChar, cyChar, i, y, bx, maxx, maxy, wx, wy;
325 static HWND hwndList = 0, hwndEdit = 0;
326 DWORD style;
327 RECT rect;
329 switch( msg ) {
330 case WM_CREATE:
332 hdc = GetDC(hWnd);
333 GetTextMetrics(hdc, &tm);
334 cxChar = tm.tmAveCharWidth;
335 cyChar = tm.tmHeight + tm.tmExternalLeading;
336 ReleaseDC(hWnd, hdc);
337 /* FIXME: implement sorting and use LBS_SORT here ! */
338 style = (WS_CHILD|WS_VISIBLE|LBS_STANDARD) & ~LBS_SORT;
339 #ifdef USE_MULTIPLESEL
340 style |= LBS_MULTIPLESEL;
341 #endif
342 bx = maxx = cxChar * 5;
343 y = maxy = cyChar * 1;
344 CreateWindow("static", program_description,
345 WS_CHILD|WS_VISIBLE|SS_LEFT,
346 maxx, maxy,
347 cxChar * sizeof(program_description), cyChar * 1,
348 hWnd, (HMENU)1,
349 ((LPCREATESTRUCT)lParam)->hInstance, NULL);
350 maxy += cyChar * 2; /*static text + distance */
351 hwndList = CreateWindow("listbox", NULL,
352 style,
353 maxx, maxy,
354 cxChar * 50 + GetSystemMetrics(SM_CXVSCROLL), cyChar * 10,
355 hWnd, (HMENU) 1,
356 (HINSTANCE)GetWindowLong(hWnd, GWL_HINSTANCE), NULL);
357 GetWindowRect(hwndList, &rect);
358 maxx += (rect.right - rect.left)*1.1;
359 maxy += (rect.bottom - rect.top)*1.1;
360 wx = 20*cxChar;
361 wy = 7*cyChar/4;
362 y = cyChar * 3;
363 for (i=0; i < NUM; i++)
365 button[i].hwnd = CreateWindow("button", button[i].text,
366 WS_CHILD|WS_VISIBLE|BS_PUSHBUTTON,
367 maxx, y,
368 wx, wy,
369 hWnd, (HMENU)i,
370 ((LPCREATESTRUCT)lParam)->hInstance, NULL);
371 if (!button[i].hwnd)
372 PostQuitMessage(0);
373 y += 2*cyChar;
375 maxx += wx + cxChar * 5;
376 CreateWindow("static", "Command line to be executed:",
377 WS_CHILD|WS_VISIBLE|SS_LEFT,
378 bx, maxy,
379 cxChar * 50, cyChar,
380 hWnd, (HMENU)1,
381 ((LPCREATESTRUCT)lParam)->hInstance, NULL);
382 maxy += cyChar;
383 hwndEdit = CreateWindow("edit", NULL,
384 WS_CHILD|WS_VISIBLE|WS_BORDER|ES_LEFT|ES_MULTILINE|ES_READONLY,
385 bx, maxy, maxx-(2*bx), (cyChar*2)+4,
386 hWnd, (HMENU)1,
387 ((LPCREATESTRUCT)lParam)->hInstance, NULL);
388 maxy += (cyChar*2)+4 + cyChar * 3; /* edit ctrl + bottom border */
389 SetWindowPos( hWnd, 0,
390 0, 0, maxx, maxy,
391 SWP_NOMOVE);
392 return 0;
395 case WM_PAINT:
397 hdc = BeginPaint( hWnd, &ps );
398 if (list_need_update)
400 int prevsel;
401 prevsel = SendMessage(hwndList, LB_GETCURSEL, 0, 0);
402 if (!(FetchUninstallInformation()))
404 PostQuitMessage(0);
405 return 0;
407 SendMessage(hwndList, LB_RESETCONTENT, 0, 0);
408 SendMessage(hwndList, WM_SETREDRAW, FALSE, 0);
409 for (i=0; i < numentries; i++)
411 WINE_TRACE("adding %s\n", wine_dbgstr_w(entries[i].descr));
412 SendMessageW(hwndList, LB_ADDSTRING, 0, (LPARAM)entries[i].descr);
414 WINE_TRACE("setting prevsel %d\n", prevsel);
415 if (prevsel != -1)
416 SendMessage(hwndList, LB_SETCURSEL, prevsel, 0 );
417 SendMessage(hwndList, WM_SETREDRAW, TRUE, 0);
418 list_need_update = 0;
420 EndPaint( hWnd, &ps );
421 return 0;
424 case WM_DESTROY:
425 PostQuitMessage( 0 );
426 return 0;
428 case WM_COMMAND:
429 if ((HWND)lParam == hwndList)
431 if (HIWORD(wParam) == LBN_SELCHANGE)
433 int sel = SendMessage(hwndList, LB_GETCURSEL, 0, 0);
435 #ifndef USE_MULTIPLESEL
436 if (oldsel != -1)
438 entries[oldsel].active ^= 1; /* toggle */
439 WINE_TRACE("toggling %d old %s\n", entries[oldsel].active,
440 wine_dbgstr_w(entries[oldsel].descr));
442 #endif
443 entries[sel].active ^= 1; /* toggle */
444 WINE_TRACE("toggling %d %s\n", entries[sel].active,
445 wine_dbgstr_w(entries[oldsel].descr));
446 SendMessage(hwndEdit, WM_SETTEXT, 0, (LPARAM)entries[sel].command);
447 oldsel = sel;
450 else
451 if ((HWND)lParam == button[0].hwnd) /* Uninstall button */
453 UninstallProgram();
455 InvalidateRect(hWnd, NULL, TRUE);
456 UpdateWindow(hWnd);
459 else
460 if ((HWND)lParam == button[1].hwnd) /* About button */
461 MessageBox(0, about_string, "About Wine Application Uninstaller", MB_OK);
462 else
463 if ((HWND)lParam == button[2].hwnd) /* Exit button */
464 PostQuitMessage(0);
465 return 0;
468 return( DefWindowProc( hWnd, msg, wParam, lParam ));