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.

353 lines
11 KiB

  1. #define _UNICODE
  2. #define UNICODE
  3. #include <tchar.h>
  4. #include <stdio.h>
  5. #include <stdlib.h>
  6. #include <windows.h>
  7. void Usage();
  8. BOOL ParseCmdLine(int argc, TCHAR **argv);
  9. void SetVersionOfImage(IN LPTSTR lpszFileName);
  10. void VersionDwordLong2String(IN DWORDLONG Version, OUT LPTSTR lpszVerString);
  11. void VersionString2DwordLong(IN LPCTSTR lpszVerString, OUT PDWORDLONG pVersion);
  12. void DirWalker(LPCTSTR lpszPath, BOOL fRecursive, void (*pFunc)());
  13. BOOL g_fRecursive = FALSE;
  14. BOOL g_fForceTrue = FALSE;
  15. TCHAR g_szPath[MAX_PATH]; // contains the DirName/FileName we're interested
  16. BOOL g_fSet = FALSE; // TRUE if set new version, FALSE to only display version info
  17. DWORDLONG g_dwlNewVersion = 0;
  18. void __cdecl _tmain(int argc, TCHAR **argv)
  19. {
  20. void (*pFunc)();
  21. if (ParseCmdLine(argc, argv) == FALSE) {
  22. Usage();
  23. return;
  24. }
  25. pFunc = SetVersionOfImage;
  26. DirWalker(g_szPath, g_fRecursive, pFunc);
  27. return;
  28. }
  29. void SetVersionOfImage(IN LPTSTR lpszFileName)
  30. /*++
  31. Routine Description:
  32. Get/Set file version.
  33. The version is specified in the dwFileVersionMS and dwFileVersionLS fields
  34. of a VS_FIXEDFILEINFO, as filled in by the win32 version APIs.
  35. Arguments:
  36. lpszFileName - supplies the full path of the file whose version data is desired.
  37. Return Value:
  38. --*/
  39. {
  40. DWORD d;
  41. PVOID pVersionBlock;
  42. VS_FIXEDFILEINFO *pFixedVersionInfo;
  43. UINT iDataLength;
  44. BOOL b = FALSE;
  45. DWORD dwIgnored;
  46. HANDLE hHandle = NULL;
  47. PVOID pTranslation;
  48. PWORD pLangId, pCodePage;
  49. TCHAR szQueryString[MAX_PATH];
  50. TCHAR *lpszVerString;
  51. TCHAR szOldVerString[MAX_PATH], szNewVerString[MAX_PATH];
  52. DWORDLONG dwlOldVersion = 0;
  53. VersionDwordLong2String(g_dwlNewVersion, szNewVerString);
  54. //
  55. // Get the size of version info block.
  56. //
  57. if(d = GetFileVersionInfoSize((LPTSTR)lpszFileName,&dwIgnored)) {
  58. //
  59. // Allocate memory block of sufficient size to hold version info block
  60. //
  61. pVersionBlock = LocalAlloc(LPTR, d);
  62. if(pVersionBlock) {
  63. //
  64. // Get the version block from the file.
  65. //
  66. if(GetFileVersionInfo((LPTSTR)lpszFileName,0,d,pVersionBlock)) {
  67. //
  68. // Get fixed version info.
  69. //
  70. if(VerQueryValue(pVersionBlock,TEXT("\\"),(LPVOID *)&pFixedVersionInfo,&iDataLength)) {
  71. //
  72. // display the verions info first
  73. //
  74. dwlOldVersion = (((DWORDLONG)pFixedVersionInfo->dwFileVersionMS) << 32)
  75. + pFixedVersionInfo->dwFileVersionLS;
  76. VersionDwordLong2String(dwlOldVersion, szOldVerString);
  77. _tprintf(TEXT("%s: %s"), lpszFileName, szOldVerString);
  78. if (g_fSet == FALSE) {
  79. _tprintf(TEXT("\n"));
  80. } else {
  81. //
  82. // set to the new version
  83. //
  84. pFixedVersionInfo->dwFileVersionMS = (DWORD)((g_dwlNewVersion >> 32) & 0xffffffff);
  85. pFixedVersionInfo->dwFileVersionLS = (DWORD)(g_dwlNewVersion & 0xffffffff);
  86. // Attempt to get language of file. We'll simply ask for the
  87. // translation table and use the first language id we find in there
  88. // as *the* language of the file.
  89. //
  90. // The translation table consists of LANGID/Codepage pairs.
  91. //
  92. if(VerQueryValue(pVersionBlock,TEXT("\\VarFileInfo\\Translation"),&pTranslation,&iDataLength)) {
  93. pLangId = (PWORD)pTranslation;
  94. pCodePage = (PWORD)pTranslation + 1;
  95. // update FileVersion string
  96. _stprintf(szQueryString, TEXT("\\StringFileInfo\\%04x%04x\\FileVersion"), *pLangId, *pCodePage);
  97. if (VerQueryValue(pVersionBlock,szQueryString,(LPVOID *)&lpszVerString,&iDataLength)) {
  98. memset(lpszVerString, 0, iDataLength * sizeof(TCHAR));
  99. _tcsncpy(lpszVerString, szNewVerString, iDataLength - 1);
  100. }
  101. // update ProductVersion string
  102. _stprintf(szQueryString, TEXT("\\StringFileInfo\\%04x%04x\\ProductVersion"), *pLangId, *pCodePage);
  103. if (VerQueryValue(pVersionBlock,szQueryString,(LPVOID *)&lpszVerString,&iDataLength)) {
  104. memset(lpszVerString, 0, iDataLength * sizeof(TCHAR));
  105. _tcsncpy(lpszVerString, szNewVerString, iDataLength - 1);
  106. }
  107. } // Language-related String Update
  108. //
  109. // Update the version resource
  110. //
  111. b = FALSE;
  112. hHandle = BeginUpdateResource((LPTSTR) lpszFileName, FALSE);
  113. if (hHandle) {
  114. b = UpdateResource(
  115. hHandle,
  116. RT_VERSION,
  117. MAKEINTRESOURCE(VS_VERSION_INFO),
  118. MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US),
  119. pVersionBlock,
  120. d);
  121. if (b)
  122. b = EndUpdateResource(hHandle, FALSE);
  123. }
  124. if (b)
  125. _tprintf(TEXT(" ==> %s\n"), szNewVerString);
  126. else
  127. _tprintf(TEXT("\nError = %d\n"), GetLastError());
  128. } // g_fGet
  129. } // VerQueryValue() on FixedVersionInfo
  130. } // GetFileVersionInfo()
  131. LocalFree(pVersionBlock);
  132. } // malloc()
  133. }
  134. return;
  135. }
  136. void DirWalker(LPCTSTR lpszPath, BOOL fRecursive, void (*pFunc)())
  137. {
  138. DWORD retCode;
  139. WIN32_FIND_DATA FindFileData;
  140. HANDLE hFile = INVALID_HANDLE_VALUE;
  141. TCHAR szSubDir[MAX_PATH] = _T("");
  142. TCHAR szDirName[MAX_PATH] = _T("");
  143. int len = 0;
  144. retCode = GetFileAttributes(lpszPath);
  145. if (retCode == 0xFFFFFFFF) {
  146. // lpszPath is not a valid DirName or FileName
  147. return;
  148. }
  149. if ( !(retCode & FILE_ATTRIBUTE_DIRECTORY) ) {
  150. // apply the function call
  151. (*pFunc)(lpszPath);
  152. return;
  153. }
  154. len = _tcslen(lpszPath);
  155. if (lpszPath[len - 1] == _T('\\'))
  156. _stprintf(szDirName, _T("%s*"), lpszPath);
  157. else
  158. _stprintf(szDirName, _T("%s\\*"), lpszPath);
  159. hFile = FindFirstFile(szDirName, &FindFileData);
  160. if (hFile != INVALID_HANDLE_VALUE) {
  161. do {
  162. if (_tcsicmp(FindFileData.cFileName, _T(".")) != 0 &&
  163. _tcsicmp(FindFileData.cFileName, _T("..")) != 0 ) {
  164. if (lpszPath[len - 1] == _T('\\'))
  165. _stprintf(szSubDir, _T("%s%s"), lpszPath, FindFileData.cFileName);
  166. else
  167. _stprintf(szSubDir, _T("%s\\%s"), lpszPath, FindFileData.cFileName);
  168. if (FindFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
  169. if (fRecursive)
  170. DirWalker(szSubDir, fRecursive, pFunc);
  171. } else {
  172. (*pFunc)(szSubDir);
  173. }
  174. }
  175. if (!FindNextFile(hFile, &FindFileData)) {
  176. FindClose(hFile);
  177. break;
  178. }
  179. } while (TRUE);
  180. }
  181. return;
  182. }
  183. void VersionDwordLong2String(IN DWORDLONG Version, OUT LPTSTR lpszVerString)
  184. {
  185. WORD a, b, c, d;
  186. a = (WORD)(Version >> 48);
  187. b = (WORD)((Version >> 32) & 0xffff);
  188. c = (WORD)((Version >> 16) & 0xffff);
  189. d = (WORD)(Version & 0xffff);
  190. _stprintf(lpszVerString, TEXT("%d.%d.%d.%d"), a, b, c, d);
  191. return;
  192. }
  193. void VersionString2DwordLong(IN LPCTSTR lpszVerString, OUT PDWORDLONG pVersion)
  194. {
  195. WORD a=0, b=0, c=0, d=0;
  196. _stscanf(lpszVerString, TEXT("%d.%d.%d.%d"), &a, &b, &c, &d);
  197. *pVersion = (((DWORDLONG)a) << 48) +
  198. (((DWORDLONG)b) << 32) +
  199. (((DWORDLONG)c) << 16) +
  200. (DWORDLONG)d;
  201. return;
  202. }
  203. BOOL ParseCmdLine(int argc, TCHAR **argv)
  204. {
  205. BOOL fReturn = FALSE;
  206. TCHAR szVerString[MAX_PATH];
  207. TCHAR c;
  208. int i = 0;
  209. if (argc < 2 || argc > 4 ||
  210. _tcsicmp(argv[1], TEXT("/?")) == 0 ||
  211. _tcsicmp(argv[1], TEXT("-?")) == 0) {
  212. fReturn = FALSE;
  213. } else {
  214. i = 1;
  215. if (_tcsicmp(argv[1], TEXT("/r")) == 0 || _tcsicmp(argv[1], TEXT("-r")) == 0) {
  216. g_fRecursive = TRUE;
  217. i = 2;
  218. }
  219. if (_tcsicmp(argv[1], TEXT("/rf")) == 0 || _tcsicmp(argv[1], TEXT("-rf")) == 0) {
  220. g_fRecursive = TRUE;
  221. g_fForceTrue = TRUE;
  222. i = 2;
  223. }
  224. if (_tcsicmp(argv[1], TEXT("/f")) == 0 || _tcsicmp(argv[1], TEXT("-f")) == 0) {
  225. g_fForceTrue = TRUE;
  226. i = 2;
  227. }
  228. if (argv[i]) {
  229. if (GetFileAttributes(argv[i]) != 0xFFFFFFFF) {
  230. // argv[i] is pointing to a valid DirName or FileName
  231. _tcscpy(g_szPath, argv[i]);
  232. i++;
  233. if (argv[i] == NULL) {
  234. // display version info only
  235. // parse is done
  236. g_fSet = FALSE;
  237. fReturn = TRUE;
  238. } else {
  239. // set version info
  240. g_fSet = TRUE;
  241. // make sure it's a valid version string
  242. VersionString2DwordLong(argv[i], &g_dwlNewVersion);
  243. VersionDwordLong2String(g_dwlNewVersion, szVerString);
  244. _tprintf(TEXT("Stamp files with new version %s ? (y/n) "), szVerString);
  245. if (g_fForceTrue)
  246. {
  247. _tprintf(TEXT("Yes\n"));
  248. fReturn = TRUE;
  249. }
  250. else
  251. {
  252. _tscanf(TEXT("%c"), &c);
  253. if (c == TEXT('y') || c == TEXT('Y')) {
  254. fReturn = TRUE;
  255. } else {
  256. fReturn = FALSE;
  257. }
  258. }
  259. }
  260. } else {
  261. _tprintf(TEXT("Error: no such file called %s!\n"), argv[i]);
  262. }
  263. }
  264. }
  265. return fReturn;
  266. }
  267. void Usage()
  268. {
  269. _tprintf(TEXT("\n"));
  270. _tprintf(TEXT("Display or change version info of files.\n"));
  271. _tprintf(TEXT("\n"));
  272. _tprintf(TEXT("Usage:\n"));
  273. _tprintf(TEXT("\n"));
  274. _tprintf(TEXT("verstamp [-rf] Path [newVersion]\n"));
  275. _tprintf(TEXT("\t-r\t\trecursively apply the Path\n"));
  276. _tprintf(TEXT("\t-rf\t\trecursively apply the Path and force to Yes.\n"));
  277. _tprintf(TEXT("\tPath\t\ta file name or directory name\n"));
  278. _tprintf(TEXT("\tnewVersion\tstamp file with this new version\n"));
  279. _tprintf(TEXT("\n"));
  280. _tprintf(TEXT("verstamp [-?]\t\tprint out this usage info.\n"));
  281. _tprintf(TEXT("\n"));
  282. _tprintf(TEXT("\n"));
  283. _tprintf(TEXT("Example:\n"));
  284. _tprintf(TEXT("verstamp iis.dll 5.0.1780.0\n"));
  285. return;
  286. }