436 lines
8.9 KiB
C
436 lines
8.9 KiB
C
/*++
|
|
|
|
Copyright (c) 1997 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
version.c
|
|
|
|
Abstract:
|
|
|
|
Implements calls to version APIs.
|
|
|
|
Author:
|
|
|
|
Calin Negreanu (calinn) 20-Jan-1999
|
|
|
|
Revision History:
|
|
|
|
<alias> <date> <comments>
|
|
|
|
--*/
|
|
|
|
#include "utils.h"
|
|
#include "version.h"
|
|
|
|
static PCTSTR g_DefaultTranslations[] = {
|
|
TEXT("04090000"),
|
|
TEXT("040904E4"),
|
|
TEXT("040904B0"),
|
|
NULL
|
|
};
|
|
|
|
BOOL
|
|
ShCreateVersionStruct (
|
|
OUT PVERSION_STRUCT VersionStruct,
|
|
IN PCTSTR FileSpec
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
ShCreateVersionStruct is 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 ShDestroyVersionStruct after the VersionStruct is no
|
|
longer needed.
|
|
|
|
Arguments:
|
|
|
|
VersionStruct - Receives the version stamp info to be used by other
|
|
functions in this module
|
|
|
|
FileSpec - Specifies the file to obtain version info from
|
|
|
|
Return Value:
|
|
|
|
TRUE if the routine was able to get version info, or FALSE if an
|
|
error occurred.
|
|
|
|
--*/
|
|
|
|
{
|
|
ZeroMemory (VersionStruct, sizeof (VERSION_STRUCT));
|
|
VersionStruct->FileSpec = FileSpec;
|
|
|
|
//
|
|
// Allocate enough memory for the version stamp
|
|
//
|
|
|
|
VersionStruct->Size = GetFileVersionInfoSize (
|
|
(PTSTR) FileSpec,
|
|
&VersionStruct->Handle
|
|
);
|
|
if (!VersionStruct->Size) {
|
|
return FALSE;
|
|
}
|
|
|
|
VersionStruct->VersionBuffer = HeapAlloc (GetProcessHeap (), 0, VersionStruct->Size);
|
|
|
|
if (!VersionStruct->VersionBuffer) {
|
|
return FALSE;
|
|
}
|
|
|
|
VersionStruct->StringBuffer = HeapAlloc (GetProcessHeap (), 0, VersionStruct->Size);
|
|
|
|
if (!VersionStruct->StringBuffer) {
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
//
|
|
// Now get the version info from the file
|
|
//
|
|
|
|
if (!GetFileVersionInfo (
|
|
(PTSTR) FileSpec,
|
|
VersionStruct->Handle,
|
|
VersionStruct->Size,
|
|
VersionStruct->VersionBuffer
|
|
)) {
|
|
ShDestroyVersionStruct (VersionStruct);
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Extract the fixed info
|
|
//
|
|
|
|
VerQueryValue (
|
|
VersionStruct->VersionBuffer,
|
|
TEXT("\\"),
|
|
&VersionStruct->FixedInfo,
|
|
&VersionStruct->FixedInfoSize
|
|
);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
VOID
|
|
ShDestroyVersionStruct (
|
|
IN PVERSION_STRUCT VersionStruct
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
ShDestroyVersionStruct cleans up all memory allocated by the routines
|
|
in this module.
|
|
|
|
Arguments:
|
|
|
|
VersionStruct - Specifies the structure to clean up
|
|
|
|
Return Value:
|
|
|
|
none
|
|
|
|
--*/
|
|
|
|
{
|
|
if (VersionStruct->VersionBuffer) {
|
|
HeapFree (GetProcessHeap (), 0, VersionStruct->VersionBuffer);
|
|
}
|
|
if (VersionStruct->StringBuffer) {
|
|
HeapFree (GetProcessHeap (), 0, VersionStruct->StringBuffer);
|
|
}
|
|
|
|
ZeroMemory (VersionStruct, sizeof (VERSION_STRUCT));
|
|
}
|
|
|
|
|
|
ULONGLONG
|
|
ShVerGetFileVer (
|
|
IN PVERSION_STRUCT VersionStruct
|
|
)
|
|
{
|
|
ULONGLONG result = 0;
|
|
if (VersionStruct->FixedInfoSize >= sizeof (VS_FIXEDFILEINFO)) {
|
|
*((PDWORD) (&result)) = VersionStruct->FixedInfo->dwFileVersionLS;
|
|
*(((PDWORD) (&result)) + 1) = VersionStruct->FixedInfo->dwFileVersionMS;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
ULONGLONG
|
|
ShVerGetProductVer (
|
|
IN PVERSION_STRUCT VersionStruct
|
|
)
|
|
{
|
|
ULONGLONG result = 0;
|
|
if (VersionStruct->FixedInfoSize >= sizeof (VS_FIXEDFILEINFO)) {
|
|
*((PDWORD) (&result)) = VersionStruct->FixedInfo->dwProductVersionLS;
|
|
*(((PDWORD) (&result)) + 1) = VersionStruct->FixedInfo->dwProductVersionMS;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
DWORD
|
|
ShVerGetFileDateLo (
|
|
IN PVERSION_STRUCT VersionStruct
|
|
)
|
|
{
|
|
if (VersionStruct->FixedInfoSize >= sizeof (VS_FIXEDFILEINFO)) {
|
|
return VersionStruct->FixedInfo->dwFileDateLS;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
DWORD
|
|
ShVerGetFileDateHi (
|
|
IN PVERSION_STRUCT VersionStruct
|
|
)
|
|
{
|
|
if (VersionStruct->FixedInfoSize >= sizeof (VS_FIXEDFILEINFO)) {
|
|
return VersionStruct->FixedInfo->dwFileDateMS;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
DWORD
|
|
ShVerGetFileVerOs (
|
|
IN PVERSION_STRUCT VersionStruct
|
|
)
|
|
{
|
|
if (VersionStruct->FixedInfoSize >= sizeof (VS_FIXEDFILEINFO)) {
|
|
return VersionStruct->FixedInfo->dwFileOS;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
DWORD
|
|
ShVerGetFileVerType (
|
|
IN PVERSION_STRUCT VersionStruct
|
|
)
|
|
{
|
|
if (VersionStruct->FixedInfoSize >= sizeof (VS_FIXEDFILEINFO)) {
|
|
return VersionStruct->FixedInfo->dwFileType;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
PCTSTR
|
|
pShEnumVersionValueCommon (
|
|
IN OUT PVERSION_STRUCT VersionStruct
|
|
);
|
|
|
|
PCTSTR
|
|
pShEnumNextVersionTranslation (
|
|
IN OUT PVERSION_STRUCT VersionStruct
|
|
);
|
|
|
|
PCTSTR
|
|
pShEnumFirstVersionTranslation (
|
|
IN OUT PVERSION_STRUCT VersionStruct
|
|
)
|
|
{
|
|
UINT ArraySize;
|
|
|
|
if (!VerQueryValue (
|
|
VersionStruct->VersionBuffer,
|
|
TEXT("\\VarFileInfo\\Translation"),
|
|
&VersionStruct->Translations,
|
|
&ArraySize
|
|
)) {
|
|
//
|
|
// No translations are available
|
|
//
|
|
|
|
ArraySize = 0;
|
|
}
|
|
|
|
//
|
|
// Return a pointer to the first translation
|
|
//
|
|
|
|
VersionStruct->CurrentDefaultTranslation = 0;
|
|
VersionStruct->MaxTranslations = ArraySize / sizeof (TRANSLATION);
|
|
VersionStruct->CurrentTranslation = 0;
|
|
|
|
return pShEnumNextVersionTranslation (VersionStruct);
|
|
}
|
|
|
|
BOOL
|
|
pShIsDefaultTranslation (
|
|
IN PCTSTR TranslationStr
|
|
)
|
|
{
|
|
INT i;
|
|
|
|
for (i = 0 ; g_DefaultTranslations[i] ; i++) {
|
|
if (lstrcmpi (TranslationStr, g_DefaultTranslations[i]) == 0) {
|
|
return TRUE;
|
|
}
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
PCTSTR
|
|
pShEnumNextVersionTranslation (
|
|
IN OUT PVERSION_STRUCT VersionStruct
|
|
)
|
|
{
|
|
PTRANSLATION Translation;
|
|
|
|
if (g_DefaultTranslations[VersionStruct->CurrentDefaultTranslation]) {
|
|
|
|
lstrcpy (VersionStruct->TranslationStr, g_DefaultTranslations[VersionStruct->CurrentDefaultTranslation]);
|
|
VersionStruct->CurrentDefaultTranslation++;
|
|
|
|
} else {
|
|
|
|
do {
|
|
if (VersionStruct->CurrentTranslation == VersionStruct->MaxTranslations) {
|
|
return NULL;
|
|
}
|
|
|
|
Translation = &VersionStruct->Translations[VersionStruct->CurrentTranslation];
|
|
|
|
wsprintf (
|
|
VersionStruct->TranslationStr,
|
|
TEXT("%04x%04x"),
|
|
Translation->CodePage,
|
|
Translation->Language
|
|
);
|
|
|
|
VersionStruct->CurrentTranslation++;
|
|
|
|
} while (pShIsDefaultTranslation (VersionStruct->TranslationStr));
|
|
}
|
|
|
|
return VersionStruct->TranslationStr;
|
|
}
|
|
|
|
|
|
PCTSTR
|
|
pShEnumNextVersionValue (
|
|
IN OUT PVERSION_STRUCT VersionStruct
|
|
)
|
|
{
|
|
PCTSTR rc = NULL;
|
|
|
|
do {
|
|
if (!pShEnumNextVersionTranslation (VersionStruct)) {
|
|
break;
|
|
}
|
|
|
|
rc = pShEnumVersionValueCommon (VersionStruct);
|
|
|
|
} while (!rc);
|
|
|
|
return rc;
|
|
}
|
|
|
|
PCTSTR
|
|
pShEnumFirstVersionValue (
|
|
IN OUT PVERSION_STRUCT VersionStruct,
|
|
IN PCTSTR VersionField
|
|
)
|
|
{
|
|
PCTSTR rc;
|
|
|
|
if (!pShEnumFirstVersionTranslation (VersionStruct)) {
|
|
return NULL;
|
|
}
|
|
|
|
VersionStruct->VersionField = VersionField;
|
|
|
|
rc = pShEnumVersionValueCommon (VersionStruct);
|
|
|
|
if (!rc) {
|
|
rc = pShEnumNextVersionValue (VersionStruct);
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
PCTSTR
|
|
pShEnumVersionValueCommon (
|
|
IN OUT PVERSION_STRUCT VersionStruct
|
|
)
|
|
{
|
|
PTSTR Text;
|
|
UINT StringLen;
|
|
PBYTE String;
|
|
PCTSTR Result = NULL;
|
|
|
|
//
|
|
// Prepare sub block for VerQueryValue API
|
|
//
|
|
Text = HeapAlloc (GetProcessHeap (), 0, (18 + lstrlen (VersionStruct->TranslationStr) + lstrlen (VersionStruct->VersionField)) * sizeof (TCHAR));
|
|
|
|
if (!Text) {
|
|
return NULL;
|
|
}
|
|
|
|
wsprintf (
|
|
Text,
|
|
TEXT("\\StringFileInfo\\%s\\%s"),
|
|
VersionStruct->TranslationStr,
|
|
VersionStruct->VersionField
|
|
);
|
|
|
|
__try {
|
|
//
|
|
// Get the value from the version stamp
|
|
//
|
|
|
|
if (!VerQueryValue (
|
|
VersionStruct->VersionBuffer,
|
|
Text,
|
|
&String,
|
|
&StringLen
|
|
)) {
|
|
//
|
|
// No value is available
|
|
//
|
|
|
|
return NULL;
|
|
}
|
|
CopyMemory (VersionStruct->StringBuffer, String, StringLen * sizeof (TCHAR));
|
|
VersionStruct->StringBuffer [StringLen * sizeof (TCHAR)] = 0;
|
|
Result = (PTSTR) VersionStruct->StringBuffer;
|
|
|
|
}
|
|
__finally {
|
|
HeapFree (GetProcessHeap (), 0, Text);
|
|
}
|
|
|
|
return Result;
|
|
}
|
|
|
|
BOOL
|
|
ShGlobalVersionCheck (
|
|
IN PVERSION_STRUCT VersionData,
|
|
IN PCTSTR NameToCheck,
|
|
IN PCTSTR ValueToCheck
|
|
)
|
|
{
|
|
PCTSTR CurrentStr;
|
|
BOOL result = FALSE;
|
|
|
|
CurrentStr = pShEnumFirstVersionValue (VersionData, NameToCheck);
|
|
while (CurrentStr) {
|
|
if (ShIsPatternMatch (ValueToCheck, CurrentStr)) {
|
|
result = TRUE;
|
|
break;
|
|
}
|
|
CurrentStr = pShEnumNextVersionValue (VersionData);
|
|
}
|
|
return result;
|
|
}
|
|
|