Visual Studio 2012 Support
[xy_vsfilter.git] / src / thirdparty / VirtualDub / system / source / w32assist.cpp
blob76b6e516f9d68f25fcf2fe9f825bb7317b6bc2ad
1 // VirtualDub - Video processing and capture application
2 // System library component
3 // Copyright (C) 1998-2004 Avery Lee, All Rights Reserved.
4 //
5 // Beginning with 1.6.0, the VirtualDub system library is licensed
6 // differently than the remainder of VirtualDub. This particular file is
7 // thus licensed as follows (the "zlib" license):
8 //
9 // This software is provided 'as-is', without any express or implied
10 // warranty. In no event will the authors be held liable for any
11 // damages arising from the use of this software.
13 // Permission is granted to anyone to use this software for any purpose,
14 // including commercial applications, and to alter it and redistribute it
15 // freely, subject to the following restrictions:
17 // 1. The origin of this software must not be misrepresented; you must
18 // not claim that you wrote the original software. If you use this
19 // software in a product, an acknowledgment in the product
20 // documentation would be appreciated but is not required.
21 // 2. Altered source versions must be plainly marked as such, and must
22 // not be misrepresented as being the original software.
23 // 3. This notice may not be removed or altered from any source
24 // distribution.
26 #include "stdafx.h"
27 #include <vd2/system/w32assist.h>
28 #include <vd2/system/seh.h>
29 #include <vd2/system/text.h>
30 #include <vd2/system/vdstdc.h>
31 #include <vd2/system/vdstl.h>
33 bool VDIsForegroundTaskW32() {
34 HWND hwndFore = GetForegroundWindow();
36 if (!hwndFore)
37 return false;
39 DWORD dwProcessId = 0;
40 GetWindowThreadProcessId(hwndFore, &dwProcessId);
42 return dwProcessId == GetCurrentProcessId();
45 LPVOID VDConvertThreadToFiberW32(LPVOID parm) {
46 typedef LPVOID (WINAPI *tpConvertThreadToFiber)(LPVOID p);
47 static tpConvertThreadToFiber ctof = (tpConvertThreadToFiber)GetProcAddress(GetModuleHandle("kernel32"), "ConvertThreadToFiber");
49 if (!ctof)
50 return NULL;
52 return ctof(parm);
55 void VDSwitchToFiberW32(LPVOID fiber) {
56 typedef void (WINAPI *tpSwitchToFiber)(LPVOID p);
57 static tpSwitchToFiber stof = (tpSwitchToFiber)GetProcAddress(GetModuleHandle("kernel32"), "SwitchToFiber");
59 if (stof)
60 stof(fiber);
63 int VDGetSizeOfBitmapHeaderW32(const BITMAPINFOHEADER *pHdr) {
64 int palents = 0;
66 if ((pHdr->biCompression == BI_RGB || pHdr->biCompression == BI_RLE4 || pHdr->biCompression == BI_RLE8) && pHdr->biBitCount <= 8) {
67 palents = pHdr->biClrUsed;
68 if (!palents)
69 palents = 1 << pHdr->biBitCount;
71 int size = pHdr->biSize + palents * sizeof(RGBQUAD);
73 if (pHdr->biSize < sizeof(BITMAPV4HEADER) && pHdr->biCompression == BI_BITFIELDS)
74 size += sizeof(DWORD) * 3;
76 return size;
79 void VDSetWindowTextW32(HWND hwnd, const wchar_t *s) {
80 if (VDIsWindowsNT()) {
81 SetWindowTextW(hwnd, s);
82 } else {
83 SetWindowTextA(hwnd, VDTextWToA(s).c_str());
87 void VDSetWindowTextFW32(HWND hwnd, const wchar_t *format, ...) {
88 va_list val;
90 va_start(val, format);
92 wchar_t buf[512];
93 int r = vdvswprintf(buf, 512, format, val);
95 if ((unsigned)r < 512) {
96 VDSetWindowTextW32(hwnd, buf);
97 va_end(val);
98 return;
102 VDStringW s;
103 s.append_vsprintf(format, val);
104 VDSetWindowTextW32(hwnd, s.c_str());
106 va_end(val);
109 VDStringA VDGetWindowTextAW32(HWND hwnd) {
110 char buf[512];
112 int len = GetWindowTextLengthA(hwnd);
114 if (len > 511) {
115 vdblock<char> tmp(len + 1);
116 len = GetWindowTextA(hwnd, tmp.data(), tmp.size());
118 const char *s = tmp.data();
119 VDStringA text(s, s+len);
120 return text;
121 } else if (len > 0) {
122 len = GetWindowTextA(hwnd, buf, 512);
124 return VDStringA(buf, buf + len);
127 return VDStringA();
130 VDStringW VDGetWindowTextW32(HWND hwnd) {
131 union {
132 wchar_t w[256];
133 char a[512];
134 } buf;
136 if (VDIsWindowsNT()) {
137 int len = GetWindowTextLengthW(hwnd);
139 if (len > 255) {
140 vdblock<wchar_t> tmp(len + 1);
141 len = GetWindowTextW(hwnd, tmp.data(), tmp.size());
143 VDStringW text(tmp.data(), len);
144 return text;
145 } else if (len > 0) {
146 len = GetWindowTextW(hwnd, buf.w, 256);
148 VDStringW text(buf.w, len);
149 return text;
151 } else {
152 int len = GetWindowTextLengthA(hwnd);
154 if (len > 511) {
155 vdblock<char> tmp(len + 1);
156 len = GetWindowTextA(hwnd, tmp.data(), tmp.size());
158 VDStringW text(VDTextAToW(tmp.data(), len));
159 return text;
160 } else if (len > 0) {
161 len = GetWindowTextA(hwnd, buf.a, 512);
163 VDStringW text(VDTextAToW(buf.a, len));
164 return text;
168 return VDStringW();
171 void VDAppendMenuW32(HMENU hmenu, UINT flags, UINT id, const wchar_t *text){
172 if (VDIsWindowsNT()) {
173 AppendMenuW(hmenu, flags, id, text);
174 } else {
175 AppendMenuA(hmenu, flags, id, VDTextWToA(text).c_str());
179 void VDAppendMenuSeparatorW32(HMENU hmenu) {
180 int pos = GetMenuItemCount(hmenu);
181 if (pos < 0)
182 return;
184 if (VDIsWindowsNT()) {
185 MENUITEMINFOW mmiW;
186 vdfastfixedvector<wchar_t, 256> bufW;
188 mmiW.cbSize = MENUITEMINFO_SIZE_VERSION_400W;
189 mmiW.fMask = MIIM_TYPE;
190 mmiW.fType = MFT_SEPARATOR;
192 InsertMenuItemW(hmenu, pos, TRUE, &mmiW);
193 } else {
194 MENUITEMINFOA mmiA;
196 mmiA.cbSize = MENUITEMINFO_SIZE_VERSION_400A;
197 mmiA.fMask = MIIM_TYPE;
198 mmiA.fType = MFT_SEPARATOR;
200 InsertMenuItemA(hmenu, pos, TRUE, &mmiA);
204 void VDCheckMenuItemByPositionW32(HMENU hmenu, uint32 pos, bool checked) {
205 CheckMenuItem(hmenu, pos, checked ? MF_BYPOSITION|MF_CHECKED : MF_BYPOSITION|MF_UNCHECKED);
208 void VDCheckMenuItemByCommandW32(HMENU hmenu, UINT cmd, bool checked) {
209 CheckMenuItem(hmenu, cmd, checked ? MF_BYCOMMAND|MF_CHECKED : MF_BYCOMMAND|MF_UNCHECKED);
212 void VDCheckRadioMenuItemByPositionW32(HMENU hmenu, uint32 pos, bool checked) {
213 MENUITEMINFOA mii;
215 mii.cbSize = sizeof(MENUITEMINFOA);
216 mii.fMask = MIIM_FTYPE | MIIM_STATE;
217 if (GetMenuItemInfo(hmenu, pos, TRUE, &mii)) {
218 mii.fType |= MFT_RADIOCHECK;
219 mii.fState &= ~MFS_CHECKED;
220 if (checked)
221 mii.fState |= MFS_CHECKED;
222 SetMenuItemInfo(hmenu, pos, TRUE, &mii);
226 void VDCheckRadioMenuItemByCommandW32(HMENU hmenu, UINT cmd, bool checked) {
227 MENUITEMINFOA mii;
229 mii.cbSize = sizeof(MENUITEMINFOA);
230 mii.fMask = MIIM_FTYPE | MIIM_STATE;
231 if (GetMenuItemInfo(hmenu, cmd, FALSE, &mii)) {
232 mii.fType |= MFT_RADIOCHECK;
233 mii.fState &= ~MFS_CHECKED;
234 if (checked)
235 mii.fState |= MFS_CHECKED;
236 SetMenuItemInfo(hmenu, cmd, FALSE, &mii);
240 void VDEnableMenuItemByCommandW32(HMENU hmenu, UINT cmd, bool checked) {
241 EnableMenuItem(hmenu, cmd, checked ? MF_BYCOMMAND|MF_ENABLED : MF_BYCOMMAND|MF_GRAYED);
244 VDStringW VDGetMenuItemTextByCommandW32(HMENU hmenu, UINT cmd) {
245 VDStringW s;
247 if (VDIsWindowsNT()) {
248 MENUITEMINFOW mmiW;
249 vdfastfixedvector<wchar_t, 256> bufW;
251 mmiW.cbSize = MENUITEMINFO_SIZE_VERSION_400W;
252 mmiW.fMask = MIIM_TYPE;
253 mmiW.fType = MFT_STRING;
254 mmiW.dwTypeData = NULL;
255 mmiW.cch = 0; // required to avoid crash on NT4
257 if (GetMenuItemInfoW(hmenu, cmd, FALSE, &mmiW)) {
258 bufW.resize(mmiW.cch + 1, 0);
259 ++mmiW.cch;
260 mmiW.dwTypeData = bufW.data();
262 if (GetMenuItemInfoW(hmenu, cmd, FALSE, &mmiW))
263 s = bufW.data();
265 } else {
266 MENUITEMINFOA mmiA;
267 vdfastfixedvector<char, 256> bufA;
269 mmiA.cbSize = MENUITEMINFO_SIZE_VERSION_400A;
270 mmiA.fMask = MIIM_TYPE;
271 mmiA.fType = MFT_STRING;
272 mmiA.dwTypeData = NULL;
274 if (GetMenuItemInfoA(hmenu, cmd, FALSE, &mmiA)) {
275 bufA.resize(mmiA.cch + 1, 0);
276 ++mmiA.cch;
277 mmiA.dwTypeData = bufA.data();
279 if (GetMenuItemInfoA(hmenu, cmd, FALSE, &mmiA))
280 s = VDTextAToW(bufA.data());
284 return s;
287 void VDSetMenuItemTextByCommandW32(HMENU hmenu, UINT cmd, const wchar_t *text) {
288 if (VDIsWindowsNT()) {
289 MENUITEMINFOW mmiW;
291 mmiW.cbSize = MENUITEMINFO_SIZE_VERSION_400W;
292 mmiW.fMask = MIIM_TYPE;
293 mmiW.fType = MFT_STRING;
294 mmiW.dwTypeData = (LPWSTR)text;
296 SetMenuItemInfoW(hmenu, cmd, FALSE, &mmiW);
297 } else {
298 MENUITEMINFOA mmiA;
299 VDStringA textA(VDTextWToA(text));
301 mmiA.cbSize = MENUITEMINFO_SIZE_VERSION_400A;
302 mmiA.fMask = MIIM_TYPE;
303 mmiA.fType = MFT_STRING;
304 mmiA.dwTypeData = (LPSTR)textA.c_str();
306 SetMenuItemInfoA(hmenu, cmd, FALSE, &mmiA);
310 LRESULT VDDualCallWindowProcW32(WNDPROC wp, HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
311 return (IsWindowUnicode(hwnd) ? CallWindowProcW : CallWindowProcA)(wp, hwnd, msg, wParam, lParam);
314 LRESULT VDDualDefWindowProcW32(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
315 return IsWindowUnicode(hwnd) ? DefWindowProcW(hwnd, msg, wParam, lParam) : DefWindowProcA(hwnd, msg, wParam, lParam);
318 EXECUTION_STATE VDSetThreadExecutionStateW32(EXECUTION_STATE esFlags) {
319 EXECUTION_STATE es = 0;
321 // SetThreadExecutionState(): requires Windows 98+/2000+.
322 typedef EXECUTION_STATE (WINAPI *tSetThreadExecutionState)(EXECUTION_STATE);
323 static tSetThreadExecutionState pFunc = (tSetThreadExecutionState)GetProcAddress(GetModuleHandle("kernel32"), "SetThreadExecutionState");
325 if (pFunc)
326 es = pFunc(esFlags);
328 return es;
331 bool VDSetFilePointerW32(HANDLE h, sint64 pos, DWORD dwMoveMethod) {
332 LONG posHi = (LONG)(pos >> 32);
333 DWORD result = SetFilePointer(h, (LONG)pos, &posHi, dwMoveMethod);
335 if (result != INVALID_SET_FILE_POINTER)
336 return true;
338 DWORD dwError = GetLastError();
340 return (dwError == NO_ERROR);
343 bool VDGetFileSizeW32(HANDLE h, sint64& size) {
344 DWORD dwSizeHigh;
345 DWORD dwSizeLow = GetFileSize(h, &dwSizeHigh);
347 if (dwSizeLow == (DWORD)-1 && GetLastError() != NO_ERROR)
348 return false;
350 size = dwSizeLow + ((sint64)dwSizeHigh << 32);
351 return true;
354 #if !defined(_MSC_VER) || _MSC_VER < 1300
355 HMODULE VDGetLocalModuleHandleW32() {
356 MEMORY_BASIC_INFORMATION meminfo;
357 static HMODULE shmod = (VirtualQuery((HINSTANCE)&VDGetLocalModuleHandleW32, &meminfo, sizeof meminfo), (HMODULE)meminfo.AllocationBase);
359 return shmod;
361 #endif
363 bool VDDrawTextW32(HDC hdc, const wchar_t *s, int nCount, LPRECT lpRect, UINT uFormat) {
364 RECT r;
365 if (VDIsWindowsNT()) {
366 // If multiline and vcentered (not normally supported...)
367 if (!((uFormat ^ DT_VCENTER) & (DT_VCENTER|DT_SINGLELINE))) {
368 uFormat &= ~DT_VCENTER;
370 r = *lpRect;
371 if (!DrawTextW(hdc, s, nCount, &r, uFormat | DT_CALCRECT))
372 return false;
374 int dx = ((lpRect->right - lpRect->left) - (r.right - r.left)) >> 1;
375 int dy = ((lpRect->bottom - lpRect->top) - (r.bottom - r.top)) >> 1;
377 r.left += dx;
378 r.right += dx;
379 r.top += dy;
380 r.bottom += dy;
381 lpRect = &r;
384 return !!DrawTextW(hdc, s, nCount, lpRect, uFormat);
385 } else {
386 VDStringA strA(VDTextWToA(s, nCount));
388 // If multiline and vcentered (not normally supported...)
389 if (!((uFormat ^ DT_VCENTER) & (DT_VCENTER|DT_SINGLELINE))) {
390 uFormat &= ~DT_VCENTER;
392 r = *lpRect;
393 if (!DrawTextA(hdc, strA.data(), strA.size(), &r, uFormat | DT_CALCRECT))
394 return false;
396 int dx = ((lpRect->right - lpRect->left) - (r.right - r.left)) >> 1;
397 int dy = ((lpRect->bottom - lpRect->top) - (r.bottom - r.top)) >> 1;
399 r.left += dx;
400 r.right += dx;
401 r.top += dy;
402 r.bottom += dy;
403 lpRect = &r;
406 return !!DrawTextA(hdc, strA.data(), strA.size(), lpRect, uFormat);
410 bool VDPatchModuleImportTableW32(HMODULE hmod, const char *srcModule, const char *name, void *pCompareValue, void *pNewValue, void *volatile *ppOldValue) {
411 char *pBase = (char *)hmod;
413 vd_seh_guard_try {
414 // The PEheader offset is at hmod+0x3c. Add the size of the optional header
415 // to step to the section headers.
417 const uint32 peoffset = ((const long *)pBase)[15];
418 const uint32 signature = *(uint32 *)(pBase + peoffset);
420 if (signature != IMAGE_NT_SIGNATURE)
421 return false;
423 const IMAGE_FILE_HEADER *pHeader = (const IMAGE_FILE_HEADER *)(pBase + peoffset + 4);
425 // Verify the PE optional structure.
427 if (pHeader->SizeOfOptionalHeader < 104)
428 return false;
430 // Find import header.
432 const IMAGE_IMPORT_DESCRIPTOR *pImportDir;
433 int nImports;
435 switch(*(short *)((char *)pHeader + IMAGE_SIZEOF_FILE_HEADER)) {
437 #ifdef _M_AMD64
438 case IMAGE_NT_OPTIONAL_HDR64_MAGIC:
440 const IMAGE_OPTIONAL_HEADER64 *pOpt = (IMAGE_OPTIONAL_HEADER64 *)((const char *)pHeader + sizeof(IMAGE_FILE_HEADER));
442 if (pOpt->NumberOfRvaAndSizes < 2)
443 return false;
445 pImportDir = (const IMAGE_IMPORT_DESCRIPTOR *)(pBase + pOpt->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress);
446 nImports = pOpt->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size / sizeof(IMAGE_IMPORT_DESCRIPTOR);
448 break;
449 #else
450 case IMAGE_NT_OPTIONAL_HDR32_MAGIC:
452 const IMAGE_OPTIONAL_HEADER32 *pOpt = (IMAGE_OPTIONAL_HEADER32 *)((const char *)pHeader + sizeof(IMAGE_FILE_HEADER));
454 if (pOpt->NumberOfRvaAndSizes < 2)
455 return false;
457 pImportDir = (const IMAGE_IMPORT_DESCRIPTOR *)(pBase + pOpt->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress);
458 nImports = pOpt->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size / sizeof(IMAGE_IMPORT_DESCRIPTOR);
460 break;
461 #endif
463 default: // reject PE32+
464 return false;
467 // Hmmm... no imports?
469 if ((const char *)pImportDir == pBase)
470 return false;
472 // Scan down the import entries. We are looking for MSVFW32.
474 int i;
476 for(i=0; i<nImports; ++i) {
477 if (!_stricmp(pBase + pImportDir[i].Name, srcModule))
478 break;
481 if (i >= nImports)
482 return false;
484 // Found it. Start scanning MSVFW32 imports until we find DrawDibDraw.
486 const long *pImports = (const long *)(pBase + pImportDir[i].OriginalFirstThunk);
487 void * volatile *pVector = (void * volatile *)(pBase + pImportDir[i].FirstThunk);
489 while(*pImports) {
490 if (*pImports >= 0) {
491 const char *pName = pBase + *pImports + 2;
493 if (!strcmp(pName, name)) {
495 // Found it! Reset the protection.
497 DWORD dwOldProtect;
499 if (VirtualProtect((void *)pVector, sizeof(void *), PAGE_EXECUTE_READWRITE, &dwOldProtect)) {
500 if (ppOldValue) {
501 for(;;) {
502 void *old = *pVector;
503 if (pCompareValue && pCompareValue != old)
504 return false;
506 *ppOldValue = old;
507 if (old == VDAtomicCompareExchangePointer(pVector, pNewValue, old))
508 break;
510 } else {
511 *pVector = pNewValue;
514 VirtualProtect((void *)pVector, sizeof(void *), dwOldProtect, &dwOldProtect);
516 return true;
519 break;
523 ++pImports;
524 ++pVector;
526 } vd_seh_guard_except {
529 return false;
532 bool VDPatchModuleExportTableW32(HMODULE hmod, const char *name, void *pCompareValue, void *pNewValue, void *volatile *ppOldValue) {
533 char *pBase = (char *)hmod;
535 vd_seh_guard_try {
536 // The PEheader offset is at hmod+0x3c. Add the size of the optional header
537 // to step to the section headers.
539 const uint32 peoffset = ((const long *)pBase)[15];
540 const uint32 signature = *(uint32 *)(pBase + peoffset);
542 if (signature != IMAGE_NT_SIGNATURE)
543 return false;
545 const IMAGE_FILE_HEADER *pHeader = (const IMAGE_FILE_HEADER *)(pBase + peoffset + 4);
547 // Verify the PE optional structure.
549 if (pHeader->SizeOfOptionalHeader < 104)
550 return false;
552 // Find export directory.
554 const IMAGE_EXPORT_DIRECTORY *pExportDir;
556 switch(*(short *)((char *)pHeader + IMAGE_SIZEOF_FILE_HEADER)) {
558 #ifdef _M_AMD64
559 case IMAGE_NT_OPTIONAL_HDR64_MAGIC:
561 const IMAGE_OPTIONAL_HEADER64 *pOpt = (IMAGE_OPTIONAL_HEADER64 *)((const char *)pHeader + sizeof(IMAGE_FILE_HEADER));
563 if (pOpt->NumberOfRvaAndSizes < 1)
564 return false;
566 DWORD exportDirRVA = pOpt->DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress;
568 if (!exportDirRVA)
569 return false;
571 pExportDir = (const IMAGE_EXPORT_DIRECTORY *)(pBase + exportDirRVA);
573 break;
574 #else
575 case IMAGE_NT_OPTIONAL_HDR32_MAGIC:
577 const IMAGE_OPTIONAL_HEADER32 *pOpt = (IMAGE_OPTIONAL_HEADER32 *)((const char *)pHeader + sizeof(IMAGE_FILE_HEADER));
579 if (pOpt->NumberOfRvaAndSizes < 1)
580 return false;
582 DWORD exportDirRVA = pOpt->DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress;
584 if (!exportDirRVA)
585 return false;
587 pExportDir = (const IMAGE_EXPORT_DIRECTORY *)(pBase + exportDirRVA);
589 break;
590 #endif
592 default: // reject PE32+
593 return false;
596 // Scan for the export name.
597 DWORD nameCount = pExportDir->AddressOfNames;
598 const DWORD *nameRVAs = (const DWORD *)(pBase + pExportDir->AddressOfNames);
599 const WORD *nameOrdinals = (const WORD *)(pBase + pExportDir->AddressOfNameOrdinals);
600 DWORD *functionTable = (DWORD *)(pBase + pExportDir->AddressOfFunctions);
602 for(DWORD i=0; i<nameCount; ++i) {
603 DWORD nameRVA = nameRVAs[i];
604 const char *pName = (const char *)(pBase + nameRVA);
606 // compare names
607 if (!strcmp(pName, name)) {
609 // name matches -- look up the function entry
610 WORD ordinal = nameOrdinals[i];
611 DWORD *pRVA = &functionTable[ordinal];
613 // Reset the protection.
615 DWORD newRVA = (DWORD)pNewValue - (DWORD)pBase;
617 DWORD dwOldProtect;
618 if (VirtualProtect((void *)pRVA, sizeof(DWORD), PAGE_EXECUTE_READWRITE, &dwOldProtect)) {
619 if (ppOldValue) {
620 for(;;) {
621 DWORD oldRVA = *pRVA;
622 void *old = pBase + oldRVA;
623 if (pCompareValue && pCompareValue != old)
624 return false;
626 *ppOldValue = pBase + oldRVA;
627 if (oldRVA == VDAtomicInt::staticCompareExchange((volatile int *)pRVA, newRVA, oldRVA))
628 break;
630 } else {
631 *pRVA = newRVA;
634 VirtualProtect((void *)pRVA, sizeof(DWORD), dwOldProtect, &dwOldProtect);
636 return true;
639 break;
642 } vd_seh_guard_except {
645 return false;
648 HMODULE VDLoadSystemLibraryW32(const char *name) {
649 if (VDIsWindowsNT()) {
650 vdfastvector<wchar_t> pathW(MAX_PATH, 0);
652 size_t len = GetSystemDirectoryW(pathW.data(), MAX_PATH);
654 if (!len)
655 return NULL;
657 if (len > MAX_PATH) {
658 pathW.resize(len + 1, 0);
660 len = GetSystemDirectoryW(pathW.data(), len);
661 if (!len || len >= pathW.size())
662 return NULL;
665 pathW.resize(len);
667 if (pathW.back() != '\\')
668 pathW.push_back('\\');
670 while(const char c = *name++)
671 pathW.push_back(c);
673 pathW.push_back(0);
675 return LoadLibraryW(pathW.data());
676 } else {
677 vdfastvector<char> pathA(MAX_PATH, 0);
678 size_t len = GetSystemDirectoryA(pathA.data(), MAX_PATH);
680 if (!len)
681 return NULL;
683 if (len > MAX_PATH) {
684 pathA.resize(len + 1, 0);
686 len = GetSystemDirectoryA(pathA.data(), len);
687 if (!len || len >= pathA.size())
688 return NULL;
691 pathA.resize(len);
693 if (pathA.back() != '\\')
694 pathA.push_back('\\');
696 pathA.insert(pathA.end(), name, name + strlen(name));
697 pathA.push_back(0);
699 return LoadLibraryA(pathA.data());