LoadIconWithScaleDown() を使用してアイコンをロード
- compat_win.cpp にAPI追加
- SxS DLLロードに対応(dllutil.cpp)
@@ -63,6 +63,8 @@ | ||
63 | 63 | DWORD (WINAPI *pExpandEnvironmentStringsW)(LPCWSTR lpSrc, LPWSTR lpDst, DWORD nSize); |
64 | 64 | static ULONGLONG (WINAPI *pVerSetConditionMask)(ULONGLONG dwlConditionMask, DWORD dwTypeBitMask, BYTE dwConditionMask); |
65 | 65 | static BOOL (WINAPI *pVerifyVersionInfoA)(LPOSVERSIONINFOEX lpVersionInformation, DWORD dwTypeMask, DWORDLONG dwlConditionMask); |
66 | +BOOL (WINAPI *pSetDefaultDllDirectories)(DWORD DirectoryFlags); | |
67 | +BOOL (WINAPI *pSetDllDirectoryA)(LPCSTR lpPathName); | |
66 | 68 | |
67 | 69 | // gdi32 |
68 | 70 | int (WINAPI *pAddFontResourceExW)(LPCWSTR name, DWORD fl, PVOID res); |
@@ -95,7 +97,10 @@ | ||
95 | 97 | // shell32.dll |
96 | 98 | static HRESULT (WINAPI *pSHGetKnownFolderPath)(REFKNOWNFOLDERID rfid, DWORD dwFlags, HANDLE hToken, PWSTR* ppszPath); |
97 | 99 | |
100 | +// comctl32.dll | |
101 | +static HRESULT (WINAPI *pLoadIconWithScaleDown)(HINSTANCE hinst, PCWSTR pszName, int cx, int cy, HICON *phico); | |
98 | 102 | |
103 | + | |
99 | 104 | class Initializer { |
100 | 105 | public: |
101 | 106 | Initializer() { |
@@ -196,6 +201,8 @@ | ||
196 | 201 | { "GetConsoleWindow", (void **)&pGetConsoleWindow }, |
197 | 202 | { "VerSetConditionMask", (void **)&pVerSetConditionMask }, |
198 | 203 | { "VerifyVersionInfoA", (void **)&pVerifyVersionInfoA }, |
204 | + { "SetDefaultDllDirectories", (void **)&pSetDefaultDllDirectories }, | |
205 | + { "SetDllDirectoryA", (void **)&pSetDllDirectoryA }, | |
199 | 206 | {}, |
200 | 207 | }; |
201 | 208 |
@@ -228,6 +235,11 @@ | ||
228 | 235 | {}, |
229 | 236 | }; |
230 | 237 | |
238 | +static const APIInfo Lists_comctl32[] = { | |
239 | + { "LoadIconWithScaleDown", (void **)&pLoadIconWithScaleDown }, | |
240 | + {}, | |
241 | +}; | |
242 | + | |
231 | 243 | static const DllInfo DllInfos[] = { |
232 | 244 | { L"user32.dll", DLL_LOAD_LIBRARY_SYSTEM, DLL_ACCEPT_NOT_EXIST, Lists_user32 }, |
233 | 245 | { L"msimg32.dll", DLL_LOAD_LIBRARY_SYSTEM, DLL_ACCEPT_NOT_EXIST, Lists_msimg32 }, |
@@ -239,6 +251,7 @@ | ||
239 | 251 | { L"imagehlp.dll", DLL_LOAD_LIBRARY_SYSTEM, DLL_ACCEPT_NOT_EXIST, Lists_imagehlp }, |
240 | 252 | { L"dbghelp.dll", DLL_LOAD_LIBRARY_SYSTEM, DLL_ACCEPT_NOT_EXIST, Lists_dbghelp }, |
241 | 253 | { L"shell32.dll", DLL_LOAD_LIBRARY_SYSTEM, DLL_ACCEPT_NOT_EXIST, Lists_shell32 }, |
254 | + { L"comctl32.dll", DLL_LOAD_LIBRARY_SxS, DLL_ACCEPT_NOT_EXIST, Lists_comctl32 }, | |
242 | 255 | {}, |
243 | 256 | }; |
244 | 257 |
@@ -256,6 +269,20 @@ | ||
256 | 269 | } |
257 | 270 | } |
258 | 271 | |
272 | +static bool IsWindowsNT4() | |
273 | +{ | |
274 | + OSVERSIONINFOA osvi; | |
275 | + osvi.dwOSVersionInfoSize = sizeof(osvi); | |
276 | + GetVersionExA(&osvi); | |
277 | + if (osvi.dwPlatformId == VER_PLATFORM_WIN32_NT && | |
278 | + osvi.dwMajorVersion == 4 && | |
279 | + osvi.dwMinorVersion == 0) { | |
280 | + // NT4 | |
281 | + return true; | |
282 | + } | |
283 | + return false; | |
284 | +} | |
285 | + | |
259 | 286 | void WinCompatInit() |
260 | 287 | { |
261 | 288 | static BOOL done = FALSE; |
@@ -361,12 +388,12 @@ | ||
361 | 388 | DWORD dwTypeMask, |
362 | 389 | DWORDLONG dwlConditionMask) |
363 | 390 | { |
364 | - OSVERSIONINFO osvi; | |
391 | + OSVERSIONINFOA osvi; | |
365 | 392 | WORD cond; |
366 | 393 | BOOL ret, check_next; |
367 | 394 | |
368 | - osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); | |
369 | - GetVersionEx(&osvi); | |
395 | + osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOA); | |
396 | + GetVersionExA(&osvi); | |
370 | 397 | |
371 | 398 | if (dwTypeMask & VER_BUILDNUMBER) { |
372 | 399 | cond = (WORD)((dwlConditionMask >> (2*3)) & 0x07); |
@@ -585,3 +612,28 @@ | ||
585 | 612 | *ppszPath = _wcsdup(path); |
586 | 613 | return S_OK; |
587 | 614 | } |
615 | + | |
616 | +HRESULT _LoadIconWithScaleDown(HINSTANCE hinst, PCWSTR pszName, int cx, int cy, HICON *phico) | |
617 | +{ | |
618 | + if (pLoadIconWithScaleDown != NULL) { | |
619 | + HRESULT hr = pLoadIconWithScaleDown(hinst, pszName, cx, cy, phico); | |
620 | + if (SUCCEEDED(hr)) { | |
621 | + return hr; | |
622 | + } | |
623 | + } | |
624 | + | |
625 | + HICON hIcon; | |
626 | + int fuLoad = LR_DEFAULTCOLOR; | |
627 | + if (IsWindowsNT4()) { | |
628 | + // Windows NT 4.0 は 4bit アイコンしかサポートしていない | |
629 | + // 16(4bit) color = VGA color | |
630 | + fuLoad = LR_VGACOLOR; | |
631 | + } | |
632 | + hIcon = (HICON)LoadImageW(hinst, pszName, IMAGE_ICON, cx, cy, fuLoad); | |
633 | + if (hIcon == NULL) { | |
634 | + *phico = NULL; | |
635 | + return E_NOTIMPL; | |
636 | + } | |
637 | + *phico = hIcon; | |
638 | + return S_OK; | |
639 | +} |
@@ -153,6 +153,8 @@ | ||
153 | 153 | extern HWND (WINAPI *pGetConsoleWindow)(void); |
154 | 154 | ULONGLONG _VerSetConditionMask(ULONGLONG dwlConditionMask, DWORD dwTypeBitMask, BYTE dwConditionMask); |
155 | 155 | BOOL _VerifyVersionInfoA(LPOSVERSIONINFOEXA lpVersionInformation, DWORD dwTypeMask, DWORDLONG dwlConditionMask); |
156 | +extern BOOL (WINAPI *pSetDefaultDllDirectories)(DWORD DirectoryFlags); | |
157 | +extern BOOL (WINAPI *pSetDllDirectoryA)(LPCSTR lpPathName); | |
156 | 158 | |
157 | 159 | // htmlhelp.dll (hhctrl.ocx) |
158 | 160 | HWND _HtmlHelpW(HWND hwndCaller, LPCWSTR pszFile, UINT uCommand, DWORD_PTR dwData); |
@@ -186,6 +188,10 @@ | ||
186 | 188 | #endif |
187 | 189 | HRESULT _SHGetKnownFolderPath(REFKNOWNFOLDERID rfid, DWORD dwFlags, HANDLE hToken, PWSTR* ppszPath); |
188 | 190 | |
191 | +// comctl32.dll | |
192 | +HRESULT _LoadIconWithScaleDown(HINSTANCE hinst, PCWSTR pszName, int cx, int cy, HICON *phico); | |
193 | + | |
194 | + | |
189 | 195 | void WinCompatInit(); |
190 | 196 | |
191 | 197 | #ifdef __cplusplus |
@@ -333,9 +333,9 @@ | ||
333 | 333 | * アイコンをロードする |
334 | 334 | * @param[in] hinst |
335 | 335 | * @param[in] name |
336 | - * @param[in] cx アイコンサイズ | |
336 | + * @param[in] cx アイコンサイズ(96dpi時) | |
337 | 337 | * @param[in] cy アイコンサイズ |
338 | - * @param[in] dpi cx,cy は 96dpiからの比率 | |
338 | + * @param[in] dpi アイコンサイズ(cx,cy)はdpi/96倍のサイズで読み込まれる | |
339 | 339 | * @return HICON |
340 | 340 | * |
341 | 341 | * cx == 0 && cy == 0 のときデフォルトのアイコンサイズで読み込む |
@@ -343,8 +343,6 @@ | ||
343 | 343 | */ |
344 | 344 | static HICON TTLoadIcon(HINSTANCE hinst, const wchar_t *name, int cx, int cy, UINT dpi) |
345 | 345 | { |
346 | - HICON hIcon; | |
347 | - HRESULT hr; | |
348 | 346 | if (cx == 0 && cy == 0) { |
349 | 347 | // 100%(96dpi?)のとき、GetSystemMetrics(SM_CXICON)=32 |
350 | 348 | if (pGetSystemMetricsForDpi != NULL) { |
@@ -360,21 +358,10 @@ | ||
360 | 358 | cx = cx * dpi / 96; |
361 | 359 | cy = cy * dpi / 96; |
362 | 360 | } |
363 | -#if 0 // defined(NTDDI_VISTA) && (NTDDI_VERSION >= NTDDI_VISTA) | |
364 | - // LoadIconWithScaleDown() は vistaから | |
365 | - hr = LoadIconWithScaleDown(hInst, name, cx, cy, &hIcon); | |
366 | - // LoadIconMetric(); | |
367 | -#else | |
368 | - hr = E_NOTIMPL; | |
369 | -#endif | |
361 | + HICON hIcon; | |
362 | + HRESULT hr = _LoadIconWithScaleDown(hinst, name, cx, cy, &hIcon); | |
370 | 363 | if(FAILED(hr)) { |
371 | - int fuLoad = LR_DEFAULTCOLOR; | |
372 | - if (IsWindowsNT4()) { | |
373 | - // Windows NT 4.0 は 4bit アイコンしかサポートしていない | |
374 | - // 16(4bit) color = VGA color | |
375 | - fuLoad = LR_VGACOLOR; | |
376 | - } | |
377 | - hIcon = (HICON)LoadImageW(hinst, name, IMAGE_ICON, cx, cy, fuLoad); | |
364 | + hIcon = NULL; | |
378 | 365 | } |
379 | 366 | return hIcon; |
380 | 367 | } |
@@ -33,11 +33,14 @@ | ||
33 | 33 | #endif |
34 | 34 | #include <crtdbg.h> |
35 | 35 | |
36 | +#include "compat_win.h" | |
37 | +#include "ttlib.h" // for IsWindowsXPOrLater() | |
38 | + | |
36 | 39 | #include "dllutil.h" |
37 | 40 | |
38 | 41 | typedef struct { |
39 | 42 | const wchar_t *fname; |
40 | - DLLLoadFlag LoadFlag; | |
43 | + BOOL NeedFreeLibrary; | |
41 | 44 | HMODULE handle; |
42 | 45 | int refCount; |
43 | 46 | } HandleList_t; |
@@ -47,67 +50,86 @@ | ||
47 | 50 | |
48 | 51 | static HMODULE GetHandle(const wchar_t *fname, DLLLoadFlag LoadFlag) |
49 | 52 | { |
50 | - wchar_t dllPath[MAX_PATH]; | |
51 | 53 | HMODULE module; |
52 | - int i; | |
53 | 54 | HandleList_t *p; |
54 | - int r; | |
55 | 55 | |
56 | - if (LoadFlag == DLL_GET_MODULE_HANDLE) { | |
57 | - module = GetModuleHandleW(fname); | |
58 | - assert(module != NULL); | |
59 | - return module; | |
60 | - } | |
61 | - | |
62 | 56 | // 以前にロードした? |
63 | - p = HandleList; | |
64 | - for (i = 0; i < HandleListCount; i++) { | |
65 | - if (wcscmp(p->fname, fname) == 0) { | |
66 | - p->refCount++; | |
67 | - return p->handle; | |
57 | + if (LoadFlag != DLL_GET_MODULE_HANDLE) { | |
58 | + p = HandleList; | |
59 | + for (int i = 0; i < HandleListCount; i++) { | |
60 | + if (wcscmp(p->fname, fname) == 0) { | |
61 | + p->refCount++; | |
62 | + return p->handle; | |
63 | + } | |
64 | + p++; | |
68 | 65 | } |
69 | - p++; | |
70 | 66 | } |
71 | 67 | |
72 | - // 新たにロードする | |
73 | - dllPath[0] = 0; | |
74 | - switch (LoadFlag) { | |
75 | - case DLL_LOAD_LIBRARY_SYSTEM: | |
76 | - r = GetSystemDirectoryW(dllPath, _countof(dllPath)); | |
77 | - assert(r != 0); | |
78 | - if (r == 0) return NULL; | |
79 | - break; | |
80 | - case DLL_LOAD_LIBRARY_CURRENT: | |
81 | - r = GetModuleFileNameW(NULL, dllPath, _countof(dllPath)); | |
82 | - assert(r != 0); | |
83 | - if (r == 0) return NULL; | |
84 | - *wcsrchr(dllPath, L'\\') = 0; | |
85 | - break; | |
86 | - default: | |
87 | - return NULL; | |
68 | + // モジュールがロード済みならハンドルが取得できる | |
69 | + // exeをロードしたときにdllがロードされていれば、ハンドルが返ってくる | |
70 | + module = GetModuleHandleW(fname); | |
71 | + if (LoadFlag == DLL_GET_MODULE_HANDLE) { | |
72 | + // module == NULL でも return する | |
73 | + return module; | |
88 | 74 | } |
89 | - wcscat_s(dllPath, _countof(dllPath), L"\\"); | |
90 | - wcscat_s(dllPath, _countof(dllPath), fname); | |
91 | - module = LoadLibraryW(dllPath); | |
75 | + | |
76 | + BOOL NeedFreeLibrary = FALSE; | |
92 | 77 | if (module == NULL) { |
93 | - // 存在しない,dllじゃない? | |
94 | - return NULL; | |
78 | + // 新たにロードする | |
79 | + int r; | |
80 | + wchar_t dllPath[MAX_PATH]; | |
81 | + dllPath[0] = 0; | |
82 | + switch (LoadFlag) { | |
83 | + case DLL_LOAD_LIBRARY_SxS: | |
84 | + if (IsWindowsXPOrLater()) { | |
85 | + // Side by Side ローディングを利用するためフルパスにしない | |
86 | + ; | |
87 | + } else { | |
88 | + // dllインジェクション対策でフルパスでロード | |
89 | + r = GetSystemDirectoryW(dllPath, _countof(dllPath)); | |
90 | + assert(r != 0); | |
91 | + if (r == 0) return NULL; | |
92 | + wcscat_s(dllPath, _countof(dllPath), L"\\"); | |
93 | + } | |
94 | + break; | |
95 | + case DLL_LOAD_LIBRARY_SYSTEM: | |
96 | + r = GetSystemDirectoryW(dllPath, _countof(dllPath)); | |
97 | + assert(r != 0); | |
98 | + if (r == 0) return NULL; | |
99 | + wcscat_s(dllPath, _countof(dllPath), L"\\"); | |
100 | + break; | |
101 | + case DLL_LOAD_LIBRARY_CURRENT: | |
102 | + r = GetModuleFileNameW(NULL, dllPath, _countof(dllPath)); | |
103 | + assert(r != 0); | |
104 | + if (r == 0) return NULL; | |
105 | + *(wcsrchr(dllPath, L'\\') + 1) = 0; | |
106 | + break; | |
107 | + default: | |
108 | + return NULL; | |
109 | + } | |
110 | + wcscat_s(dllPath, _countof(dllPath), fname); | |
111 | + module = LoadLibraryW(dllPath); | |
112 | + if (module == NULL) { | |
113 | + // 存在しない,dllじゃない? | |
114 | + return NULL; | |
115 | + } | |
116 | + NeedFreeLibrary = TRUE; | |
95 | 117 | } |
96 | 118 | |
97 | 119 | // リストに追加 |
98 | - HandleListCount++; | |
99 | - HandleList = (HandleList_t *)realloc(HandleList, sizeof(HandleList_t)*HandleListCount); | |
100 | - p = &HandleList[i]; | |
120 | + HandleList = (HandleList_t *)realloc(HandleList, sizeof(HandleList_t) * (HandleListCount + 1)); | |
121 | + p = &HandleList[HandleListCount]; | |
101 | 122 | p->fname = _wcsdup(fname); |
102 | 123 | p->handle = module; |
103 | - p->LoadFlag = LoadFlag; | |
124 | + p->NeedFreeLibrary = NeedFreeLibrary; | |
104 | 125 | p->refCount = 1; |
126 | + HandleListCount++; | |
105 | 127 | return module; |
106 | 128 | } |
107 | 129 | |
108 | 130 | static void DLLFree(HandleList_t *p) |
109 | 131 | { |
110 | - if (p->LoadFlag != DLL_GET_MODULE_HANDLE) { | |
132 | + if (p->NeedFreeLibrary) { | |
111 | 133 | FreeLibrary(p->handle); |
112 | 134 | } |
113 | 135 | free((void *)p->fname); |
@@ -281,10 +303,6 @@ | ||
281 | 303 | BOOL (WINAPI *pSetDllDirectoryA)(LPCSTR); |
282 | 304 | const wchar_t *kernel32 = L"kernel32.dll"; |
283 | 305 | |
284 | -#if !defined(LOAD_LIBRARY_SEARCH_SYSTEM32) | |
285 | -#define LOAD_LIBRARY_SEARCH_SYSTEM32 0x00000800 | |
286 | -#endif | |
287 | - | |
288 | 306 | // SetDefaultDllDirectories() が使える場合は、 |
289 | 307 | // 検索パスを %WINDOWS%\system32 のみに設定する |
290 | 308 | DLLGetApiAddress(kernel32, DLL_GET_MODULE_HANDLE, |
@@ -317,11 +335,10 @@ | ||
317 | 335 | |
318 | 336 | void DLLExit() |
319 | 337 | { |
320 | - int i; | |
321 | 338 | if (HandleListCount == 0) { |
322 | 339 | return; // 未使用 |
323 | 340 | } |
324 | - for (i = 0; i < HandleListCount; i++) { | |
341 | + for (int i = 0; i < HandleListCount; i++) { | |
325 | 342 | HandleList_t *p = &HandleList[i]; |
326 | 343 | DLLFree(p); |
327 | 344 | } |
@@ -33,7 +33,8 @@ | ||
33 | 33 | typedef enum { |
34 | 34 | DLL_GET_MODULE_HANDLE, // GetModuleHandleW() APIを使用する |
35 | 35 | DLL_LOAD_LIBRARY_SYSTEM, // system ディレクトリから LoadLiberaryW() APIでロード |
36 | - DLL_LOAD_LIBRARY_CURRENT, // カレントディレクトリから LoadLiberaryW() APIでロード | |
36 | + DLL_LOAD_LIBRARY_CURRENT, // exe,dllと同一ディレクトリから LoadLiberaryW() APIでロード | |
37 | + DLL_LOAD_LIBRARY_SxS, // Side by Side | |
37 | 38 | } DLLLoadFlag; |
38 | 39 | |
39 | 40 | typedef enum { |