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.

276 lines
8.5 KiB

  1. /********************************************************************
  2. Copyright (c) 1999 Microsoft Corporation
  3. Module Name:
  4. version.CPP
  5. Abstract:
  6. Implementation of class to provide version information about
  7. a file using functions pulled from the Dr. Watson source.
  8. Revision History:
  9. Jim Martin (a-jammar) 05/22/99
  10. - Created.
  11. ********************************************************************/
  12. #include "stdafx.h"
  13. #include <winver.h>
  14. #include "mscfgver.h"
  15. typedef CFileVersionInfo::VERSIONSTATE * PVERSIONSTATE;
  16. typedef CFileVersionInfo::FILEVERSION * PFILEVERSION;
  17. BOOL _GetVersionString(PVERSIONSTATE pvs, LPCTSTR ptszKey, LPTSTR ptszBuf);
  18. BOOL __GetVersionString(PVOID pvData, LPCTSTR ptszLang, LPCTSTR ptszKey, LPTSTR ptszBuf);
  19. void GetFileVersion(LPTSTR ptszFile, CFileVersionInfo::FILEVERSION * pfv);
  20. #define pvSubPvCb(pv, cb) ((PVOID)((PBYTE)pv - (cb)))
  21. #define pvAddPvCb(pv, cb) ((PVOID)((PBYTE)pv + (cb)))
  22. #define cbSubPvPv(p1, p2) ((PBYTE)(p1) - (PBYTE)(p2))
  23. #define cbX(X) sizeof(X)
  24. #define cA(a) (cbX(a)/cbX(a[0]))
  25. TCHAR c_szStringFileInfo[] = _T("StringFileInfo");
  26. //-----------------------------------------------------------------------------
  27. // The constructor and destructor don't have too much to do.
  28. //-----------------------------------------------------------------------------
  29. CFileVersionInfo::CFileVersionInfo() : m_pfv(NULL)
  30. {
  31. }
  32. CFileVersionInfo::~CFileVersionInfo()
  33. {
  34. delete m_pfv;
  35. }
  36. //-----------------------------------------------------------------------------
  37. // The Get functions are also really simple.
  38. //-----------------------------------------------------------------------------
  39. LPCTSTR CFileVersionInfo::GetVersion()
  40. {
  41. return (m_pfv) ? (m_pfv->tszFileVersion) : NULL;
  42. }
  43. LPCTSTR CFileVersionInfo::GetDescription()
  44. {
  45. return (m_pfv) ? (m_pfv->tszDesc) : NULL;
  46. }
  47. LPCTSTR CFileVersionInfo::GetCompany()
  48. {
  49. return (m_pfv) ? (m_pfv->tszCompany) : NULL;
  50. }
  51. LPCTSTR CFileVersionInfo::GetProduct()
  52. {
  53. return (m_pfv) ? (m_pfv->tszProduct) : NULL;
  54. }
  55. //-----------------------------------------------------------------------------
  56. // QueryFile get information about the requested file. If necessary, it will
  57. // convert a path with double backslashes to single backslashes before calling
  58. // the helper function GetFileVersion from Dr. Watson code.
  59. //-----------------------------------------------------------------------------
  60. HRESULT CFileVersionInfo::QueryFile(LPCSTR szFile, BOOL fHasDoubleBackslashes)
  61. {
  62. HRESULT hRes = S_OK;
  63. LPTSTR szWorking = NULL;
  64. if (!m_pfv)
  65. m_pfv = new FILEVERSION;
  66. if (!m_pfv)
  67. {
  68. hRes = E_OUTOFMEMORY;
  69. goto END;
  70. }
  71. if (fHasDoubleBackslashes)
  72. {
  73. szWorking = new TCHAR[strlen(szFile)];
  74. if (!szWorking)
  75. {
  76. hRes = E_OUTOFMEMORY;
  77. goto END;
  78. }
  79. // Scan through the passed string, converting double backslashes to single
  80. // backslashes.
  81. int i = 0, j = 0;
  82. while (szFile[i])
  83. {
  84. if (szFile[i] == '\\' && szFile[i + 1] == '\\')
  85. i += 1;
  86. szWorking[j++] = (TCHAR)szFile[i++];
  87. }
  88. szWorking[j] = _T('\0');
  89. }
  90. else
  91. {
  92. USES_CONVERSION;
  93. szWorking = A2T(szFile);
  94. }
  95. if (szWorking != NULL)
  96. {
  97. GetFileVersion(szWorking, m_pfv);
  98. if (fHasDoubleBackslashes)
  99. delete [] szWorking;
  100. }
  101. END:
  102. return hRes;
  103. }
  104. //-----------------------------------------------------------------------------
  105. // An alternate version of the previous function which takes a UNICODE string.
  106. //-----------------------------------------------------------------------------
  107. HRESULT CFileVersionInfo::QueryFile(LPCWSTR szFile, BOOL fHasDoubleBackslashes)
  108. {
  109. // Convert the string from UNICODE to ANSI.
  110. USES_CONVERSION;
  111. LPSTR szConvertedFile = W2A(szFile);
  112. HRESULT hRes = E_FAIL;
  113. if (szConvertedFile)
  114. hRes = this->QueryFile(szConvertedFile, fHasDoubleBackslashes);
  115. return hRes;
  116. }
  117. //-----------------------------------------------------------------------------
  118. // Gets the version information for the file ptszFile, and fillsin the pfv
  119. // FILEVERSION structure.
  120. //-----------------------------------------------------------------------------
  121. void GetFileVersion(LPTSTR ptszFile, CFileVersionInfo::FILEVERSION * pfv)
  122. {
  123. // Open the file and suck out the description.
  124. DWORD cbScratch, cbRc;
  125. memset(pfv, 0, sizeof(CFileVersionInfo::FILEVERSION));
  126. cbRc = GetFileVersionInfoSize(ptszFile, &cbScratch);
  127. if (cbRc)
  128. {
  129. CFileVersionInfo::VERSIONSTATE vs;
  130. memset(&vs, 0, sizeof(CFileVersionInfo::VERSIONSTATE));
  131. vs.pvData = new unsigned char[cbRc]; // BUGBUG
  132. if (vs.pvData)
  133. {
  134. if (GetFileVersionInfo(ptszFile, cbScratch, cbRc, vs.pvData))
  135. {
  136. UINT uiRc;
  137. LPDWORD pdwLang;
  138. if (VerQueryValue(vs.pvData, TEXT("VarFileInfo\\Translation"), (PVOID *) &pdwLang, &uiRc) && uiRc >= 4)
  139. {
  140. wsprintf(vs.tszLang, TEXT("%04x%04x"), LOWORD(*pdwLang), HIWORD(*pdwLang));
  141. if (cbRc > 0x70 && ((LPBYTE)pvAddPvCb(vs.pvData, 0x4C))[14] == 0 &&
  142. lstrcmpi(c_szStringFileInfo, (LPCTSTR) pvAddPvCb(vs.pvData, 0x4C)) == 0)
  143. {
  144. lstrcpyn(vs.tszLang2, (LPCTSTR) pvAddPvCb(vs.pvData, 0x60), cA(vs.tszLang2));
  145. }
  146. else
  147. {
  148. vs.tszLang2[0] = 0;
  149. }
  150. }
  151. if (vs.tszLang[0] == 0)
  152. {
  153. #ifdef UNICODE
  154. // Try English Unicode
  155. lstrcpy(vs.tszLang, TEXT("040904B0"));
  156. if (!_GetVersionString(&vs, TEXT("FileVersion"), pfv->tszFileVersion))
  157. {
  158. #endif
  159. // Try English
  160. lstrcpy(vs.tszLang, TEXT("040904E4"));
  161. if (!_GetVersionString(&vs, TEXT("FileVersion"), pfv->tszFileVersion))
  162. {
  163. // Try English null codepage
  164. lstrcpy(vs.tszLang, TEXT("04090000"));
  165. if (!_GetVersionString(&vs, TEXT("FileVersion"), pfv->tszFileVersion))
  166. goto LNoVersion;
  167. }
  168. #ifdef UNICODE
  169. }
  170. #endif
  171. }
  172. else
  173. _GetVersionString(&vs, TEXT("FileVersion"), pfv->tszFileVersion);
  174. _GetVersionString(&vs, TEXT("FileDescription"), pfv->tszDesc);
  175. _GetVersionString(&vs, TEXT("CompanyName"), pfv->tszCompany);
  176. _GetVersionString(&vs, TEXT("ProductName"), pfv->tszProduct);
  177. }
  178. LNoVersion:
  179. delete [] vs.pvData;
  180. }
  181. }
  182. }
  183. //-----------------------------------------------------------------------------
  184. // Using the version state, retrieve the version string specified by ptszKey
  185. // and put it in the ptszBuf. This just calls another internal function, trying
  186. // both possible languages.
  187. //-----------------------------------------------------------------------------
  188. BOOL _GetVersionString(PVERSIONSTATE pvs, LPCTSTR ptszKey, LPTSTR ptszBuf)
  189. {
  190. BOOL fRc;
  191. fRc = __GetVersionString(pvs->pvData, pvs->tszLang, ptszKey, ptszBuf);
  192. if (!fRc)
  193. fRc = __GetVersionString(pvs->pvData, pvs->tszLang2, ptszKey, ptszBuf);
  194. return fRc;
  195. }
  196. //-----------------------------------------------------------------------------
  197. // An internal function to try to get the data specified by the ptszKey, using
  198. // the ptszLang language and codepage.
  199. //-----------------------------------------------------------------------------
  200. BOOL __GetVersionString(PVOID pvData, LPCTSTR ptszLang, LPCTSTR ptszKey, LPTSTR ptszBuf)
  201. {
  202. TCHAR tszBuf[128];
  203. LPCTSTR ptszResult;
  204. UINT uiRc;
  205. BOOL fRc;
  206. // Replacing this unbounded string copy:
  207. //
  208. // wsprintf(tszBuf, TEXT("\\%s\\%s\\%s"), c_szStringFileInfo, ptszLang, ptszKey);
  209. CString strBuf;
  210. strBuf.Format(TEXT("\\%s\\%s\\%s"), c_szStringFileInfo, ptszLang, ptszKey);
  211. lstrcpyn(tszBuf, (LPCTSTR)strBuf, sizeof(tszBuf) / sizeof(TCHAR));
  212. if (VerQueryValue(pvData, tszBuf, (PVOID *)&ptszResult, &uiRc))
  213. fRc = (lstrcpyn(ptszBuf, ptszResult, MAX_PATH) != NULL);
  214. else
  215. fRc = FALSE;
  216. return fRc;
  217. }