Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

485 lines
20 KiB

//***************************************************************************
//* Copyright (c) Microsoft Corporation 1996. All rights reserved. *
//***************************************************************************
//* *
//* VERSION.C - Function to overwrite the versin information from *
//* wextract.exe *
//* *
//***************************************************************************
//***************************************************************************
//* INCLUDE FILES *
//***************************************************************************
#include "pch.h"
#pragma hdrstop
#include "cabpack.h"
#include <memory.h>
extern CDF g_CDF;
extern TCHAR g_szOverideCDF[MAX_PATH];
extern TCHAR g_szOverideSec[SMALL_BUF_LEN];
// Function prototypes
BOOL UpdateVersionInfo(LPBYTE lpOldVersionInfo, LPBYTE *lplpNewVersionInfo, WORD *pwSize);
BOOL FindVerValue( WCHAR *lpKey, WCHAR *lpszData, WORD *pwLen);
BOOL CALLBACK MyEnumLangsFunc(HANDLE hModule, LPSTR lpType, LPSTR lpName, WORD languages, LONG lParam);
// External function and variables
DWORD MyGetPrivateProfileString( LPCTSTR lpSec, LPCTSTR lpKey, LPCTSTR lpDefault,
LPTSTR lpBuf, UINT uSize, LPCTSTR lpOverSec );
void MyWritePrivateProfileString( LPCTSTR lpSec, LPCTSTR lpKey, LPTSTR lpBuf, UINT uSize );
//////////////////////////////////////////////////////////////////////////////
//// Version information overwrite functions and data types
#define KEY_FROMFILE "FromFile"
#define COMPANYNAME "CompanyName"
#define INTERNALNAME "InternalName"
#define ORIGINALFILENAME "OriginalFilename"
#define PRODUCTNAME "ProductName"
#define PRODUCTVERSION "ProductVersion"
#define FILEVERSION "FileVersion"
#define FILEDESCRIPTION "FileDescription"
#define LEGALCOPYRIGHT "LegalCopyright"
#define MAX_VALUE 256
// What language is the version information in?
WORD wVerLang = MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL);
// Structure to save the keys and values for the Version info
typedef struct _VERINFO
{
LPSTR lpszName;
CHAR szValue[MAX_VALUE];
} VERINFO;
// Array of keys and values which can be changed.
VERINFO Verinfo_Array[] = {
{ COMPANYNAME, ""},
{ INTERNALNAME, ""},
{ ORIGINALFILENAME, ""},
{ PRODUCTNAME, ""},
{ PRODUCTVERSION, ""},
{ FILEVERSION, ""},
{ FILEDESCRIPTION, ""},
{ LEGALCOPYRIGHT, ""}
};
#define ARRAYSIZE(a) (sizeof(a) / sizeof(a[0]))
UINT VerInfoElem = ARRAYSIZE(Verinfo_Array);
//... Decrement WORD at *pw by given amount w
#define DECWORDBY( pw,w) if (pw) { *(pw) = (*(pw) > (w)) ? *(pw) - (w) : 0;}
//... Increment WORD at *pw by given amount w
#define INCWORDBY( pw,w) if (pw) { *(pw) += (w);}
#define MEMSIZE( x ) ((x) * 2)
// was sizeof( TCHAR))
#define STRINGFILEINFOLEN 15
#define LANGSTRINGLEN 8 //... # WCHARs in string denoting language
//... and code page in a Version resource.
#define VERTYPESTRING 1 //... Version data value is a string
#pragma pack(1)
typedef struct VERBLOCK
{
WORD wLength; // Length of this block
WORD wValueLength; // Length of the valuedata
WORD wType; // Type of data (1=string, 0=binary)
WCHAR szKey[1]; // data
} VERBLOCK ;
typedef VERBLOCK * PVERBLOCK;
typedef struct VERHEAD
{
WORD wTotLen;
WORD wValLen;
WORD wType;
TCHAR szKey[( sizeof( TEXT("VS_VERSION_INFO" )) +3 )&~03];
VS_FIXEDFILEINFO vsf;
} VERHEAD ;
#pragma pack()
// Do the version info update
//
// szFile is the file we want to update the version info from
// hUpdate is the handle to the resource info which will be used to update all resources
//
BOOL DoVersionInfo(HWND hDlg, LPSTR szFile, HANDLE hUpdate)
{
HINSTANCE hModule;
HRSRC hrsrc;
HGLOBAL hgbl;
LPBYTE lp;
LPBYTE lpCopy;
WORD wSize;
if (GetVersionInfoFromFile())
{
// Get the current version info from the file
hModule = LoadLibraryEx(szFile, NULL,LOAD_LIBRARY_AS_DATAFILE| DONT_RESOLVE_DLL_REFERENCES);
if (hModule == NULL)
return FALSE; // Should not happen, we loaded the module before
// Determine the language of the version information
EnumResourceLanguages(hModule, RT_VERSION, MAKEINTRESOURCE(VS_VERSION_INFO), (ENUMRESLANGPROC)MyEnumLangsFunc, 0L);
hrsrc = FindResourceEx (hModule, RT_VERSION, MAKEINTRESOURCE(VS_VERSION_INFO), wVerLang);
if (hrsrc == NULL)
{
FreeLibrary(hModule);
return FALSE; // Should we continue???
}
if ((hgbl = LoadResource(hModule, hrsrc)) == NULL)
{
FreeResource(hrsrc);
FreeLibrary(hModule);
return FALSE; // Should we continue???
}
if ((lp = LockResource(hgbl)) == NULL)
{
FreeResource(hrsrc);
FreeLibrary(hModule);
return FALSE; // Should we continue???
}
// UPdate the version information, If success, lpCopy has the pointer to the update info
UpdateVersionInfo(lp, &lpCopy, &wSize);
UnlockResource(hgbl);
FreeResource(hrsrc);
FreeLibrary(hModule);
if (lpCopy != NULL)
{
// Now update the resource for the file
if ( LocalUpdateResource( hUpdate, RT_VERSION,
MAKEINTRESOURCE(VS_VERSION_INFO), wVerLang, //MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL),
lpCopy, wSize) == FALSE )
{
free (lpCopy);
ErrorMsg( hDlg, IDS_ERR_UPDATE_RESOURCE );
return FALSE;
}
free (lpCopy);
}
return TRUE;
}
return TRUE;
}
// Get the version information we use to overwrite from the CDF file
BOOL GetVersionInfoFromFile()
{
char szFilename[MAX_STRING];
HLOCAL hInfoBuffer;
LPSTR lpValueBuffer;
char szQuery[128];
DWORD dwBytes;
DWORD dwLangCharset;
DWORD dwInfoBuffer;
DWORD dwDummy;
UINT i;
if ( MyGetPrivateProfileString(SEC_OPTIONS, KEY_VERSIONINFO, "", g_CDF.achVerInfo, sizeof(g_CDF.achVerInfo), g_szOverideSec ) > 0)
{
// We better zero the version info in our array.
for (i = 0; i < VerInfoElem; i++)
{
Verinfo_Array[i].szValue[0] = '\0';
}
if ( MyGetPrivateProfileString( g_CDF.achVerInfo, KEY_FROMFILE, "", szFilename, sizeof(szFilename), g_CDF.achVerInfo) > 0)
{
// Fill the version info from the file version info
// determine if the file contains version information
// and get the size of the information if so
dwInfoBuffer = GetFileVersionInfoSize(szFilename, &dwDummy);
if (dwInfoBuffer != 0)
{
// allocate memory to hold the version information
hInfoBuffer = LocalAlloc(LMEM_FIXED, dwInfoBuffer);
if (hInfoBuffer != NULL)
{
// read version information into our memory
if (GetFileVersionInfo(szFilename, 0, dwInfoBuffer, (LPVOID)hInfoBuffer) != 0)
{
// get language and character set information
if (VerQueryValue((LPVOID)hInfoBuffer, "\\VarFileInfo\\Translation",
&lpValueBuffer, &dwBytes))
dwLangCharset = *(LPDWORD)lpValueBuffer;
else
dwLangCharset = 0x04E40409; // If we don't have any default to US. Should never happen
// Now get the version info from the file
for (i = 0; i < VerInfoElem; i++)
{
// get version information string
wsprintf(szQuery, "\\StringFileInfo\\%4.4X%4.4X\\%s",
LOWORD(dwLangCharset), HIWORD(dwLangCharset), Verinfo_Array[i].lpszName);
if (VerQueryValue((LPVOID)hInfoBuffer, szQuery, (LPVOID)&lpValueBuffer, &dwBytes) != 0)
lstrcpyn(Verinfo_Array[i].szValue,lpValueBuffer, MAX_VALUE-1); // Found one, take it
}
}
LocalFree(hInfoBuffer);
}
}
} // Got version info from file
// Now see if we have to overwrite some info from the batch file.
for (i = 0; i < VerInfoElem; i++)
{
if (MyGetPrivateProfileString(g_CDF.achVerInfo, Verinfo_Array[i].lpszName, "", szFilename, MAX_VALUE, g_CDF.achVerInfo) > 0)
{
lstrcpyn(Verinfo_Array[i].szValue, szFilename, MAX_VALUE-1);
}
}
return TRUE;
}
return FALSE;
}
// Update the lpOldVersionInfo with the overwritable data.
// lpOldVersionInfo: pointer to the old version info data block
// lplpNewVersionInfo: Will get the pointer to the updated version info data,
// the caller has to free the buffer if the pointer is not NULL,
// pwSize: pointer to a word which will return the size of the new version info block
//
// Note: This code assumes that there is only one language data block in the version info data.
//
BOOL UpdateVersionInfo(LPBYTE lpOldVersionInfo, LPBYTE *lplpNewVersionInfo, WORD *pwSize)
{
WCHAR szData[MAX_STRING]; // Will hold the data to put into the versin info
WORD wDataLen = 0; //... Length of old resource data
WORD wVerHeadSize; //... Sizeof of the VERHEAD struct
int nNewVerBlockSize = 0; // Size of the new version info data block
PVERBLOCK pNewVerStamp = NULL; // Pointer to the new version info data block
PVERBLOCK pNewBlk = NULL; // Pointer to the currently worked on data in new verblock
VERHEAD *pVerHdr = (VERHEAD*)lpOldVersionInfo; // Pointer to old verinfo
VERBLOCK *pVerBlk; // Pointer to the currently worked on data in old verblock
LPBYTE lp; // Pointer to the data area to copy (overwrite)
WORD wStringTableLen = 0; // Bytes (left) in the language data block
PVERBLOCK pNewStringTblBlk; // Pointer to the language part for the version info
WORD wStringInfoLen = 0; //... # of bytes in StringFileInfo
PVERBLOCK pNewStringInfoBlk; //... Start of this StringFileInfo blk
WORD wLen = 0;
*lplpNewVersionInfo = NULL;
*pwSize = 0;
wVerHeadSize = (WORD)(3 * sizeof(WORD) + MEMSIZE(lstrlen("VS_FIXEDFILEINFO") + 1) + sizeof(VS_FIXEDFILEINFO));
wVerHeadSize = ROUNDUP(wVerHeadSize, 4);
// Total length of the version information
wDataLen = pVerHdr->wTotLen;
if ( wDataLen == 0 || wDataLen == (WORD)-1 )
{
return(FALSE); //... No resource data
}
//... Allocate buffer to hold New Version
//... Stamping Block (make the buffer large to
//... account for expansion of strings
pVerBlk = (PVERBLOCK)((PBYTE)pVerHdr + wVerHeadSize); // point into version block of the old info
// we potentialy replace 8 (VerInfoElem=8) string in the version info
// I alloc 9 * 2 * 256 + size of the current version info. This should give us plenty of space
// I need to multiply by 2 because we work with unicode strings. One character = 2 bytes.
nNewVerBlockSize = wDataLen + (2 * (VerInfoElem+1) * MAX_VALUE);
pNewVerStamp = (PVERBLOCK)malloc( nNewVerBlockSize );
//... Fill new memory block with zeros
memset((void *)pNewVerStamp, 0, nNewVerBlockSize);
//... Copy version info header into new version buffer
memcpy((void *)pNewVerStamp, (void *)pVerHdr, wVerHeadSize);
pNewVerStamp->wLength = wVerHeadSize;
//... Move after version info header
pNewBlk = (PVERBLOCK)((PBYTE)pNewVerStamp + wVerHeadSize);
wDataLen -= wVerHeadSize;
if (wDataLen > 0)
{ //... Start of a StringFileInfo block?
pNewStringInfoBlk = pNewBlk;
//... Get # of bytes in this StringFileInfo
//... (Length of value is always 0 here)
wStringInfoLen = pVerBlk->wLength;
//... Move to start of first StringTable blk.
// -2 is for the starting WCHAR part of the VERBLOCK
wLen = ROUNDUP(sizeof(VERBLOCK) - 2 + MEMSIZE( STRINGFILEINFOLEN),4);
// Copy StringFileVersion header
CopyMemory( pNewBlk, pVerBlk, wLen);
pNewStringInfoBlk->wLength = 0; // Set length, will be updated dynamicly
// Go to the language ID block
pVerBlk = (PVERBLOCK)((PBYTE)pVerBlk + wLen);
pNewBlk = (PVERBLOCK)((PBYTE)pNewBlk + wLen);
// Decrement byte counter
DECWORDBY(&wDataLen, wLen);
DECWORDBY(&wStringInfoLen, wLen);
// Update the size values
INCWORDBY(&pNewVerStamp->wLength, wLen);
INCWORDBY(&pNewStringInfoBlk->wLength, wLen);
// We should be now at the language codepage ID string
if (wStringInfoLen > 0)
{
//... Get # of bytes in this StringTable
wStringTableLen = pVerBlk->wLength;
pNewStringTblBlk = pNewBlk;
//... Move to start of first String.
// -2 is for the starting WCHAR part of the VERBLOCK
wLen = ROUNDUP( sizeof(VERBLOCK) - 2 + MEMSIZE( LANGSTRINGLEN),4);
// Copy language/codepage header
CopyMemory( pNewBlk, pVerBlk, wLen);
pNewStringTblBlk->wLength = 0; // Set length, will be updated dynamicly
// Go to the first data block
pVerBlk = (PVERBLOCK)((PBYTE)pVerBlk + wLen);
pNewBlk = (PVERBLOCK)((PBYTE)pNewBlk + wLen);
DECWORDBY(&wDataLen, wLen);
DECWORDBY(&wStringInfoLen, wLen);
DECWORDBY(&wStringTableLen, wLen);
// Update the size values
INCWORDBY(&pNewVerStamp->wLength, wLen);
INCWORDBY(&pNewStringInfoBlk->wLength, wLen);
INCWORDBY(&pNewStringTblBlk->wLength, wLen);
while ( wStringTableLen > 0 )
{
// Copy the old data
CopyMemory( pNewBlk, pVerBlk, ROUNDUP(pVerBlk->wLength,4));
wLen = pVerBlk->wLength;
//... Is value a string?
if (pVerBlk->wType == VERTYPESTRING)
{
//... See if we need to replace the value for this data
wLen = sizeof(szData);
if (FindVerValue( pVerBlk->szKey, szData, &wLen))
{
// Update the length values
pNewBlk->wValueLength = wLen;
// Find the start of the data
lp = (LPBYTE) ((PBYTE)pNewBlk + ROUNDUP(pVerBlk->wLength,4) - ROUNDUP(MEMSIZE(pVerBlk->wValueLength),4));
// Get the size of the new data
wLen = ROUNDUP(MEMSIZE(pNewBlk->wValueLength),4);
// Overwrite the old data
CopyMemory(lp, szData, wLen);
// calculate the size of this data and set it.
wLen = MEMSIZE(pNewBlk->wValueLength);
pNewBlk->wLength += (wLen - MEMSIZE(pVerBlk->wValueLength));
}
}
// Update the size values
wLen = ROUNDUP(pNewBlk->wLength,4);
INCWORDBY(&pNewVerStamp->wLength, wLen);
INCWORDBY(&pNewStringInfoBlk->wLength, wLen);
INCWORDBY(&pNewStringTblBlk->wLength, wLen);
// Go to the next data block in the old version info
wLen = ROUNDUP(pVerBlk->wLength,4);
pVerBlk = (PVERBLOCK)((PBYTE)pVerBlk + wLen);
DECWORDBY(&wDataLen, wLen);
DECWORDBY(&wStringInfoLen, wLen);
DECWORDBY(&wStringTableLen, wLen);
// Go to where the next data block in the new version info would be.
pNewBlk = (PVERBLOCK)((PBYTE)pNewBlk + ROUNDUP(pNewBlk->wLength,4));
} //... END while wStringTableLen
// Copy the rest of the VERBLOCK, this should be the VarFileInfo part.
if (wDataLen > 0)
{
// Update the most outer length info.
INCWORDBY(&pNewVerStamp->wLength, wDataLen);
// Update length info
CopyMemory(pNewBlk, pVerBlk, wDataLen);
}
// Set the values to return to the caller.
*pwSize = pNewVerStamp->wLength;
*lplpNewVersionInfo = (LPBYTE)pNewVerStamp;
} //... END if wStringInfoLen
}
// If some thing went wrong in finding the first language common part of the version info
// we did not update the version info, therefore we have to free the buffer we allocated
if (*pwSize == 0)
free (pNewVerStamp);
return(TRUE);
}
// Try to find the string in our array of version info we can overwrite
// lpKey: is a pointer to the value string in the old versin info block (UNICODE)
// lpszData: will contain the data string (UNICODE) if we found the value
// pwLen: pointer to a word which contains the size of the lpszData buffer on input
// if we found the value it contains the length the version info uses as ValueLength
// which is the size in single byte + zero termination
//
BOOL FindVerValue( WCHAR *lpKey, WCHAR *lpszData, WORD *pwLen)
{
char szValue[MAX_STRING];
UINT i = 0;
// Make it a SB character string
WideCharToMultiByte(CP_ACP, 0, lpKey, -1, szValue, sizeof(szValue), NULL, NULL);
// Zero out the buffer, I use so that the caller can over write more memory then the
// data in the string would take up. This is because the data is WORD aligned.
memset(lpszData, 0, *pwLen);
while (i < VerInfoElem)
{
if (lstrcmpi(Verinfo_Array[i].lpszName, szValue) == 0)
{
if ((Verinfo_Array[i].szValue[0] != '\0') &&
(*pwLen >= MEMSIZE(lstrlen(Verinfo_Array[i].szValue) + 1) ) )
{
// Convert the ANSI data string into UNICODE
*pwLen = (WORD)MultiByteToWideChar(CP_ACP, 0, Verinfo_Array[i].szValue, -1 ,
lpszData, *pwLen);
}
i = VerInfoElem; // Stop searching
}
i++;
}
// Return if we found the value and the array contained data.
return (*lpszData != '\0');
}
BOOL CALLBACK MyEnumLangsFunc(HANDLE hModule, LPSTR lpType, LPSTR lpName, WORD languages, LONG lParam)
{
// The first language we find is OK.
wVerLang = languages;
return FALSE;
}