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