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.
1226 lines
25 KiB
1226 lines
25 KiB
/*++
|
|
|
|
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 = JoinPathsInPoolExA ((
|
|
NULL,
|
|
"StringFileInfo",
|
|
VrValueEnum->TranslationStr,
|
|
VrValueEnum->VersionField,
|
|
NULL
|
|
));
|
|
|
|
if (!text) {
|
|
return NULL;
|
|
}
|
|
|
|
__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 {
|
|
FreePathStringA (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 = JoinPathsInPoolExW ((
|
|
NULL,
|
|
L"StringFileInfo",
|
|
VrValueEnum->TranslationStr,
|
|
VrValueEnum->VersionField,
|
|
NULL
|
|
));
|
|
|
|
if (!text) {
|
|
return NULL;
|
|
}
|
|
|
|
__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 {
|
|
FreePathStringW (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;
|
|
}
|