1 /*
2    Copyright (C) 2004-2007 Christopher E. Miller
3 
4    This software is provided 'as-is', without any express or implied
5    warranty.  In no event will the authors be held liable for any damages
6    arising from the use of this software.
7 
8    Permission is granted to anyone to use this software for any purpose,
9    including commercial applications, and to alter it and redistribute it
10    freely, subject to the following restrictions:
11 
12    1. The origin of this software must not be misrepresented; you must not
13       claim that you wrote the original software. If you use this software
14       in a product, an acknowledgment in the product documentation would be
15       appreciated but is not required.
16    2. Altered source versions must be plainly marked as such, and must not be
17       misrepresented as being the original software.
18    3. This notice may not be removed or altered from any source distribution.
19 */
20 
21 
22 module dfl.internal.utf;
23 
24 import core.sys.windows.windows;
25 import core.sys.windows.richedit;
26 
27 import dfl.internal.dlib;
28 import dfl.internal.clib;
29 
30 // FIX: import dfl.internal.winapi;
31 
32 import std.windows.charset;
33 
34 
35 version(DFL_NO_D2_AND_ABOVE) {
36 } else {
37    version(D_Version2) {
38       version = DFL_D2_AND_ABOVE;
39    } else version(D_Version3) {
40       version = DFL_D3_AND_ABOVE;
41       version = DFL_D2_AND_ABOVE;
42    }
43 }
44 
45 // Do not support Win9x.
46 version = DFL_UNICODE;
47 enum useUnicode = true;
48 
49 package:
50 
51 version(DFL_LOAD_INTERNAL_LIBS) {
52    alias LoadLibraryA initInternalLib;
53 }
54 else {
55    version = DFL_GET_INTERNAL_LIBS;
56 
57    alias GetModuleHandleA initInternalLib;
58 }
59 
60 
61 HMODULE _user32, _kernel32, _advapi32, _gdi32;
62 
63 package @property HMODULE advapi32() nothrow { // getter
64    // advapi32 generally always delay loads.
65    if(!_advapi32) {
66       _advapi32 = LoadLibraryA("advapi32.dll");
67    }
68    return _advapi32;
69 }
70 
71 package @property HMODULE gdi32() nothrow { // getter
72    // gdi32 sometimes delay loads.
73    version(DFL_GET_INTERNAL_LIBS) {
74       if(!_gdi32) {
75          _gdi32 = LoadLibraryA("gdi32.dll");
76       }
77    }
78    return _gdi32;
79 }
80 
81 package @property HMODULE user32() nothrow { // getter
82    version(DFL_GET_INTERNAL_LIBS) {
83       if(!_user32) {
84          _user32 = LoadLibraryA("user32.dll");
85       }
86    }
87    return _user32;
88 }
89 
90 package @property HMODULE kernel32() nothrow { // getter
91    version(DFL_GET_INTERNAL_LIBS) {
92       if(!_kernel32) {
93          _kernel32 = LoadLibraryA("kernel32.dll");
94       }
95    }
96    return _kernel32;
97 }
98 
99 
100 private:
101 
102 version(DFL_UNICODE)
103 version = STATIC_UNICODE;
104 
105 
106 public void _utfinit() { // package
107    version(DFL_UNICODE) {
108    }
109    else version(DFL_ANSI) {
110    }
111    else {
112       /+
113       OSVERSIONINFOA osv;
114       osv.dwOSVersionInfoSize = OSVERSIONINFOA.sizeof;
115       if(GetVersionExA(&osv)) {
116          useUnicode = osv.dwPlatformId == VER_PLATFORM_WIN32_NT;
117       }
118       +/
119 
120       _user32 = initInternalLib("user32.dll");
121       _kernel32 = initInternalLib("kernel32.dll");
122       _advapi32 = GetModuleHandleA("advapi32.dll"); // Not guaranteed to be loaded.
123       _gdi32 = initInternalLib("gdi32.dll");
124    }
125 }
126 
127 
128 template _getlen(T) {
129    size_t _getlen(T* tz)
130    in {
131       assert(tz);
132    }
133    body {
134       T* p;
135       for(p = tz; *p; p++) {
136       }
137       return p - tz;
138    }
139 }
140 
141 
142 public:
143 
144 Dstringz unsafeStringz(Dstring s) nothrow {
145    if(!s.length) {
146       return "";
147    }
148 
149    // Check if already null terminated.
150    if(!s.ptr[s.length]) { // Disables bounds checking.
151       return s.ptr;
152    }
153 
154    // Need to duplicate with null terminator.
155    char[] result;
156    result = new char[s.length + 1];
157    result[0 .. s.length] = s[];
158    result[s.length] = 0;
159    //return result.ptr;
160    return cast(Dstringz)result.ptr; // Needed in D2.
161 }
162 
163 
164 Dstring unicodeToAnsi(Dwstringz unicode, size_t ulen) {
165    if(!ulen) {
166       return null;
167    }
168 
169    wchar* wsz;
170    char[] result;
171    int len;
172 
173    len = WideCharToMultiByte(0, 0, unicode, ulen, null, 0, null, null);
174    assert(len > 0);
175 
176    result = new char[len];
177    len = WideCharToMultiByte(0, 0, unicode, ulen, result.ptr, len, null, null);
178    assert(len == result.length);
179    //return result[0 .. len - 1];
180    return cast(Dstring)result[0 .. len - 1]; // Needed in D2.
181 }
182 
183 
184 Dwstring ansiToUnicode(Dstringz ansi, size_t len) {
185    wchar[] ws;
186 
187    len++;
188    ws = new wchar[len];
189 
190    len = MultiByteToWideChar(0, 0, ansi, len, ws.ptr, len);
191    //assert(len == ws.length);
192    ws = ws[0 .. len - 1]; // Exclude null char at end.
193 
194    //return ws;
195    return cast(Dwstring)ws; // Needed in D2.
196 }
197 
198 
199 Dstring fromAnsi(Dstringz ansi, size_t len) {
200    return utf16stringtoUtf8string(ansiToUnicode(ansi, len));
201 }
202 
203 version(DFL_D2_AND_ABOVE) {
204    Dstring fromAnsi(char* ansi, size_t len) {
205       return fromAnsi(cast(Dstringz)ansi, len);
206    }
207 }
208 
209 
210 Dstring fromAnsiz(Dstringz ansiz) {
211    if(!ansiz) {
212       return null;
213    }
214 
215    //return fromAnsi(ansiz, _getlen!(char)(ansiz));
216    return fromAnsi(ansiz, _getlen(ansiz));
217 }
218 
219 version(DFL_D2_AND_ABOVE) {
220    Dstring fromAnsiz(char* ansi) {
221       return fromAnsiz(cast(Dstringz)ansi);
222    }
223 }
224 
225 
226 private Dstring _toAnsiz(Dstring utf8, bool safe = true) {
227    // This function is intentionally unsafe; depends on "safe" param.
228    foreach(char ch; utf8) {
229       if(ch >= 0x80) {
230          char[] result;
231          auto wsz = utf8stringToUtf16stringz(utf8);
232          auto len = WideCharToMultiByte(0, 0, wsz, -1, null, 0, null, null);
233          assert(len > 0);
234 
235          result = new char[len];
236          len = WideCharToMultiByte(0, 0, wsz, -1, result.ptr, len, null, null);
237          assert(len == result.length);
238          //return result[0 .. len - 1];
239          return cast(Dstring)result[0 .. len - 1]; // Needed in D2.
240       }
241    }
242 
243    // Don't need conversion.
244    if(safe)
245       //return stringToStringz(utf8)[0 .. utf8.length];
246    {
247       return cast(Dstring)stringToStringz(utf8)[0 .. utf8.length];   // Needed in D2.
248    }
249    return unsafeStringz(utf8)[0 .. utf8.length];
250 }
251 
252 
253 private size_t toAnsiLength(Dstring utf8) {
254    foreach(char ch; utf8) {
255       if(ch >= 0x80) {
256          auto wsz = utf8stringToUtf16stringz(utf8);
257          auto len = WideCharToMultiByte(0, 0, wsz, -1, null, 0, null, null);
258          assert(len > 0);
259          return len - 1; // Minus null.
260       }
261    }
262    return utf8.length; // Just ASCII; same length.
263 }
264 
265 
266 private Dstring _unsafeAnsiz(Dstring utf8) {
267    return _toAnsiz(utf8, false);
268 }
269 
270 
271 Dstringz toAnsiz(Dstring utf8, bool safe = true) {
272    return _toAnsiz(utf8, safe).ptr;
273 }
274 
275 
276 Dstringz unsafeAnsiz(Dstring utf8) {
277    return _toAnsiz(utf8, false).ptr;
278 }
279 
280 
281 Dstring toAnsi(Dstring utf8, bool safe = true) {
282    return _toAnsiz(utf8, safe);
283 }
284 
285 
286 Dstring unsafeAnsi(Dstring utf8) {
287    return _toAnsiz(utf8, false);
288 }
289 
290 
291 Dstring fromUnicode(Dwstringz unicode, size_t len) {
292    return utf16stringtoUtf8string(unicode[0 .. len]);
293 }
294 
295 version(DFL_D2_AND_ABOVE) {
296    Dstring fromUnicode(wchar* unicode, size_t len) {
297       return fromUnicode(cast(Dwstringz)unicode, len);
298    }
299 }
300 
301 
302 Dstring fromUnicodez(Dwstringz unicodez) {
303    if(!unicodez) {
304       return null;
305    }
306 
307    //return fromUnicode(unicodez, _getlen!(wchar)(unicodez));
308    return fromUnicode(unicodez, _getlen(unicodez));
309 }
310 
311 version(DFL_D2_AND_ABOVE) {
312    Dstring fromUnicodez(wchar* unicodez) {
313       return fromUnicodez(cast(Dwstringz)unicodez);
314    }
315 }
316 
317 
318 Dwstringz toUnicodez(Dstring utf8) {
319    //return utf8stringToUtf16stringz(utf8);
320    return cast(Dwstringz)utf8stringToUtf16stringz(utf8); // Needed in D2.
321 }
322 
323 
324 Dwstring toUnicode(Dstring utf8) {
325    return utf8stringtoUtf16string(utf8);
326 }
327 
328 
329 size_t toUnicodeLength(Dstring utf8) {
330    size_t result = 0;
331    foreach(wchar wch; utf8) {
332       result++;
333    }
334    return result;
335 }
336 
337 
338 extern(Windows) {
339    alias HWND function(DWORD dwExStyle, LPCWSTR lpClassName, LPCWSTR lpWindowName, DWORD dwStyle,
340                        int x, int y, int nWidth, int nHeight, HWND hWndParent, HMENU hMenu, HINSTANCE hInstance,
341                        LPVOID lpParam) CreateWindowExWProc;
342    alias int function(HWND hWnd) GetWindowTextLengthWProc;
343    alias int function(HWND hWnd, LPCWSTR lpString, int nMaxCount) GetWindowTextWProc;
344    alias BOOL function(HWND hWnd, LPCWSTR lpString) SetWindowTextWProc;
345    alias LRESULT function(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) SendMessageWProc;
346    alias LRESULT function(WNDPROC lpPrevWndFunc, HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
347    CallWindowProcWProc;
348    alias UINT function(LPCWSTR lpszFormat) RegisterClipboardFormatWProc;
349    alias int function (UINT format, LPWSTR lpszFormatName, int cchMaxCount)
350    GetClipboardFormatNameWProc;
351    alias int function(HDC hdc, LPWSTR lpchText, int cchText, LPRECT lprc, UINT dwDTFormat,
352                       LPDRAWTEXTPARAMS lpDTParams) DrawTextExWProc;
353    alias BOOL function(LPCWSTR lpPathName) SetCurrentDirectoryWProc;
354    alias DWORD function(DWORD nBufferLength, LPWSTR lpBuffer) GetCurrentDirectoryWProc;
355    alias BOOL function(LPWSTR lpBuffer, LPDWORD nSize) GetComputerNameWProc;
356    alias UINT function(LPWSTR lpBuffer, UINT uSize) GetSystemDirectoryWProc;
357    alias BOOL function(LPWSTR lpBuffer, LPDWORD nSize) GetUserNameWProc;
358    alias DWORD function(LPCWSTR lpSrc, LPWSTR lpDst, DWORD nSize) ExpandEnvironmentStringsWProc;
359    alias DWORD function(LPCWSTR lpName, LPWSTR lpBuffer, DWORD nSize) GetEnvironmentVariableWProc;
360    alias LONG function(HKEY hKey, LPCWSTR lpValueName, DWORD Reserved, DWORD dwType, BYTE* lpData,
361                        DWORD cbData) RegSetValueExWProc;
362    alias LONG function(HKEY hKey, LPCWSTR lpSubKey, DWORD Reserved, LPWSTR lpClass, DWORD dwOptions,
363                        REGSAM samDesired, LPSECURITY_ATTRIBUTES lpSecurityAttributes, PHKEY phkResult,
364                        LPDWORD lpdwDisposition) RegCreateKeyExWProc;
365    alias LONG function(HKEY hKey, LPCWSTR lpSubKey, DWORD ulOptions, REGSAM samDesired,
366                        PHKEY phkResult) RegOpenKeyExWProc;
367    alias LONG function(HKEY hKey, LPCWSTR lpSubKey) RegDeleteKeyWProc;
368    alias LONG function(HKEY hKey, DWORD dwIndex, LPWSTR lpName, LPDWORD lpcbName, LPDWORD lpReserved,
369                        LPWSTR lpClass, LPDWORD lpcbClass, PFILETIME lpftLastWriteTime) RegEnumKeyExWProc;
370    alias LONG function(HKEY hKey, LPCWSTR lpValueName, LPDWORD lpReserved, LPDWORD lpType, LPBYTE lpData,
371                        LPDWORD lpcbData) RegQueryValueExWProc;
372    alias LONG function(HKEY hKey, DWORD dwIndex, LPTSTR lpValueName, LPDWORD lpcbValueName,
373                        LPDWORD lpReserved, LPDWORD lpType, LPBYTE lpData, LPDWORD lpcbData) RegEnumValueWProc;
374    alias ATOM function(WNDCLASSW* lpWndClass) RegisterClassWProc;
375    alias BOOL function(HDC hdc, LPCWSTR lpString, int cbString, LPSIZE lpSize) GetTextExtentPoint32WProc;
376    alias HANDLE function(HINSTANCE hinst, LPCWSTR lpszName, UINT uType, int cxDesired, int cyDesired, UINT fuLoad)
377    LoadImageWProc;
378    alias UINT function(HDROP hDrop, UINT iFile, LPWSTR lpszFile, UINT cch) DragQueryFileWProc;
379    alias DWORD function(HMODULE hModule, LPWSTR lpFilename, DWORD nSize) GetModuleFileNameWProc;
380    alias LONG function(MSG* lpmsg) DispatchMessageWProc;
381    alias BOOL function(LPMSG lpMsg, HWND hWnd, UINT wMsgFilterMin, UINT wMsgFilterMax, UINT wRemoveMsg)
382    PeekMessageWProc;
383    alias BOOL function(HWND hDlg, LPMSG lpMsg) IsDialogMessageWProc;
384    alias LRESULT function(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) DefWindowProcWProc;
385    alias LRESULT function(HWND hDlg, UINT Msg, WPARAM wParam, LPARAM lParam) DefDlgProcWProc;
386    alias LRESULT function(HWND hWnd, HWND hWndMDIClient, UINT uMsg, WPARAM wParam, LPARAM lParam) DefFrameProcWProc;
387    alias LRESULT function(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) DefMDIChildProcWProc;
388    alias BOOL function(HINSTANCE hInstance, LPCWSTR lpClassName, LPWNDCLASSW lpWndClass) GetClassInfoWProc;
389    alias HANDLE function(LPCWSTR lpPathName, BOOL bWatchSubtree, DWORD dwNotifyFilter) FindFirstChangeNotificationWProc;
390    alias DWORD function(LPCWSTR lpFileName, DWORD nBufferLength, LPWSTR lpBuffer, LPWSTR *lpFilePart) GetFullPathNameWProc;
391    alias typeof(&LoadLibraryExW) LoadLibraryExWProc;
392    alias typeof(&SetMenuItemInfoW) SetMenuItemInfoWProc;
393    alias typeof(&InsertMenuItemW) InsertMenuItemWProc;
394    alias typeof(&CreateFontIndirectW) CreateFontIndirectWProc;
395    package alias typeof(&GetObjectW) GetObjectWProc;
396 }
397 
398 
399 private void getProcErr(Dstring procName) {
400    Dstring errdesc;
401    version(DFL_NO_PROC_ERROR_INFO) {
402    }
403    else {
404       auto le = cast(int)GetLastError();
405       if(le) {
406          errdesc = " (error " ~ intToString(le) ~ ")";
407       }
408    }
409    throw new Exception("Unable to load procedure " ~ procName ~ errdesc);
410 }
411 
412 
413 // If loading from a resource just use LoadImageA().
414 HANDLE loadImage(HINSTANCE hinst, Dstring name, UINT uType, int cxDesired, int cyDesired, UINT fuLoa) {
415    if(useUnicode) {
416       version(STATIC_UNICODE) {
417          alias LoadImageW proc;
418       }
419       else {
420          enum NAME = "LoadImageW";
421          static LoadImageWProc proc = null;
422 
423          if(!proc) {
424             proc = cast(LoadImageWProc)GetProcAddress(user32, NAME.ptr);
425             if(!proc) {
426                getProcErr(NAME);
427             }
428          }
429       }
430 
431       return proc(hinst, toUnicodez(name), uType, cxDesired, cyDesired, fuLoa);
432    } else {
433       return LoadImageA(hinst, unsafeAnsiz(name), uType, cxDesired, cyDesired, fuLoa);
434    }
435 }
436 
437 
438 HWND createWindowEx(DWORD dwExStyle, Dstring className, Dstring windowName, DWORD dwStyle,
439                     int x, int y, int nWidth, int nHeight, HWND hWndParent, HMENU hMenu, HINSTANCE hInstance,
440                     LPVOID lpParam) {
441    if(useUnicode) {
442       version(STATIC_UNICODE) {
443          alias CreateWindowExW proc;
444       }
445       else {
446          enum NAME = "CreateWindowExW";
447          static CreateWindowExWProc proc = null;
448 
449          if(!proc) {
450             proc = cast(CreateWindowExWProc)GetProcAddress(user32, NAME.ptr);
451             if(!proc) {
452                getProcErr(NAME);
453             }
454          }
455       }
456 
457       //if(windowName.length)
458       // MessageBoxW(null, toUnicodez(windowName), toUnicodez(className ~ " caption"), 0);
459       return proc(dwExStyle, toUnicodez(className), toUnicodez(windowName), dwStyle,
460                   x, y, nWidth, nHeight, hWndParent, hMenu, hInstance, lpParam);
461    } else {
462       return CreateWindowExA(dwExStyle, unsafeAnsiz(className), unsafeAnsiz(windowName), dwStyle,
463                              x, y, nWidth, nHeight, hWndParent, hMenu, hInstance, lpParam);
464    }
465 }
466 
467 
468 HWND createWindow(Dstring className, Dstring windowName, DWORD dwStyle, int x, int y,
469                   int nWidth, int nHeight, HWND hWndParent, HMENU hMenu, HANDLE hInstance, LPVOID lpParam) {
470    return createWindowEx(0, className, windowName, dwStyle, x, y,
471                          nWidth, nHeight, hWndParent, hMenu, hInstance, lpParam);
472 }
473 
474 
475 Dstring getWindowText(HWND hwnd) {
476    if(useUnicode) {
477       version(STATIC_UNICODE) {
478          alias GetWindowTextW proc;
479          alias GetWindowTextLengthW proclen;
480       }
481       else {
482          enum NAME = "GetWindowTextW";
483          static GetWindowTextWProc proc = null;
484 
485          enum NAMELEN = "GetWindowTextLengthW";
486          static GetWindowTextLengthWProc proclen = null;
487 
488          if(!proc) {
489             proc = cast(GetWindowTextWProc)GetProcAddress(user32, NAME.ptr);
490             if(!proc) {
491                getProcErr(NAME);
492             }
493 
494             //if(!proclen)
495             {
496                proclen = cast(GetWindowTextLengthWProc)GetProcAddress(user32, NAMELEN.ptr);
497                //if(!proclen)
498                // getProcErr(NAMELEN);
499             }
500          }
501       }
502 
503       wchar* buf;
504       size_t len;
505 
506       len = proclen(hwnd);
507       if(!len) {
508          return null;
509       }
510       len++;
511       buf = (new wchar[len]).ptr;
512 
513       len = proc(hwnd, buf, len);
514       return fromUnicode(buf, len);
515    } else {
516       char* buf;
517       size_t len;
518 
519       len = GetWindowTextLengthA(hwnd);
520       if(!len) {
521          return null;
522       }
523       len++;
524       buf = (new char[len]).ptr;
525 
526       len = GetWindowTextA(hwnd, buf, len);
527       return fromAnsi(buf, len);
528    }
529 }
530 
531 
532 BOOL setWindowText(HWND hwnd, Dstring str) {
533    if(useUnicode) {
534       version(STATIC_UNICODE) {
535          alias SetWindowTextW proc;
536       }
537       else {
538          enum NAME = "SetWindowTextW";
539          static SetWindowTextWProc proc = null;
540 
541          if(!proc) {
542             proc = cast(SetWindowTextWProc)GetProcAddress(user32, NAME.ptr);
543             if(!proc) {
544                getProcErr(NAME);
545             }
546          }
547       }
548 
549       return proc(hwnd, toUnicodez(str));
550    } else {
551       return SetWindowTextA(hwnd, unsafeAnsiz(str));
552    }
553 }
554 
555 
556 Dstring getModuleFileName(HMODULE hmod) {
557    if(useUnicode) {
558       version(STATIC_UNICODE) {
559          alias GetModuleFileNameW proc;
560       }
561       else {
562          enum NAME = "GetModuleFileNameW";
563          static GetModuleFileNameWProc proc = null;
564 
565          if(!proc) {
566             proc = cast(GetModuleFileNameWProc)GetProcAddress(kernel32, NAME.ptr);
567             if(!proc) {
568                getProcErr(NAME);
569             }
570          }
571       }
572 
573       wchar[] s;
574       DWORD len;
575       s = new wchar[MAX_PATH];
576       len = proc(hmod, s.ptr, s.length);
577       return fromUnicode(s.ptr, len);
578    } else {
579       char[] s;
580       DWORD len;
581       s = new char[MAX_PATH];
582       len = GetModuleFileNameA(hmod, s.ptr, s.length);
583       return fromAnsi(s.ptr, len);
584    }
585 }
586 
587 
588 version = STATIC_UNICODE_SEND_MESSAGE;
589 
590 
591 version(STATIC_UNICODE_SEND_MESSAGE) {
592 }
593 else {
594    version(DFL_UNICODE) {
595       version = STATIC_UNICODE_SEND_MESSAGE;
596    }
597    else version(DFL_ANSI) {
598    }
599    else {
600       private SendMessageWProc _loadSendMessageW() {
601          enum NAME = "SendMessageW";
602          static SendMessageWProc proc = null;
603 
604          if(!proc) {
605             proc = cast(SendMessageWProc)GetProcAddress(user32, NAME.ptr);
606             if(!proc) {
607                getProcErr(NAME);
608             }
609          }
610 
611          return proc;
612       }
613    }
614 }
615 
616 
617 // Sends EM_GETSELTEXT to a rich text box and returns the text.
618 Dstring emGetSelText(HWND hwnd, size_t selTextLength) {
619    if(useUnicode) {
620       version(STATIC_UNICODE_SEND_MESSAGE) {
621          alias SendMessageW proc;
622       }
623       else {
624          SendMessageWProc proc;
625          proc = _loadSendMessageW();
626       }
627 
628       wchar[] buf;
629       size_t len;
630       buf = new wchar[selTextLength + 1];
631       len = proc(hwnd, EM_GETSELTEXT, 0, cast(LPARAM)buf.ptr);
632       return fromUnicode(buf.ptr, len);
633    } else {
634       char[] buf;
635       size_t len;
636       buf = new char[selTextLength + 1];
637       len = SendMessageA(hwnd, EM_GETSELTEXT, 0, cast(LPARAM)buf.ptr);
638       return fromAnsi(buf.ptr, len);
639    }
640 }
641 
642 
643 // Gets the selected text of an edit box.
644 // This needs to retrieve the entire text and strip out the extra.
645 Dstring getSelectedText(HWND hwnd) {
646    uint v1, v2;
647    uint len;
648 
649    if(useUnicode) {
650       version(STATIC_UNICODE_SEND_MESSAGE) {
651          alias SendMessageW proc;
652       }
653       else {
654          SendMessageWProc proc;
655          proc = _loadSendMessageW();
656       }
657 
658       proc(hwnd, EM_GETSEL, cast(WPARAM)&v1, cast(LPARAM)&v2);
659       if(v1 == v2) {
660          return null;
661       }
662       assert(v2 > v1);
663 
664       len = proc(hwnd, WM_GETTEXTLENGTH, 0, 0);
665       if(len) {
666          len++;
667          wchar* buf;
668          buf = (new wchar[len]).ptr;
669 
670          len = proc(hwnd, WM_GETTEXT, len, cast(LPARAM)buf);
671          if(len) {
672             wchar[] s;
673             s = buf[v1 .. v2].dup;
674             return fromUnicode(s.ptr, s.length);
675          }
676       }
677    } else {
678       SendMessageA(hwnd, EM_GETSEL, cast(WPARAM)&v1, cast(LPARAM)&v2);
679       if(v1 == v2) {
680          return null;
681       }
682       assert(v2 > v1);
683 
684       len = SendMessageA(hwnd, WM_GETTEXTLENGTH, 0, 0);
685       if(len) {
686          len++;
687          char* buf;
688          buf = (new char[len]).ptr;
689 
690          len = SendMessageA(hwnd, WM_GETTEXT, len, cast(LPARAM)buf);
691          if(len) {
692             char[] s;
693             s = buf[v1 .. v2].dup;
694             return fromAnsi(s.ptr, s.length);
695          }
696       }
697    }
698 
699    return null;
700 }
701 
702 
703 // Sends EM_SETPASSWORDCHAR to an edit box.
704 // TODO: check if correct implementation.
705 void emSetPasswordChar(HWND hwnd, dchar pwc) {
706    if(useUnicode) {
707       version(STATIC_UNICODE_SEND_MESSAGE) {
708          alias SendMessageW proc;
709       }
710       else {
711          SendMessageWProc proc;
712          proc = _loadSendMessageW();
713       }
714 
715       proc(hwnd, EM_SETPASSWORDCHAR, pwc, 0); // ?
716    } else {
717       Dstring chs;
718       Dstring ansichs;
719       chs = utf32stringtoUtf8string((&pwc)[0 .. 1]);
720       ansichs = unsafeAnsi(chs);
721 
722       if(ansichs) {
723          SendMessageA(hwnd, EM_SETPASSWORDCHAR, ansichs[0], 0);   // ?
724       }
725    }
726 }
727 
728 
729 // Sends EM_GETPASSWORDCHAR to an edit box.
730 // TODO: check if correct implementation.
731 dchar emGetPasswordChar(HWND hwnd) {
732    if(useUnicode) {
733       version(STATIC_UNICODE_SEND_MESSAGE) {
734          alias SendMessageW proc;
735       }
736       else {
737          SendMessageWProc proc;
738          proc = _loadSendMessageW();
739       }
740 
741       return cast(dchar)proc(hwnd, EM_GETPASSWORDCHAR, 0, 0); // ?
742    } else {
743       char ansich;
744       Dstring chs;
745       Ddstring dchs;
746       ansich = cast(char)SendMessageA(hwnd, EM_GETPASSWORDCHAR, 0, 0);
747       //chs = fromAnsi((&ansich)[0 .. 1], 1);
748       chs = fromAnsi(&ansich, 1);
749       dchs = utf8stringtoUtf32string(chs);
750       if(dchs.length == 1) {
751          return dchs[0];   // ?
752       }
753       return 0;
754    }
755 }
756 
757 
758 LRESULT sendMessage(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) {
759    if(useUnicode) {
760       version(STATIC_UNICODE_SEND_MESSAGE) {
761          alias SendMessageW proc;
762       }
763       else {
764          SendMessageWProc proc;
765          proc = _loadSendMessageW();
766       }
767 
768       return proc(hwnd, msg, wparam, lparam);
769    } else {
770       return SendMessageA(hwnd, msg, wparam, lparam);
771    }
772 }
773 
774 
775 LRESULT sendMessage(HWND hwnd, UINT msg, WPARAM wparam, Dstring lparam, bool safe = true) {
776    if(useUnicode) {
777       version(STATIC_UNICODE_SEND_MESSAGE) {
778          alias SendMessageW proc;
779       }
780       else {
781          SendMessageWProc proc;
782          proc = _loadSendMessageW();
783       }
784 
785       return proc(hwnd, msg, wparam, cast(LPARAM)toUnicodez(lparam));
786    } else {
787       return SendMessageA(hwnd, msg, wparam, cast(LPARAM)toAnsiz(lparam, safe)); // Can't assume unsafeAnsiz() is OK here.
788    }
789 }
790 
791 
792 LRESULT sendMessageUnsafe(HWND hwnd, UINT msg, WPARAM wparam, Dstring lparam) {
793    return sendMessage(hwnd, msg, wparam, lparam, false);
794 }
795 
796 
797 version = STATIC_UNICODE_CALL_WINDOW_PROC;
798 
799 
800 LRESULT callWindowProc(WNDPROC lpPrevWndFunc, HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) {
801    if(useUnicode) {
802       version(STATIC_UNICODE_CALL_WINDOW_PROC) {
803          alias CallWindowProcW proc;
804       }
805       else {
806          enum NAME = "CallWindowProcW";
807          static CallWindowProcWProc proc = null;
808 
809          if(!proc) {
810             proc = cast(CallWindowProcWProc)GetProcAddress(user32, NAME.ptr);
811             if(!proc) {
812                getProcErr(NAME);
813             }
814          }
815       }
816 
817       return proc(lpPrevWndFunc, hwnd, msg, wparam, lparam);
818    } else {
819       return CallWindowProcA(lpPrevWndFunc, hwnd, msg, wparam, lparam);
820    }
821 }
822 
823 
824 UINT registerClipboardFormat(Dstring formatName) {
825    if(useUnicode) {
826       version(STATIC_UNICODE) {
827          alias RegisterClipboardFormatW proc;
828       }
829       else {
830          enum NAME = "RegisterClipboardFormatW";
831          static RegisterClipboardFormatWProc proc = null;
832 
833          if(!proc) {
834             proc = cast(RegisterClipboardFormatWProc)GetProcAddress(user32, NAME.ptr);
835             if(!proc) {
836                getProcErr(NAME);
837             }
838          }
839       }
840 
841       return proc(toUnicodez(formatName));
842    } else {
843       return RegisterClipboardFormatA(unsafeAnsiz(formatName));
844    }
845 }
846 
847 
848 Dstring getClipboardFormatName(UINT format) {
849    if(useUnicode) {
850       version(STATIC_UNICODE) {
851          alias GetClipboardFormatNameW proc;
852       }
853       else {
854          enum NAME = "GetClipboardFormatNameW";
855          static GetClipboardFormatNameWProc proc = null;
856 
857          if(!proc) {
858             proc = cast(GetClipboardFormatNameWProc)GetProcAddress(user32, NAME.ptr);
859             if(!proc) {
860                getProcErr(NAME);
861             }
862          }
863       }
864 
865       wchar[] buf;
866       int len;
867       buf = new wchar[64];
868       len = proc(format, buf.ptr, buf.length);
869       if(!len) {
870          return null;
871       }
872       return fromUnicode(buf.ptr, len);
873    } else {
874       char[] buf;
875       int len;
876       buf = new char[64];
877       len = GetClipboardFormatNameA(format, buf.ptr, buf.length);
878       if(!len) {
879          return null;
880       }
881       return fromAnsi(buf.ptr, len);
882    }
883 }
884 
885 
886 // On Windows 9x, the number of characters cannot exceed 8192.
887 int drawTextEx(HDC hdc, Dstring text, LPRECT lprc, UINT dwDTFormat, LPDRAWTEXTPARAMS lpDTParams) {
888    // Note: an older version of MSDN says cchText should be -1 for a null terminated string,
889    // whereas the newer MSDN says 1. Lets just play it safe and use a local null terminated
890    // string when the length is 1 so that it won't continue reading past the 1 character,
891    // reguardless of which MSDN version is correct.
892 
893    if(useUnicode) {
894       version(STATIC_UNICODE) {
895          alias DrawTextExW proc;
896       }
897       else {
898          enum NAME = "DrawTextExW";
899          static DrawTextExWProc proc = null;
900 
901          if(!proc) {
902             proc = cast(DrawTextExWProc)GetProcAddress(user32, NAME.ptr);
903             if(!proc) {
904                getProcErr(NAME);
905             }
906          }
907       }
908 
909       /+
910       wchar* strz;
911       strz = toUnicodez(text);
912       return proc(hdc, strz, -1, lprc, dwDTFormat, lpDTParams);
913       +/
914       Dwstring str;
915       wchar[2] tempStr;
916       str = toUnicode(text);
917       if(str.length == 1) {
918          tempStr[0] = str[0];
919          tempStr[1] = 0;
920          //str = tempStr[0 .. 1];
921          str = cast(Dwstring)tempStr[0 .. 1]; // Needed in D2.
922       }
923       //return proc(hdc, str.ptr, str.length, lprc, dwDTFormat, lpDTParams);
924       return proc(hdc, cast(wchar*)str.ptr, str.length, lprc, dwDTFormat, lpDTParams); // Needed in D2.
925    } else {
926       /+
927       char* strz;
928       strz = unsafeAnsiz(text);
929       return DrawTextExA(hdc, strz, -1, lprc, dwDTFormat, lpDTParams);
930       +/
931       Dstring str;
932       char[2] tempStr;
933       str = unsafeAnsi(text);
934       if(str.length == 1) {
935          tempStr[0] = str[0];
936          tempStr[1] = 0;
937          //str = tempStr[0 .. 1];
938          str = cast(Dstring)tempStr[0 .. 1]; // Needed in D2.
939       }
940       //return DrawTextExA(hdc, str.ptr, str.length, lprc, dwDTFormat, lpDTParams);
941       return DrawTextExA(hdc, cast(char*)str.ptr, str.length, lprc, dwDTFormat, lpDTParams); // Needed in D2.
942    }
943 }
944 
945 
946 Dstring getCommandLine() {
947    // Windows 9x supports GetCommandLineW().
948    return dfl.internal.utf.fromUnicodez(GetCommandLineW());
949 }
950 
951 
952 /* MSDN:
953    The current directory state written by the SetCurrentDirectory function
954    is stored as a global variable in each process, therefore multithreaded
955    applications cannot reliably use this value without possible data
956    corruption from other threads that may also be reading or setting this
957    value. This limitation also applies to the GetCurrentDirectory and
958    GetFullPathName functions.
959 */
960 // This doesn't prevent the problem, but it can minimize it.
961 // e.g. file dialogs set it.
962 //class CurDirLockType { }
963 
964 
965 BOOL setCurrentDirectory(Dstring pathName) {
966    //synchronized(typeid(CurDirLockType))
967    {
968       if(useUnicode) {
969          version(STATIC_UNICODE) {
970             alias SetCurrentDirectoryW proc;
971          }
972          else {
973             enum NAME = "SetCurrentDirectoryW";
974             static SetCurrentDirectoryWProc proc = null;
975 
976             if(!proc) {
977                proc = cast(SetCurrentDirectoryWProc)GetProcAddress(kernel32, NAME.ptr);
978                if(!proc) {
979                   getProcErr(NAME);
980                }
981             }
982          }
983 
984          return proc(toUnicodez(pathName));
985       } else {
986          return SetCurrentDirectoryA(unsafeAnsiz(pathName));
987       }
988    }
989 }
990 
991 
992 Dstring getCurrentDirectory() {
993    //synchronized(typeid(CurDirLockType))
994    {
995       if(useUnicode) {
996          version(STATIC_UNICODE) {
997             alias GetCurrentDirectoryW proc;
998          }
999          else {
1000             enum NAME = "GetCurrentDirectoryW";
1001             static GetCurrentDirectoryWProc proc = null;
1002 
1003             if(!proc) {
1004                proc = cast(GetCurrentDirectoryWProc)GetProcAddress(kernel32, NAME.ptr);
1005                if(!proc) {
1006                   getProcErr(NAME);
1007                }
1008             }
1009          }
1010 
1011          wchar* buf;
1012          int len;
1013          len = proc(0, null);
1014          buf = (new wchar[len]).ptr;
1015          len = proc(len, buf);
1016          if(!len) {
1017             return null;
1018          }
1019          return fromUnicode(buf, len);
1020       } else {
1021          char* buf;
1022          int len;
1023          len = GetCurrentDirectoryA(0, null);
1024          buf = (new char[len]).ptr;
1025          len = GetCurrentDirectoryA(len, buf);
1026          if(!len) {
1027             return null;
1028          }
1029          return fromAnsi(buf, len);
1030       }
1031    }
1032 }
1033 
1034 
1035 Dstring getFullPathName(Dstring fileName) {
1036    //synchronized(typeid(CurDirLockType))
1037    {
1038       DWORD len;
1039 
1040       if(useUnicode) {
1041          version(STATIC_UNICODE) {
1042             alias GetFullPathNameW proc;
1043          }
1044          else {
1045             enum NAME = "GetFullPathNameW";
1046             static GetFullPathNameWProc proc = null;
1047 
1048             if(!proc) {
1049                proc = cast(GetFullPathNameWProc)GetProcAddress(kernel32, NAME.ptr);
1050                if(!proc) {
1051                   getProcErr(NAME);
1052                }
1053             }
1054          }
1055 
1056          auto fnw = toUnicodez(fileName);
1057          len = proc(fnw, 0, null, null);
1058          if(!len) {
1059             return null;
1060          }
1061          wchar[260] _wbuf;
1062          wchar[] wbuf = _wbuf;
1063          if(len > _wbuf.sizeof) {
1064             wbuf = new wchar[len];
1065          }
1066          len = proc(fnw, wbuf.length, wbuf.ptr, null);
1067          assert(len < wbuf.length);
1068          return fromUnicode(wbuf.ptr, len);
1069       } else {
1070          auto fna = unsafeAnsiz(fileName);
1071          len = GetFullPathNameA(fna, 0, null, null);
1072          if(!len) {
1073             return null;
1074          }
1075          char[260] _abuf;
1076          char[] abuf = _abuf;
1077          if(len > _abuf.sizeof) {
1078             abuf = new char[len];
1079          }
1080          len = GetFullPathNameA(fna, abuf.length, abuf.ptr, null);
1081          assert(len < abuf.length);
1082          return fromAnsi(abuf.ptr, len);
1083       }
1084    }
1085 }
1086 
1087 
1088 Dstring getComputerName() {
1089    if(useUnicode) {
1090       version(STATIC_UNICODE) {
1091          alias GetComputerNameW proc;
1092       }
1093       else {
1094          enum NAME = "GetComputerNameW";
1095          static GetComputerNameWProc proc = null;
1096 
1097          if(!proc) {
1098             proc = cast(GetComputerNameWProc)GetProcAddress(kernel32, NAME.ptr);
1099             if(!proc) {
1100                getProcErr(NAME);
1101             }
1102          }
1103       }
1104 
1105       wchar[] buf;
1106       DWORD len = MAX_COMPUTERNAME_LENGTH + 1;
1107       buf = new wchar[len];
1108       if(!proc(buf.ptr, &len)) {
1109          return null;
1110       }
1111       return fromUnicode(buf.ptr, len);
1112    } else {
1113       char[] buf;
1114       DWORD len = MAX_COMPUTERNAME_LENGTH + 1;
1115       buf = new char[len];
1116       if(!GetComputerNameA(buf.ptr, &len)) {
1117          return null;
1118       }
1119       return fromAnsi(buf.ptr, len);
1120    }
1121 }
1122 
1123 
1124 Dstring getSystemDirectory() {
1125    if(useUnicode) {
1126       version(STATIC_UNICODE) {
1127          alias GetSystemDirectoryW proc;
1128       }
1129       else {
1130          enum NAME = "GetSystemDirectoryW";
1131          static GetSystemDirectoryWProc proc = null;
1132 
1133          if(!proc) {
1134             proc = cast(GetSystemDirectoryWProc)GetProcAddress(kernel32, NAME.ptr);
1135             if(!proc) {
1136                getProcErr(NAME);
1137             }
1138          }
1139       }
1140 
1141       wchar[] buf;
1142       UINT len;
1143       buf = new wchar[MAX_PATH];
1144       len = proc(buf.ptr, buf.length);
1145       if(!len) {
1146          return null;
1147       }
1148       return fromUnicode(buf.ptr, len);
1149    } else {
1150       char[] buf;
1151       UINT len;
1152       buf = new char[MAX_PATH];
1153       len = GetSystemDirectoryA(buf.ptr, buf.length);
1154       if(!len) {
1155          return null;
1156       }
1157       return fromAnsi(buf.ptr, len);
1158    }
1159 }
1160 
1161 
1162 Dstring getUserName() {
1163    if(useUnicode) {
1164       version(STATIC_UNICODE) {
1165          alias GetUserNameW proc;
1166       }
1167       else {
1168          enum NAME = "GetUserNameW";
1169          static GetUserNameWProc proc = null;
1170 
1171          if(!proc) {
1172             proc = cast(GetUserNameWProc)GetProcAddress(advapi32, NAME.ptr);
1173             if(!proc) {
1174                getProcErr(NAME);
1175             }
1176          }
1177       }
1178 
1179       wchar[256 + 1] buf;
1180       DWORD len = buf.length;
1181       if(!proc(buf.ptr, &len) || !len || !--len) { // Also remove null-terminator.
1182          return null;
1183       }
1184       return fromUnicode(buf.ptr, len);
1185    } else {
1186       char[256 + 1] buf;
1187       DWORD len = buf.length;
1188       if(!GetUserNameA(buf.ptr, &len) || !len || !--len) { // Also remove null-terminator.
1189          return null;
1190       }
1191       return fromAnsi(buf.ptr, len);
1192    }
1193 }
1194 
1195 
1196 // Returns 0 on failure.
1197 DWORD expandEnvironmentStrings(Dstring src, out Dstring result) {
1198    if(useUnicode) {
1199       version(STATIC_UNICODE) {
1200          alias ExpandEnvironmentStringsW proc;
1201       }
1202       else {
1203          enum NAME = "ExpandEnvironmentStringsW";
1204          static ExpandEnvironmentStringsWProc proc = null;
1205 
1206          if(!proc) {
1207             proc = cast(ExpandEnvironmentStringsWProc)GetProcAddress(kernel32, NAME.ptr);
1208             if(!proc) {
1209                getProcErr(NAME);
1210             }
1211          }
1212       }
1213 
1214       wchar* dest;
1215       DWORD len;
1216 
1217       auto strz = toUnicodez(src);
1218       len = proc(strz, null, 0);
1219       if(!len) {
1220          return 0;
1221       }
1222       dest = (new wchar[len]).ptr;
1223       len = proc(strz, dest, len);
1224       if(!len) {
1225          return 0;
1226       }
1227       result = fromUnicode(dest, len - 1);
1228       return len;
1229    } else {
1230       char* dest;
1231       DWORD len;
1232 
1233       auto strz = unsafeAnsiz(src);
1234       len = ExpandEnvironmentStringsA(strz, null, 0);
1235       if(!len) {
1236          return 0;
1237       }
1238       dest = (new char[len]).ptr;
1239       len = ExpandEnvironmentStringsA(strz, dest, len);
1240       if(!len) {
1241          return 0;
1242       }
1243       result = fromAnsi(dest, len - 1);
1244       return len;
1245    }
1246 }
1247 
1248 
1249 Dstring getEnvironmentVariable(Dstring name) {
1250    if(useUnicode) {
1251       version(STATIC_UNICODE) {
1252          alias GetEnvironmentVariableW proc;
1253       }
1254       else {
1255          enum NAME = "GetEnvironmentVariableW";
1256          static GetEnvironmentVariableWProc proc = null;
1257 
1258          if(!proc) {
1259             proc = cast(GetEnvironmentVariableWProc)GetProcAddress(kernel32, NAME.ptr);
1260             if(!proc) {
1261                getProcErr(NAME);
1262             }
1263          }
1264       }
1265 
1266       wchar* buf;
1267       DWORD len;
1268       auto strz = toUnicodez(name);
1269       len = proc(strz, null, 0);
1270       if(!len) {
1271          return null;
1272       }
1273       buf = (new wchar[len]).ptr;
1274       len = proc(strz, buf, len);
1275       return fromUnicode(buf, len);
1276    } else {
1277       char* buf;
1278       DWORD len;
1279       auto strz = unsafeAnsiz(name);
1280       len = GetEnvironmentVariableA(strz, null, 0);
1281       if(!len) {
1282          return null;
1283       }
1284       buf = (new char[len]).ptr;
1285       len = GetEnvironmentVariableA(strz, buf, len);
1286       return fromAnsi(buf, len);
1287    }
1288 }
1289 
1290 
1291 int messageBox(HWND hWnd, Dstring text, Dstring caption, UINT uType) {
1292    // Windows 9x supports MessageBoxW().
1293    return MessageBoxW(hWnd, toUnicodez(text), toUnicodez(caption), uType);
1294 }
1295 
1296 
1297 struct WndClass {
1298    union {
1299       WNDCLASSW wcw;
1300       WNDCLASSA wca;
1301    }
1302    alias wcw wc;
1303 
1304    Dstring className;
1305 }
1306 
1307 
1308 ATOM registerClass(ref WndClass wc) {
1309    if(useUnicode) {
1310       version(STATIC_UNICODE) {
1311          alias RegisterClassW proc;
1312       }
1313       else {
1314          enum NAME = "RegisterClassW";
1315          static RegisterClassWProc proc = null;
1316 
1317          if(!proc) {
1318             proc = cast(RegisterClassWProc)GetProcAddress(user32, NAME.ptr);
1319             if(!proc) {
1320                getProcErr(NAME);
1321             }
1322          }
1323       }
1324 
1325       wc.wcw.lpszClassName = toUnicodez(wc.className);
1326       return proc(&wc.wcw);
1327    } else {
1328       wc.wca.lpszClassName = unsafeAnsiz(wc.className);
1329       return RegisterClassA(&wc.wca);
1330    }
1331 }
1332 
1333 
1334 BOOL getClassInfo(HINSTANCE hinst, Dstring className, ref WndClass wc) {
1335    wc.className = className; // ?
1336 
1337    if(useUnicode) {
1338       version(STATIC_UNICODE) {
1339          alias GetClassInfoW proc;
1340       }
1341       else {
1342          enum NAME = "GetClassInfoW";
1343          static GetClassInfoWProc proc = null;
1344 
1345          if(!proc) {
1346             proc = cast(GetClassInfoWProc)GetProcAddress(user32, NAME.ptr);
1347             if(!proc) {
1348                getProcErr(NAME);
1349             }
1350          }
1351       }
1352 
1353       return proc(hinst, toUnicodez(className), &wc.wcw);
1354    } else {
1355       return GetClassInfoA(hinst, unsafeAnsiz(className), &wc.wca);
1356    }
1357 }
1358 
1359 
1360 // Shouldn't have been implemented this way.
1361 deprecated BOOL getTextExtentPoint32(HDC hdc, Dstring text, LPSIZE lpSize) {
1362    if(useUnicode) {
1363       version(STATIC_UNICODE) {
1364          alias GetTextExtentPoint32W proc;
1365       }
1366       else {
1367          enum NAME = "GetTextExtentPoint32W";
1368          static GetTextExtentPoint32WProc proc = null;
1369 
1370          if(!proc) {
1371             proc = cast(GetTextExtentPoint32WProc)GetProcAddress(gdi32, NAME.ptr);
1372             if(!proc) {
1373                getProcErr(NAME);
1374             }
1375          }
1376       }
1377 
1378       Dwstring str;
1379       str = toUnicode(text);
1380       return proc(hdc, str.ptr, str.length, lpSize);
1381    } else {
1382       // Using GetTextExtentPoint32A here even though W is supported in order
1383       // to keep the measurements accurate with DrawTextA.
1384       Dstring str;
1385       str = unsafeAnsi(text);
1386       return GetTextExtentPoint32A(hdc, str.ptr, str.length, lpSize);
1387    }
1388 }
1389 
1390 
1391 Dstring dragQueryFile(HDROP hDrop, UINT iFile) {
1392    if(iFile >= 0xFFFFFFFF) {
1393       return null;
1394    }
1395 
1396    if(useUnicode) {
1397       version(STATIC_UNICODE) {
1398          alias DragQueryFileW proc;
1399       }
1400       else {
1401          enum NAME = "DragQueryFileW";
1402          static DragQueryFileWProc proc = null;
1403 
1404          if(!proc) {
1405             proc = cast(DragQueryFileWProc)GetProcAddress(GetModuleHandleA("shell32.dll"), NAME.ptr);
1406             if(!proc) {
1407                getProcErr(NAME);
1408             }
1409          }
1410       }
1411 
1412       wchar[] str;
1413       UINT len;
1414       len = proc(hDrop, iFile, null, 0);
1415       if(!len) {
1416          return null;
1417       }
1418       str = new wchar[len + 1];
1419       proc(hDrop, iFile, str.ptr, str.length);
1420       return fromUnicode(str.ptr, len);
1421    } else {
1422       char[] str;
1423       UINT len;
1424       len = DragQueryFileA(hDrop, iFile, null, 0);
1425       if(!len) {
1426          return null;
1427       }
1428       str = new char[len + 1];
1429       DragQueryFileA(hDrop, iFile, str.ptr, str.length);
1430       return fromAnsi(str.ptr, len);
1431    }
1432 }
1433 
1434 
1435 // Just gets the number of files.
1436 UINT dragQueryFile(HDROP hDrop) {
1437    return DragQueryFileA(hDrop, 0xFFFFFFFF, null, 0);
1438 }
1439 
1440 
1441 HANDLE createFile(Dstring fileName, DWORD dwDesiredAccess, DWORD dwShareMode, LPSECURITY_ATTRIBUTES lpSecurityAttributes,
1442                   DWORD dwCreationDistribution, DWORD dwFlagsAndAttributes, HANDLE hTemplateFile) {
1443    if(useUnicode) {
1444       return CreateFileW(toUnicodez(fileName), dwDesiredAccess, dwShareMode, lpSecurityAttributes,
1445                          dwCreationDistribution, dwFlagsAndAttributes, hTemplateFile);
1446    } else {
1447       return CreateFileA(unsafeAnsiz(fileName), dwDesiredAccess, dwShareMode, lpSecurityAttributes,
1448                          dwCreationDistribution, dwFlagsAndAttributes, hTemplateFile);
1449    }
1450 }
1451 
1452 
1453 version = STATIC_UNICODE_DEF_WINDOW_PROC;
1454 
1455 
1456 LRESULT defWindowProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) {
1457    if(useUnicode) {
1458       version(STATIC_UNICODE_DEF_WINDOW_PROC) {
1459          alias DefWindowProcW proc;
1460       }
1461       else {
1462          enum NAME = "DefWindowProcW";
1463          static DefWindowProcWProc proc = null;
1464 
1465          if(!proc) {
1466             proc = cast(DefWindowProcWProc)GetProcAddress(user32, NAME.ptr);
1467             if(!proc) {
1468                getProcErr(NAME);
1469             }
1470          }
1471       }
1472 
1473       return proc(hwnd, msg, wparam, lparam);
1474    } else {
1475       return DefWindowProcA(hwnd, msg, wparam, lparam);
1476    }
1477 }
1478 
1479 
1480 LRESULT defDlgProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) {
1481    if(useUnicode) {
1482       version(STATIC_UNICODE_DEF_WINDOW_PROC) {
1483          alias DefDlgProcW proc;
1484       }
1485       else {
1486          enum NAME = "DefDlgProcW";
1487          static DefDlgProcWProc proc = null;
1488 
1489          if(!proc) {
1490             proc = cast(DefDlgProcWProc)GetProcAddress(user32, NAME.ptr);
1491             if(!proc) {
1492                getProcErr(NAME);
1493             }
1494          }
1495       }
1496 
1497       return proc(hwnd, msg, wparam, lparam);
1498    } else {
1499       return DefDlgProcA(hwnd, msg, wparam, lparam);
1500    }
1501 }
1502 
1503 
1504 LRESULT defFrameProc(HWND hwnd, HWND hwndMdiClient, UINT msg, WPARAM wparam, LPARAM lparam) {
1505    if(useUnicode) {
1506       version(STATIC_UNICODE_DEF_WINDOW_PROC) {
1507          alias DefFrameProcW proc;
1508       }
1509       else {
1510          enum NAME = "DefFrameProcW";
1511          static DefFrameProcWProc proc = null;
1512 
1513          if(!proc) {
1514             proc = cast(DefFrameProcWProc)GetProcAddress(user32, NAME.ptr);
1515             if(!proc) {
1516                getProcErr(NAME);
1517             }
1518          }
1519       }
1520 
1521       return proc(hwnd, hwndMdiClient, msg, wparam, lparam);
1522    } else {
1523       return DefFrameProcA(hwnd, hwndMdiClient, msg, wparam, lparam);
1524    }
1525 }
1526 
1527 
1528 LRESULT defMDIChildProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) {
1529    if(useUnicode) {
1530       version(STATIC_UNICODE_DEF_WINDOW_PROC) {
1531          alias DefMDIChildProcW proc;
1532       }
1533       else {
1534          enum NAME = "DefMDIChildProcW";
1535          static DefMDIChildProcWProc proc = null;
1536 
1537          if(!proc) {
1538             proc = cast(DefMDIChildProcWProc)GetProcAddress(user32, NAME.ptr);
1539             if(!proc) {
1540                getProcErr(NAME);
1541             }
1542          }
1543       }
1544 
1545       return proc(hwnd, msg, wparam, lparam);
1546    } else {
1547       return DefMDIChildProcA(hwnd, msg, wparam, lparam);
1548    }
1549 }
1550 
1551 
1552 version = STATIC_UNICODE_PEEK_MESSAGE;
1553 version = STATIC_UNICODE_DISPATCH_MESSAGE;
1554 
1555 
1556 LONG dispatchMessage(MSG* pmsg) {
1557    if(useUnicode) {
1558       version(STATIC_UNICODE_DISPATCH_MESSAGE) {
1559          alias DispatchMessageW dispatchproc;
1560       }
1561       else {
1562          enum DISPATCHNAME = "DispatchMessageW";
1563          static DispatchMessageWProc dispatchproc = null;
1564 
1565          if(!dispatchproc) {
1566             dispatchproc = cast(DispatchMessageWProc)GetProcAddress(user32, DISPATCHNAME);
1567             if(!dispatchproc) {
1568                getProcErr(DISPATCHNAME);
1569             }
1570          }
1571       }
1572 
1573       return dispatchproc(pmsg);
1574    } else {
1575       return DispatchMessageA(pmsg);
1576    }
1577 }
1578 
1579 
1580 BOOL peekMessage(MSG* pmsg, HWND hwnd = HWND.init, UINT wmFilterMin = 0, UINT wmFilterMax = 0, UINT removeMsg = PM_NOREMOVE) {
1581    if(useUnicode) {
1582       version(STATIC_UNICODE_PEEK_MESSAGE) {
1583          alias PeekMessageW peekproc;
1584       }
1585       else {
1586          enum PEEKNAME = "PeekMessageW";
1587          static PeekMessageWProc peekproc = null;
1588 
1589          if(!peekproc) {
1590             peekproc = cast(PeekMessageWProc)GetProcAddress(user32, PEEKNAME);
1591             if(!peekproc) {
1592                getProcErr(PEEKNAME);
1593             }
1594          }
1595       }
1596 
1597       /+
1598       // Using PeekMessageA to test if the window is unicod.
1599       if(!PeekMessageA(pmsg, hwnd, wmFilterMin, wmFilterMax, PM_NOREMOVE)) { // Don't remove to test if unicode.
1600          return 0;
1601       }
1602       if(!IsWindowUnicode(pmsg.hwnd)) { // Window is not unicode.
1603          if(removeMsg == PM_NOREMOVE) {
1604             return 1;   // No need to do extra work here.
1605          }
1606          return PeekMessageA(pmsg, hwnd, wmFilterMin, wmFilterMax, removeMsg);
1607       } else { // Window is unicode.
1608          return peekproc(pmsg, hwnd, wmFilterMin, wmFilterMax, removeMsg);
1609       }
1610       +/
1611       // Since I already know useUnicode, use PeekMessageW to test if the window is unicode.
1612       if(!peekproc(pmsg, hwnd, wmFilterMin, wmFilterMax, PM_NOREMOVE)) { // Don't remove to test if unicode.
1613          return 0;
1614       }
1615       if(!IsWindowUnicode(pmsg.hwnd)) { // Window is not unicode.
1616          return PeekMessageA(pmsg, hwnd, wmFilterMin, wmFilterMax, removeMsg);
1617       } else { // Window is unicode.
1618          if(removeMsg == PM_NOREMOVE) {
1619             return 1;   // No need to do extra work here.
1620          }
1621          return peekproc(pmsg, hwnd, wmFilterMin, wmFilterMax, removeMsg);
1622       }
1623    } else {
1624       return PeekMessageA(pmsg, hwnd, wmFilterMin, wmFilterMax, removeMsg);
1625    }
1626 }
1627 
1628 
1629 BOOL getMessage(MSG* pmsg, HWND hwnd = HWND.init, UINT wmFilterMin = 0, UINT wmFilterMax = 0) {
1630    if(!WaitMessage()) {
1631       return -1;
1632    }
1633    if(!peekMessage(pmsg, hwnd, wmFilterMin, wmFilterMax, PM_REMOVE)) {
1634       return -1;
1635    }
1636    if(WM_QUIT == pmsg.message) {
1637       return 0;
1638    }
1639    return 1;
1640 }
1641 
1642 
1643 BOOL isDialogMessage(HWND hwnd, MSG* pmsg) {
1644    if(useUnicode) {
1645       version(STATIC_UNICODE) {
1646          alias IsDialogMessageW proc;
1647       }
1648       else {
1649          enum NAME = "IsDialogMessageW";
1650          static IsDialogMessageWProc proc = null;
1651 
1652          if(!proc) {
1653             proc = cast(IsDialogMessageWProc)GetProcAddress(user32, NAME.ptr);
1654             if(!proc) {
1655                getProcErr(NAME);
1656             }
1657          }
1658       }
1659 
1660       return proc(hwnd, pmsg);
1661    } else {
1662       return IsDialogMessageA(hwnd, pmsg);
1663    }
1664 }
1665 
1666 
1667 HANDLE findFirstChangeNotification(Dstring pathName, BOOL watchSubtree, DWORD notifyFilter) {
1668    if(useUnicode) {
1669       version(STATIC_UNICODE) {
1670          alias FindFirstChangeNotificationW proc;
1671       }
1672       else {
1673          enum NAME = "FindFirstChangeNotificationW";
1674          static FindFirstChangeNotificationWProc proc = null;
1675 
1676          if(!proc) {
1677             proc = cast(FindFirstChangeNotificationWProc)GetProcAddress(kernel32, NAME.ptr);
1678             if(!proc) {
1679                getProcErr(NAME);
1680             }
1681          }
1682       }
1683 
1684       return proc(toUnicodez(pathName), watchSubtree, notifyFilter);
1685    } else {
1686       return FindFirstChangeNotificationA(unsafeAnsiz(pathName), watchSubtree, notifyFilter);
1687    }
1688 }
1689 
1690 
1691 HINSTANCE loadLibraryEx(Dstring libFileName, DWORD flags) {
1692    if(useUnicode) {
1693       version(STATIC_UNICODE) {
1694          alias LoadLibraryExW proc;
1695       }
1696       else {
1697          enum NAME = "LoadLibraryExW";
1698          static LoadLibraryExWProc proc = null;
1699 
1700          if(!proc) {
1701             proc = cast(LoadLibraryExWProc)GetProcAddress(kernel32, NAME.ptr);
1702             if(!proc) {
1703                getProcErr(NAME);
1704             }
1705          }
1706       }
1707 
1708       return proc(toUnicodez(libFileName), HANDLE.init, flags);
1709    } else {
1710       return LoadLibraryExA(unsafeAnsiz(libFileName), HANDLE.init, flags);
1711    }
1712 }
1713 
1714 
1715 BOOL _setMenuItemInfoW(HMENU hMenu, UINT uItem, BOOL fByPosition, LPMENUITEMINFOW lpmii) { // package
1716    if(useUnicode) {
1717       version(STATIC_UNICODE) {
1718          alias SetMenuItemInfoW proc;
1719       }
1720       else {
1721          enum NAME = "SetMenuItemInfoW";
1722          static SetMenuItemInfoWProc proc = null;
1723 
1724          if(!proc) {
1725             proc = cast(SetMenuItemInfoWProc)GetProcAddress(user32, NAME.ptr);
1726             if(!proc) {
1727                getProcErr(NAME);
1728             }
1729          }
1730       }
1731 
1732       return proc(hMenu, uItem, fByPosition, lpmii);
1733    } else {
1734       assert(0);
1735    }
1736 }
1737 
1738 
1739 BOOL _insertMenuItemW(HMENU hMenu, UINT uItem, BOOL fByPosition, LPMENUITEMINFOW lpmii) { // package
1740    if(useUnicode) {
1741       version(STATIC_UNICODE) {
1742          alias InsertMenuItemW proc;
1743       }
1744       else {
1745          enum NAME = "InsertMenuItemW";
1746          static InsertMenuItemWProc proc = null;
1747 
1748          if(!proc) {
1749             proc = cast(InsertMenuItemWProc)GetProcAddress(user32, NAME.ptr);
1750             if(!proc) {
1751                getProcErr(NAME);
1752             }
1753          }
1754       }
1755 
1756       return proc(hMenu, uItem, fByPosition, lpmii);
1757    } else {
1758       assert(0);
1759    }
1760 }
1761 
1762 
1763 Dstring regQueryValueString(HKEY hkey, Dstring valueName, LPDWORD lpType = null) {
1764    DWORD _type;
1765    if(!lpType) {
1766       lpType = &_type;
1767    }
1768 
1769    DWORD sz;
1770 
1771    if(useUnicode) {
1772       version(STATIC_UNICODE) {
1773          alias RegQueryValueExW proc;
1774       }
1775       else {
1776          enum NAME = "RegQueryValueExW";
1777          static RegQueryValueExWProc proc = null;
1778 
1779          if(!proc) {
1780             proc = cast(RegQueryValueExWProc)GetProcAddress(advapi32, NAME.ptr);
1781             if(!proc) {
1782                getProcErr(NAME);
1783             }
1784          }
1785       }
1786 
1787       //sz = 0;
1788       auto lpValueName = toUnicodez(valueName);
1789       proc(hkey, lpValueName, null, lpType, null, &sz);
1790       if(!sz || (REG_SZ != *lpType && REG_EXPAND_SZ != *lpType)) {
1791          return null;
1792       }
1793       wchar[] ws = new wchar[sz];
1794       if(ERROR_SUCCESS != proc(hkey, lpValueName, null, null, cast(LPBYTE)ws.ptr, &sz)) {
1795          return null;
1796       }
1797       //return fromUnicode(ws.ptr, ws.length - 1); // Somehow ends up throwing invalid UTF-16.
1798       return fromUnicodez(ws.ptr);
1799    } else {
1800       //sz = 0;
1801       auto lpValueName = toAnsiz(valueName);
1802       RegQueryValueExA(hkey, lpValueName, null, lpType, null, &sz);
1803       if(!sz || (REG_SZ != *lpType && REG_EXPAND_SZ != *lpType)) {
1804          return null;
1805       }
1806       char[] s = new char[sz];
1807       if(ERROR_SUCCESS != RegQueryValueExA(hkey, lpValueName, null, null, cast(LPBYTE)s.ptr, &sz)) {
1808          return null;
1809       }
1810       //return fromAnsi(s.ptr, s.length - 1);
1811       return fromAnsiz(s.ptr);
1812    }
1813 }
1814 
1815 
1816 struct LogFont {
1817    union {
1818       LOGFONTW lfw;
1819       LOGFONTA lfa;
1820    }
1821    alias lfw lf;
1822 
1823    Dstring faceName;
1824 }
1825 
1826 
1827 HFONT createFontIndirect(ref LogFont lf) {
1828    if(useUnicode) {
1829       version(STATIC_UNICODE) {
1830          alias CreateFontIndirectW proc;
1831       }
1832       else {
1833          enum NAME = "CreateFontIndirectW";
1834          static CreateFontIndirectWProc proc = null;
1835 
1836          if(!proc) {
1837             proc = cast(CreateFontIndirectWProc)GetProcAddress(gdi32, NAME.ptr);
1838             if(!proc) {
1839                getProcErr(NAME);
1840             }
1841          }
1842       }
1843 
1844       Dwstring ws = toUnicode(lf.faceName);
1845       if(ws.length >= LF_FACESIZE) {
1846          ws = ws[0 .. LF_FACESIZE - 1];   // ?
1847       }
1848       foreach(idx, wch; ws) {
1849          lf.lfw.lfFaceName[idx] = wch;
1850       }
1851       lf.lfw.lfFaceName[ws.length] = 0;
1852 
1853       return proc(&lf.lfw);
1854    } else {
1855       Dstring as = toAnsi(lf.faceName);
1856       if(as.length >= LF_FACESIZE) {
1857          as = as[0 .. LF_FACESIZE - 1];   // ?
1858       }
1859       foreach(idx, ach; as) {
1860          lf.lfa.lfFaceName[idx] = ach;
1861       }
1862       lf.lfa.lfFaceName[as.length] = 0;
1863 
1864       return CreateFontIndirectA(&lf.lfa);
1865    }
1866 }
1867 
1868 
1869 // GetObject for a LogFont.
1870 int getLogFont(HFONT hf, ref LogFont lf) {
1871    if(useUnicode) {
1872       version(STATIC_UNICODE) {
1873          alias GetObjectW proc;
1874       }
1875       else {
1876          enum NAME = "GetObjectW";
1877          static GetObjectWProc proc = null;
1878 
1879          if(!proc) {
1880             proc = cast(GetObjectWProc)GetProcAddress(gdi32, NAME.ptr);
1881             if(!proc) {
1882                getProcErr(NAME);
1883             }
1884          }
1885       }
1886 
1887       if(LOGFONTW.sizeof != proc(hf, LOGFONTW.sizeof, &lf.lfw)) {
1888          return 0;
1889       }
1890       lf.faceName = fromUnicodez(lf.lfw.lfFaceName.ptr);
1891       return LOGFONTW.sizeof;
1892    } else {
1893       if(LOGFONTA.sizeof != GetObjectA(hf, LOGFONTA.sizeof, &lf.lfa)) {
1894          return 0;
1895       }
1896       lf.faceName = fromAnsiz(lf.lfa.lfFaceName.ptr);
1897       return LOGFONTA.sizeof;
1898    }
1899 }
1900