以下在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;
}