WinAPI - 从 DLL 加载资源
Posted
技术标签:
【中文标题】WinAPI - 从 DLL 加载资源【英文标题】:WinAPI - Loading Ressources from a DLL 【发布时间】:2018-04-24 05:52:11 【问题描述】:我正在使用 VisualStudio2017 开发适用于 Windows 7 的应用程序。此应用程序希望有从 DLL 加载的特殊游标。所以首先我创建了一个 DLL 并添加了以下 .rc 文件:
BM_CURSOR_GRAB CURSOR "./grab.cur"
BM_CURSOR_GRABBING CURSOR "./grabbing.cur"
BM_CURSOR_GRAB 和 BM_CURSOR_GRABBING 在头文件中定义为:
#define BM_CURSOR_GRAB 100
#define BM_CURSOR_GRABBING 101
我编译了 DLL - 可以使用并使用 ResourceEditor.exe
检查它我的资源包括在内:
现在“非工作”部分开始了。我的应用程序想要加载光标,但 FindResource
没有找到它。这是我的代码:
HMODULE dll = LoadLibrary("BenjaMiniRessources.dll");
HRSRC hRes = FindResource(dll, MAKEINTRESOURCE(100), RT_CURSOR);
DWORD dwSize = SizeofResource(dll,hRes);
HGLOBAL hMem = LoadResource(dll, hRes);
LPBYTE pBytes = (LPBYTE)LockResource(hMem);
Cursor = CreateIconFromResource(pBytes, dwSize, false, 0x00030000);
我做错了什么?
【问题讨论】:
“我做错了什么?” - 不检查失败,不调用GetLastError()
。
您是否尝试过枚举资源。 RT_CURSOR 资源不直接包含在资源部分中,iirc,它们通常作为子资源包含在 RT_GROUP_CURSOR 中。
【参考方案1】:
只需将LoadCursor 与相应的hInstance 一起使用。这适用于 MFC 和我的所有 Windows 应用程序。
【讨论】:
好的!那行得通……但是怎么知道我可以将模块用作实例?!啊……WinAPI……谢谢! @DragonEgg 根据Win32 Data Types 文档:“HMODULE 和 HINSTANCE 在当前版本的 Windows 中是相同的,但在 16 位 Windows 中表示不同的东西。”另请参阅What is the difference between HINSTANCE and HMODULE? 在 Raymond Chen 的博客中。【参考方案2】:当你包括
BM_CURSOR_GRAB CURSOR "./grab.cur"
到 rc 文件的行,在生成的 PE 中将是 (BM_CURSOR_GRAB, RT_GROUP_CURSOR)
资源。所以类型将是RT_GROUP_CURSOR
,但不是RT_CURSOR
。
那么您需要调用LookupIconIdFromDirectoryEx
函数来获取最适合指定大小的游标名称(id)。
在此之后,您需要再次加载资源 - 已经是 RT_CURSOR
,其 id 从 LookupIconIdFromDirectoryEx
返回。
最后在电话CreateIconFromResourceEx
中使用它。
但是,更简单地使用 IMAGE_CURSOR
资源类型调用 LoadImage
。
(HCURSOR)LoadImageW(hmod, MAKEINTRESOURCE(BM_CURSOR_GRAB), IMAGE_CURSOR,
0, 0, 0);
例如,用于使用实际资源大小。还是您想使用默认系统光标大小:
(HCURSOR)LoadImageW(hmod, MAKEINTRESOURCE(BM_CURSOR_GRAB), IMAGE_CURSOR,
GetSystemMetrics(SM_CXCURSOR), GetSystemMetrics(SM_CYCURSOR), 0);
或
(HCURSOR)LoadImageW(hmod, MAKEINTRESOURCE(BM_CURSOR_GRAB), IMAGE_CURSOR,
0, 0, LR_DEFAULTSIZE);
或者干脆
LoadCursorW(hmod, MAKEINTRESOURCE(BM_CURSOR_GRAB));
最后一次呼叫内部呼叫LoadImageW
带有LR_DEFAULTSIZE | LR_SHARED
标志
但是直接访问资源的代码(LoadImageW
内部执行)
ULONG GetResourcePointer(void** ppv, ULONG* pcb, HMODULE hModule, PCWSTR lpName, PCWSTR lpType)
if (HRSRC hResource = FindResource(hModule, lpName, lpType))
if (HGLOBAL hResData = LoadResource(hModule, hResource))
if (PVOID pv = LockResource(hResData))
if (ULONG cb = SizeofResource(hModule, hResource))
*ppv = pv, *pcb = cb;
return NOERROR;
return GetLastError();
ULONG err = NOERROR;
HCURSOR hcur;
if (HMODULE hmod = (HMODULE)LoadLibraryW(L"*"))
ULONG cb, err;
PVOID pv;
if (!(err = GetResourcePointer(&pv, &cb, hmod, MAKEINTRESOURCE(BM_CURSOR_GRAB), RT_GROUP_CURSOR)))
if (int nID = LookupIconIdFromDirectoryEx((PBYTE)pv, FALSE, 0, 0, LR_DEFAULTCOLOR))
if (!(err = GetResourcePointer(&pv, &cb, hmod, MAKEINTRESOURCE(nID), RT_CURSOR)))
if (!(hcur = (HCURSOR)CreateIconFromResourceEx((PBYTE)pv, cb,
FALSE, 0x00030000, 0, 0, LR_DEFAULTCOLOR|LR_DEFAULTSIZE)))
err = GetLastError();
else
err = GetLastError();
【讨论】:
这也有效...但它相当...复杂 D:而且...我不知道如何解决这个问题...您的答案比我的问题更接近第一个 - 但我将第一个标记为已解决,因为它更易于使用。 @DragonEgg - 但我一开始就说LoadImageW
是最适合您的解决方案。 LoadCursorW
是 LoadImageW
的特例,如果您同意使用光标的默认大小。我提供的代码 - 仅用于演示【参考方案3】:
各种错误:
-
如果
LoadLibrary("BenjaMiniRessources.dll")
中的返回值为NULL,则系统找不到指定名称BenjaMiniRessources.dll的库;
如果FindResource(dll, MAKEINTRESOURCE(100), RT_CURSOR)
中的返回值为NULL,则系统在BenjaMiniRessources.dll 中找不到RT_CURSOR 类型的资源。 (可能此资源的类型是 RT_GROUP_CURSOR 或 RT_ANICURSOR);
如果返回值为NULL,则错误在字符串SizeofResource(dll,hRes),
中;
问题出在LoadResource(dll, hRes)
,如果这个函数返回NULL;
LockResource(hMem)
中的故障,如果该函数返回NULL;
错误在字符串CreateIconFromResource(pBytes, dwSize, false, 0x00030000)
中。
你可以通过调试器下的代码,看看程序的哪一行最先返回错误。
【讨论】:
如果 LoadLibrary 中的返回值小于 32; - 看起来你混淆了LoadLibrary
和 ShellExecute
。失败时的LoadLibrary
恰好返回 0,并且返回值必须仅与 0 进行比较(而不是 32)。可能不是this resource is RT_GROUP_CURSOR
,而是准确的
对不起,我把 LoadLibrary() 和 LoadModule() 弄混了。以上是关于WinAPI - 从 DLL 加载资源的主要内容,如果未能解决你的问题,请参考以下文章
如何使用 WinApi/user32.dll 或类似的东西远程执行 ListBox 的 ListBox1_DoubleClick 事件?