Source code of Windows XP (NT5)
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.

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