以下在win32中的实现:
bool StringResourceFind(LPTSTR strResExePath, int ID, LPTSTR * pRresult) // 参数1 ,exe路径,参数2,想要获得的资源id, 参数3 返回的字符串
{
int iGroup;
HRSRC hObject;
HGLOBAL hResourceData;
HGLOBAL lpResourceData;
DWORD cbResource;
HMODULE hModule;
//BYTE *lpData;
BYTE *lpReadData;
int lenOfData;
//int cbText;
if(ID<1) //不能修改第0个字符串
return FALSE;
iGroup = ID/16 + 1; //计算字符串所在的串组
hModule = ::LoadLibrary(strResExePath);
//找到这个串组
LANGID LangID = GetUserDefaultUILanguage();
hObject = ::FindResourceEx(hModule,RT_STRING,MAKEINTRESOURCE(iGroup),LangID);
hResourceData = ::LoadResource(hModule, hObject); //加载串组
lpResourceData = ::LockResource(hResourceData); //返回串组数据的地址
cbResource = ::SizeofResource(hModule, hObject); //获取串组数据长度(字节)
lpReadData = new BYTE[cbResource];
lenOfData = cbResource;
::CopyMemory(lpReadData, lpResourceData, cbResource);//复制串组原来的内容
long countX = 0;
int CHECKLNG = 0;
//遍历本串组第一个串到本串前一个串
for(int x=0; x<(ID-(iGroup-1)*16); x++)
{
::CopyMemory(&CHECKLNG, lpReadData+countX, 2); //读出每个串的长度
countX = countX + 2 + CHECKLNG*2; //指向下一个字符串
}
//至此,countX代表了本串之前的所有串所占据的空间大小(字节)
//读出当前字串的的长度
::CopyMemory(&CHECKLNG, lpReadData+countX, 2);
int curStrLen = CHECKLNG*2;
BYTE *pString = new BYTE[curStrLen+1];
memset(pString,0,curStrLen+1);
//复制当前字串
CopyMemory(pString,lpReadData+countX+2,curStrLen);
*pRresult = new TCHAR[curStrLen/2+1];
memset(pRresult,0,sizeof(TCHAR) *(curStrLen/2+1));
memcpy((BYTE *)pRresult,(BYTE*)pString,curStrLen);
FreeResource(hResourceData);
::FreeLibrary(hModule);
// MessageBox(NULL,pRresult,L"test",MB_OK);
delete []pString;
//delete []pRresult;
return true;
}
原文地址:http://www.4ucode.com/Study/Topic/1655713
原理:
字符串资源的存放格式与处理单位
不想其他资源,字符串是不能单独处理的,像UpdateResource()等函数要求的最小处理单位是“串组”,这是由字符串资源的存放方式决定的。每16个字符串为一个串组,字符串的排序以字符串的资源ID号为依据,0-15为第一串组,16-31位第二串组,32-47位第三串组,...。串组ID号从1开始,字符串ID号从0开始。由此可以得到如下公式:
串组ID = (取整)(字符串ID/16) + 1
同一串组的字符串是相邻存放的,我们以7号串组为例说明。如下图所示:
2 你好
3 你好abc
1 你
上图列出了几个代表的串,其中最开头的串的ID为96,一个串有两部分组成,前一部分占2个字节,用于描述本串的长度,以UNICODE字符为单位(也就是2个字节),注意字符串资源里的字符都是采用UNICODE16位编码的。后一部分是串的具体内容,注意没有结尾标志。从上图可以看出,ID号为96的串的长度为2个字符,内容为“你好”。下一个串也就是ID为97的串的长度为0,所以没有内容;接着98号串长度为5,内容为“你好abc"(请注意,在UNICODE编码方式下,所有字符都占据2个字节,英文字母也一样)。最后一个字符串,也就是111号,长度为1,内容为“你”。
处理方法:
理解了字符串资源的存放方式与处理单位,对于其处理方法也就不难了。基本思路是,首先根据字符串的ID号,找到所处的串组号,然后找到整个串组的内容,随后定位到需要处理的串,修改其长度标示和内容。修改不会影响到前面的串,但却会影响到后面的串,所以首先要把后面的所有串先备份,然后添加到修改后的串的尾部。
BOOL StringResourceModify(CString strResExePath, int ID, CString strNew, long LangID)
{
long ret;
long x;
HANDLE hResource;
int iGroup;
HRSRC hObject;
HGLOBAL hResourceData;
HGLOBAL lpResourceData;
DWORD cbResource;
HMODULE hModule;
byte *lpData;
byte *lpReadData;
int lenOfData;
int cbText;
if(ID<1) //不能修改第0个字符串
return FALSE;
iGroup = ID/16 + 1; //计算字符串所在的串组
hModule = ::LoadLibrary(strResExePath);
//找到这个串组
hObject = ::FindResourceEx(hModule,RT_STRING,MAKEINTRESOURCE(iGroup),LangID );
hResourceData = ::LoadResource(hModule, hObject); //加载串组
lpResourceData = ::LockResource(hResourceData); //返回串组数据的地址
cbResource = ::SizeofResource(hModule, hObject); //获取串组数据长度(字节)
if(cbResource <= 32 || hObject == 0) //串组不存在,则增加一个串组
{
cbResource = 32 + strNew.GetLength()*2;//串组至少2*16=32字节长度(全空)
lpData = new byte[cbResource];
lenOfData = cbResource;
cbText = strNew.GetLength(); //串的字符数
//写入串长度,此时前面的串都是空串,各占据2个字节
::CopyMemory((lpData + 2*(ID-(iGroup-1)*16)), &cbText, 2);
if(strNew.GetLength())
{
::CopyMemory(lpData+2*(ID-(iGroup-1)*16)+2,
strNew.GetBuffer(), strNew.GetLength()*2); //写入串内容
}
}
else //串组中有串非空,则修改
{
lpReadData = new byte[cbResource];
lenOfData = cbResource;
::CopyMemory(lpReadData, lpResourceData, cbResource);//复制串组原来的内容
long countX = 0;
int CHECKLNG = 0;
//遍历本串组第一个串到本串前一个串
for(x=0; x<(ID-(iGroup-1)*16); x++)
{
::CopyMemory(&CHECKLNG, lpReadData+countX, 2); //读出每个串的长度
countX = countX + 2 + CHECKLNG*2; //指向下一个字符串
}
//至此,countX代表了本串之前的所有串所占据的空间大小(字节)
//读出要修改串修改前的长度
::CopyMemory(&CHECKLNG, lpReadData+countX, 2);
//至此,CHECKLNG代表修改前本串的长度
lpData = new byte[countX+2+strNew.GetLength()*2 + //从开头到本串(修改后)结束的长度
( cbResource-(countX+2 + CHECKLNG*2)) ]; //从本串后一个串开始到结束的总长度
::CopyMemory(lpData, lpReadData, countX); //读入开头到本串前一个串结束
cbText = strNew.GetLength();
::CopyMemory(lpData+countX, &cbText, 2); //写入修改后串长度
if(cbText)
{
//写入修改后串的内容
::CopyMemory(lpData+countX+2, strNew.GetBuffer(), cbText*2);
}
if( (cbResource - (countX+2+CHECKLNG*2)) >0 ) //修改前,本串后面还有串
{
::CopyMemory(lpData+countX+2+cbText*2,
lpReadData+countX+2+CHECKLNG*2, cbResource-(countX+2+CHECKLNG*2));//原来的内容保留
}
}
::FreeLibrary(hModule);
hResource = BeginUpdateResource(strResExePath, FALSE);
ret = UpdateResource(hResource, RT_STRING, MAKEINTRESOURCE(iGroup),
LangID, lpData, lenOfData);
ret = ::EndUpdateResource(hResource, FALSE);
return ret;
}