如何在 Visual C++ 2010 中打开资源字符串?

Posted

技术标签:

【中文标题】如何在 Visual C++ 2010 中打开资源字符串?【英文标题】:How do you open a resource string in Visual C++ 2010? 【发布时间】:2011-07-16 21:12:15 【问题描述】:

我在 Visual C++ 中创建了一个基本的字符串表资源。我正在尝试访问该资源。但是,我的程序似乎找不到资源。这里:

int main(int argc, char* argv[])

    HRSRC hRsrc;
    hRsrc = FindResource(NULL, MAKEINTRESOURCE(IDS_STRING102), RT_STRING);
    if (hRsrc == NULL) 
        printf("Not found\n");
     else 
        printf("Found\n");
    

这个程序找不到资源并且总是返回 null。

我创建了一个简单的位图资源,这个新程序可以很好地识别它。这里:

int main(int argc, char* argv[])

    HRSRC hRsrc;
    hRsrc = FindResource(NULL, MAKEINTRESOURCE(IDB_BITMAP1), RT_BITMAP);
    if (hRsrc == NULL) 
        printf("Not found\n");
     else 
        printf("Found\n");
    

这会找到位图。

stringtable 资源的处理方式是否有所不同?

【问题讨论】:

Updating a string table with UpdateResource 解释了字符串表是如何实现的。 Win32 LoadString wrapper 提供了一个不需要您了解这些内部结构的解决方案。 【参考方案1】:

假设您不想使用 LoadString() 这应该会有所帮助...

在使用 FindResource() 和 FindResourceEx() 时,字符串和字符串表的处理方式确实不同。来自this KB文章:

字符串资源存储为字符串块。每个块可以有 最多十六个字符串,代表最小粒度 可以加载/更新的字符串资源。每个块都被识别 通过标识符 (ID),从一 (1) 开始。我们使用此 ID 时 调用 FindResource、LoadResource 和 UpdateResource 函数。

具有 ID 的字符串 nStringID 位于具有 ID 的块中, nBlockID,由以下公式给出:

nBlockID = (nStringID / 16) + 1; // 注意整数除法。

nStringID 的低 4 位指示块中的哪个条目包含实际字符串。一旦你计算出要传递给 FindResource() 的块 ID 和存在字符串的块中的索引,你必须扫描它的内容以找到你正在寻找的字符串。

以下代码应该可以帮助您入门。

const WCHAR *stringPtr;
WCHAR stringLen;

//  Get the id of the string table block containing the target string
const DWORD blockID = (nID >> 4) + 1;

//  Get the offset of teh target string in the block
const DWORD itemID = nID % 0x10;

//  Find the resource
HRSRC hRes = FindResourceEx(
    hInst,
    RT_STRING,
    MAKEINTRESOURCE(blockID),
    wLanguage);
if (hRes)

    HGLOBAL hBlock = LoadResource(hInst, hRes);
    const WCHAR *tableDataBlock = reinterpret_cast<LPCWSTR>(LockResource(hBlock));
    const DWORD tableBlockSize = SizeofResource(hInst, hRes);
    DWORD searchOffset = 0;
    DWORD stringIndex = 0;

    //  Search through the section for the appropriate entry.
    //  The first two bytes of each entry is the length of the string
    //  followed by the Unicode string itself. All strings entries 
    //  are stored one after another with no padding.
    while(searchOffset < tableBlockSize)
    
        if (stringIndex == itemID)
        
            //  If the string has size. use it!
            if (tableDataBlock[searchOffset] != 0x0000)
            
                stringPtr = &tableDataBlock[searchOffset + 1];
                stringLen = tableDataBlock[searchOffset];
            
            //  Nothing there -
            else
            
                stringPtr = NULL;
                stringLen = 0;
            

            //  Done
            break;
        

        //  Go to the next string in the table
        searchOffset += tableDataBlock[searchOffset] + 1;

        //  Bump the index
        stringIndex++;
    

【讨论】:

知识库条目脱机。这是最新的archive.org snapshot。【参考方案2】:

您可以直接使用LoadString。这是 MSDN FindResource 文档中的一些文本...

应用程序可以使用 FindResource 来查找任何类型的资源,但仅当应用程序必须通过随后调用 LoadResource 然后调用 LockResource 来访问二进制资源数据时才应使用此函数。

立即使用资源...

...使用加载字符串!

【讨论】:

如果你必须使用FindResource作为字符串,那么你需要传入ID MAKEINTRESOURCE((IDS_STRING102&gt;&gt;4)+1)LoadString 更易于使用,然后... FindResource 不是为直观的字符串加载而设计的。 :(【参考方案3】:

经过 2 天的研究,我发现了这个(它有效!):

#include <atlstr.h>

......

ATL::CString str;
WORD LangID = MAKELANGID(LANG_ENGLISH,SUBLANG_DEFAULT); 
str.LoadString(NULL,IDS_STRING101, LangID);

【讨论】:

以上是关于如何在 Visual C++ 2010 中打开资源字符串?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Visual C++ 2010 中使用 C++ 库 [重复]

我用 Microsoft Visual Studio 2010 新建一个 C++ 的对话框窗口程序的时候 该如何设置它的窗口类名?谢谢!

如何在 Visual C++ 中保持控制台窗口打开?

visual studio 2010 一个解决方案里有多个c++源文件 怎么只执行其中一个?

如何在Visual Studio 2010中使用C++“准”标准库 Boost 1.44.0

Visual Studio 2010中的Visual C++如何编译、连接和运行?