BOOL CVersionInfo::ToFile(const CString &strModulePath, LPCTSTR lpszResourceId, WORD wLangId, const bool bReplace) { CString strUseModulePath(strModulePath); if (strUseModulePath.IsEmpty()) { strUseModulePath = m_strModulePath; } if (NULL == lpszResourceId) { //Try resource ID that we loaded from; lpszResourceId = m_lpszResourceId; if (NULL == lpszResourceId) { //Use default lpszResourceId = MAKEINTRESOURCE(1); } } if (0xFFFF == wLangId) { //Try using language that we loaded from wLangId = m_wLangId; if (0xFFFF == wLangId) { //Use neutral wLangId = NULL; } } CVersionInfoBuffer viSaveBuf; Write(viSaveBuf); return UpdateModuleResource(strUseModulePath, lpszResourceId, wLangId, viSaveBuf.GetData(), viSaveBuf.GetPosition(), bReplace); }
BOOL CVersionInfo::LoadVersionInfoResource(const CString& strModulePath, CVersionInfoBuffer &viBuf, LPCTSTR lpszResourceId, WORD wLangId) { HRSRC hResInfo; HMODULE hModule = LoadLibraryEx(strModulePath, NULL, DONT_RESOLVE_DLL_REFERENCES | LOAD_LIBRARY_AS_DATAFILE); if (NULL == hModule) return FALSE; if ((NULL == lpszResourceId) && (wLangId == 0xFFFF)) { //Load first RT_VERSION resource that will be found m_lpszResourceId = NULL; EnumResourceNames(hModule, RT_VERSION, (ENUMRESNAMEPROC)EnumResourceNamesFuncFindFirst, (LONG_PTR)this); if (NULL == m_lpszResourceId) { FreeLibrary(hModule); return FALSE; } // Now the m_lpszResourceId must be the name of the resource m_wLangId = 0xFFFF; EnumResourceLanguages(hModule, RT_VERSION, m_lpszResourceId, (ENUMRESLANGPROC)EnumResourceLangFuncFindFirst, (LONG_PTR)this); // Found resource, copy the ID's to local vars lpszResourceId = m_lpszResourceId; wLangId = m_wLangId; } hResInfo = FindResourceEx(hModule, RT_VERSION, lpszResourceId, wLangId); // Write the resource language to the resource information file. DWORD dwSize = SizeofResource(hModule, hResInfo); if (dwSize) { HGLOBAL hgRes = LoadResource(hModule, hResInfo); if (hgRes) { LPVOID lpMemory = LockResource(hgRes); if (lpMemory) { viBuf.Write(lpMemory,dwSize); UnlockResource(hgRes); FreeLibrary(hModule); return TRUE; } } } FreeLibrary(hModule); return FALSE; }
void CStringTable::Write(CVersionInfoBuffer & viBuf) { //Pad to DWORD and save position for wLength DWORD pos = viBuf.PadToDWORD(); //Skip size for now; viBuf.Pad(sizeof WORD); //Write wValueLength viBuf.WriteWord(0); //Write wType viBuf.WriteWord(1); //Write key viBuf.WriteString(m_strKey); POSITION posString = m_lstStrings.GetHeadPosition(); while (posString) { CVersionInfoString * pString = (CVersionInfoString*) m_lstStrings.GetNext(posString); pString->Write(viBuf); } //Set the size of the structure based on current offset from the position viBuf.WriteStructSize(pos); }
void CVersionInfo::Write(CVersionInfoBuffer & viBuf) { //Pad to DWORD and save position for wLength DWORD pos = viBuf.PadToDWORD(); //Skip size for now; viBuf.Pad(sizeof WORD); //Write wValueLength viBuf.WriteWord(sizeof VS_FIXEDFILEINFO); //Write wType viBuf.WriteWord(0); //Write key viBuf.WriteString(L"VS_VERSION_INFO"); //Pad Fixed info viBuf.PadToDWORD(); //Write Fixed file info viBuf.Write(&m_vsFixedFileInfo, sizeof VS_FIXEDFILEINFO); if (m_bRegularInfoOrder) { //Write string file info, it will pad as needed m_stringFileInfo.Write(viBuf); WriteVarInfo(viBuf); } else { WriteVarInfo(viBuf); //Write string file info, it will pad as needed m_stringFileInfo.Write(viBuf); } //Set the size of the Version Info viBuf.WriteStructSize(pos); }
void CVersionInfo::WriteVarInfo(CVersionInfoBuffer & viBuf) { //Check string tables if (m_stringFileInfo.IsEmpty()) return; //Prepare to write VarFileInfo DWORD posVarInfo = viBuf.PadToDWORD(); //Skip size of VarFileInfo for now; viBuf.Pad(sizeof WORD); //Write wValueLength viBuf.WriteWord(0); //Write type viBuf.WriteWord(1); viBuf.WriteString(L"VarFileInfo"); //Save offset of Var structure (Translation) DWORD posTranslation = viBuf.PadToDWORD(); viBuf.Pad(sizeof WORD); //Write size of translation, that is number of string tables * size of DWORD DWORD dwTableCount = m_stringFileInfo.GetStringTableCount(); viBuf.WriteWord(LOWORD(dwTableCount * sizeof DWORD)); //Write type viBuf.WriteWord(0); //Write key (Translation) viBuf.WriteString(L"Translation"); //Pad for value viBuf.PadToDWORD(); //Collect all id's in one DWORD array DWORD *pTranslationBuf = (DWORD*)_alloca(dwTableCount * sizeof DWORD); DWORD *pTranslation = pTranslationBuf; POSITION posTable = m_stringFileInfo.GetFirstStringTablePosition(); while (posTable) { CStringTable * pStringTable = m_stringFileInfo.GetNextStringTable(posTable); TCHAR* pchEnding = NULL; DWORD dwKey = _tcstol(pStringTable->GetKey(),&pchEnding, 16); *pTranslation = (LOWORD(dwKey) << 16) | (HIWORD(dwKey)); pTranslation++; } viBuf.Write(pTranslationBuf, dwTableCount * sizeof DWORD); //Write structure sizes viBuf.WriteStructSize(posTranslation); viBuf.WriteStructSize(posVarInfo); }
BOOL CVersionInfo::FromFile(const CString &strModulePath, LPCTSTR lpszResourceId, WORD wLangId) { CVersionInfoBuffer viLoadBuf; m_wLangId = wLangId; m_lpszResourceId = (LPTSTR)lpszResourceId; //LoadVersionInfoResource will update member variables m_wLangId, m_lpszResourceId, which is awkward, need to change this flow if (!LoadVersionInfoResource(strModulePath, viLoadBuf, lpszResourceId, wLangId)) return FALSE; m_strModulePath = strModulePath; DWORD dwSize = viLoadBuf.GetPosition(); VERSION_INFO_HEADER* pVI = (VERSION_INFO_HEADER*) viLoadBuf.GetData(); ASSERT(!wcscmp(pVI->szKey, L"VS_VERSION_INFO")); VS_FIXEDFILEINFO* pFixedInfo = (VS_FIXEDFILEINFO*)DWORDALIGN(&pVI->szKey[wcslen(pVI->szKey)+1]); memcpy(&m_vsFixedFileInfo, pFixedInfo, sizeof(VS_FIXEDFILEINFO)); // Iterate children StringFileInfo or VarFileInfo BaseFileInfo *pChild = (BaseFileInfo*) DWORDALIGN((DWORD)pFixedInfo + pVI->wValueLength); BOOL bHasVar = FALSE; BOOL bHasStrings = FALSE; BOOL bBlockOrderKnown = FALSE; CStringList lstTranslations; while ((DWORD)pChild < ((DWORD)(pVI) + pVI->wLength)) { if (!wcscmp(pChild->szKey, L"StringFileInfo")) { //It is a StringFileInfo //ASSERT(1 == pChild->wType); //如果类型是0表示二进制内容,类型为1时才包含字符串内容 if (1 != pChild->wType) { //pChild = (BaseFileInfo*)DWORDALIGN((DWORD)pChild + pChild->wLength); //continue; } StringFileInfo* pStringFI = (StringFileInfo*)pChild; ASSERT(!pStringFI->wValueLength); //MSDN says: Specifies an array of zero or one StringFileInfo structures. So there should be only one StringFileInfo at most ASSERT(m_stringFileInfo.IsEmpty()); m_stringFileInfo.FromStringFileInfo(pStringFI); bHasStrings = TRUE; } else { VarFileInfo* pVarInfo = (VarFileInfo*)pChild; //ASSERT(1 == pVarInfo->wType); //如果类型是0表示二进制内容,类型为1时才包含字符串内容 if (1 != pChild->wType) { //pChild = (BaseFileInfo*)DWORDALIGN((DWORD)pChild + pChild->wLength); //continue; } ASSERT(!wcscmp(pVarInfo->szKey, L"VarFileInfo")); ASSERT(!pVarInfo->wValueLength); //Iterate Var elements //There really must be only one Var* pVar = (Var*) DWORDALIGN(&pVarInfo->szKey[wcslen(pVarInfo->szKey)+1]); while ((DWORD)pVar < ((DWORD) pVarInfo + pVarInfo->wLength)) { ASSERT(!bHasVar && "Multiple Vars in VarFileInfo"); ASSERT(!wcscmp(pVar->szKey, L"Translation")); ASSERT(pVar->wValueLength); DWORD *pValue = (DWORD*) DWORDALIGN(&pVar->szKey[wcslen(pVar->szKey)+1]); DWORD *pdwTranslation = pValue; while ((LPBYTE)pdwTranslation < (LPBYTE)pValue + pVar->wValueLength) { CString strStringTableKey; strStringTableKey.Format(_T("%04x%04x"), LOWORD(*pdwTranslation), HIWORD(*pdwTranslation)); lstTranslations.AddTail(strStringTableKey); pdwTranslation++; } bHasVar = TRUE; pVar = (Var*) DWORDALIGN((DWORD)pVar + pVar->wLength); } ASSERT(bHasVar && "No Var in VarFileInfo"); } if (!bBlockOrderKnown) { bBlockOrderKnown = TRUE; m_bRegularInfoOrder = bHasStrings; } pChild = (BaseFileInfo*) DWORDALIGN((DWORD)pChild + pChild->wLength); } #ifdef _DEBUG ASSERT((DWORD)lstTranslations.GetCount() == m_stringFileInfo.GetStringTableCount()); CString strKey = m_stringFileInfo.GetFirstStringTable().GetKey(); POSITION posTranslation = lstTranslations.GetHeadPosition(); while (posTranslation) { CString strTranslation = lstTranslations.GetNext(posTranslation); CString strTranslationUpper (strTranslation); strTranslation.MakeUpper(); ASSERT(m_stringFileInfo.HasStringTable(strTranslation) || m_stringFileInfo.HasStringTable(strTranslationUpper)); } //Verify Write CVersionInfoBuffer viSaveBuf; Write(viSaveBuf); ASSERT(viSaveBuf.GetPosition() == viLoadBuf.GetPosition()); ASSERT(!memcmp(viSaveBuf.GetData(), viLoadBuf.GetData(), viSaveBuf.GetPosition())); CFile fOriginal(_T("f1.res"), CFile::modeCreate | CFile::modeWrite); fOriginal.Write(viLoadBuf.GetData(), viLoadBuf.GetPosition()); fOriginal.Close(); CFile fSaved(_T("f2.res"), CFile::modeCreate | CFile::modeWrite); fSaved.Write(viSaveBuf.GetData(), viSaveBuf.GetPosition()); fSaved.Close(); #endif return TRUE; }