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