windows-nt/Source/XPSP1/NT/windows/winstate/cobra/utils/version/version.c
2020-09-26 16:20:57 +08:00

1237 lines
24 KiB
C

/*++
Copyright (c) 1996 Microsoft Corporation
Module Name:
version.c
Abstract:
Implements a set of enumeration routines to access version
information from a Win32 binary.
Author:
Jim Schmidt (jimschm) 03-Dec-1997
Revision History:
calinn 03-Sep-1999 Moved over from Win9xUpg project.
--*/
//
// Includes
//
#include "pch.h"
//
// Debug constants
//
#define DBG_VERSION "VerAPI"
//
// Strings
//
// None
//
// Constants
//
// None
//
// Macros
//
// None
//
// Types
//
// None
//
// Globals
//
PCSTR g_DefaultTranslationsA[] = {
"04090000",
"040904E4",
"040904B0",
NULL
};
PCWSTR g_DefaultTranslationsW[] = {
L"04090000",
L"040904E4",
L"040904B0",
NULL
};
//
// Macro expansion list
//
// None
//
// Private function prototypes
//
PCSTR
pVrEnumValueA (
IN OUT PVRVALUE_ENUMA VrValueEnum
);
PCWSTR
pVrEnumValueW (
IN OUT PVRVALUE_ENUMW VrValueEnum
);
PCSTR
pVrEnumNextTranslationA (
IN OUT PVRVALUE_ENUMA VrValueEnum
);
PCWSTR
pVrEnumNextTranslationW (
IN OUT PVRVALUE_ENUMW VrValueEnum
);
//
// Macro expansion definition
//
// None
//
// Code
//
/*++
Routine Description:
VrCreateEnumStructA and VrCreateEnumStructW are called to load a version
structure from a file and to obtain the fixed version stamp info that is
language-independent.
The caller must call VrDestroyEnumStruct after the VrValueEnum is no
longer needed.
Arguments:
VrValueEnum - Receives the version stamp info to be used by other
functions in this module
FileSpec - Specifies the file to obtain version information from
Return Value:
TRUE if the routine was able to get version info, or FALSE if an
error occurred.
--*/
BOOL
VrCreateEnumStructA (
OUT PVRVALUE_ENUMA VrValueEnum,
IN PCSTR FileSpec
)
{
//
// Initialize the structure
//
ZeroMemory (VrValueEnum, sizeof (VRVALUE_ENUMA));
VrValueEnum->FileSpec = FileSpec;
//
// Allocate enough memory for the version stamp
//
VrValueEnum->Size = GetFileVersionInfoSizeA (
(PSTR) FileSpec,
&VrValueEnum->Handle
);
if (!VrValueEnum->Size) {
DEBUGMSG ((DBG_VERSION, "File %s does not have version information", FileSpec));
return FALSE;
}
//
// fix for version info bug:
// allocate both buffers at once; this way the first buffer will not point to invalid
// memory when a reallocation occurs because of the second grow
//
VrValueEnum->VersionBuffer = GbGrow (&VrValueEnum->GrowBuf, VrValueEnum->Size * 2);
if (!VrValueEnum->VersionBuffer) {
return FALSE;
}
VrValueEnum->StringBuffer = VrValueEnum->GrowBuf.Buf + VrValueEnum->Size;
//
// Now get the version info from the file
//
if (!GetFileVersionInfoA (
(PSTR) FileSpec,
VrValueEnum->Handle,
VrValueEnum->Size,
VrValueEnum->VersionBuffer
)) {
VrDestroyEnumStructA (VrValueEnum);
return FALSE;
}
//
// Extract the fixed info
//
VerQueryValueA (
VrValueEnum->VersionBuffer,
"\\",
&VrValueEnum->FixedInfo,
&VrValueEnum->FixedInfoSize
);
return TRUE;
}
BOOL
VrCreateEnumStructW (
OUT PVRVALUE_ENUMW VrValueEnum,
IN PCWSTR FileSpec
)
{
ZeroMemory (VrValueEnum, sizeof (VRVALUE_ENUMW));
VrValueEnum->FileSpec = FileSpec;
//
// Allocate enough memory for the version stamp
//
VrValueEnum->Size = GetFileVersionInfoSizeW (
(PWSTR) FileSpec,
&VrValueEnum->Handle
);
if (!VrValueEnum->Size) {
DEBUGMSG ((DBG_VERSION, "File %S does not have version info", FileSpec));
return FALSE;
}
//
// fix for version info bug:
// allocate both buffers at once; this way the first buffer will not point to invalid
// memory when a reallocation occurs because of the second grow
//
VrValueEnum->VersionBuffer = GbGrow (&VrValueEnum->GrowBuf, VrValueEnum->Size * 2);
if (!VrValueEnum->VersionBuffer) {
return FALSE;
}
VrValueEnum->StringBuffer = VrValueEnum->GrowBuf.Buf + VrValueEnum->Size;
//
// Now get the version info from the file
//
if (!GetFileVersionInfoW (
(PWSTR) FileSpec,
VrValueEnum->Handle,
VrValueEnum->Size,
VrValueEnum->VersionBuffer
)) {
VrDestroyEnumStructW (VrValueEnum);
return FALSE;
}
//
// Extract the fixed info
//
VerQueryValueW (
VrValueEnum->VersionBuffer,
L"\\",
&VrValueEnum->FixedInfo,
&VrValueEnum->FixedInfoSize
);
return TRUE;
}
/*++
Routine Description:
VrDestroyEnumStructA and VrDestroyEnumStructW cleans up all memory
allocated by the routines in this module.
Arguments:
VrValueEnum - Specifies the structure to clean up
Return Value:
none
--*/
VOID
VrDestroyEnumStructA (
IN PVRVALUE_ENUMA VrValueEnum
)
{
//
// Clean up all allocations made by any routine using
// the VrValueEnum
//
if (VrValueEnum->GrowBuf.Buf) {
GbFree (&VrValueEnum->GrowBuf);
}
ZeroMemory (VrValueEnum, sizeof (VRVALUE_ENUMA));
}
VOID
VrDestroyEnumStructW (
IN PVRVALUE_ENUMW VrValueEnum
)
{
//
// Clean up all allocations made by any routine using
// the VrValueEnum
//
if (VrValueEnum->GrowBuf.Buf) {
GbFree (&VrValueEnum->GrowBuf);
}
ZeroMemory (VrValueEnum, sizeof (VRVALUE_ENUMW));
}
/*++
Routine Description:
pVrEnumFirstTranslationA and pVrEnumFirstTranslationW return the translation
string needed to access the string table of a version stamp.
Arguments:
VrValueEnum - Specifies the structure that has been initialized
by VrCreateEnumStruct.
Return Value:
A pointer to a string specifying the first translation, or
NULL if no translations exist.
--*/
PCSTR
pVrEnumFirstTranslationA (
IN OUT PVRVALUE_ENUMA VrValueEnum
)
{
UINT arraySize;
//
// Query version block for array of code pages/languages
//
if (!VerQueryValueA (
VrValueEnum->VersionBuffer,
"\\VarFileInfo\\Translation",
&VrValueEnum->Translations,
&arraySize
)) {
//
// No translations are available
//
arraySize = 0;
}
//
// Return a pointer to the first translation
//
VrValueEnum->CurrentDefaultTranslation = 0;
VrValueEnum->MaxTranslations = arraySize / sizeof (TRANSLATION);
VrValueEnum->CurrentTranslation = 0;
DEBUGMSG_IF ((
VrValueEnum->MaxTranslations == 0,
DBG_VERSION,
"File %s has no translations",
VrValueEnum->FileSpec
));
return pVrEnumNextTranslationA (VrValueEnum);
}
PCWSTR
pVrEnumFirstTranslationW (
IN OUT PVRVALUE_ENUMW VrValueEnum
)
{
UINT arraySize;
//
// Query version block for array of code pages/languages
//
if (!VerQueryValueW (
VrValueEnum->VersionBuffer,
L"\\VarFileInfo\\Translation",
&VrValueEnum->Translations,
&arraySize
)) {
//
// No translations are available
//
arraySize = 0;
}
//
// Return a pointer to the first translation
//
VrValueEnum->CurrentDefaultTranslation = 0;
VrValueEnum->MaxTranslations = arraySize / sizeof (TRANSLATION);
VrValueEnum->CurrentTranslation = 0;
DEBUGMSG_IF ((
VrValueEnum->MaxTranslations == 0,
DBG_VERSION,
"File %S has no translations",
VrValueEnum->FileSpec
));
return pVrEnumNextTranslationW (VrValueEnum);
}
/*++
Routine Description:
pIsDefaultTranslationA and pIsDefaultTranslationW return TRUE
if the specified translation string is enumerated by default.
These routines stops multiple enumeration of the same
translation string.
Arguments:
TranslationStr - Specifies the translation string to test
Return Value:
TRUE if the translation string is the same as a default translation
string, or FALSE if it is not.
--*/
BOOL
pIsDefaultTranslationA (
IN PCSTR TranslationStr
)
{
INT i;
for (i = 0 ; g_DefaultTranslationsA[i] ; i++) {
if (StringIMatchA (TranslationStr, g_DefaultTranslationsA[i])) {
return TRUE;
}
}
return FALSE;
}
BOOL
pIsDefaultTranslationW (
IN PCWSTR TranslationStr
)
{
INT i;
for (i = 0 ; g_DefaultTranslationsW[i] ; i++) {
if (StringIMatchW (TranslationStr, g_DefaultTranslationsW[i])) {
return TRUE;
}
}
return FALSE;
}
/*++
Routine Description:
pVrEnumNextTranslationA and pVrEnumNextTranslationW continue
the enumeration of translation strings, needed to access the
string table in a version stamp.
Arguments:
VrValueEnum - Specifies the same structure passed to
pVrEnumFirstTranslation.
Return Value:
A pointer to a string specifying the next translation, or
NULL if no additional translations exist.
--*/
PCSTR
pVrEnumNextTranslationA (
IN OUT PVRVALUE_ENUMA VrValueEnum
)
{
PTRANSLATION translation;
if (g_DefaultTranslationsA[VrValueEnum->CurrentDefaultTranslation]) {
//
// Return default translations first
//
StringCopyA (
VrValueEnum->TranslationStr,
g_DefaultTranslationsA[VrValueEnum->CurrentDefaultTranslation]
);
VrValueEnum->CurrentDefaultTranslation++;
} else {
do {
//
// Return NULL if all translations have been enumerated
//
if (VrValueEnum->CurrentTranslation == VrValueEnum->MaxTranslations) {
return NULL;
}
//
// Otherwise build translation string and return pointer to it
//
translation = &VrValueEnum->Translations[VrValueEnum->CurrentTranslation];
wsprintfA (
VrValueEnum->TranslationStr,
"%04x%04x",
translation->CodePage,
translation->Language
);
VrValueEnum->CurrentTranslation++;
} while (pIsDefaultTranslationA (VrValueEnum->TranslationStr));
}
return VrValueEnum->TranslationStr;
}
PCWSTR
pVrEnumNextTranslationW (
IN OUT PVRVALUE_ENUMW VrValueEnum
)
{
PTRANSLATION translation;
if (g_DefaultTranslationsW[VrValueEnum->CurrentDefaultTranslation]) {
StringCopyW (
VrValueEnum->TranslationStr,
g_DefaultTranslationsW[VrValueEnum->CurrentDefaultTranslation]
);
VrValueEnum->CurrentDefaultTranslation++;
} else {
do {
//
// Return NULL if all translations have been enumerated
//
if (VrValueEnum->CurrentTranslation == VrValueEnum->MaxTranslations) {
return NULL;
}
//
// Otherwise build translation string and return pointer to it
//
translation = &VrValueEnum->Translations[VrValueEnum->CurrentTranslation];
wsprintfW (
VrValueEnum->TranslationStr,
L"%04x%04x",
translation->CodePage,
translation->Language
);
VrValueEnum->CurrentTranslation++;
} while (pIsDefaultTranslationW (VrValueEnum->TranslationStr));
}
return VrValueEnum->TranslationStr;
}
/*++
Routine Description:
VrEnumFirstValueA and VrEnumFirstValueW return the first value
stored in a version stamp for a specific field. If the field
does not exist, the functions returns NULL.
An enumeration of VrEnumFirstValue/VrEnumNextValue
is used to list all localized strings for a field.
Arguments:
VrValueEnum - Specifies the structure that was initialized by
VrCreateEnumStruct.
VersionField - Specifies the name of the version field to enumerate
Return Value:
A pointer to the first value of the field, or NULL if the field does
not exist.
--*/
PCSTR
VrEnumFirstValueA (
IN OUT PVRVALUE_ENUMA VrValueEnum,
IN PCSTR VersionField
)
{
PCSTR result = NULL;
if (!pVrEnumFirstTranslationA (VrValueEnum)) {
return NULL;
}
VrValueEnum->VersionField = VersionField;
result = pVrEnumValueA (VrValueEnum);
if (!result) {
result = VrEnumNextValueA (VrValueEnum);
}
return result;
}
PCWSTR
VrEnumFirstValueW (
IN OUT PVRVALUE_ENUMW VrValueEnum,
IN PCWSTR VersionField
)
{
PCWSTR result = NULL;
if (!pVrEnumFirstTranslationW (VrValueEnum)) {
return NULL;
}
VrValueEnum->VersionField = VersionField;
result = pVrEnumValueW (VrValueEnum);
if (!result) {
result = VrEnumNextValueW (VrValueEnum);
}
return result;
}
/*++
Routine Description:
VrEnumNextValueA and VrEnumNextValueW return the next value
stored in a version stamp for a specific field.
Arguments:
VrValueEnum - Specifies the same structure passed to VrEnumFirstValue
Return Value:
A pointer to the next value of the field, or NULL if another field
does not exist.
--*/
PCSTR
VrEnumNextValueA (
IN OUT PVRVALUE_ENUMA VrValueEnum
)
{
PCSTR result = NULL;
do {
if (!pVrEnumNextTranslationA (VrValueEnum)) {
break;
}
result = pVrEnumValueA (VrValueEnum);
} while (!result);
return result;
}
PCWSTR
VrEnumNextValueW (
IN OUT PVRVALUE_ENUMW VrValueEnum
)
{
PCWSTR result = NULL;
do {
if (!pVrEnumNextTranslationW (VrValueEnum)) {
break;
}
result = pVrEnumValueW (VrValueEnum);
} while (!result);
return result;
}
/*++
Routine Description:
pVrEnumValueA and pVrEnumValueW are routines that obtain
the value of a version field. They are used for both
VrEnumFirstValue and VrEnumNextValue.
Arguments:
VrValueEnum - Specifies the structure being processed
Return Value:
A pointer to the version value for the current translation, or
NULL if the value does not exist for the current translation.
--*/
PCSTR
pVrEnumValueA (
IN OUT PVRVALUE_ENUMA VrValueEnum
)
{
PSTR text;
UINT stringLen;
PBYTE string;
PCSTR result = NULL;
//
// Prepare sub block for VerQueryValue API
//
text = AllocTextA (
SizeOfStringA (VrValueEnum->TranslationStr) +
SizeOfStringA (VrValueEnum->VersionField) +
16
);
if (!text) {
return NULL;
}
wsprintfA (
text,
"\\StringFileInfo\\%s\\%s",
VrValueEnum->TranslationStr,
VrValueEnum->VersionField
);
__try {
//
// Get the value from the version stamp
//
if (!VerQueryValueA (
VrValueEnum->VersionBuffer,
text,
&string,
&stringLen
)) {
//
// No value is available
//
__leave;
}
//
// Copy value into buffer
//
StringCopyByteCountA (VrValueEnum->StringBuffer, (PCSTR) string, stringLen);
result = (PCSTR)VrValueEnum->StringBuffer;
}
__finally {
FreeTextA (text);
}
return result;
}
PCWSTR
pVrEnumValueW (
IN OUT PVRVALUE_ENUMW VrValueEnum
)
{
PWSTR text;
UINT stringLen;
PBYTE string;
PCWSTR result = NULL;
//
// Prepare sub block for VerQueryValue API
//
text = AllocTextW (
18 +
CharCountW (VrValueEnum->TranslationStr) +
CharCountW (VrValueEnum->VersionField)
);
if (!text) {
return NULL;
}
wsprintfW (
text,
L"\\StringFileInfo\\%s\\%s",
VrValueEnum->TranslationStr,
VrValueEnum->VersionField
);
__try {
//
// Get the value from the version stamp
//
if (!VerQueryValueW (
VrValueEnum->VersionBuffer,
text,
&string,
&stringLen
)) {
//
// No value is available
//
__leave;
}
//
// Copy value into buffer
//
CopyMemory (VrValueEnum->StringBuffer, string, stringLen * sizeof (WCHAR));
VrValueEnum->StringBuffer [stringLen * sizeof (WCHAR)] = 0;
result = (PWSTR) VrValueEnum->StringBuffer;
}
__finally {
FreeTextW (text);
}
return result;
}
/*++
Routine Description:
VrCheckVersionValueA and VrCheckVersionValueW return TRUE
if the version value name specified has the specified version
value.
Arguments:
VrValueEnum - Specifies the structure being processed
VersionName - Specifies the version value name.
VersionValue - Specifies the version value.
Return value:
TRUE - the query was successful
FALSE - the query failed
--*/
BOOL
VrCheckVersionValueA (
IN PVRVALUE_ENUMA VrValueEnum,
IN PCSTR VersionName,
IN PCSTR VersionValue
)
{
PCSTR CurrentStr;
BOOL result = FALSE;
if ((!VersionName) || (!VersionValue)) {
return FALSE;
}
CurrentStr = VrEnumFirstValueA (VrValueEnum, VersionName);
while (CurrentStr) {
CurrentStr = SkipSpaceA (CurrentStr);
TruncateTrailingSpaceA ((PSTR) CurrentStr);
if (IsPatternMatchA (VersionValue, CurrentStr)) {
result = TRUE;
break;
}
CurrentStr = VrEnumNextValueA (VrValueEnum);
}
return result;
}
BOOL
VrCheckVersionValueW (
IN PVRVALUE_ENUMW VrValueEnum,
IN PCWSTR VersionName,
IN PCWSTR VersionValue
)
{
PCWSTR CurrentStr;
BOOL result = FALSE;
if ((!VersionName) || (!VersionValue)) {
return FALSE;
}
CurrentStr = VrEnumFirstValueW (VrValueEnum, VersionName);
while (CurrentStr) {
CurrentStr = SkipSpaceW (CurrentStr);
TruncateTrailingSpaceW ((PWSTR) CurrentStr);
if (IsPatternMatchW (VersionValue, CurrentStr)) {
result = TRUE;
break;
}
CurrentStr = VrEnumNextValueW (VrValueEnum);
}
return result;
}
ULONGLONG
VrGetBinaryFileVersionA (
IN PVRVALUE_ENUMA VrValueEnum
)
/*++
Routine Description:
VrGetBinaryFileVersion returns the FileVersion field from
the fixed info structure of version information.
Arguments:
VrValueEnum - Specifies the structure being processed
Return Value:
A ULONGLONG FileVersion field
--*/
{
ULONGLONG result = 0;
if (VrValueEnum->FixedInfoSize >= sizeof (VS_FIXEDFILEINFO)) {
*((PDWORD) (&result)) = VrValueEnum->FixedInfo->dwFileVersionLS;
*(((PDWORD) (&result)) + 1) = VrValueEnum->FixedInfo->dwFileVersionMS;
}
return result;
}
ULONGLONG
VrGetBinaryProductVersionA (
IN PVRVALUE_ENUMA VrValueEnum
)
/*++
Routine Description:
VrGetBinaryProductVersion returns the ProductVersion field from
the fixed info structure of version information.
Arguments:
VrValueEnum - Specifies the structure being processed
Return Value:
A ULONGLONG ProductVersion field
--*/
{
ULONGLONG result = 0;
if (VrValueEnum->FixedInfoSize >= sizeof (VS_FIXEDFILEINFO)) {
*((PDWORD) (&result)) = VrValueEnum->FixedInfo->dwProductVersionLS;
*(((PDWORD) (&result)) + 1) = VrValueEnum->FixedInfo->dwProductVersionMS;
}
return result;
}
DWORD
VrGetBinaryFileDateLoA (
IN PVRVALUE_ENUMA VrValueEnum
)
/*++
Routine Description:
VrGetBinaryFileDateLo returns the LS dword from FileDate field from
the fixed info structure of version information.
Arguments:
VrValueEnum - Specifies the structure being processed
Return Value:
A DWORD, LS dword of the FileDate field
--*/
{
if (VrValueEnum->FixedInfoSize >= sizeof (VS_FIXEDFILEINFO)) {
return VrValueEnum->FixedInfo->dwFileDateLS;
}
return 0;
}
DWORD
VrGetBinaryFileDateHiA (
IN PVRVALUE_ENUMA VrValueEnum
)
/*++
Routine Description:
VrGetBinaryFileDateHi returns the MS dword from FileDate field from
the fixed info structure of version information.
Arguments:
VrValueEnum - Specifies the structure being processed
Return Value:
A DWORD, MS dword of the FileDate field
--*/
{
if (VrValueEnum->FixedInfoSize >= sizeof (VS_FIXEDFILEINFO)) {
return VrValueEnum->FixedInfo->dwFileDateMS;
}
return 0;
}
DWORD
VrGetBinaryOsVersionA (
IN PVRVALUE_ENUMA VrValueEnum
)
/*++
Routine Description:
VrGetBinaryOsVersion returns the FileOS field from
the fixed info structure of version information.
Arguments:
VrValueEnum - Specifies the structure being processed
Return Value:
A DWORD FileOS field
--*/
{
if (VrValueEnum->FixedInfoSize >= sizeof (VS_FIXEDFILEINFO)) {
return VrValueEnum->FixedInfo->dwFileOS;
}
return 0;
}
DWORD
VrGetBinaryFileTypeA (
IN PVRVALUE_ENUMA VrValueEnum
)
/*++
Routine Description:
VrGetBinaryFileType returns the FileType field from
the fixed info structure of version information.
Arguments:
VrValueEnum - Specifies the structure being processed
Return Value:
A DWORD FileType field
--*/
{
if (VrValueEnum->FixedInfoSize >= sizeof (VS_FIXEDFILEINFO)) {
return VrValueEnum->FixedInfo->dwFileType;
}
return 0;
}
/*++
Routine Description:
VrCheckFileVersionA and VrCheckFileVersionW look in the file's version
structure trying to see if a specific name has a specific value.
Arguments:
FileName - File to query for version struct.
NameToCheck - Name to query in version structure.
ValueToCheck - Value to query in version structure.
Return value:
TRUE - the query was successful
FALSE - the query failed
--*/
BOOL
VrCheckFileVersionA (
IN PCSTR FileName,
IN PCSTR NameToCheck,
IN PCSTR ValueToCheck
)
{
VRVALUE_ENUMA Version;
PCSTR CurrentStr;
BOOL result = FALSE;
MYASSERT (NameToCheck);
MYASSERT (ValueToCheck);
if (VrCreateEnumStructA (&Version, FileName)) {
__try {
CurrentStr = VrEnumFirstValueA (&Version, NameToCheck);
while (CurrentStr) {
CurrentStr = SkipSpaceA (CurrentStr);
TruncateTrailingSpaceA ((PSTR) CurrentStr);
if (IsPatternMatchA (ValueToCheck, CurrentStr)) {
result = TRUE;
__leave;
}
CurrentStr = VrEnumNextValueA (&Version);
}
}
__finally {
VrDestroyEnumStructA (&Version);
}
}
return result;
}
BOOL
VrCheckFileVersionW (
IN PCWSTR FileName,
IN PCWSTR NameToCheck,
IN PCWSTR ValueToCheck
)
{
VRVALUE_ENUMW Version;
PCWSTR CurrentStr;
BOOL result = FALSE;
MYASSERT (NameToCheck);
MYASSERT (ValueToCheck);
if (VrCreateEnumStructW (&Version, FileName)) {
__try {
CurrentStr = VrEnumFirstValueW (&Version, NameToCheck);
while (CurrentStr) {
CurrentStr = SkipSpaceW (CurrentStr);
TruncateTrailingSpaceW ((PWSTR) CurrentStr);
if (IsPatternMatchW (ValueToCheck, CurrentStr)) {
result = TRUE;
__leave;
}
CurrentStr = VrEnumNextValueW (&Version);
}
}
__finally {
VrDestroyEnumStructW (&Version);
}
}
return result;
}