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