WinAPI - 从DLL加载Ressources

时间:2018-04-24 05:52:12

标签: c++ winapi dll

我正在使用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检查它包括我的资源:

Picture from the Resource Editor

现在“非工作”部分开始了。我的应用程序想要加载光标,但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);

我做错了什么?

3 个答案:

答案 0 :(得分:3)

简单地使用LoadCursor和相应的hInstance。这适用于MFC和我的所有Windows应用程序。

答案 1 :(得分:1)

当你包括 BM_CURSOR_GRAB CURSOR "./grab.cur"行到rc文件,在生成的PE中将是(BM_CURSOR_GRAB, RT_GROUP_CURSOR)资源。所以类型为RT_GROUP_CURSOR但不是RT_CURSOR

然后你需要调用LookupIconIdFromDirectoryEx函数来获取最适合指定大小的光标的名称(id)。

在此之后您需要再次加载资源 - 已RT_CURSOR已从LookupIconIdFromDirectoryEx返回ID。

最后在通话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();
                }
            }
        }

答案 2 :(得分:0)

错误的变种:

  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)中。

  7. 您可以浏览调试器下的代码,看看程序中哪一行首先返回错误。