【问题标题】:WinAPI - Loading Ressources from a DLLWinAPI - 从 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 中。

标签: c++ winapi dll


【解决方案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 是最适合您的解决方案。 LoadCursorWLoadImageW 的特例,如果您同意使用光标的默认大小。我提供的代码 - 仅用于演示
【解决方案3】:

各种错误:

  1. 如果LoadLibrary("BenjaMiniRessources.dll")中的返回值为NULL,则系统找不到指定名称BenjaMiniRessources.dll的库;
  2. 如果FindResource(dll, MAKEINTRESOURCE(100), RT_CURSOR) 中的返回值为NULL,则系统在BenjaMiniRessources.dll 中找不到RT_CURSOR 类型的资源。 (可能此资源的类型是 RT_GROUP_CURSOR 或 RT_ANICURSOR);
  3. 如果返回值为NULL,则错误在字符串SizeofResource(dll,hRes),中;

  4. 问题出在LoadResource(dll, hRes),如果这个函数返回NULL;

  5. LockResource(hMem)中的故障,如果该函数返回NULL;

  6. 错误在字符串CreateIconFromResource(pBytes, dwSize, false, 0x00030000)中。

你可以通过调试器下的代码,看看程序的哪一行最先返回错误。

【讨论】:

  • 如果 LoadLibrary 中的返回值小于 32; - 看起来你混淆了 LoadLibraryShellExecute。失败时的LoadLibrary 恰好返回 0,并且返回值必须仅与 0 进行比较(而不是 32)。可能不是this resource is RT_GROUP_CURSOR,而是准确的
  • 对不起,我把 LoadLibrary() 和 LoadModule() 弄混了。
猜你喜欢
  • 2015-03-25
  • 1970-01-01
  • 2012-09-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-11-29
  • 2013-08-26
相关资源
最近更新 更多