如何使用VS11在C程序中嵌入和使用资源文件?

ary*_*ard 2 c embedded-resource visual-studio

这是我第一次尝试使用资源文件.我已经看到很多适用于C#的答案,但不适用于C.任何建议?

0xC*_*22L 5

假设您的意思是Sysinternals和其他人在程序的资源部分(例如Sysinternals的Process Explorer)中携带驱动程序或所需的DLL(甚至程序本身的x64版本)所使用的方法,使用Microsoft Visual C您可以使用这段代码:

BOOL ExtractResTo(HINSTANCE Instance, LPCTSTR BinResName, LPCTSTR NewPath, LPCTSTR ResType)
{
    BOOL bResult = FALSE;
    HRSRC hRsrc;
    if(hRsrc = FindResource(HMODULE(Instance), BinResName, ResType))
    {
        HGLOBAL hGlob
        if(HGLOBAL hGlob = LoadResource(Instance, hRsrc))
        {
            DWORD dwResSize = SizeofResource(Instance, hRsrc);
            HANDLE hFileWrite = CreateFile(NewPath, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_ARCHIVE, 0);
            if(hFileWrite != INVALID_HANDLE_VALUE)
            __try
            {
                DWORD dwSizeWritten = 0;
                bResult = (WriteFile(hFileWrite, LockResource(hGlob), dwResSize, &dwSizeWritten, NULL) && (dwSizeWritten == dwResSize));
            }
            __finally
            {
                CloseHandle(hFileWrite);
            }
        }
    }
    return bResult;
}
Run Code Online (Sandbox Code Playgroud)

这将BinResName资源类型(ResType)的给定资源()从模块(例如DLL)保存Instance到文件NewPath.显然,如果您的C不理解__try,__finally您将不得不相应地调整代码.

取自此处(in SIDT.rar)并针对C进行调整.根据网站,该代码属于自由BSD许可.

现在,如果你想获得指向data(ppRes)及其大小(pwdResSize)的指针:

BOOL GetResourcePointer(HINSTANCE Instance, LPCTSTR ResName, LPCTSTR ResType, LPVOID* ppRes, DWORD* pdwResSize)
{
    // Check the pointers to which we want to write
    if(ppRes && pdwResSize)
    {
        HRSRC hRsrc;
        // Find the resource ResName of type ResType in the DLL/EXE described by Instance
        if(hRsrc = FindResource((HMODULE)Instance, ResName, ResType))
        {
            HGLOBAL hGlob;
            // Make sure it's in memory ...
            if(hGlob = LoadResource(Instance, hRsrc))
            {
                // Now lock it to get a pointer
                *ppRes = LockResource(hGlob);
                // Also retrieve the size of the resource
                *pdwResSize = SizeofResource(Instance, hRsrc);
                // Return TRUE only if both succeeded
                return (*ppRes && *pdwResSize);
            }
        }
    }
    // Failure means don't use the values in *ppRes and *pdwResSize
    return FALSE;
}
Run Code Online (Sandbox Code Playgroud)

像这样打电话:

LPVOID pResource;
DWORD pResourceSize;
if(GetResourcePointer(hInstance, _T("somename"), _T("sometype"), &pResource, &pResourceSize))
{
    // use pResource and pResourceSize
    // e.g. store into a string buffer or whatever you want to do with it ...
}
Run Code Online (Sandbox Code Playgroud)

注意,这也适用于具有整数ID的资源.您可以使用宏来检测这些IS_INTRESOURCE.

资源脚本,例如myresources.rc,本身很简单:

#include <winnt.rh>
"somename" "sometype" "path\to\file\to\embed"
Run Code Online (Sandbox Code Playgroud)

RCDATA 而不是某种类型是一个合理的选择

#include <winnt.rh> // for RCDATA to be known to rc.exe
"somename" RCDATA "path\to\file\to\embed"
Run Code Online (Sandbox Code Playgroud)

...在这种情况下,您可以将上述调用调整为:

GetResourcePointer(hInstance, _T("somename"), RT_RCDATA, &pResource, &pResourceSize)
Run Code Online (Sandbox Code Playgroud)

使用GetResourcePointer上面的完整示例.假设您有一个指针变量,char* buf并且您知道您的资源是实际文本,那么您需要确保它在用作字符串时是零终止的,这就是全部.

资源脚本:

#include <winnt.rh>

"test" RCDATA "Test.txt"
Run Code Online (Sandbox Code Playgroud)

访问它的代码

char* buf = NULL;
LPVOID pResource;
DWORD pResourceSize;
if(GetResourcePointer(hInstance, _T("test"), RT_RCDATA, &pResource, &pResourceSize))
{
    if(buf = calloc(pResourceSize+1, sizeof(char)))
    {
        memcpy(buf, pResource, pResourceSize);
        // Now use buf
        free(buf);
    }
}
Run Code Online (Sandbox Code Playgroud)

当然,除非你想.res通过将文件传递给链接器命令行来简单地链接一个文件.