version.c
Upload User: xhy777
Upload Date: 2007-02-14
Package Size: 24088k
Code Size: 17k
Category:

Windows Kernel

Development Platform:

Visual C++

  1. //
  2. // processes the version property sheet page.
  3. //
  4. #include "shellprv.h"
  5. #pragma  hdrstop
  6. #ifndef WIN32
  7. #include <ver.h>
  8. #include <version.h>
  9. #endif
  10. #include "help.h"
  11. #define DWORDUP(x)              (((x)+3)&~3)
  12. #define VerKeyToValue(lpKey)    (lpKey + DWORDUP(lstrlen(lpKey)+1))
  13. #pragma warning(disable: 4200)   // zero size array in struct
  14. // magic undoced explort from version.dll
  15. STDAPI_(BOOL) VerQueryValueIndexW(const void *pBlock, LPTSTR lpSubBlock, DWORD dwIndex, void **ppBuffer, void **ppValue, PUINT puLen);
  16. #ifdef UNICODE
  17. #define VerQueryValueIndex VerQueryValueIndexW
  18. #endif
  19. typedef struct 
  20. {
  21.     WORD wTotLen;
  22.     WORD wValLen;
  23.     TCHAR szKey[];
  24. } SHELLVERBLOCK, *LPSHELLVERBLOCK;
  25. // Following code is copied from filemanwfdlgs2.c
  26. //    The following data structure associates a version stamp datum
  27. //    name (which is not localized) with a string ID.  This is so we
  28. //    can show translations of these names to the user.
  29. struct vertbl {
  30.     TCHAR const *pszName;
  31.     short idString;
  32. };
  33. //   Note that version stamp datum names are NEVER internationalized,
  34. //   so the following literal strings are just fine.
  35. const struct vertbl vernames[] = {
  36.     { TEXT("FileVersion"),              IDD_VERSION_FILEVERSION },
  37.     { TEXT("LegalCopyright"),   IDD_VERSION_COPYRIGHT },
  38.     { TEXT("FileDescription"),  IDD_VERSION_DESCRIPTION },
  39.     { TEXT("Comments"),                 IDS_VN_COMMENTS },
  40.     { TEXT("CompanyName"),              IDS_VN_COMPANYNAME },
  41.     { TEXT("InternalName"),             IDS_VN_INTERNALNAME },
  42.     { TEXT("LegalTrademarks"),  IDS_VN_LEGALTRADEMARKS },
  43.     { TEXT("OriginalFilename"), IDS_VN_ORIGINALFILENAME },
  44.     { TEXT("PrivateBuild"),             IDS_VN_PRIVATEBUILD },
  45.     { TEXT("ProductName"),              IDS_VN_PRODUCTNAME },
  46.     { TEXT("ProductVersion"),           IDS_VN_PRODUCTVERSION },
  47.     { TEXT("SpecialBuild"),             IDS_VN_SPECIALBUILD }
  48. };
  49. #define NUM_SPECIAL_STRINGS     3
  50. typedef struct { // vp
  51.     PROPSHEETPAGE psp;
  52.     HWND hDlg;
  53.     LPTSTR pVerBuffer;          /* pointer to version data */
  54.     TCHAR szVersionKey[60];     /* big enough for anything we need */
  55.     struct _VERXLATE
  56.     {
  57.         WORD wLanguage;
  58.         WORD wCodePage;
  59.     } *lpXlate;                     /* ptr to translations data */
  60.     int cXlate;                 /* count of translations */
  61.     LPTSTR pszXlate;
  62.     int cchXlateString;
  63.     TCHAR szFile[MAX_PATH];
  64. } VERPROPSHEETPAGE, * LPVERPROPSHEETPAGE;
  65. #define VER_KEY_END     25      /* length of "StringFileInfoxxxxyyyy" */
  66.                                 /* (not localized) */
  67. #define MAXMESSAGELEN   (50 + MAX_PATH * 2)
  68. /*
  69.     Gets a particular datum about a file.  The file's version info
  70.     should have already been loaded by GetVersionInfo.  If no datum
  71.     by the specified name is available, NULL is returned.  The name
  72.     specified should be just the name of the item itself;  it will
  73.     be concatenated onto "StringFileInfoxxxxyyyy" automatically.
  74.     Version datum names are not localized, so it's OK to pass literals
  75.     such as "FileVersion" to this function.
  76.     Note that since the returned datum is in a global memory block,
  77.     the return value of this function is LPSTR, not PSTR.
  78. */
  79. LPTSTR GetVersionDatum(LPVERPROPSHEETPAGE pvp, LPCTSTR pszName)
  80. {
  81.     UINT cbValue = 0;
  82.     LPTSTR lpValue;
  83.     if (!pvp->pVerBuffer)
  84.         return NULL;
  85.     lstrcpy(pvp->szVersionKey + VER_KEY_END, pszName);
  86.     VerQueryValue(pvp->pVerBuffer, pvp->szVersionKey, (void **)&lpValue, &cbValue);
  87.     return (cbValue != 0) ? lpValue : NULL;
  88. }
  89. /*
  90.     Frees global version data about a file.  After this call, all
  91.     GetVersionDatum calls will return NULL.  To avoid memory leaks,
  92.     always call this before the main properties dialog exits.
  93. */
  94. void FreeVersionInfo(LPVERPROPSHEETPAGE pvp)
  95. {
  96.     if (pvp->pVerBuffer) 
  97.     {
  98.         GlobalFree(pvp->pVerBuffer);
  99.         pvp->pVerBuffer = NULL;
  100.     }
  101.     if (pvp->pszXlate) 
  102.     {
  103.         LocalFree((HLOCAL)(HANDLE)pvp->pszXlate);
  104.         pvp->pszXlate = NULL;
  105.     }
  106.     pvp->lpXlate = NULL;
  107. }
  108. /*
  109.     Initialize version information for the properties dialog.  The
  110.     above global variables are initialized by this function, and
  111.     remain valid (for the specified file only) until FreeVersionInfo
  112.     is called.
  113.     The first language we try will be the first item in the
  114.     "VarFileInfoTranslations" section;  if there's nothing there,
  115.     we try the one coded into the IDS_FILEVERSIONKEY resource string.
  116.     If we can't even load that, we just use English (040904E4).  We
  117.     also try English with a null codepage (04090000) since many apps
  118.     were stamped according to an old spec which specified this as
  119.     the required language instead of 040904E4.
  120.     GetVersionInfo returns TRUE if the version info was read OK,
  121.     otherwise FALSE.  If the return is FALSE, the buffer may still
  122.     have been allocated;  always call FreeVersionInfo to be safe.
  123.     pszPath is modified by this call (pszName is appended).
  124. */
  125. BOOL GetVersionInfo(LPVERPROPSHEETPAGE pvp, LPCTSTR pszPath)
  126. {
  127.     UINT cbValue = 0;
  128.     LPTSTR pszValue = NULL;
  129.     DWORD dwHandle;             /* version subsystem handle */
  130.     DWORD dwVersionSize;        /* size of the version data */
  131.     FreeVersionInfo(pvp);       /* free old version buffer */
  132.     // cast const -> non const for bad API def
  133.     dwVersionSize = GetFileVersionInfoSize((LPTSTR)pszPath, &dwHandle);
  134.     if (dwVersionSize == 0L)
  135.         return FALSE;           /* no version info */
  136.     pvp->pVerBuffer = GlobalAlloc(GPTR, dwVersionSize);
  137.     if (pvp->pVerBuffer == NULL)
  138.         return FALSE;
  139.     // cast const -> non const for bad API def
  140.     
  141.     if (!GetFileVersionInfo((LPTSTR)pszPath, dwHandle, dwVersionSize, pvp->pVerBuffer))
  142.     {
  143.         return FALSE;
  144.     }
  145.     // Look for translations
  146.     if (VerQueryValue(pvp->pVerBuffer, TEXT("\VarFileInfo\Translation"), (void **)&pvp->lpXlate, &cbValue)
  147.                 && cbValue)
  148.     {
  149.         pvp->cXlate = cbValue / SIZEOF(DWORD);
  150.         pvp->cchXlateString = pvp->cXlate * 64;  /* figure 64 chars per lang name */
  151.         pvp->pszXlate = (LPTSTR)(void*)LocalAlloc(LPTR, pvp->cchXlateString*SIZEOF(TCHAR));
  152.         // failure of above will be handled later
  153.     }
  154.     else
  155.     {
  156.         pvp->lpXlate = NULL;
  157.     }
  158.     // Try same language as this program
  159.     if (LoadString(HINST_THISDLL, IDS_VN_FILEVERSIONKEY, pvp->szVersionKey, ARRAYSIZE(pvp->szVersionKey)))
  160.     {
  161.         if (GetVersionDatum(pvp, vernames[0].pszName))
  162.         {
  163.             return TRUE;
  164.         }
  165.     }
  166.     // Try first language this supports
  167.     if (pvp->lpXlate)
  168.     {
  169.         wsprintf(pvp->szVersionKey, TEXT("\StringFileInfo\%04X%04X\"),
  170.                 pvp->lpXlate[0].wLanguage, pvp->lpXlate[0].wCodePage);
  171.         if (GetVersionDatum(pvp, vernames[0].pszName))  /* a required field */
  172.         {
  173.             return TRUE;
  174.         }
  175.     }
  176. #ifdef UNICODE
  177.     // try English, unicode code page
  178.     lstrcpy(pvp->szVersionKey, TEXT("\StringFileInfo\040904B0\"));
  179.     if (GetVersionDatum(pvp, vernames[0].pszName))
  180.     {
  181.         return TRUE;
  182.     }
  183. #endif
  184.     // try English
  185.     lstrcpy(pvp->szVersionKey, TEXT("\StringFileInfo\040904E4\"));
  186.     if (GetVersionDatum(pvp, vernames[0].pszName))
  187.     {
  188.         return TRUE;
  189.     }
  190.     // try English, null codepage
  191.     lstrcpy(pvp->szVersionKey, TEXT("\StringFileInfo\04090000\"));
  192.     if (GetVersionDatum(pvp, vernames[0].pszName))
  193.     {
  194.         return TRUE;
  195.     }
  196.     // Could not find FileVersion info in a reasonable format
  197.     return FALSE;
  198. }
  199. /*
  200.     Fills the version key listbox with all available keys in the
  201.     StringFileInfo block, and sets the version value text to the
  202.     value of the first item.
  203. */
  204. #ifndef WINNT
  205. #define NOQUERYVALUEINDEX
  206. #endif
  207. void FillVersionList(LPVERPROPSHEETPAGE pvp)
  208. {
  209.     LPTSTR pszName;
  210.     LPTSTR pszValue;
  211.     TCHAR szStringBase[VER_KEY_END+1];
  212.     int i, j, idx;
  213.     HWND hwndLB;
  214.     TCHAR szMessage[MAXMESSAGELEN+1];
  215.     UINT uOffset, cbValue;
  216. #ifdef NOQUERYVALUEINDEX
  217.     LPSHELLVERBLOCK pszBlock, pszEnd;      /* will point to a block */
  218. #endif
  219.     
  220.     hwndLB = GetDlgItem(pvp->hDlg, IDD_VERSION_KEY);
  221.     
  222.     ListBox_ResetContent(hwndLB);
  223.     for (i=0; i<NUM_SPECIAL_STRINGS; ++i)
  224.     {
  225.         SetDlgItemText(pvp->hDlg, vernames[i].idString, szNULL);
  226.     }
  227.     
  228.     pvp->szVersionKey[VER_KEY_END] = 0;        /* don't copy too much */
  229.     lstrcpy(szStringBase, pvp->szVersionKey);   /* copy to our buffer */
  230.     szStringBase[VER_KEY_END - 1] = 0; /* strip the backslash */
  231.     
  232.     // Note: The Nt Version of version.dll has other exports.  If/When they are
  233.     // available in Win version then we can remove this section...
  234. #ifdef NOQUERYVALUEINDEX
  235.     if (!VerQueryValue(pvp->pVerBuffer, szStringBase, (void **)&pszBlock, &cbValue))
  236.     {
  237.         goto NoVersionStrings;
  238.     }
  239.     
  240.     /*
  241.     Now pszBlock points to where the value of the StringFileInfoxxxxyyyy
  242.     block would be.  Add on the value length (which should be 0) and
  243.     dword padding, and we're pointing at the child blocks.
  244.     
  245.       We also get the total size of the StringFileInfo block.  We do this
  246.       by backing up 16 bytes:  4 for the two words (block len, value len),
  247.       the size of "xxxxyyyy", and dword padding.  This is fetching the
  248.       block length of the Var block.  We subtract 16 from that length
  249.       because it includes the name of the Var block itself, etc.
  250.     */
  251.     
  252.     pszBlock = (LPSHELLVERBLOCK)((LPSTR)pszBlock - (DWORDUP(sizeof("040904e4")) + sizeof(SHELLVERBLOCK)));
  253.     pszEnd   = (LPSHELLVERBLOCK)((LPSTR)pszBlock + pszBlock->wTotLen);
  254.     
  255.     pszBlock = (LPSHELLVERBLOCK)((LPSTR)pszBlock + DWORDUP(sizeof("040904e4")) + sizeof(SHELLVERBLOCK) +
  256.         DWORDUP(pszBlock->wValLen));
  257. #endif // NOQUERYVALUEINDEX
  258.     
  259.     //
  260.     // Now iterate through all of the strings
  261.     //
  262.     for (j = 0; ; j++)
  263.     {
  264. #ifdef NOQUERYVALUEINDEX
  265.         if (pszBlock >= pszEnd)
  266.             break;
  267.         pszName = pszBlock->szKey;
  268.         pszValue = VerKeyToValue(pszName);
  269. #else
  270.         if (!VerQueryValueIndex(pvp->pVerBuffer, szStringBase, j, &pszName, &pszValue, &cbValue))
  271.             break;
  272. #endif
  273.         
  274.         for (i = 0; i < ARRAYSIZE(vernames); i++)
  275.         {
  276.             if (!lstrcmp(vernames[i].pszName, pszName))
  277.             {
  278.                 break;
  279.             }
  280.         }
  281.         
  282.         if (i < NUM_SPECIAL_STRINGS)
  283.         {
  284.             VS_FIXEDFILEINFO *pffi;
  285.             if ((vernames[i].idString == IDD_VERSION_FILEVERSION) &&
  286.                 VerQueryValue(pvp->pVerBuffer, TEXT("\"), (void **)&pffi, &cbValue) && cbValue)
  287.             {
  288.                 TCHAR szString[128];
  289.                 // display the binary version info, not the useless 
  290.                 // string version (that can be out of sync)
  291.                 wnsprintf(szString, ARRAYSIZE(szString), TEXT("%d.%d.%d.%d"), 
  292.                     HIWORD(pffi->dwFileVersionMS),
  293.                     LOWORD(pffi->dwFileVersionMS),
  294.                     HIWORD(pffi->dwFileVersionLS),
  295.                     LOWORD(pffi->dwFileVersionLS));
  296.                 SetDlgItemText(pvp->hDlg, vernames[i].idString, szString);
  297.             }
  298.             else
  299.                 SetDlgItemText(pvp->hDlg, vernames[i].idString, pszValue);
  300.         }
  301.         else
  302.         {
  303.             if (i == ARRAYSIZE(vernames) ||
  304.                 !LoadString(HINST_THISDLL, vernames[i].idString, szMessage, ARRAYSIZE(szMessage)))
  305.             {
  306.                 lstrcpy(szMessage, pszName);
  307.             }
  308.             
  309.             idx = ListBox_AddString(hwndLB, szMessage);
  310.             if (idx != LB_ERR)
  311.             {
  312.                 ListBox_SetItemData(hwndLB, idx, (DWORD_PTR)pszValue);
  313.             }
  314.         }
  315. #ifdef NOQUERYVALUEINDEX
  316.         pszBlock = (LPSHELLVERBLOCK)((LPSTR)pszBlock + DWORDUP(pszBlock->wTotLen));
  317. #endif
  318.     }
  319.     
  320.     // Now look at the VarFileInfoTranslations section and add an
  321.     // item for the language(s) this file supports.
  322. #ifdef NOQUERYVALUEINDEX
  323. NoVersionStrings:
  324. #endif
  325.     
  326.     if (pvp->lpXlate == NULL || pvp->pszXlate == NULL)
  327.         return;
  328.     
  329.     if (!LoadString(HINST_THISDLL, (pvp->cXlate == 1) ? IDS_VN_LANGUAGE : IDS_VN_LANGUAGES,
  330.         szMessage, ARRAYSIZE(szMessage)))
  331.         return;
  332.     
  333.     idx = ListBox_AddString(hwndLB, szMessage);
  334.     if (idx == LB_ERR)
  335.         return;
  336.     
  337.     pvp->pszXlate[0] = 0;
  338.     uOffset = 0;
  339.     for (i = 0; i < pvp->cXlate; i++) {
  340.         if (uOffset + 2 > (UINT)pvp->cchXlateString)
  341.             break;
  342.         if (i != 0) {
  343.             lstrcat(pvp->pszXlate, TEXT(", "));
  344.             uOffset += 2;       // skip over ", "
  345.         }
  346.         if (VerLanguageName(pvp->lpXlate[i].wLanguage, pvp->pszXlate + uOffset, pvp->cchXlateString - uOffset) >
  347.             (DWORD)(pvp->cchXlateString - uOffset))
  348.             break;
  349.         uOffset += lstrlen(pvp->pszXlate + uOffset);
  350.     }
  351.     pvp->pszXlate[pvp->cchXlateString - 1] = 0;
  352.     ListBox_SetItemData(hwndLB, idx, (LPARAM)(LPTSTR)pvp->pszXlate);
  353.     ListBox_SetCurSel(hwndLB, 0);
  354.     
  355.     FORWARD_WM_COMMAND(pvp->hDlg, IDD_VERSION_KEY, hwndLB, LBN_SELCHANGE, PostMessage);
  356. }
  357. //
  358. // Function:    _UpdateVersionPrsht, private
  359. //
  360. // Descriptions:
  361. //   This function fills fields of the "version" dialog box (a page of
  362. //  a property sheet) with attributes of the associated file.
  363. //
  364. // Returns:
  365. //  TRUE, if successfully done; FALSE, otherwise.
  366. //
  367. // History:
  368. //  01-06-93 Shrikant   Created
  369. //
  370. BOOL _UpdateVersionPrsht(LPVERPROPSHEETPAGE pvp)
  371. {
  372.     if (GetVersionInfo(pvp, pvp->szFile))           /* changes szPath */
  373.         FillVersionList(pvp);
  374.     return TRUE;
  375. }
  376. void _VersionPrshtCommand(HWND hwnd, int id, HWND hwndCtl, UINT codeNotify)
  377. {
  378.         LPTSTR pszValue;
  379.         int idx;
  380.         switch (id)
  381.         {
  382.         case IDD_VERSION_KEY:
  383.                 if (codeNotify != LBN_SELCHANGE)
  384.                 {
  385.                         break;
  386.                 }
  387.                 idx = ListBox_GetCurSel(hwndCtl);
  388.                 pszValue = (LPTSTR)ListBox_GetItemData(hwndCtl, idx);
  389.                 if (pszValue)
  390.                 {
  391.                         SetDlgItemText(hwnd, IDD_VERSION_VALUE, pszValue);
  392.                 }
  393.                 break;
  394.         }
  395. }
  396. // Array for context help:
  397. static const DWORD aVersionHelpIds[] = {
  398.     IDD_VERSION_FILEVERSION, IDH_FPROP_VER_ABOUT,
  399.     IDD_VERSION_DESCRIPTION, IDH_FPROP_VER_ABOUT,
  400.     IDD_VERSION_COPYRIGHT,   IDH_FPROP_VER_ABOUT,
  401.     IDD_VERSION_FRAME,       IDH_FPROP_VER_INFO,
  402.     IDD_VERSION_KEY,         IDH_FPROP_VER_INFO,
  403.     IDD_VERSION_VALUE,       IDH_FPROP_VER_INFO,
  404.     0, 0
  405. };
  406. BOOL_PTR CALLBACK _VersionPrshtDlgProc(HWND hDlg, UINT uMessage, WPARAM wParam, LPARAM lParam)
  407. {
  408.     LPVERPROPSHEETPAGE pvp = (LPVERPROPSHEETPAGE)GetWindowLongPtr(hDlg, DWLP_USER);
  409.     switch (uMessage)
  410.     {
  411.     case WM_INITDIALOG:
  412.         SetWindowLongPtr(hDlg, DWLP_USER, lParam);
  413.         pvp = (LPVERPROPSHEETPAGE)lParam;
  414.         pvp->hDlg = hDlg;
  415.         break;
  416.     case WM_DESTROY:
  417.         FreeVersionInfo(pvp);   // free anything we created
  418.         break;
  419.     case WM_HELP:
  420.         WinHelp((HWND) ((LPHELPINFO) lParam)->hItemHandle, NULL, HELP_WM_HELP,
  421.             (ULONG_PTR) (LPTSTR) aVersionHelpIds);
  422.         break;
  423.     case WM_CONTEXTMENU:      // right mouse click
  424.         WinHelp((HWND) wParam, NULL, HELP_CONTEXTMENU,
  425.             (ULONG_PTR) (LPTSTR) aVersionHelpIds);
  426.         break;
  427.     case WM_NOTIFY:
  428.         switch (((NMHDR *)lParam)->code)
  429.         {
  430.         case PSN_SETACTIVE:
  431.             _UpdateVersionPrsht(pvp);
  432.             break;
  433.         }
  434.         break;
  435.     case WM_COMMAND:
  436.         HANDLE_WM_COMMAND(hDlg, wParam, lParam, _VersionPrshtCommand);
  437.         break;
  438.     default:
  439.         return FALSE;
  440.     }
  441.     return TRUE;
  442. }
  443. //
  444. // Descriptions:
  445. //   This function creates a property sheet for the "version" page
  446. //  which shows version information.
  447. //
  448. void AddVersionPage(LPCTSTR pszFile, LPFNADDPROPSHEETPAGE pfnAddPage, LPARAM lParam)
  449. {
  450.     DWORD dwAttr, dwVerLen, dwVerHandle;
  451.     VERPROPSHEETPAGE vp = {0};
  452. #ifndef WINNT
  453.     // Note Win9x version.dll can not currently handle long file names
  454.     GetShortPathName(pszFile, vp.szFile, ARRAYSIZE(vp.szFile));
  455. #else
  456.     lstrcpyn(vp.szFile, pszFile, ARRAYSIZE(vp.szFile));
  457. #endif
  458.     // REVIEW: dwVerHandle is unused, and can be NULL on NT.  If the same 
  459.     // is true on Win9x, we can delete the dwVerHandle local var
  460.     dwAttr = GetFileAttributes(vp.szFile);
  461.     if (0xFFFFFFFF != dwAttr && 0 == (dwAttr & FILE_ATTRIBUTE_OFFLINE) /*avoid HSM recall*/)
  462.     {
  463.         dwVerLen = GetFileVersionInfoSize(vp.szFile, &dwVerHandle);
  464.         if (dwVerLen) 
  465.         {
  466.             HPROPSHEETPAGE hpage;
  467.             vp.psp.dwSize = SIZEOF(VERPROPSHEETPAGE);     // extra data
  468.             vp.psp.dwFlags = PSP_DEFAULT;
  469.             vp.psp.hInstance = HINST_THISDLL;
  470.             vp.psp.pszTemplate = MAKEINTRESOURCE(DLG_VERSION);
  471.             vp.psp.pfnDlgProc = _VersionPrshtDlgProc;
  472.             hpage = CreatePropertySheetPage(&vp.psp);
  473.             if (hpage)
  474.                 if (!pfnAddPage(hpage, lParam))
  475.                     DestroyPropertySheetPage(hpage);
  476.         }
  477.     }
  478. }