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

  1. //***************************************************************************
  2. //* Copyright (c) Microsoft Corporation 1996. All rights reserved. *
  3. //***************************************************************************
  4. //* *
  5. //* VERSION.C - Function to overwrite the versin information from *
  6. //* wextract.exe *
  7. //* *
  8. //***************************************************************************
  9. //***************************************************************************
  10. //* INCLUDE FILES *
  11. //***************************************************************************
  12. #include "pch.h"
  13. #pragma hdrstop
  14. #include "cabpack.h"
  15. #include <memory.h>
  16. extern CDF g_CDF;
  17. extern TCHAR g_szOverideCDF[MAX_PATH];
  18. extern TCHAR g_szOverideSec[SMALL_BUF_LEN];
  19. // Function prototypes
  20. BOOL UpdateVersionInfo(LPBYTE lpOldVersionInfo, LPBYTE *lplpNewVersionInfo, WORD *pwSize);
  21. BOOL FindVerValue( WCHAR *lpKey, WCHAR *lpszData, WORD *pwLen);
  22. BOOL CALLBACK MyEnumLangsFunc(HANDLE hModule, LPSTR lpType, LPSTR lpName, WORD languages, LONG lParam);
  23. // External function and variables
  24. DWORD MyGetPrivateProfileString( LPCTSTR lpSec, LPCTSTR lpKey, LPCTSTR lpDefault,
  25. LPTSTR lpBuf, UINT uSize, LPCTSTR lpOverSec );
  26. void MyWritePrivateProfileString( LPCTSTR lpSec, LPCTSTR lpKey, LPTSTR lpBuf, UINT uSize );
  27. //////////////////////////////////////////////////////////////////////////////
  28. //// Version information overwrite functions and data types
  29. #define KEY_FROMFILE "FromFile"
  30. #define COMPANYNAME "CompanyName"
  31. #define INTERNALNAME "InternalName"
  32. #define ORIGINALFILENAME "OriginalFilename"
  33. #define PRODUCTNAME "ProductName"
  34. #define PRODUCTVERSION "ProductVersion"
  35. #define FILEVERSION "FileVersion"
  36. #define FILEDESCRIPTION "FileDescription"
  37. #define LEGALCOPYRIGHT "LegalCopyright"
  38. #define MAX_VALUE 256
  39. // What language is the version information in?
  40. WORD wVerLang = MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL);
  41. // Structure to save the keys and values for the Version info
  42. typedef struct _VERINFO
  43. {
  44. LPSTR lpszName;
  45. CHAR szValue[MAX_VALUE];
  46. } VERINFO;
  47. // Array of keys and values which can be changed.
  48. VERINFO Verinfo_Array[] = {
  49. { COMPANYNAME, ""},
  50. { INTERNALNAME, ""},
  51. { ORIGINALFILENAME, ""},
  52. { PRODUCTNAME, ""},
  53. { PRODUCTVERSION, ""},
  54. { FILEVERSION, ""},
  55. { FILEDESCRIPTION, ""},
  56. { LEGALCOPYRIGHT, ""}
  57. };
  58. #define ARRAYSIZE(a) (sizeof(a) / sizeof(a[0]))
  59. UINT VerInfoElem = ARRAYSIZE(Verinfo_Array);
  60. //... Decrement WORD at *pw by given amount w
  61. #define DECWORDBY( pw,w) if (pw) { *(pw) = (*(pw) > (w)) ? *(pw) - (w) : 0;}
  62. //... Increment WORD at *pw by given amount w
  63. #define INCWORDBY( pw,w) if (pw) { *(pw) += (w);}
  64. #define MEMSIZE( x ) ((x) * 2)
  65. // was sizeof( TCHAR))
  66. #define STRINGFILEINFOLEN 15
  67. #define LANGSTRINGLEN 8 //... # WCHARs in string denoting language
  68. //... and code page in a Version resource.
  69. #define VERTYPESTRING 1 //... Version data value is a string
  70. #pragma pack(1)
  71. typedef struct VERBLOCK
  72. {
  73. WORD wLength; // Length of this block
  74. WORD wValueLength; // Length of the valuedata
  75. WORD wType; // Type of data (1=string, 0=binary)
  76. WCHAR szKey[1]; // data
  77. } VERBLOCK ;
  78. typedef VERBLOCK * PVERBLOCK;
  79. typedef struct VERHEAD
  80. {
  81. WORD wTotLen;
  82. WORD wValLen;
  83. WORD wType;
  84. TCHAR szKey[( sizeof( TEXT("VS_VERSION_INFO" )) +3 )&~03];
  85. VS_FIXEDFILEINFO vsf;
  86. } VERHEAD ;
  87. #pragma pack()
  88. // Do the version info update
  89. //
  90. // szFile is the file we want to update the version info from
  91. // hUpdate is the handle to the resource info which will be used to update all resources
  92. //
  93. BOOL DoVersionInfo(HWND hDlg, LPSTR szFile, HANDLE hUpdate)
  94. {
  95. HINSTANCE hModule;
  96. HRSRC hrsrc;
  97. HGLOBAL hgbl;
  98. LPBYTE lp;
  99. LPBYTE lpCopy;
  100. WORD wSize;
  101. if (GetVersionInfoFromFile())
  102. {
  103. // Get the current version info from the file
  104. hModule = LoadLibraryEx(szFile, NULL,LOAD_LIBRARY_AS_DATAFILE| DONT_RESOLVE_DLL_REFERENCES);
  105. if (hModule == NULL)
  106. return FALSE; // Should not happen, we loaded the module before
  107. // Determine the language of the version information
  108. EnumResourceLanguages(hModule, RT_VERSION, MAKEINTRESOURCE(VS_VERSION_INFO), (ENUMRESLANGPROC)MyEnumLangsFunc, 0L);
  109. hrsrc = FindResourceEx (hModule, RT_VERSION, MAKEINTRESOURCE(VS_VERSION_INFO), wVerLang);
  110. if (hrsrc == NULL)
  111. {
  112. FreeLibrary(hModule);
  113. return FALSE; // Should we continue???
  114. }
  115. if ((hgbl = LoadResource(hModule, hrsrc)) == NULL)
  116. {
  117. FreeResource(hrsrc);
  118. FreeLibrary(hModule);
  119. return FALSE; // Should we continue???
  120. }
  121. if ((lp = LockResource(hgbl)) == NULL)
  122. {
  123. FreeResource(hrsrc);
  124. FreeLibrary(hModule);
  125. return FALSE; // Should we continue???
  126. }
  127. // UPdate the version information, If success, lpCopy has the pointer to the update info
  128. UpdateVersionInfo(lp, &lpCopy, &wSize);
  129. UnlockResource(hgbl);
  130. FreeResource(hrsrc);
  131. FreeLibrary(hModule);
  132. if (lpCopy != NULL)
  133. {
  134. // Now update the resource for the file
  135. if ( LocalUpdateResource( hUpdate, RT_VERSION,
  136. MAKEINTRESOURCE(VS_VERSION_INFO), wVerLang, //MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL),
  137. lpCopy, wSize) == FALSE )
  138. {
  139. free (lpCopy);
  140. ErrorMsg( hDlg, IDS_ERR_UPDATE_RESOURCE );
  141. return FALSE;
  142. }
  143. free (lpCopy);
  144. }
  145. return TRUE;
  146. }
  147. return TRUE;
  148. }
  149. // Get the version information we use to overwrite from the CDF file
  150. BOOL GetVersionInfoFromFile()
  151. {
  152. char szFilename[MAX_STRING];
  153. HLOCAL hInfoBuffer;
  154. LPSTR lpValueBuffer;
  155. char szQuery[128];
  156. DWORD dwBytes;
  157. DWORD dwLangCharset;
  158. DWORD dwInfoBuffer;
  159. DWORD dwDummy;
  160. UINT i;
  161. if ( MyGetPrivateProfileString(SEC_OPTIONS, KEY_VERSIONINFO, "", g_CDF.achVerInfo, sizeof(g_CDF.achVerInfo), g_szOverideSec ) > 0)
  162. {
  163. // We better zero the version info in our array.
  164. for (i = 0; i < VerInfoElem; i++)
  165. {
  166. Verinfo_Array[i].szValue[0] = '\0';
  167. }
  168. if ( MyGetPrivateProfileString( g_CDF.achVerInfo, KEY_FROMFILE, "", szFilename, sizeof(szFilename), g_CDF.achVerInfo) > 0)
  169. {
  170. // Fill the version info from the file version info
  171. // determine if the file contains version information
  172. // and get the size of the information if so
  173. dwInfoBuffer = GetFileVersionInfoSize(szFilename, &dwDummy);
  174. if (dwInfoBuffer != 0)
  175. {
  176. // allocate memory to hold the version information
  177. hInfoBuffer = LocalAlloc(LMEM_FIXED, dwInfoBuffer);
  178. if (hInfoBuffer != NULL)
  179. {
  180. // read version information into our memory
  181. if (GetFileVersionInfo(szFilename, 0, dwInfoBuffer, (LPVOID)hInfoBuffer) != 0)
  182. {
  183. // get language and character set information
  184. if (VerQueryValue((LPVOID)hInfoBuffer, "\\VarFileInfo\\Translation",
  185. &lpValueBuffer, &dwBytes))
  186. dwLangCharset = *(LPDWORD)lpValueBuffer;
  187. else
  188. dwLangCharset = 0x04E40409; // If we don't have any default to US. Should never happen
  189. // Now get the version info from the file
  190. for (i = 0; i < VerInfoElem; i++)
  191. {
  192. // get version information string
  193. wsprintf(szQuery, "\\StringFileInfo\\%4.4X%4.4X\\%s",
  194. LOWORD(dwLangCharset), HIWORD(dwLangCharset), Verinfo_Array[i].lpszName);
  195. if (VerQueryValue((LPVOID)hInfoBuffer, szQuery, (LPVOID)&lpValueBuffer, &dwBytes) != 0)
  196. lstrcpyn(Verinfo_Array[i].szValue,lpValueBuffer, MAX_VALUE-1); // Found one, take it
  197. }
  198. }
  199. LocalFree(hInfoBuffer);
  200. }
  201. }
  202. } // Got version info from file
  203. // Now see if we have to overwrite some info from the batch file.
  204. for (i = 0; i < VerInfoElem; i++)
  205. {
  206. if (MyGetPrivateProfileString(g_CDF.achVerInfo, Verinfo_Array[i].lpszName, "", szFilename, MAX_VALUE, g_CDF.achVerInfo) > 0)
  207. {
  208. lstrcpyn(Verinfo_Array[i].szValue, szFilename, MAX_VALUE-1);
  209. }
  210. }
  211. return TRUE;
  212. }
  213. return FALSE;
  214. }
  215. // Update the lpOldVersionInfo with the overwritable data.
  216. // lpOldVersionInfo: pointer to the old version info data block
  217. // lplpNewVersionInfo: Will get the pointer to the updated version info data,
  218. // the caller has to free the buffer if the pointer is not NULL,
  219. // pwSize: pointer to a word which will return the size of the new version info block
  220. //
  221. // Note: This code assumes that there is only one language data block in the version info data.
  222. //
  223. BOOL UpdateVersionInfo(LPBYTE lpOldVersionInfo, LPBYTE *lplpNewVersionInfo, WORD *pwSize)
  224. {
  225. WCHAR szData[MAX_STRING]; // Will hold the data to put into the versin info
  226. WORD wDataLen = 0; //... Length of old resource data
  227. WORD wVerHeadSize; //... Sizeof of the VERHEAD struct
  228. int nNewVerBlockSize = 0; // Size of the new version info data block
  229. PVERBLOCK pNewVerStamp = NULL; // Pointer to the new version info data block
  230. PVERBLOCK pNewBlk = NULL; // Pointer to the currently worked on data in new verblock
  231. VERHEAD *pVerHdr = (VERHEAD*)lpOldVersionInfo; // Pointer to old verinfo
  232. VERBLOCK *pVerBlk; // Pointer to the currently worked on data in old verblock
  233. LPBYTE lp; // Pointer to the data area to copy (overwrite)
  234. WORD wStringTableLen = 0; // Bytes (left) in the language data block
  235. PVERBLOCK pNewStringTblBlk; // Pointer to the language part for the version info
  236. WORD wStringInfoLen = 0; //... # of bytes in StringFileInfo
  237. PVERBLOCK pNewStringInfoBlk; //... Start of this StringFileInfo blk
  238. WORD wLen = 0;
  239. *lplpNewVersionInfo = NULL;
  240. *pwSize = 0;
  241. wVerHeadSize = (WORD)(3 * sizeof(WORD) + MEMSIZE(lstrlen("VS_FIXEDFILEINFO") + 1) + sizeof(VS_FIXEDFILEINFO));
  242. wVerHeadSize = ROUNDUP(wVerHeadSize, 4);
  243. // Total length of the version information
  244. wDataLen = pVerHdr->wTotLen;
  245. if ( wDataLen == 0 || wDataLen == (WORD)-1 )
  246. {
  247. return(FALSE); //... No resource data
  248. }
  249. //... Allocate buffer to hold New Version
  250. //... Stamping Block (make the buffer large to
  251. //... account for expansion of strings
  252. pVerBlk = (PVERBLOCK)((PBYTE)pVerHdr + wVerHeadSize); // point into version block of the old info
  253. // we potentialy replace 8 (VerInfoElem=8) string in the version info
  254. // I alloc 9 * 2 * 256 + size of the current version info. This should give us plenty of space
  255. // I need to multiply by 2 because we work with unicode strings. One character = 2 bytes.
  256. nNewVerBlockSize = wDataLen + (2 * (VerInfoElem+1) * MAX_VALUE);
  257. pNewVerStamp = (PVERBLOCK)malloc( nNewVerBlockSize );
  258. //... Fill new memory block with zeros
  259. memset((void *)pNewVerStamp, 0, nNewVerBlockSize);
  260. //... Copy version info header into new version buffer
  261. memcpy((void *)pNewVerStamp, (void *)pVerHdr, wVerHeadSize);
  262. pNewVerStamp->wLength = wVerHeadSize;
  263. //... Move after version info header
  264. pNewBlk = (PVERBLOCK)((PBYTE)pNewVerStamp + wVerHeadSize);
  265. wDataLen -= wVerHeadSize;
  266. if (wDataLen > 0)
  267. { //... Start of a StringFileInfo block?
  268. pNewStringInfoBlk = pNewBlk;
  269. //... Get # of bytes in this StringFileInfo
  270. //... (Length of value is always 0 here)
  271. wStringInfoLen = pVerBlk->wLength;
  272. //... Move to start of first StringTable blk.
  273. // -2 is for the starting WCHAR part of the VERBLOCK
  274. wLen = ROUNDUP(sizeof(VERBLOCK) - 2 + MEMSIZE( STRINGFILEINFOLEN),4);
  275. // Copy StringFileVersion header
  276. CopyMemory( pNewBlk, pVerBlk, wLen);
  277. pNewStringInfoBlk->wLength = 0; // Set length, will be updated dynamicly
  278. // Go to the language ID block
  279. pVerBlk = (PVERBLOCK)((PBYTE)pVerBlk + wLen);
  280. pNewBlk = (PVERBLOCK)((PBYTE)pNewBlk + wLen);
  281. // Decrement byte counter
  282. DECWORDBY(&wDataLen, wLen);
  283. DECWORDBY(&wStringInfoLen, wLen);
  284. // Update the size values
  285. INCWORDBY(&pNewVerStamp->wLength, wLen);
  286. INCWORDBY(&pNewStringInfoBlk->wLength, wLen);
  287. // We should be now at the language codepage ID string
  288. if (wStringInfoLen > 0)
  289. {
  290. //... Get # of bytes in this StringTable
  291. wStringTableLen = pVerBlk->wLength;
  292. pNewStringTblBlk = pNewBlk;
  293. //... Move to start of first String.
  294. // -2 is for the starting WCHAR part of the VERBLOCK
  295. wLen = ROUNDUP( sizeof(VERBLOCK) - 2 + MEMSIZE( LANGSTRINGLEN),4);
  296. // Copy language/codepage header
  297. CopyMemory( pNewBlk, pVerBlk, wLen);
  298. pNewStringTblBlk->wLength = 0; // Set length, will be updated dynamicly
  299. // Go to the first data block
  300. pVerBlk = (PVERBLOCK)((PBYTE)pVerBlk + wLen);
  301. pNewBlk = (PVERBLOCK)((PBYTE)pNewBlk + wLen);
  302. DECWORDBY(&wDataLen, wLen);
  303. DECWORDBY(&wStringInfoLen, wLen);
  304. DECWORDBY(&wStringTableLen, wLen);
  305. // Update the size values
  306. INCWORDBY(&pNewVerStamp->wLength, wLen);
  307. INCWORDBY(&pNewStringInfoBlk->wLength, wLen);
  308. INCWORDBY(&pNewStringTblBlk->wLength, wLen);
  309. while ( wStringTableLen > 0 )
  310. {
  311. // Copy the old data
  312. CopyMemory( pNewBlk, pVerBlk, ROUNDUP(pVerBlk->wLength,4));
  313. wLen = pVerBlk->wLength;
  314. //... Is value a string?
  315. if (pVerBlk->wType == VERTYPESTRING)
  316. {
  317. //... See if we need to replace the value for this data
  318. wLen = sizeof(szData);
  319. if (FindVerValue( pVerBlk->szKey, szData, &wLen))
  320. {
  321. // Update the length values
  322. pNewBlk->wValueLength = wLen;
  323. // Find the start of the data
  324. lp = (LPBYTE) ((PBYTE)pNewBlk + ROUNDUP(pVerBlk->wLength,4) - ROUNDUP(MEMSIZE(pVerBlk->wValueLength),4));
  325. // Get the size of the new data
  326. wLen = ROUNDUP(MEMSIZE(pNewBlk->wValueLength),4);
  327. // Overwrite the old data
  328. CopyMemory(lp, szData, wLen);
  329. // calculate the size of this data and set it.
  330. wLen = MEMSIZE(pNewBlk->wValueLength);
  331. pNewBlk->wLength += (wLen - MEMSIZE(pVerBlk->wValueLength));
  332. }
  333. }
  334. // Update the size values
  335. wLen = ROUNDUP(pNewBlk->wLength,4);
  336. INCWORDBY(&pNewVerStamp->wLength, wLen);
  337. INCWORDBY(&pNewStringInfoBlk->wLength, wLen);
  338. INCWORDBY(&pNewStringTblBlk->wLength, wLen);
  339. // Go to the next data block in the old version info
  340. wLen = ROUNDUP(pVerBlk->wLength,4);
  341. pVerBlk = (PVERBLOCK)((PBYTE)pVerBlk + wLen);
  342. DECWORDBY(&wDataLen, wLen);
  343. DECWORDBY(&wStringInfoLen, wLen);
  344. DECWORDBY(&wStringTableLen, wLen);
  345. // Go to where the next data block in the new version info would be.
  346. pNewBlk = (PVERBLOCK)((PBYTE)pNewBlk + ROUNDUP(pNewBlk->wLength,4));
  347. } //... END while wStringTableLen
  348. // Copy the rest of the VERBLOCK, this should be the VarFileInfo part.
  349. if (wDataLen > 0)
  350. {
  351. // Update the most outer length info.
  352. INCWORDBY(&pNewVerStamp->wLength, wDataLen);
  353. // Update length info
  354. CopyMemory(pNewBlk, pVerBlk, wDataLen);
  355. }
  356. // Set the values to return to the caller.
  357. *pwSize = pNewVerStamp->wLength;
  358. *lplpNewVersionInfo = (LPBYTE)pNewVerStamp;
  359. } //... END if wStringInfoLen
  360. }
  361. // If some thing went wrong in finding the first language common part of the version info
  362. // we did not update the version info, therefore we have to free the buffer we allocated
  363. if (*pwSize == 0)
  364. free (pNewVerStamp);
  365. return(TRUE);
  366. }
  367. // Try to find the string in our array of version info we can overwrite
  368. // lpKey: is a pointer to the value string in the old versin info block (UNICODE)
  369. // lpszData: will contain the data string (UNICODE) if we found the value
  370. // pwLen: pointer to a word which contains the size of the lpszData buffer on input
  371. // if we found the value it contains the length the version info uses as ValueLength
  372. // which is the size in single byte + zero termination
  373. //
  374. BOOL FindVerValue( WCHAR *lpKey, WCHAR *lpszData, WORD *pwLen)
  375. {
  376. char szValue[MAX_STRING];
  377. UINT i = 0;
  378. // Make it a SB character string
  379. WideCharToMultiByte(CP_ACP, 0, lpKey, -1, szValue, sizeof(szValue), NULL, NULL);
  380. // Zero out the buffer, I use so that the caller can over write more memory then the
  381. // data in the string would take up. This is because the data is WORD aligned.
  382. memset(lpszData, 0, *pwLen);
  383. while (i < VerInfoElem)
  384. {
  385. if (lstrcmpi(Verinfo_Array[i].lpszName, szValue) == 0)
  386. {
  387. if ((Verinfo_Array[i].szValue[0] != '\0') &&
  388. (*pwLen >= MEMSIZE(lstrlen(Verinfo_Array[i].szValue) + 1) ) )
  389. {
  390. // Convert the ANSI data string into UNICODE
  391. *pwLen = (WORD)MultiByteToWideChar(CP_ACP, 0, Verinfo_Array[i].szValue, -1 ,
  392. lpszData, *pwLen);
  393. }
  394. i = VerInfoElem; // Stop searching
  395. }
  396. i++;
  397. }
  398. // Return if we found the value and the array contained data.
  399. return (*lpszData != '\0');
  400. }
  401. BOOL CALLBACK MyEnumLangsFunc(HANDLE hModule, LPSTR lpType, LPSTR lpName, WORD languages, LONG lParam)
  402. {
  403. // The first language we find is OK.
  404. wVerLang = languages;
  405. return FALSE;
  406. }