// VersionInfo.cpp: implementation of the CVersionInfo class.
//
//////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "StringTable.h"
#include "StringFileInfo.h"
#include "VersionInfoHelperStructures.h"
#include "VersionInfoBuffer.h"
#include "VersionInfo.h"
#include <malloc.h>
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif
//////////////////////////////////////////////////////////////////////
// CVersionInfo main class wrapping Version info for modules
CVersionInfo::CVersionInfo():m_lpszResourceId(NULL), m_wLangId(0xFFFF), m_bRegularInfoOrder(TRUE)
{
ZeroMemory(&m_vsFixedFileInfo, sizeof VS_VERSION_INFO);
}
CVersionInfo::CVersionInfo(const CString& strModulePath, LPCTSTR lpszResourceId, WORD wLangId):
m_strModulePath(strModulePath), m_lpszResourceId((LPTSTR)lpszResourceId), m_wLangId(wLangId), m_bRegularInfoOrder(TRUE)
{
// LPCTSTR lpszResourceId may contain integer value pointer to string, in case it's a string make a local copy of it
if (IS_INTRESOURCE(lpszResourceId))
{
m_strStringResourceId = lpszResourceId;
}
ZeroMemory(&m_vsFixedFileInfo, sizeof VS_VERSION_INFO);
FromFile(strModulePath, lpszResourceId, wLangId);
}
CVersionInfo::~CVersionInfo()
{
}
BOOL CVersionInfo::Save()
{
return ToFile();
}
BOOL CVersionInfo::ToFile(const CString &strModulePath, LPCTSTR lpszResourceId, WORD wLangId)
{
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());
}
BOOL CVersionInfo::UpdateModuleResource(const CString &strFilePath, LPCTSTR lpszResourceId, WORD wLangId, LPVOID lpData, DWORD dwDataLength)
{
HANDLE hUpdate = ::BeginUpdateResource(strFilePath, FALSE);
if (hUpdate == NULL)
return FALSE;
BOOL bUpdateResult = FALSE;
bUpdateResult = UpdateResource(hUpdate, RT_VERSION, lpszResourceId, wLangId, lpData, dwDataLength);
return EndUpdateResource(hUpdate, FALSE) && bUpdateResult;
}
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);
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);
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;
}
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
最新资源