Windows NT 4.0 source code leak
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.
 
 
 
 
 
 

509 lines
15 KiB

//
// processes the version property sheet page.
//
#include "shellprv.h"
#pragma hdrstop
#ifndef WIN32
#include <ver.h>
#include <version.h>
#endif
#include "help.h"
#define DWORDUP(x) (((x)+3)&~3)
#define VerKeyToValue(lpKey) (lpKey + DWORDUP(lstrlen(lpKey)+1))
#pragma warning(disable: 4200) // zero size array in struct
typedef struct _SHELLVERBLOCK
{
WORD wTotLen;
WORD wValLen;
TCHAR szKey[];
} SHELLVERBLOCK, *LPSHELLVERBLOCK;
// Following code is copied from fileman\wfdlgs2.c
// The following data structure associates a version stamp datum
// name (which is not localized) with a string ID. This is so we
// can show translations of these names to the user.
struct vertbl {
TCHAR const *pszName;
short idString;
};
// Note that version stamp datum names are NEVER internationalized,
// so the following literal strings are just fine.
struct vertbl vernames[] = {
{ TEXT("FileVersion"), IDD_VERSION_FILEVERSION },
{ TEXT("LegalCopyright"), IDD_VERSION_COPYRIGHT },
{ TEXT("FileDescription"), IDD_VERSION_DESCRIPTION },
{ TEXT("Comments"), IDS_VN_COMMENTS },
{ TEXT("CompanyName"), IDS_VN_COMPANYNAME },
{ TEXT("InternalName"), IDS_VN_INTERNALNAME },
{ TEXT("LegalTrademarks"), IDS_VN_LEGALTRADEMARKS },
{ TEXT("OriginalFilename"), IDS_VN_ORIGINALFILENAME },
{ TEXT("PrivateBuild"), IDS_VN_PRIVATEBUILD },
{ TEXT("ProductName"), IDS_VN_PRODUCTNAME },
{ TEXT("ProductVersion"), IDS_VN_PRODUCTVERSION },
{ TEXT("SpecialBuild"), IDS_VN_SPECIALBUILD }
};
#define NUM_SPECIAL_STRINGS 3
typedef struct { // vp
PROPSHEETPAGE psp;
HWND hDlg;
HGLOBAL hmemVersion; /* global handle for version data buffer */
LPTSTR lpVersionBuffer; /* pointer to version data */
TCHAR szVersionKey[60]; /* big enough for anything we need */
struct _VERXLATE
{
WORD wLanguage;
WORD wCodePage;
} *lpXlate; /* ptr to translations data */
int cXlate; /* count of translations */
LPTSTR pszXlate;
int cchXlateString;
TCHAR szFile[MAX_PATH];
} VERPROPSHEETPAGE, * LPVERPROPSHEETPAGE;
#define VER_KEY_END 25 /* length of "\StringFileInfo\xxxxyyyy\" */
/* (not localized) */
#define MAXMESSAGELEN (50 + MAXPATHLEN * 2)
/*
Gets a particular datum about a file. The file's version info
should have already been loaded by GetVersionInfo. If no datum
by the specified name is available, NULL is returned. The name
specified should be just the name of the item itself; it will
be concatenated onto "\StringFileInfo\xxxxyyyy\" automatically.
Version datum names are not localized, so it's OK to pass literals
such as "FileVersion" to this function.
Note that since the returned datum is in a global memory block,
the return value of this function is LPSTR, not PSTR.
*/
LPTSTR GetVersionDatum(LPVERPROPSHEETPAGE pvp, LPCTSTR pszName)
{
UINT cbValue = 0;
LPTSTR lpValue;
if (!pvp->hmemVersion)
return NULL;
lstrcpy(pvp->szVersionKey + VER_KEY_END, pszName);
g_pfnVerQueryValue(pvp->lpVersionBuffer, pvp->szVersionKey, (LPVOID *)&lpValue, &cbValue);
return (cbValue != 0) ? lpValue : NULL;
}
/*
Frees global version data about a file. After this call, all
GetVersionDatum calls will return NULL. To avoid memory leaks,
always call this before the main properties dialog exits.
*/
void FreeVersionInfo(LPVERPROPSHEETPAGE pvp)
{
if (pvp->hmemVersion) {
GlobalFree(pvp->hmemVersion);
pvp->hmemVersion = 0;
pvp->lpVersionBuffer = NULL;
}
if (pvp->pszXlate) {
LocalFree((HLOCAL)(HANDLE)pvp->pszXlate);
pvp->pszXlate = NULL;
}
pvp->lpXlate = NULL;
}
/*
Initialize version information for the properties dialog. The
above global variables are initialized by this function, and
remain valid (for the specified file only) until FreeVersionInfo
is called.
The first language we try will be the first item in the
"\VarFileInfo\Translations" section; if there's nothing there,
we try the one coded into the IDS_FILEVERSIONKEY resource string.
If we can't even load that, we just use English (040904E4). We
also try English with a null codepage (04090000) since many apps
were stamped according to an old spec which specified this as
the required language instead of 040904E4.
GetVersionInfo returns TRUE if the version info was read OK,
otherwise FALSE. If the return is FALSE, the buffer may still
have been allocated; always call FreeVersionInfo to be safe.
pszPath is modified by this call (pszName is appended).
*/
BOOL GetVersionInfo(LPVERPROPSHEETPAGE pvp, LPCTSTR pszPath)
{
UINT cbValue = 0;
LPTSTR lpszValue = NULL;
DWORD dwHandle; /* version subsystem handle */
DWORD dwVersionSize; /* size of the version data */
FreeVersionInfo(pvp); /* free old version buffer */
dwVersionSize = g_pfnGetFileVersionInfoSize(pszPath, &dwHandle);
if (dwVersionSize == 0L)
return FALSE; /* no version info */
pvp->hmemVersion = GlobalAlloc(GPTR, dwVersionSize);
if (pvp->hmemVersion == NULL)
return FALSE;
pvp->lpVersionBuffer = MAKELP(pvp->hmemVersion, 0);
if (!g_pfnGetFileVersionInfo(pszPath, dwHandle, dwVersionSize, pvp->lpVersionBuffer))
{
return(FALSE);
}
// Look for translations
if (g_pfnVerQueryValue(pvp->lpVersionBuffer, TEXT("\\VarFileInfo\\Translation"),
(LPVOID *)&pvp->lpXlate, &cbValue)
&& cbValue)
{
pvp->cXlate = cbValue / SIZEOF(DWORD);
pvp->cchXlateString = pvp->cXlate * 64; /* figure 64 chars per lang name */
pvp->pszXlate = (LPTSTR)(void*)LocalAlloc(LPTR, pvp->cchXlateString*SIZEOF(TCHAR));
// failure of above will be handled later
}
else
{
pvp->lpXlate = NULL;
}
// Try same language as this program
if (LoadString(HINST_THISDLL, IDS_VN_FILEVERSIONKEY, pvp->szVersionKey, ARRAYSIZE(pvp->szVersionKey)))
{
if (GetVersionDatum(pvp, vernames[0].pszName))
{
return(TRUE);
}
}
// Try first language this supports
if (pvp->lpXlate)
{
wsprintf(pvp->szVersionKey, TEXT("\\StringFileInfo\\%04X%04X\\"),
pvp->lpXlate[0].wLanguage, pvp->lpXlate[0].wCodePage);
if (GetVersionDatum(pvp, vernames[0].pszName)) /* a required field */
{
return TRUE;
}
}
#ifdef UNICODE
// try English, unicode code page
lstrcpy(pvp->szVersionKey, TEXT("\\StringFileInfo\\040904B0\\"));
if (GetVersionDatum(pvp, vernames[0].pszName))
{
return(TRUE);
}
#endif
// try English
lstrcpy(pvp->szVersionKey, TEXT("\\StringFileInfo\\040904E4\\"));
if (GetVersionDatum(pvp, vernames[0].pszName))
{
return(TRUE);
}
// try English, null codepage
lstrcpy(pvp->szVersionKey, TEXT("\\StringFileInfo\\04090000\\"));
if (GetVersionDatum(pvp, vernames[0].pszName))
{
return(TRUE);
}
// Could not find FileVersion info in a reasonable format
return(FALSE);
}
/*
Fills the version key listbox with all available keys in the
StringFileInfo block, and sets the version value text to the
value of the first item.
*/
void FillVersionList(LPVERPROPSHEETPAGE pvp)
{
LPTSTR lpszName;
LPTSTR lpszValue;
TCHAR szStringBase[VER_KEY_END+1];
int i, j, idx;
HWND hwndLB, hDlg;
TCHAR szMessage[MAXMESSAGELEN+1];
UINT uOffset, cbValue;
hDlg = pvp->hDlg;
hwndLB = GetDlgItem(hDlg, IDD_VERSION_KEY);
ListBox_ResetContent(hwndLB);
for (i=0; i<NUM_SPECIAL_STRINGS; ++i)
{
SetDlgItemText(hDlg, vernames[i].idString, szNULL);
}
pvp->szVersionKey[VER_KEY_END] = TEXT('\0'); /* don't copy too much */
lstrcpy(szStringBase, pvp->szVersionKey); /* copy to our buffer */
szStringBase[VER_KEY_END - 1] = TEXT('\0'); /* strip the backslash */
//
// Now iterate through all of the strings
//
for (j=0; g_pfnVerQueryValueIndex(pvp->lpVersionBuffer,
szStringBase,
j,
&lpszName,
&lpszValue,
&cbValue); j++)
{
for (i=0; i<ARRAYSIZE(vernames); i++)
{
if (!lstrcmp(vernames[i].pszName, lpszName))
{
break;
}
}
if (i < NUM_SPECIAL_STRINGS)
{
SetDlgItemText(hDlg, vernames[i].idString, lpszValue);
}
else
{
if (i==ARRAYSIZE(vernames) ||
!LoadString(HINST_THISDLL, vernames[i].idString, szMessage, ARRAYSIZE(szMessage)))
{
lstrcpy(szMessage, lpszName);
}
idx = ListBox_AddString(hwndLB, szMessage);
if (idx != LB_ERR)
{
ListBox_SetItemData(hwndLB, idx, (DWORD)lpszValue);
}
}
}
/*
Now look at the \VarFileInfo\Translations section and add an
item for the language(s) this file supports.
*/
if (pvp->lpXlate == NULL || pvp->pszXlate == NULL)
return;
if (!LoadString(HINST_THISDLL, (pvp->cXlate == 1) ? IDS_VN_LANGUAGE : IDS_VN_LANGUAGES,
szMessage, ARRAYSIZE(szMessage)))
return;
idx = ListBox_AddString(hwndLB, szMessage);
if (idx == LB_ERR)
return;
pvp->pszXlate[0] = 0;
uOffset = 0;
for (i = 0; i < pvp->cXlate; i++) {
if (uOffset + 2 > (UINT)pvp->cchXlateString)
break;
if (i != 0) {
lstrcat(pvp->pszXlate, TEXT(", "));
uOffset += 2; // skip over ", "
}
if (g_pfnVerLanguageName(pvp->lpXlate[i].wLanguage, pvp->pszXlate + uOffset, pvp->cchXlateString - uOffset) >
(DWORD)(pvp->cchXlateString - uOffset))
break;
uOffset += lstrlen(pvp->pszXlate + uOffset);
}
pvp->pszXlate[pvp->cchXlateString - 1] = 0;
ListBox_SetItemData(hwndLB, idx, (LPARAM)(LPTSTR)pvp->pszXlate);
ListBox_SetCurSel(hwndLB, 0);
FORWARD_WM_COMMAND(hDlg, IDD_VERSION_KEY, hwndLB, LBN_SELCHANGE, PostMessage);
}
//
// Function: _UpdateVersionPrsht, private
//
// Descriptions:
// This function fills fields of the "version" dialog box (a page of
// a property sheet) with attributes of the associated file.
//
// Arguments:
// hDlg -- specifies the dialog box
//
// Returns:
// TRUE, if successfully done; FALSE, otherwise.
//
// History:
// 01-06-93 Shrikant Created
//
BOOL _UpdateVersionPrsht(LPVERPROPSHEETPAGE pvp)
{
if ( GetVersionInfo(pvp, pvp->szFile) ) /* changes szPath */
FillVersionList(pvp);
return TRUE;
}
void _VersionPrshtCommand(HWND hwnd, int id, HWND hwndCtl, UINT codeNotify)
{
LPTSTR lpszValue;
int idx;
switch (id)
{
case IDD_VERSION_KEY:
if (codeNotify != LBN_SELCHANGE)
{
break;
}
idx = ListBox_GetCurSel(hwndCtl);
lpszValue = (LPTSTR)ListBox_GetItemData(hwndCtl, idx);
if (lpszValue)
{
SetDlgItemText(hwnd, IDD_VERSION_VALUE, lpszValue);
}
break;
}
}
//
// Function: _VersionPrshtDlgProc, dialog procedure
//
// Descriptions:
// This is the dialog procedure for the "version" page of a property sheet.
//
// Arguments:
// hDlg, uMessage, wParam, lParam -- specifies the message
//
// History:
// 04-31-93 Shrikant Created
//
BOOL CALLBACK _VersionPrshtDlgProc(HWND hDlg, UINT uMessage, WPARAM wParam, LPARAM lParam)
{
LPVERPROPSHEETPAGE pvp = (LPVERPROPSHEETPAGE)GetWindowLong(hDlg, DWL_USER);
// Array for context help:
static DWORD aVersionHelpIds[] = {
IDD_VERSION_FILEVERSION, IDH_FPROP_VER_ABOUT,
IDD_VERSION_DESCRIPTION, IDH_FPROP_VER_ABOUT,
IDD_VERSION_COPYRIGHT, IDH_FPROP_VER_ABOUT,
IDD_VERSION_FRAME, IDH_FPROP_VER_INFO,
IDD_VERSION_KEY, IDH_FPROP_VER_INFO,
IDD_VERSION_VALUE, IDH_FPROP_VER_INFO,
0, 0
};
switch (uMessage)
{
case WM_INITDIALOG:
SetWindowLong(hDlg, DWL_USER, lParam);
pvp = (LPVERPROPSHEETPAGE)lParam;
pvp->hDlg = hDlg;
break;
case WM_DESTROY:
FreeVersionInfo(pvp); // free anything we created
break;
case WM_HELP:
WinHelp((HWND) ((LPHELPINFO) lParam)->hItemHandle, NULL, HELP_WM_HELP,
(DWORD) (LPTSTR) aVersionHelpIds);
break;
case WM_CONTEXTMENU: // right mouse click
WinHelp((HWND) wParam, NULL, HELP_CONTEXTMENU,
(DWORD) (LPTSTR) aVersionHelpIds);
break;
case WM_NOTIFY:
switch (((NMHDR *)lParam)->code)
{
case PSN_SETACTIVE:
_UpdateVersionPrsht(pvp);
break;
}
break;
case WM_COMMAND:
HANDLE_WM_COMMAND(hDlg, wParam, lParam, _VersionPrshtCommand);
break;
default:
return FALSE;
}
return TRUE;
}
//
// Descriptions:
// This function creates a property sheet for the "version" page
// which shows version information.
//
void AddVersionPage(LPCTSTR pszFile, LPFNADDPROPSHEETPAGE pfnAddPage, LPARAM lParam)
{
HPROPSHEETPAGE hpage;
DWORD dwVerLen, dwVerHandle;
VERPROPSHEETPAGE vp;
// Make sure the Version dll is loaded properly
if (!VersionDLL_Init())
return; // nope it did not load properly.
// Note version.dll can not currently handle long file names
GetShortPathName(pszFile, vp.szFile, ARRAYSIZE(vp.szFile));
// REVIEW: do we need to free the dwVerHandle?
dwVerLen = g_pfnGetFileVersionInfoSize(vp.szFile, &dwVerHandle);
if (dwVerLen) {
vp.psp.dwSize = SIZEOF(VERPROPSHEETPAGE); // extra data
vp.psp.dwFlags = PSP_DEFAULT;
vp.psp.hInstance = HINST_THISDLL;
vp.psp.pszTemplate = MAKEINTRESOURCE(DLG_VERSION);
vp.psp.pfnDlgProc = _VersionPrshtDlgProc;
vp.hDlg = NULL;
vp.hmemVersion = NULL;
vp.lpVersionBuffer = NULL;
vp.szVersionKey[0] = TEXT('0');
vp.lpXlate = NULL;
vp.cXlate = 0;
vp.pszXlate = NULL;
vp.cchXlateString = 0;
hpage = CreatePropertySheetPage(&vp.psp);
if (hpage) {
if (!pfnAddPage(hpage, lParam))
DestroyPropertySheetPage(hpage);
}
}
}