1 #include <wchar.h>
2 
3 #define OEMRESOURCE
4 #include <windows.h>
5 #include <commctrl.h>
6 #include <shlobj.h>
7 
8 #define WC_mainWindow L"V1541CommanderUninstall"
9 #define CID_uninstall 0x101
10 #define CID_cancel 0x102
11 
12 static HINSTANCE instance;
13 static HWND mainWindow;
14 static NONCLIENTMETRICSW ncm;
15 static HFONT messageFont;
16 static TEXTMETRICW messageFontMetrics;
17 static int buttonWidth;
18 static int buttonHeight;
19 
20 static const WCHAR *locales[] = {
21     L"C",
22     L"de",
23 };
24 
25 enum textid {
26     TID_title,
27     TID_success_title,
28     TID_success_message,
29     TID_failure_title,
30     TID_failure_message,
31     TID_message,
32     TID_uninstall,
33     TID_cancel,
34 
35     TID_N_texts
36 };
37 
38 static const WCHAR *locale_texts[][TID_N_texts] = {
39     {
40 	L"V1541Commander Uninstall",
41 	L"Uninstall completed",
42 	L"All filetype associations for V1541Commander\n"
43 	    L"were removed successfully.",
44 	L"Uninstall failed",
45 	L"There was an unexpected error removing\n"
46 	    L"file type associations for V1541Commander.",
47 	L"This tool unregisters V1541Commander with windows\n"
48             L"and removes all file type associations created by\n"
49             L"setup.exe.",
50 	L"Uninstall",
51         L"Cancel",
52     },
53     {
54 	L"V1541Commander entfernen",
55 	L"Deinstallation erfolgreich",
56 	L"Alle Zuordnungen von Dateitypen für V1541Commander\n"
57 	    L"wurden erfolgreich entfernt.",
58 	L"Deinstallation fehlgeschlagen",
59 	L"Beim Entfernen von Dateityp-Zuordnungen für V1541Commander\n"
60 	    L"ist ein unerwarteter Fehler aufgetreten.",
61 	L"Dieses Programm deregistriert V1541Commander in Windows\n"
62             L"und entfernt alle Dateityp-Zuordnungen, die von setup.exe\n"
63             L"erstellt wurden.\n",
64 	L"Entfernen",
65         L"Abbrechen",
66     },
67 };
68 
69 static const WCHAR **texts = locale_texts[0];
70 
init(void)71 static void init(void)
72 {
73     INITCOMMONCONTROLSEX icx;
74     icx.dwSize = sizeof icx;
75     icx.dwICC = ICC_WIN95_CLASSES;
76     InitCommonControlsEx(&icx);
77     ncm.cbSize = sizeof ncm;
78     SystemParametersInfoW(SPI_GETNONCLIENTMETRICS, ncm.cbSize, &ncm, 0);
79     messageFont = CreateFontIndirectW(&ncm.lfMessageFont);
80     HDC dc = GetDC(0);
81     SelectObject(dc, (HGDIOBJ) messageFont);
82     GetTextMetricsW(dc, &messageFontMetrics);
83     SIZE sampleSize;
84     GetTextExtentExPointW(dc,
85             L"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz",
86             52, 0, 0, 0, &sampleSize);
87     ReleaseDC(0, dc);
88     buttonWidth = MulDiv(sampleSize.cx, 50, 4 * 52);
89     buttonHeight = MulDiv(messageFontMetrics.tmHeight, 14, 8);
90     instance = GetModuleHandleW(0);
91 
92     WCHAR lang[10];
93     if (GetLocaleInfoW(LOCALE_USER_DEFAULT,
94 		LOCALE_SISO639LANGNAME, lang, 10) > 0)
95     {
96 	for (size_t i = 1; i < sizeof locales / sizeof *locales; ++i)
97 	{
98 	    if (!wcscmp(locales[i], lang))
99 	    {
100 		texts = locale_texts[i];
101 		break;
102 	    }
103 	}
104     }
105 }
106 
regTreeDel(HKEY key,LPCWSTR subKey)107 static void regTreeDel(HKEY key, LPCWSTR subKey)
108 {
109     HKEY sub;
110     if (RegOpenKeyExW(key, subKey, 0, DELETE|KEY_ENUMERATE_SUB_KEYS, &sub)
111 	    == ERROR_SUCCESS)
112     {
113 	WCHAR subName[256];
114 	DWORD subNameLen;
115 	while (subNameLen = 256,
116 		RegEnumKeyExW(sub, 0, subName, &subNameLen, 0, 0, 0, 0)
117 		== ERROR_SUCCESS)
118 	{
119 	    regTreeDel(sub, subName);
120 	}
121 	RegCloseKey(sub);
122 	RegDeleteKeyW(key, subKey);
123     }
124 }
125 
unregisterType(HKEY classes,LPCWSTR ext,LPCWSTR name)126 static int unregisterType(HKEY classes, LPCWSTR ext, LPCWSTR name)
127 {
128     int success = 1;
129 
130     HKEY ekey;
131 
132     if (RegOpenKeyExW(classes, ext, 0, KEY_WRITE|KEY_QUERY_VALUE, &ekey)
133 	    == ERROR_SUCCESS)
134     {
135 	WCHAR value[128];
136 	DWORD len = 128;
137 	DWORD valueType;
138 	if (RegQueryValueExW(ekey, 0, 0, &valueType, (LPBYTE)&value, &len)
139 		== ERROR_SUCCESS)
140 	{
141 	    if (valueType != REG_SZ)
142 	    {
143 		success = 0;
144 	    }
145 	    else
146 	    {
147 		value[len] = L'\0';
148 		if (!wcscmp(value, name))
149 		{
150 		    if (RegDeleteValueW(ekey, 0) != ERROR_SUCCESS)
151 		    {
152 			success = 0;
153 		    }
154 		}
155 	    }
156 	}
157 
158         HKEY owkey;
159         if (RegOpenKeyExW(ekey, L"OpenWithProgids", 0, KEY_WRITE, &owkey)
160                 == ERROR_SUCCESS)
161         {
162             RegDeleteValueW(owkey, name);
163             RegCloseKey(owkey);
164         }
165         RegCloseKey(ekey);
166     }
167 
168     regTreeDel(classes, name);
169 
170     return success;
171 }
172 
unregister(HWND w)173 static void unregister(HWND w)
174 {
175     int success = 1;
176 
177     HKEY key;
178     if (RegOpenKeyExW(HKEY_CURRENT_USER, L"SOFTWARE\\Microsoft\\Windows\\"
179 		"CurrentVersion\\App Paths", 0,
180 		DELETE|KEY_ENUMERATE_SUB_KEYS, &key) == ERROR_SUCCESS)
181     {
182 	regTreeDel(key, L"v1541commander.exe");
183 	RegCloseKey(key);
184     }
185     if (RegOpenKeyExW(HKEY_CURRENT_USER, L"SOFTWARE\\Classes\\Applications",
186 		0, DELETE|KEY_ENUMERATE_SUB_KEYS, &key) == ERROR_SUCCESS)
187     {
188 	regTreeDel(key, L"v1541commander.exe");
189 	RegCloseKey(key);
190     }
191     if (RegOpenKeyExW(HKEY_CURRENT_USER, L"SOFTWARE\\Classes", 0,
192 		KEY_WRITE|KEY_ENUMERATE_SUB_KEYS, &key) == ERROR_SUCCESS)
193     {
194         if (!unregisterType(key, L".prg", L"V1541Commander.Zipcode"))
195         {
196             success = 0;
197         }
198         if (!unregisterType(key, L".prg", L"V1541Commander.PRG"))
199         {
200             success = 0;
201         }
202         if (!unregisterType(key, L".lnx", L"V1541Commander.LyNX"))
203         {
204             success = 0;
205         }
206         if (!unregisterType(key, L".d64", L"V1541Commander.D64"))
207         {
208             success = 0;
209         }
210         RegCloseKey(key);
211     }
212     else success = 0;
213 
214     SHChangeNotify(SHCNE_ASSOCCHANGED, SHCNF_IDLIST, 0, 0);
215     if (success)
216     {
217 	MessageBoxW(w, texts[TID_success_message],
218 		texts[TID_success_title], MB_OK|MB_ICONINFORMATION);
219     }
220     else
221     {
222 	MessageBoxW(w, texts[TID_failure_message],
223 		texts[TID_failure_title], MB_OK|MB_ICONERROR);
224     }
225 }
226 
wproc(HWND w,UINT msg,WPARAM wp,LPARAM lp)227 static LRESULT CALLBACK wproc(HWND w, UINT msg, WPARAM wp, LPARAM lp)
228 {
229     switch (msg)
230     {
231     case WM_CREATE:
232 	{
233 	    HDC dc = GetDC(0);
234 	    SelectObject(dc, (HGDIOBJ) messageFont);
235 	    RECT textrect = {0, 0, 0, 0};
236 	    int padding = messageFontMetrics.tmAveCharWidth * 3 / 2;
237 	    int ypos = padding;
238 
239 	    const WCHAR *text = texts[TID_message];
240 	    DrawTextExW(dc, (WCHAR *)text, -1, &textrect, DT_CALCRECT, 0);
241 	    int fullwidth = textrect.right;
242 	    HWND ctrl = CreateWindowExW(0, L"Static", text,
243 		    WS_CHILD|WS_VISIBLE, padding, ypos,
244 		    textrect.right, textrect.bottom, w, 0, instance, 0);
245 	    SendMessageW(ctrl, WM_SETFONT, (WPARAM)messageFont, 0);
246 	    ypos += textrect.bottom + padding;
247 
248 	    ctrl = CreateWindowExW(0, L"Button", texts[TID_uninstall],
249 		    WS_CHILD|WS_VISIBLE|BS_DEFPUSHBUTTON,
250 		    fullwidth - 2*buttonWidth, ypos,
251 		    buttonWidth, buttonHeight,
252 		    w, (HMENU)CID_uninstall, instance, 0);
253 	    SendMessageW(ctrl, WM_SETFONT, (WPARAM)messageFont, 0);
254 	    ctrl = CreateWindowExW(0, L"Button", texts[TID_cancel],
255 		    WS_CHILD|WS_VISIBLE|BS_PUSHBUTTON,
256 		    padding + fullwidth - buttonWidth, ypos,
257 		    buttonWidth, buttonHeight,
258 		    w, (HMENU)CID_cancel, instance, 0);
259 	    SendMessageW(ctrl, WM_SETFONT, (WPARAM)messageFont, 0);
260 	    ypos += buttonHeight + padding;
261 
262 	    ReleaseDC(0, dc);
263 	    RECT winRect = {0, 0, fullwidth + 2*padding, ypos};
264 	    AdjustWindowRect(&winRect, WS_CAPTION|WS_SYSMENU, 0);
265 	    SetWindowPos(w, HWND_TOP, 0, 0,
266 		    winRect.right - winRect.left,
267 		    winRect.bottom - winRect.top, SWP_NOMOVE);
268 	}
269         break;
270 
271     case WM_DESTROY:
272         PostQuitMessage(0);
273         break;
274 
275     case WM_KEYDOWN:
276         if (wp == VK_RETURN)
277         {
278             unregister(w);
279             DestroyWindow(w);
280         }
281         else if (wp == VK_ESCAPE)
282         {
283             DestroyWindow(w);
284         }
285         break;
286 
287     case WM_COMMAND:
288         switch (LOWORD(wp))
289         {
290         case CID_uninstall:
291 	    unregister(w);
292             /* fall through */
293         case CID_cancel:
294 	    DestroyWindow(w);
295             break;
296         }
297         break;
298     }
299     return DefWindowProcW(w, msg, wp, lp);
300 }
301 
main(void)302 int main(void)
303 {
304     init();
305 
306     WNDCLASSEXW wc;
307     memset(&wc, 0, sizeof wc);
308     wc.cbSize = sizeof wc;
309     wc.hInstance = instance;
310     wc.lpszClassName = WC_mainWindow;
311     wc.lpfnWndProc = wproc;
312     wc.hbrBackground = (HBRUSH) COLOR_WINDOW;
313     wc.hCursor = (HCURSOR) LoadImageW(0, MAKEINTRESOURCEW(OCR_NORMAL),
314 	    IMAGE_CURSOR, 0, 0, LR_DEFAULTSIZE|LR_SHARED);
315     RegisterClassExW(&wc);
316 
317     mainWindow = CreateWindowExW(0, WC_mainWindow, texts[TID_title],
318             WS_CAPTION|WS_SYSMENU, CW_USEDEFAULT, CW_USEDEFAULT,
319 	    320, 100, 0, 0, instance, 0);
320     ShowWindow(mainWindow, SW_SHOWNORMAL);
321 
322     MSG msg;
323     while (GetMessageW(&msg, 0, 0, 0) > 0)
324     {
325         TranslateMessage(&msg);
326         DispatchMessageW(&msg);
327     }
328     return (int)msg.wParam;
329 }
330 
331