天天看點

exe中獲得資源字元串

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

}