1 #include <wchar.h>
2 
3 #define OEMRESOURCE
4 #include <windows.h>
5 #include <accctrl.h>
6 #include <aclapi.h>
7 #include <commctrl.h>
8 #include <shlwapi.h>
9 #include <shlobj.h>
10 
11 #define WC_mainWindow L"V1541CommanderSetup"
12 #define CID_register 0x101
13 #define CID_cancel 0x102
14 #define CID_d64 0x103
15 #define CID_lynx 0x104
16 #define CID_zipcode 0x105
17 
18 static HINSTANCE instance;
19 static HWND mainWindow;
20 static NONCLIENTMETRICSW ncm;
21 static HFONT messageFont;
22 static TEXTMETRICW messageFontMetrics;
23 static int buttonWidth;
24 static int buttonHeight;
25 
26 static int ftD64 = 1;
27 static int ftLynx = 1;
28 static int ftZipcode = 0;
29 
30 static WCHAR commanderPath[MAX_PATH];
31 static WCHAR commanderQuotedPath[MAX_PATH+2];
32 static WCHAR commanderRegCommand[MAX_PATH+7];
33 static DWORD commanderRegCommandSize;
34 static WCHAR regValTmp[MAX_PATH+16];
35 
36 #define FEXIDX (sizeof "SOFTWARE\\Microsoft\\Windows\\" \
37     "CurrentVersion\\Explorer\\FileExts\\" - 1)
38 #define UCNLEN ((FEXIDX) + sizeof ".xxxxxxxx\\UserChoice")
39 
40 static WCHAR userChoiceName[UCNLEN] = L"SOFTWARE\\Microsoft\\"
41     "Windows\\CurrentVersion\\Explorer\\FileExts\\";
42 
43 static PSID sid = 0;
44 
45 static const WCHAR *locales[] = {
46     L"C",
47     L"de",
48 };
49 
50 enum textid {
51     TID_title,
52     TID_notfound_title,
53     TID_notfound_message,
54     TID_regsuccess_title,
55     TID_regsuccess_message,
56     TID_regfailure_title,
57     TID_regfailure_message,
58     TID_select_types,
59     TID_prg_warn,
60     TID_register,
61     TID_cancel,
62     TID_d64,
63     TID_lynx,
64     TID_zipcode,
65 
66     TID_N_texts
67 };
68 
69 static const WCHAR *locale_texts[][TID_N_texts] = {
70     {
71 	L"V1541Commander Setup",
72 	L"v1541commander.exe not found",
73 	L"Please run this from the same directory\n"
74 	    L"where v1541commander.exe is located.",
75 	L"File types registered",
76 	L"The selected file types were associated\n"
77 	    L"to V1541Commander successfully.",
78 	L"Registration failed",
79 	L"There was an unexpected error registering\n"
80 	    L"the selected file types to V1541Commander.",
81 	L"This tool registers V1541Commander with windows\n"
82             L"and associates it with all file types that can be\n"
83             L"opened or imported.\n"
84             L"\n"
85             L"Select here for which file types V1541Commander\n"
86             L"should be set as the default application:",
87         L"It's not recommended to set V1541Commander as the\n"
88             L"default application for .prg files, as most .prg files\n"
89             L"aren't Zipcode files.",
90 	L"Register",
91         L"Cancel",
92 	L"1541 disk images (.d64)",
93 	L"LyNX archives (.lnx)",
94 	L"Zipcode files (.prg)",
95     },
96     {
97 	L"V1541Commander Einrichtung",
98 	L"v1541commander.exe nicht gefunden",
99 	L"Bitte starten Sie dieses Programm aus dem\n"
100 	    L"gleichen Verzeichnis, in dem sich auch\n"
101 	    L"v1541commander.exe befindet.",
102 	L"Dateitypen registriert",
103 	L"Die gewählten Dateitypen wurden erfolgreich\n"
104 	    L"V1541Commander zugeordnet.",
105 	L"Registrierung fehlgeschlagen",
106 	L"Bei der Registrierung der gewählten Dateitypen\n"
107 	    L"für V1541Commander ist ein unerwarteter Fehler\n"
108 	    L"aufgetreten.",
109 	L"Dieses Programm registriert V1541Commander in Windows\n"
110             L"und verknüpft es mit allen Dateitypen, die geöffnet oder\n"
111             L"importiert werden können.\n"
112             L"\n"
113             L"Wählen Sie hier die Dateitypen, für die V1541Commander\n"
114             L"als Standardanwendung gesetzt werden soll:",
115         L"Es wird nicht empfohlen, V1541Commander als Standard-\n"
116             L"anwendung für .prg-Dateien zu setzen, da die meisten .prg-\n"
117             L"Dateien keine Zipcode Dateien sind.",
118 	L"Registrieren",
119         L"Abbrechen",
120 	L"1541 Diskettenabbilddateien (.d64)",
121 	L"LyNX Archive (.lnx)",
122 	L"Zipcode Dateien (.prg)",
123     },
124 };
125 
126 static const WCHAR **texts = locale_texts[0];
127 
init(void)128 static void init(void)
129 {
130     INITCOMMONCONTROLSEX icx;
131     icx.dwSize = sizeof icx;
132     icx.dwICC = ICC_WIN95_CLASSES;
133     InitCommonControlsEx(&icx);
134     ncm.cbSize = sizeof ncm;
135     SystemParametersInfoW(SPI_GETNONCLIENTMETRICS, ncm.cbSize, &ncm, 0);
136     messageFont = CreateFontIndirectW(&ncm.lfMessageFont);
137     HDC dc = GetDC(0);
138     SelectObject(dc, (HGDIOBJ) messageFont);
139     GetTextMetricsW(dc, &messageFontMetrics);
140     SIZE sampleSize;
141     GetTextExtentExPointW(dc,
142             L"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz",
143             52, 0, 0, 0, &sampleSize);
144     ReleaseDC(0, dc);
145     buttonWidth = MulDiv(sampleSize.cx, 50, 4 * 52);
146     buttonHeight = MulDiv(messageFontMetrics.tmHeight, 14, 8);
147     instance = GetModuleHandleW(0);
148 
149     WCHAR lang[10];
150     if (GetLocaleInfoW(LOCALE_USER_DEFAULT,
151 		LOCALE_SISO639LANGNAME, lang, 10) > 0)
152     {
153 	for (size_t i = 1; i < sizeof locales / sizeof *locales; ++i)
154 	{
155 	    if (!wcscmp(locales[i], lang))
156 	    {
157 		texts = locale_texts[i];
158 		break;
159 	    }
160 	}
161     }
162 
163     HANDLE token;
164     if (OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &token))
165     {
166         DWORD size = 0;
167         GetTokenInformation(token, TokenUser, 0, 0, &size);
168         if (GetLastError() == ERROR_INSUFFICIENT_BUFFER)
169         {
170             TOKEN_USER *user = malloc(size);
171             if (GetTokenInformation(token, TokenUser, user, size, &size))
172             {
173                 if (IsValidSid(user->User.Sid))
174                 {
175                     DWORD sidSize = GetLengthSid(user->User.Sid);
176                     sid = malloc(sidSize);
177                     CopySid(sidSize, sid, user->User.Sid);
178                 }
179             }
180             free(user);
181         }
182         CloseHandle(token);
183     }
184 }
185 
getCommanderPath(void)186 static int getCommanderPath(void)
187 {
188     GetModuleFileNameW(instance, commanderPath, MAX_PATH);
189     WCHAR *pos = wcsrchr(commanderPath, L'\\');
190     if (!pos) return 0;
191     wcscpy(pos+1, L"v1541commander.exe");
192     int rc = PathFileExistsW(commanderPath);
193     if (rc)
194     {
195         size_t pathlen = wcslen(commanderPath);
196         commanderQuotedPath[0] = L'"';
197         wcscpy(commanderQuotedPath+1, commanderPath);
198         commanderQuotedPath[pathlen+1] = L'"';
199         commanderQuotedPath[pathlen+2] = L'\0';
200         wcscpy(commanderRegCommand, commanderQuotedPath);
201         wcscpy(commanderRegCommand + pathlen + 2, L" \"%1\"");
202         commanderRegCommandSize = (pathlen + 8)
203             * sizeof *commanderRegCommand;
204     }
205     return rc;
206 }
207 
regTreeDel(HKEY key,LPCWSTR subKey)208 static void regTreeDel(HKEY key, LPCWSTR subKey)
209 {
210     HKEY sub;
211     if (RegOpenKeyExW(key, subKey, 0, DELETE|KEY_ENUMERATE_SUB_KEYS, &sub)
212 	    == ERROR_SUCCESS)
213     {
214 	WCHAR subName[256];
215 	DWORD subNameLen;
216 	while (subNameLen = 256,
217 		RegEnumKeyExW(sub, 0, subName, &subNameLen, 0, 0, 0, 0)
218 		== ERROR_SUCCESS)
219 	{
220 	    regTreeDel(sub, subName);
221 	}
222 	RegCloseKey(sub);
223 	RegDeleteKeyW(key, subKey);
224     }
225 }
226 
regUnprotect(LPCWSTR subKey)227 static void regUnprotect(LPCWSTR subKey)
228 {
229     if (!sid) return;
230     SECURITY_DESCRIPTOR sd;
231     HKEY sub;
232     if (!InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION))
233     {
234         return;
235     }
236     if (RegOpenKeyExW(HKEY_CURRENT_USER, subKey, 0, WRITE_DAC, &sub)
237             != ERROR_SUCCESS) return;
238     EXPLICIT_ACCESS_W ea[1] = { 0 };
239     PACL acl = 0;
240     ea[0].grfAccessPermissions = GENERIC_ALL;
241     ea[0].grfAccessMode = SET_ACCESS;
242     ea[0].grfInheritance = SUB_OBJECTS_ONLY_INHERIT;
243     ea[0].Trustee.TrusteeForm = TRUSTEE_IS_SID;
244     ea[0].Trustee.TrusteeType = TRUSTEE_IS_USER;
245     ea[0].Trustee.ptstrName = (void *)sid;
246     if (SetEntriesInAclW(1, ea, 0, &acl) != ERROR_SUCCESS)
247     {
248         RegCloseKey(sub);
249         return;
250     }
251     if (!SetSecurityDescriptorDacl(&sd, 1, acl, 0))
252     {
253         LocalFree(acl);
254         RegCloseKey(sub);
255         return;
256     }
257     RegSetKeySecurity(sub, DACL_SECURITY_INFORMATION, &sd);
258     LocalFree(acl);
259     RegCloseKey(sub);
260 }
261 
setFriendlyTypeNameAndIcon(HKEY tkey,int nameId)262 static int setFriendlyTypeNameAndIcon(HKEY tkey, int nameId)
263 {
264     DWORD valSize = wcslen(commanderQuotedPath) + 2;
265     regValTmp[0] = L'@';
266     wcscpy(regValTmp+1, commanderQuotedPath);
267     int numlen = swprintf(regValTmp + valSize - 1, PATH_MAX - valSize,
268             L",-%d", nameId);
269     if (numlen < 1) return 0;
270     valSize += numlen;
271     valSize *= sizeof *regValTmp;
272     if (RegSetValueExW(tkey, L"FriendlyTypeName", 0, REG_SZ,
273 		(const BYTE *)regValTmp, valSize) != ERROR_SUCCESS)
274     {
275 	return 0;
276     }
277 
278     HKEY tmp;
279     if (RegCreateKeyExW(tkey, L"DefaultIcon", 0, 0, 0, KEY_WRITE, 0, &tmp, 0)
280 	    != ERROR_SUCCESS) return 0;
281 
282     valSize = wcslen(commanderQuotedPath) + 1;
283     wcscpy(regValTmp, commanderQuotedPath);
284     numlen = swprintf(regValTmp + valSize - 1, PATH_MAX - valSize,
285             L",%d", nameId);
286     if (numlen < 1)
287     {
288         RegCloseKey(tmp);
289         return 0;
290     }
291     valSize += numlen;
292     valSize *= sizeof *regValTmp;
293     if (RegSetValueExW(tmp, 0, 0, REG_SZ,
294                 (const BYTE *)regValTmp, valSize) != ERROR_SUCCESS)
295     {
296         RegCloseKey(tmp);
297         return 0;
298     }
299     RegCloseKey(tmp);
300     return 1;
301 }
302 
registerAutoType(HKEY classes,LPCWSTR ext,int nameId)303 static void registerAutoType(HKEY classes, LPCWSTR ext, int nameId)
304 {
305     HKEY tmp;
306     if (RegOpenKeyExW(classes, ext, 0, KEY_QUERY_VALUE, &tmp)
307             != ERROR_SUCCESS) return;
308 
309     WCHAR value[128];
310     DWORD len = 128;
311     DWORD valueType;
312     if (RegQueryValueExW(tmp, 0, 0, &valueType, (LPBYTE)&value, &len)
313             == ERROR_SUCCESS)
314     {
315         if (valueType != REG_SZ)
316         {
317             RegCloseKey(tmp);
318             return;
319         }
320         value[len] = L'\0';
321         WCHAR autoTypeKeyName[18];
322         wcscpy(autoTypeKeyName, ext+1);
323         wcscat(autoTypeKeyName, L"_auto_file");
324         if (!wcscmp(value, autoTypeKeyName))
325         {
326             RegCloseKey(tmp);
327             if (RegOpenKeyExW(classes, autoTypeKeyName, 0, KEY_WRITE, &tmp)
328                     != ERROR_SUCCESS) return;
329             HKEY ico;
330             if (RegOpenKeyExW(tmp, L"DefaultIcon", 0, KEY_WRITE, &ico)
331                     == ERROR_SUCCESS)
332             {
333                 RegCloseKey(ico);
334             }
335             else
336             {
337                 setFriendlyTypeNameAndIcon(tmp, nameId);
338             }
339         }
340     }
341     RegCloseKey(tmp);
342 }
343 
registerType(HKEY classes,HKEY suppTypes,LPCWSTR ext,LPCWSTR name,LPCWSTR desc,LPCWSTR contentType,int nameId,int associate)344 static int registerType(HKEY classes, HKEY suppTypes, LPCWSTR ext,
345         LPCWSTR name, LPCWSTR desc, LPCWSTR contentType, int nameId,
346         int associate)
347 {
348     HKEY tkey = 0;
349     HKEY ekey = 0;
350     HKEY tmp;
351     int rc = 0;
352 
353     if (RegCreateKeyExW(suppTypes, ext, 0, 0, 0, KEY_WRITE,
354                 0, &tmp, 0) == ERROR_SUCCESS)
355     {
356         RegCloseKey(tmp);
357     }
358     else goto done;
359 
360     if (RegCreateKeyExW(classes, ext, 0, 0, 0, KEY_WRITE, 0, &ekey, 0)
361             != ERROR_SUCCESS) goto done;
362 
363     if (RegCreateKeyExW(classes, name, 0, 0, 0, KEY_WRITE, 0, &tkey, 0)
364             != ERROR_SUCCESS) goto done;
365 
366     if (RegCreateKeyExW(tkey, L"shell\\open\\command", 0, 0, 0, KEY_WRITE,
367                 0, &tmp, 0) == ERROR_SUCCESS)
368     {
369 	if (RegSetValueExW(tmp, 0, 0, REG_SZ,
370                     (const BYTE *)commanderRegCommand,
371                     commanderRegCommandSize)
372                 != ERROR_SUCCESS)
373 	{
374 	    RegCloseKey(tmp);
375 	    goto done;
376 	}
377 	RegCloseKey(tmp);
378     }
379     else goto done;
380 
381     DWORD valSize = (wcslen(desc)+1) * sizeof *desc;
382     if (RegSetValueExW(tkey, 0, 0, REG_SZ,
383                 (const BYTE *)desc, valSize) != ERROR_SUCCESS)
384     {
385 	goto done;
386     }
387     valSize = (wcslen(contentType)+1) * sizeof *contentType;
388     if (RegSetValueExW(tkey, L"Content Type", 0, REG_SZ,
389 		(const BYTE *)contentType, valSize) != ERROR_SUCCESS)
390     {
391 	goto done;
392     }
393 
394     if (!setFriendlyTypeNameAndIcon(tkey, nameId)) goto done;
395 
396     if (RegOpenKeyExW(tkey, L"shell", 0, KEY_WRITE, &tmp) == ERROR_SUCCESS)
397     {
398         if (RegSetValueExW(tmp, 0, 0, REG_SZ, (const BYTE *)L"open",
399                     sizeof L"open") != ERROR_SUCCESS)
400         {
401             RegCloseKey(tmp);
402             goto done;
403         }
404         RegCloseKey(tmp);
405     }
406     else goto done;
407 
408     if (RegCreateKeyExW(ekey, L"OpenWithProgids", 0, 0, 0,
409                 KEY_WRITE, 0, &tmp, 0) == ERROR_SUCCESS)
410     {
411         if (RegSetValueExW(tmp, name, 0, REG_NONE, 0, 0) != ERROR_SUCCESS)
412         {
413             RegCloseKey(tmp);
414             goto done;
415         }
416         RegCloseKey(tmp);
417     }
418     else goto done;
419 
420     registerAutoType(classes, ext, nameId);
421     if (!associate)
422     {
423         rc = 1;
424         goto done;
425     }
426 
427     valSize = (wcslen(name)+1) * sizeof *name;
428     if (RegSetValueExW(ekey, 0, 0, REG_SZ, (const BYTE *)name, valSize)
429             != ERROR_SUCCESS)
430     {
431 	goto done;
432     }
433     rc = 1;
434 
435     size_t extLen = wcslen(ext);
436     wcscpy(userChoiceName + FEXIDX, ext);
437     userChoiceName[FEXIDX + extLen] = L'\\';
438     wcscpy(userChoiceName + FEXIDX + extLen + 1, L"UserChoice");
439     regUnprotect(userChoiceName);
440     userChoiceName[FEXIDX + extLen] = L'\0';
441     if (RegOpenKeyExW(HKEY_CURRENT_USER, userChoiceName, 0,
442                 DELETE|KEY_ENUMERATE_SUB_KEYS, &tmp) == ERROR_SUCCESS)
443     {
444         regTreeDel(tmp, L"UserChoice");
445         RegCloseKey(tmp);
446     }
447 
448 done:
449     if (ekey) RegCloseKey(ekey);
450     if (tkey) RegCloseKey(tkey);
451     return rc;
452 }
453 
registerTypes(HWND w)454 static void registerTypes(HWND w)
455 {
456     int success = 0;
457     HKEY regkey = 0;
458     if (RegCreateKeyExW(HKEY_CURRENT_USER, L"SOFTWARE\\Microsoft\\Windows\\"
459                 "CurrentVersion\\App Paths\\v1541commander.exe", 0,
460                 0, 0, KEY_WRITE, 0, &regkey, 0) != ERROR_SUCCESS)
461     {
462         goto done;
463     }
464     DWORD valSize = (wcslen(commanderPath)+1) * sizeof *commanderPath;
465     if (RegSetValueExW(regkey, 0, 0, REG_SZ,
466                 (const BYTE *)commanderPath, valSize) != ERROR_SUCCESS)
467     {
468         goto done;
469     }
470     RegCloseKey(regkey);
471     regkey = 0;
472 
473     HKEY classes = 0;
474     if (RegOpenKeyExW(HKEY_CURRENT_USER, L"SOFTWARE\\Classes", 0,
475 		KEY_WRITE, &classes) == ERROR_SUCCESS)
476     {
477         if (RegCreateKeyExW(classes,
478                     L"Applications\\v1541commander.exe\\shell\\open\\command",
479                     0, 0, 0, KEY_WRITE, 0, &regkey, 0) == ERROR_SUCCESS)
480         {
481             if (RegSetValueExW(regkey, 0, 0, REG_SZ,
482                         (const BYTE *)commanderRegCommand,
483                         commanderRegCommandSize)
484                     != ERROR_SUCCESS)
485             {
486                 goto done;
487 	    }
488 	    RegCloseKey(regkey);
489             regkey = 0;
490         }
491         else goto done;
492         if (RegCreateKeyExW(classes,
493                     L"Applications\\v1541commander.exe\\SupportedTypes", 0,
494                     0, 0, KEY_WRITE, 0, &regkey, 0) == ERROR_SUCCESS)
495         {
496             if (!registerType(classes, regkey,
497                         L".d64", L"V1541Commander.D64", L"D64 disk image",
498                         L"application/vnd.cbm.d64-disk-image", 1, ftD64))
499             {
500                 goto done;
501             }
502             if (!registerType(classes, regkey,
503                         L".lnx", L"V1541Commander.LyNX", L"C64 LyNX archive",
504                         L"application/x.willcorley.lynx-archive", 2, ftLynx))
505             {
506                 goto done;
507             }
508             if (!registerType(classes, regkey,
509                         L".prg", ftZipcode ? L"V1541Commander.Zipcode" :
510 			L"V1541Commander.PRG", ftZipcode ?
511 			L"C64 Zip-Code archive file" : L"Commodore program",
512                         ftZipcode ? L"application/x.c64.zip-code" :
513 			L"application/vnd.cbm.program-file",
514 			ftZipcode ? 3 : 4, ftZipcode))
515             {
516                 goto done;
517             }
518             success = 1;
519         }
520     }
521 
522 done:
523     if (regkey) RegCloseKey(regkey);
524     if (classes) RegCloseKey(classes);
525     SHChangeNotify(SHCNE_ASSOCCHANGED, SHCNF_IDLIST, 0, 0);
526     if (success)
527     {
528 	MessageBoxW(w, texts[TID_regsuccess_message],
529 		texts[TID_regsuccess_title], MB_OK|MB_ICONINFORMATION);
530     }
531     else
532     {
533 	MessageBoxW(w, texts[TID_regfailure_message],
534 		texts[TID_regfailure_title], MB_OK|MB_ICONERROR);
535     }
536 }
537 
addFileTypeCheckbox(HWND w,int cid,LPCWSTR desc,int checked,HDC dc,int padding,int * ypos,int * fullwidth)538 static void addFileTypeCheckbox(HWND w, int cid, LPCWSTR desc, int checked,
539 	HDC dc, int padding, int *ypos, int *fullwidth)
540 {
541     SIZE size;
542     GetTextExtentExPointW(dc, desc, wcslen(desc), 0, 0, 0, &size);
543     size.cx += 2*padding;
544     *fullwidth = size.cx > *fullwidth ? size.cx : *fullwidth;
545     HWND cb = CreateWindowExW(0, L"Button", desc,
546 	    WS_CHILD|WS_VISIBLE|BS_CHECKBOX, padding, *ypos,
547 	    size.cx, size.cy, w, (HMENU)cid, instance, 0);
548     *ypos += size.cy + padding;
549     SendMessageW(cb, WM_SETFONT, (WPARAM)messageFont, 0);
550     if (checked) CheckDlgButton(w, cid, BST_CHECKED);
551 }
552 
wproc(HWND w,UINT msg,WPARAM wp,LPARAM lp)553 static LRESULT CALLBACK wproc(HWND w, UINT msg, WPARAM wp, LPARAM lp)
554 {
555     switch (msg)
556     {
557     case WM_CREATE:
558 	{
559 	    HDC dc = GetDC(0);
560 	    SelectObject(dc, (HGDIOBJ) messageFont);
561 	    RECT textrect = {0, 0, 0, 0};
562 	    int padding = messageFontMetrics.tmAveCharWidth * 3 / 2;
563 	    int ypos = padding;
564 
565 	    const WCHAR *text = texts[TID_select_types];
566 	    DrawTextExW(dc, (WCHAR *)text, -1, &textrect, DT_CALCRECT, 0);
567 	    int fullwidth = textrect.right;
568 	    HWND ctrl = CreateWindowExW(0, L"Static", text,
569 		    WS_CHILD|WS_VISIBLE, padding, ypos,
570 		    textrect.right, textrect.bottom, w, 0, instance, 0);
571 	    SendMessageW(ctrl, WM_SETFONT, (WPARAM)messageFont, 0);
572 	    ypos += textrect.bottom + padding;
573 
574 	    addFileTypeCheckbox(w, CID_d64, texts[TID_d64], 1,
575 		    dc, padding, &ypos, &fullwidth);
576 	    addFileTypeCheckbox(w, CID_lynx, texts[TID_lynx], 1,
577 		    dc, padding, &ypos, &fullwidth);
578 	    addFileTypeCheckbox(w, CID_zipcode, texts[TID_zipcode], 0,
579 		    dc, padding, &ypos, &fullwidth);
580 
581 	    text = texts[TID_prg_warn];
582             memset(&textrect, 0, sizeof textrect);
583 	    DrawTextExW(dc, (WCHAR *)text, -1, &textrect, DT_CALCRECT, 0);
584 	    fullwidth = textrect.right > fullwidth
585                 ? textrect.right : fullwidth;
586 	    ctrl = CreateWindowExW(0, L"Static", text,
587 		    WS_CHILD|WS_VISIBLE, padding, ypos,
588 		    textrect.right, textrect.bottom, w, 0, instance, 0);
589 	    SendMessageW(ctrl, WM_SETFONT, (WPARAM)messageFont, 0);
590 	    ypos += textrect.bottom + padding;
591 
592 	    ctrl = CreateWindowExW(0, L"Button", texts[TID_register],
593 		    WS_CHILD|WS_VISIBLE|BS_DEFPUSHBUTTON,
594 		    fullwidth - 2*buttonWidth, ypos,
595 		    buttonWidth, buttonHeight,
596 		    w, (HMENU)CID_register, instance, 0);
597 	    SendMessageW(ctrl, WM_SETFONT, (WPARAM)messageFont, 0);
598 	    ctrl = CreateWindowExW(0, L"Button", texts[TID_cancel],
599 		    WS_CHILD|WS_VISIBLE|BS_PUSHBUTTON,
600 		    padding + fullwidth - buttonWidth, ypos,
601 		    buttonWidth, buttonHeight,
602 		    w, (HMENU)CID_cancel, instance, 0);
603 	    SendMessageW(ctrl, WM_SETFONT, (WPARAM)messageFont, 0);
604 	    ypos += buttonHeight + padding;
605 
606 	    ReleaseDC(0, dc);
607 	    RECT winRect = {0, 0, fullwidth + 2*padding, ypos};
608 	    AdjustWindowRect(&winRect, WS_CAPTION|WS_SYSMENU, 0);
609 	    SetWindowPos(w, HWND_TOP, 0, 0,
610 		    winRect.right - winRect.left,
611 		    winRect.bottom - winRect.top, SWP_NOMOVE);
612 	}
613         break;
614 
615     case WM_DESTROY:
616         PostQuitMessage(0);
617         break;
618 
619     case WM_KEYDOWN:
620         if (wp == VK_RETURN)
621         {
622             registerTypes(w);
623             DestroyWindow(w);
624         }
625         else if (wp == VK_ESCAPE)
626         {
627             DestroyWindow(w);
628         }
629         break;
630 
631     case WM_COMMAND:
632         switch (LOWORD(wp))
633         {
634 	case CID_d64:
635 	    ftD64 = !ftD64;
636 	    CheckDlgButton(w, CID_d64,
637 		    ftD64 ? BST_CHECKED : BST_UNCHECKED);
638 	    break;
639 
640 	case CID_lynx:
641 	    ftLynx = !ftLynx;
642 	    CheckDlgButton(w, CID_lynx,
643 		    ftLynx ? BST_CHECKED : BST_UNCHECKED);
644 	    break;
645 
646 	case CID_zipcode:
647 	    ftZipcode = !ftZipcode;
648 	    CheckDlgButton(w, CID_zipcode,
649 		    ftZipcode ? BST_CHECKED : BST_UNCHECKED);
650 	    break;
651 
652         case CID_register:
653 	    registerTypes(w);
654             /* fall through */
655         case CID_cancel:
656 	    DestroyWindow(w);
657             break;
658         }
659         break;
660     }
661     return DefWindowProcW(w, msg, wp, lp);
662 }
663 
main(void)664 int main(void)
665 {
666     init();
667     if (!getCommanderPath())
668     {
669 	MessageBoxW(0, texts[TID_notfound_title], texts[TID_notfound_message],
670 		MB_OK|MB_ICONERROR);
671 	return 0;
672     }
673 
674     WNDCLASSEXW wc;
675     memset(&wc, 0, sizeof wc);
676     wc.cbSize = sizeof wc;
677     wc.hInstance = instance;
678     wc.lpszClassName = WC_mainWindow;
679     wc.lpfnWndProc = wproc;
680     wc.hbrBackground = (HBRUSH) COLOR_WINDOW;
681     wc.hCursor = (HCURSOR) LoadImageW(0, MAKEINTRESOURCEW(OCR_NORMAL),
682 	    IMAGE_CURSOR, 0, 0, LR_DEFAULTSIZE|LR_SHARED);
683     RegisterClassExW(&wc);
684 
685     mainWindow = CreateWindowExW(0, WC_mainWindow, texts[TID_title],
686             WS_CAPTION|WS_SYSMENU, CW_USEDEFAULT, CW_USEDEFAULT,
687 	    320, 100, 0, 0, instance, 0);
688     ShowWindow(mainWindow, SW_SHOWNORMAL);
689 
690     MSG msg;
691     while (GetMessageW(&msg, 0, 0, 0) > 0)
692     {
693         TranslateMessage(&msg);
694         DispatchMessageW(&msg);
695     }
696     free(sid);
697     return (int)msg.wParam;
698 }
699 
700