2020 lines
72 KiB
C++
2020 lines
72 KiB
C++
/****************************************************************************
|
|
*
|
|
* File: fileinfo.cpp
|
|
* Project: DxDiag (DirectX Diagnostic Tool)
|
|
* Author: Mike Anderson (manders@microsoft.com)
|
|
* Purpose: Gather information about files on this machine
|
|
*
|
|
* (C) Copyright 1998 Microsoft Corp. All rights reserved.
|
|
*
|
|
****************************************************************************/
|
|
|
|
#include <tchar.h>
|
|
#include <Windows.h>
|
|
#include <mmsystem.h>
|
|
#include <stdio.h>
|
|
#include <capi.h>
|
|
#include <softpub.h>
|
|
#include <winsock.h>
|
|
#include "sysinfo.h" // for BIsPlatformNT
|
|
#include "fileinfo.h"
|
|
#include "resource.h"
|
|
|
|
// MsCat32.dll function prototypes
|
|
typedef BOOL (WINAPI* PfnCryptCATAdminAcquireContext)(OUT HCATADMIN *phCatAdmin,
|
|
IN const GUID *pgSubsystem,
|
|
IN DWORD dwFlags);
|
|
typedef BOOL (WINAPI* PfnCryptCATAdminReleaseContext)(IN HCATADMIN hCatAdmin,
|
|
IN DWORD dwFlags);
|
|
typedef BOOL (WINAPI* PfnCryptCATAdminReleaseCatalogContext)(IN HCATADMIN hCatAdmin,
|
|
IN HCATINFO hCatInfo,
|
|
IN DWORD dwFlags);
|
|
typedef BOOL (WINAPI* PfnCryptCATCatalogInfoFromContext)(IN HCATINFO hCatInfo,
|
|
IN OUT CATALOG_INFO *psCatInfo,
|
|
IN DWORD dwFlags);
|
|
typedef HCATINFO (WINAPI* PfnCryptCATAdminEnumCatalogFromHash)(IN HCATADMIN hCatAdmin,
|
|
IN BYTE *pbHash,
|
|
IN DWORD cbHash,
|
|
IN DWORD dwFlags,
|
|
IN OUT HCATINFO *phPrevCatInfo);
|
|
typedef BOOL (WINAPI* PfnIsCatalogFile)(IN OPTIONAL HANDLE hFile,
|
|
IN OPTIONAL WCHAR *pwszFileName);
|
|
typedef BOOL (WINAPI* PfnCryptCATAdminCalcHashFromFileHandle)(IN HANDLE hFile,
|
|
IN OUT DWORD *pcbHash,
|
|
OUT OPTIONAL BYTE *pbHash,
|
|
IN DWORD dwFlags);
|
|
|
|
// WinTrust.dll function prototypes
|
|
typedef HRESULT (WINAPI* PfnWinVerifyTrust)(HWND hWnd,
|
|
GUID *pgActionID,
|
|
WINTRUST_DATA *pWinTrustData);
|
|
|
|
// Crypt32.dll function prototypes
|
|
typedef BOOL (WINAPI* PfnCertFreeCertificateContext)(IN PCCERT_CONTEXT pCertContext);
|
|
|
|
struct DigiSignData
|
|
{
|
|
BOOL bInitialized;
|
|
BOOL bFailed;
|
|
|
|
// Need to LoadLibrary/GetProcAddress for mscat32 APIs since they
|
|
// don't exist on Win95
|
|
HINSTANCE hInstMsCat32;
|
|
PfnCryptCATAdminAcquireContext CryptCATAdminAcquireContext;
|
|
PfnCryptCATAdminReleaseContext CryptCATAdminReleaseContext;
|
|
PfnCryptCATAdminReleaseCatalogContext CryptCATAdminReleaseCatalogContext;
|
|
PfnCryptCATCatalogInfoFromContext CryptCATCatalogInfoFromContext;
|
|
PfnCryptCATAdminEnumCatalogFromHash CryptCATAdminEnumCatalogFromHash;
|
|
PfnIsCatalogFile IsCatalogFile;
|
|
PfnCryptCATAdminCalcHashFromFileHandle CryptCATAdminCalcHashFromFileHandle;
|
|
|
|
// Ditto for wintrust.dll APIs
|
|
HINSTANCE hInstWinTrust;
|
|
PfnWinVerifyTrust WinVerifyTrust;
|
|
|
|
// Ditto for cypt32.dll APIs
|
|
HINSTANCE hInstCrypt32;
|
|
PfnCertFreeCertificateContext CertFreeCertificateContext;
|
|
|
|
HCATADMIN hCatAdmin;
|
|
};
|
|
|
|
static DigiSignData s_dsd;
|
|
|
|
static BOOL GetMediaPlayerFolder(TCHAR* pszPath);
|
|
static BOOL FileIsSignedOld(LPTSTR lpszFile);
|
|
static BOOL VerifyFileNode(TCHAR* lpFileName, TCHAR* lpDirName);
|
|
static BOOL VerifyIsFileSigned(LPTSTR pcszMatchFile, PDRIVER_VER_INFO lpVerInfo);
|
|
static BOOL InitDigiSignData(VOID);
|
|
static BOOL IsFileDigitallySigned(TCHAR* pszFile);
|
|
static BOOL IsBadWin95Winsock( FileInfo* pFileInfo );
|
|
|
|
|
|
/****************************************************************************
|
|
*
|
|
* GetProgramFilesFolder
|
|
*
|
|
****************************************************************************/
|
|
VOID InitFileInfo()
|
|
{
|
|
ZeroMemory(&s_dsd, sizeof(s_dsd));
|
|
s_dsd.bFailed = FALSE;
|
|
s_dsd.bInitialized = FALSE;
|
|
}
|
|
|
|
|
|
/****************************************************************************
|
|
*
|
|
* GetProgramFilesFolder
|
|
*
|
|
****************************************************************************/
|
|
BOOL GetProgramFilesFolder(TCHAR* pszPath)
|
|
{
|
|
HKEY hkey;
|
|
DWORD dwType;
|
|
DWORD cb;
|
|
|
|
if (ERROR_SUCCESS != RegOpenKey(HKEY_LOCAL_MACHINE,
|
|
TEXT("Software\\Microsoft\\Windows\\CurrentVersion"), &hkey))
|
|
{
|
|
return FALSE;
|
|
}
|
|
cb = MAX_PATH;
|
|
RegQueryValueEx(hkey, TEXT("ProgramFilesDir"), NULL, &dwType, (LPBYTE)pszPath, &cb);
|
|
RegCloseKey(hkey);
|
|
if (cb == 0)
|
|
return FALSE;
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
/****************************************************************************
|
|
*
|
|
* FormatFileTime
|
|
*
|
|
****************************************************************************/
|
|
VOID FormatFileTime(FILETIME* pUTCFileTime, TCHAR* pszDateLocal, TCHAR* pszDateEnglish)
|
|
{
|
|
FILETIME fileTimeLocal;
|
|
SYSTEMTIME systemTime;
|
|
TCHAR szTime[100];
|
|
|
|
FileTimeToLocalFileTime(pUTCFileTime, &fileTimeLocal);
|
|
FileTimeToSystemTime(&fileTimeLocal, &systemTime);
|
|
wsprintf(pszDateEnglish, TEXT("%d/%d/%04d %02d:%02d:%02d"),
|
|
systemTime.wMonth, systemTime.wDay, systemTime.wYear,
|
|
systemTime.wHour, systemTime.wMinute, systemTime.wSecond);
|
|
GetDateFormat(LOCALE_USER_DEFAULT, DATE_SHORTDATE, &systemTime, NULL, pszDateLocal, 30);
|
|
wsprintf(szTime, TEXT(" %02d:%02d:%02d"), systemTime.wHour,
|
|
systemTime.wMinute, systemTime.wSecond);
|
|
lstrcat(pszDateLocal, szTime);
|
|
}
|
|
|
|
|
|
/****************************************************************************
|
|
*
|
|
* GetMediaPlayerFolder
|
|
*
|
|
****************************************************************************/
|
|
BOOL GetMediaPlayerFolder(TCHAR* pszPath)
|
|
{
|
|
HKEY hkey;
|
|
DWORD dwType;
|
|
DWORD cb;
|
|
|
|
if (ERROR_SUCCESS != RegOpenKey(HKEY_LOCAL_MACHINE,
|
|
TEXT("Software\\Microsoft\\MediaPlayer"), &hkey))
|
|
{
|
|
return FALSE;
|
|
}
|
|
cb = MAX_PATH;
|
|
RegQueryValueEx(hkey, TEXT("Installation Directory"), NULL, &dwType, (LPBYTE)pszPath, &cb);
|
|
RegCloseKey(hkey);
|
|
if (cb == 0)
|
|
return FALSE;
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
/****************************************************************************
|
|
*
|
|
* GetDxSetupFolder
|
|
*
|
|
****************************************************************************/
|
|
BOOL GetDxSetupFolder(TCHAR* pszPath)
|
|
{
|
|
if (!GetProgramFilesFolder(pszPath))
|
|
return FALSE;
|
|
lstrcat(pszPath, TEXT("\\DirectX\\Setup"));
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
/****************************************************************************
|
|
*
|
|
* GetComponentFiles
|
|
*
|
|
****************************************************************************/
|
|
HRESULT GetComponentFiles(TCHAR* pszFolder, FileInfo** ppFileInfoFirst,
|
|
BOOL bSkipMissingFiles, LONG ids)
|
|
{
|
|
LONG cch;
|
|
FileInfo* pFileInfo;
|
|
FileInfo* pFileInfoNew;
|
|
LONG iFile;
|
|
TCHAR szFile[50];
|
|
TCHAR szPath[MAX_PATH];
|
|
TCHAR szComponentFiles[2048];
|
|
TCHAR* pszFilePos;
|
|
TCHAR* pszFilePos2;
|
|
TCHAR* pszFirstParen;
|
|
FLOAT fStartShipAt;
|
|
FLOAT fStopShipAt;
|
|
BOOL bDriversDir;
|
|
BOOL bNTDriversDir;
|
|
BOOL bIgnoreVersionInfo;
|
|
BOOL bIgnoreDebug;
|
|
BOOL bIgnoreBeta;
|
|
BOOL bBDA;
|
|
BOOL bNotIA64;
|
|
BOOL bOptional;
|
|
BOOL bOptionalOnNT;
|
|
BOOL bOptionalOnWOW64;
|
|
BOOL bIsNT = BIsPlatformNT();
|
|
BOOL bIs95 = BIsWin95();
|
|
|
|
cch = LoadString(NULL, ids, szComponentFiles, 2048);
|
|
if (cch == 0 || cch >= 2047)
|
|
return E_FAIL;
|
|
pszFilePos = szComponentFiles;
|
|
|
|
for (iFile = 0; ; iFile++)
|
|
{
|
|
// Stop if we've gone through the whole list
|
|
if (pszFilePos == NULL)
|
|
break;
|
|
|
|
// Pull the next file out of the list
|
|
pszFilePos2 = _tcsstr(pszFilePos, TEXT(","));
|
|
if (pszFilePos2 == NULL)
|
|
{
|
|
lstrcpy(szFile, pszFilePos);
|
|
pszFilePos = NULL;
|
|
}
|
|
else
|
|
{
|
|
_tcsncpy(szFile, pszFilePos, (DWORD)(pszFilePos2 - pszFilePos));
|
|
szFile[pszFilePos2 - pszFilePos] = '\0';
|
|
pszFilePos = pszFilePos2 + 1;
|
|
}
|
|
|
|
// Clear file flags
|
|
fStartShipAt = 0.0f;
|
|
fStopShipAt = 10000.0f;
|
|
bDriversDir = FALSE;
|
|
bNTDriversDir = FALSE;
|
|
bIgnoreVersionInfo = FALSE;
|
|
bIgnoreDebug = FALSE;
|
|
bIgnoreBeta = FALSE;
|
|
bBDA = FALSE;
|
|
bNotIA64 = FALSE;
|
|
bOptional = FALSE;
|
|
bOptionalOnNT = FALSE;
|
|
bOptionalOnWOW64 = FALSE;
|
|
|
|
// Look at file flags, if any
|
|
pszFirstParen = _tcsstr(szFile, TEXT("("));
|
|
if (pszFirstParen != NULL)
|
|
{
|
|
|
|
// If this file does not exist on NT, and we are running NT, skip it.
|
|
if (_tcsstr(pszFirstParen, TEXT("notNT")) != NULL && bIsNT)
|
|
continue;
|
|
|
|
// If this file does not exist on W95, and we are running W95, skip it.
|
|
if (_tcsstr(pszFirstParen, TEXT("not95")) != NULL && bIs95)
|
|
continue;
|
|
|
|
// If this file only exists on W95, and we are not running W95, skip it.
|
|
// Note: files like vjoyd.vxd may exist on Win98, but DX setup does not
|
|
// install them or update them, so we ignore them.
|
|
// Note: can't call this "95only" because it would clash with "5only"
|
|
if (_tcsstr(pszFirstParen, TEXT("9fiveonly")) != NULL && !bIs95)
|
|
continue;
|
|
|
|
// Check for other flags
|
|
if (_tcsstr(pszFirstParen, TEXT("+")) != NULL)
|
|
{
|
|
if (_tcsstr(pszFirstParen, TEXT("+5")) != NULL)
|
|
fStartShipAt = 5.0f;
|
|
else if (_tcsstr(pszFirstParen, TEXT("+61")) != NULL)
|
|
fStartShipAt = 6.1f;
|
|
else if (_tcsstr(pszFirstParen, TEXT("+6")) != NULL)
|
|
fStartShipAt = 6.0f;
|
|
else if (_tcsstr(pszFirstParen, TEXT("+71")) != NULL)
|
|
fStartShipAt = 7.1f;
|
|
else if (_tcsstr(pszFirstParen, TEXT("+7")) != NULL)
|
|
fStartShipAt = 7.0f;
|
|
else if (_tcsstr(pszFirstParen, TEXT("+81")) != NULL)
|
|
fStartShipAt = 8.1f;
|
|
else if (_tcsstr(pszFirstParen, TEXT("+8")) != NULL)
|
|
fStartShipAt = 8.0f;
|
|
}
|
|
|
|
if (_tcsstr(pszFirstParen, TEXT("-")) != NULL)
|
|
{
|
|
if (_tcsstr(pszFirstParen, TEXT("-5")) != NULL)
|
|
fStopShipAt = 5.0f;
|
|
else if (_tcsstr(pszFirstParen, TEXT("-61")) != NULL)
|
|
fStopShipAt = 6.1f;
|
|
else if (_tcsstr(pszFirstParen, TEXT("-6")) != NULL)
|
|
fStopShipAt = 6.0f;
|
|
else if (_tcsstr(pszFirstParen, TEXT("-71")) != NULL)
|
|
fStopShipAt = 7.1f;
|
|
else if (_tcsstr(pszFirstParen, TEXT("-7")) != NULL)
|
|
fStopShipAt = 7.0f;
|
|
else if (_tcsstr(pszFirstParen, TEXT("-81")) != NULL)
|
|
fStopShipAt = 8.1f;
|
|
else if (_tcsstr(pszFirstParen, TEXT("-8")) != NULL)
|
|
fStopShipAt = 8.0f;
|
|
}
|
|
|
|
// Note: can't call this "DriversDir" because it would clash with "NTDriversDir"
|
|
if (_tcsstr(pszFirstParen, TEXT("DrivDir")) != NULL)
|
|
bDriversDir = TRUE;
|
|
if (_tcsstr(pszFirstParen, TEXT("NTDriversDir")) != NULL)
|
|
bNTDriversDir = TRUE;
|
|
|
|
if (_tcsstr(pszFirstParen, TEXT("SkipVer")) != NULL)
|
|
bIgnoreVersionInfo = TRUE;
|
|
if (_tcsstr(pszFirstParen, TEXT("SkipDebug")) != NULL)
|
|
bIgnoreDebug = TRUE;
|
|
if (_tcsstr(pszFirstParen, TEXT("SkipBeta")) != NULL)
|
|
bIgnoreBeta = TRUE;
|
|
|
|
if (_tcsstr(pszFirstParen, TEXT("notia64")) != NULL)
|
|
bNotIA64 = TRUE;
|
|
|
|
if (_tcsstr(pszFirstParen, TEXT("optnt")) != NULL)
|
|
bOptionalOnNT = TRUE;
|
|
else if (_tcsstr(pszFirstParen, TEXT("optwow")) != NULL)
|
|
bOptionalOnWOW64 = TRUE;
|
|
else if (_tcsstr(pszFirstParen, TEXT("opt")) != NULL)
|
|
bOptional = TRUE;
|
|
|
|
if (_tcsstr(pszFirstParen, TEXT("bda")) != NULL)
|
|
{
|
|
bBDA = TRUE;
|
|
bOptional = TRUE;
|
|
bIgnoreVersionInfo = TRUE;
|
|
}
|
|
|
|
// End file name at open parenthesis, if any:
|
|
*pszFirstParen = TEXT('\0');
|
|
}
|
|
|
|
pFileInfoNew = new FileInfo;
|
|
if (pFileInfoNew == NULL)
|
|
return E_OUTOFMEMORY;
|
|
ZeroMemory(pFileInfoNew, sizeof(FileInfo));
|
|
|
|
pFileInfoNew->m_fStartShipAt = fStartShipAt;
|
|
pFileInfoNew->m_fStopShipAt = fStopShipAt;
|
|
pFileInfoNew->m_bIgnoreVersionInfo = bIgnoreVersionInfo;
|
|
pFileInfoNew->m_bIgnoreDebug = bIgnoreDebug;
|
|
pFileInfoNew->m_bIgnoreBeta = bIgnoreBeta;
|
|
pFileInfoNew->m_bBDA = bBDA;
|
|
pFileInfoNew->m_bNotIA64 = bNotIA64;
|
|
pFileInfoNew->m_bOptional = bOptional;
|
|
pFileInfoNew->m_bOptionalOnNT = bOptionalOnNT;
|
|
pFileInfoNew->m_bOptionalOnWOW64 = bOptionalOnWOW64;
|
|
lstrcpy(pFileInfoNew->m_szName, szFile);
|
|
lstrcpy(szPath, pszFolder);
|
|
lstrcat(szPath, TEXT("\\"));
|
|
|
|
if (bNTDriversDir && bIsNT)
|
|
lstrcat(szPath, TEXT("Drivers\\"));
|
|
else if (bDriversDir)
|
|
lstrcat(szPath, TEXT("..\\System32\\Drivers\\"));
|
|
lstrcat(szPath, szFile);
|
|
WIN32_FIND_DATA findFileData;
|
|
HANDLE hFind = FindFirstFile(szPath, &findFileData);
|
|
if (hFind == INVALID_HANDLE_VALUE)
|
|
{
|
|
if (bSkipMissingFiles)
|
|
{
|
|
delete pFileInfoNew;
|
|
continue;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
pFileInfoNew->m_bExists = TRUE;
|
|
FindClose(hFind);
|
|
}
|
|
if (pFileInfoNew->m_bExists)
|
|
{
|
|
pFileInfoNew->m_numBytes = findFileData.nFileSizeLow;
|
|
pFileInfoNew->m_FileTime = findFileData.ftLastWriteTime;
|
|
FormatFileTime(&findFileData.ftLastWriteTime, pFileInfoNew->m_szDatestampLocal,
|
|
pFileInfoNew->m_szDatestamp);
|
|
GetFileVersion(szPath, pFileInfoNew->m_szVersion, pFileInfoNew->m_szAttributes,
|
|
pFileInfoNew->m_szLanguageLocal, pFileInfoNew->m_szLanguage, &pFileInfoNew->m_bBeta, &pFileInfoNew->m_bDebug);
|
|
}
|
|
if (*ppFileInfoFirst == NULL)
|
|
*ppFileInfoFirst = pFileInfoNew;
|
|
else
|
|
{
|
|
for (pFileInfo = *ppFileInfoFirst;
|
|
pFileInfo->m_pFileInfoNext != NULL;
|
|
pFileInfo = pFileInfo->m_pFileInfoNext)
|
|
{
|
|
}
|
|
pFileInfo->m_pFileInfoNext = pFileInfoNew;
|
|
}
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
/****************************************************************************
|
|
*
|
|
* DestroyFileList
|
|
*
|
|
****************************************************************************/
|
|
VOID DestroyFileList(FileInfo* pFileInfoFirst)
|
|
{
|
|
FileInfo* pFileInfo;
|
|
FileInfo* pFileInfoNext;
|
|
|
|
for (pFileInfo = pFileInfoFirst; pFileInfo != NULL; pFileInfo = pFileInfoNext)
|
|
{
|
|
pFileInfoNext = pFileInfo->m_pFileInfoNext;
|
|
delete pFileInfo;
|
|
}
|
|
}
|
|
|
|
|
|
/****************************************************************************
|
|
*
|
|
* GetFileDateAndSize
|
|
*
|
|
****************************************************************************/
|
|
BOOL GetFileDateAndSize(TCHAR* pszFile, TCHAR* pszDateLocal, TCHAR* pszDateEnglish,
|
|
LONG* pnumBytes)
|
|
{
|
|
WIN32_FIND_DATA findFileData;
|
|
HANDLE hFind;
|
|
|
|
pszDateLocal[0] = '\0';
|
|
pszDateEnglish[0] = '\0';
|
|
*pnumBytes = 0;
|
|
hFind = FindFirstFile(pszFile, &findFileData);
|
|
if (hFind == INVALID_HANDLE_VALUE)
|
|
return FALSE; // file not found
|
|
FindClose(hFind);
|
|
*pnumBytes = findFileData.nFileSizeLow;
|
|
FormatFileTime(&findFileData.ftLastWriteTime, pszDateLocal, pszDateEnglish);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
/****************************************************************************
|
|
*
|
|
* GetFileVersion
|
|
*
|
|
****************************************************************************/
|
|
HRESULT GetFileVersion(TCHAR* pszFile, TCHAR* pszVersion, TCHAR* pszAttributes,
|
|
TCHAR* pszLanguageLocal, TCHAR* pszLanguage, BOOL* pbBeta, BOOL* pbDebug)
|
|
{
|
|
UINT cb;
|
|
DWORD dwHandle;
|
|
BYTE FileVersionBuffer[4096];
|
|
VS_FIXEDFILEINFO* pVersion = NULL;
|
|
DWORD dwVersionAttribs = 0; // DEBUG, RETAIL, etc.
|
|
DWORD* pdwCharSet = NULL;
|
|
WORD wLanguage;
|
|
LCID lcid;
|
|
TCHAR szDebug[100];
|
|
TCHAR szRetail[100];
|
|
TCHAR szBeta[100];
|
|
TCHAR szFinal[100];
|
|
TCHAR szCombineFmt[100];
|
|
LoadString(NULL, IDS_DEBUG, szDebug, 100);
|
|
LoadString(NULL, IDS_RETAIL, szRetail, 100);
|
|
LoadString(NULL, IDS_BETA, szBeta, 100);
|
|
LoadString(NULL, IDS_FINAL, szFinal, 100);
|
|
LoadString(NULL, IDS_ATTRIBCOMBINE, szCombineFmt, 100);
|
|
|
|
cb = GetFileVersionInfoSize(pszFile, &dwHandle/*ignored*/);
|
|
if (cb > 0)
|
|
{
|
|
if (cb > sizeof(FileVersionBuffer))
|
|
cb = sizeof(FileVersionBuffer);
|
|
|
|
if (GetFileVersionInfo(pszFile, 0, cb, &FileVersionBuffer))
|
|
{
|
|
pVersion = NULL;
|
|
if (VerQueryValue(&FileVersionBuffer, TEXT("\\"), (VOID**)&pVersion, &cb)
|
|
&& pVersion != NULL)
|
|
{
|
|
if (pszVersion != NULL)
|
|
{
|
|
wsprintf(pszVersion, TEXT("%d.%02d.%02d.%04d"),
|
|
HIWORD(pVersion->dwFileVersionMS),
|
|
LOWORD(pVersion->dwFileVersionMS),
|
|
HIWORD(pVersion->dwFileVersionLS),
|
|
LOWORD(pVersion->dwFileVersionLS));
|
|
}
|
|
if (pszAttributes != NULL)
|
|
{
|
|
dwVersionAttribs = pVersion->dwFileFlags;
|
|
// Bug 18892: work around DPlay 6.0a
|
|
if (pVersion->dwFileVersionMS == 0x00040006 &&
|
|
(pVersion->dwFileVersionLS == 0x0002016b || // 4.06.02.0363
|
|
pVersion->dwFileVersionLS == 0x00020164)) // 4.06.02.0356
|
|
{
|
|
dwVersionAttribs &= ~VS_FF_PRERELEASE;
|
|
}
|
|
if (pszVersion != NULL)
|
|
{
|
|
TCHAR* pszLeaf = _tcsrchr(pszFile, TEXT('\\'));
|
|
if( pszLeaf )
|
|
{
|
|
pszLeaf++;
|
|
// Work around several DXMedia files which are incorrectly marked as beta
|
|
if (lstrcmp(pszLeaf, TEXT("oleaut32.dll")) == 0)
|
|
{
|
|
dwVersionAttribs &= ~VS_FF_PRERELEASE;
|
|
}
|
|
else if (lstrcmp(pszLeaf, TEXT("quartz.dll")) == 0 &&
|
|
lstrcmp(pszVersion, TEXT("4.00.96.0729")) == 0)
|
|
{
|
|
dwVersionAttribs &= ~VS_FF_PRERELEASE;
|
|
}
|
|
else if (lstrcmp(pszLeaf, TEXT("quartz.vxd")) == 0 &&
|
|
lstrcmp(pszVersion, TEXT("4.00.96.0729")) == 0)
|
|
{
|
|
dwVersionAttribs &= ~VS_FF_PRERELEASE;
|
|
}
|
|
else if (lstrcmp(pszLeaf, TEXT("mciqtz.drv")) == 0 &&
|
|
lstrcmp(pszVersion, TEXT("4.00.96.0729")) == 0)
|
|
{
|
|
dwVersionAttribs &= ~VS_FF_PRERELEASE;
|
|
}
|
|
else if (lstrcmp(pszLeaf, TEXT("mciqtz32.dll")) == 0 &&
|
|
lstrcmp(pszVersion, TEXT("4.00.96.0729")) == 0)
|
|
{
|
|
dwVersionAttribs &= ~VS_FF_PRERELEASE;
|
|
}
|
|
else if (lstrcmp(pszLeaf, TEXT("actmovie.exe")) == 0)
|
|
{
|
|
dwVersionAttribs &= ~VS_FF_PRERELEASE;
|
|
}
|
|
else if (lstrcmp(pszLeaf, TEXT("strmdll.dll")) == 0)
|
|
{
|
|
dwVersionAttribs &= ~VS_FF_PRERELEASE;
|
|
}
|
|
else if (lstrcmp(pszLeaf, TEXT("unam4ie.exe")) == 0 &&
|
|
lstrcmp(pszVersion, TEXT("6.00.02.0902")) == 0)
|
|
{
|
|
dwVersionAttribs &= ~VS_FF_PRERELEASE;
|
|
}
|
|
else if (lstrcmp(pszLeaf, TEXT("unam4ie.exe")) == 0 &&
|
|
lstrcmp(pszVersion, TEXT("5.01.18.1024")) == 0)
|
|
{
|
|
dwVersionAttribs &= ~VS_FF_PRERELEASE;
|
|
}
|
|
else if (lstrcmp(pszLeaf, TEXT("iac25_32.ax")) == 0 &&
|
|
lstrcmp(pszVersion, TEXT("2.00.05.0050")) == 0)
|
|
{
|
|
dwVersionAttribs &= ~VS_FF_PRERELEASE;
|
|
}
|
|
else if (lstrcmp(pszLeaf, TEXT("iac25_32.ax")) == 0 &&
|
|
lstrcmp(pszVersion, TEXT("2.00.05.0052")) == 0)
|
|
{
|
|
dwVersionAttribs &= ~VS_FF_PRERELEASE;
|
|
}
|
|
else if (lstrcmp(pszLeaf, TEXT("tm20dec.ax")) == 0)
|
|
{
|
|
dwVersionAttribs &= ~VS_FF_PRERELEASE;
|
|
}
|
|
else if (lstrcmp(pszLeaf, TEXT("tm20dec.ax")) == 0 &&
|
|
lstrcmp(pszVersion, TEXT("1.00.00.0000")) == 0)
|
|
{
|
|
dwVersionAttribs &= ~VS_FF_PRERELEASE;
|
|
}
|
|
else if (lstrcmp(pszLeaf, TEXT("msdxm.ocx")) == 0)
|
|
{
|
|
dwVersionAttribs &= ~VS_FF_PRERELEASE;
|
|
}
|
|
else if (lstrcmp(pszLeaf, TEXT("dxmasf.dll")) == 0)
|
|
{
|
|
dwVersionAttribs &= ~VS_FF_PRERELEASE;
|
|
}
|
|
else if (lstrcmp(pszLeaf, TEXT("iac25_32.ax")) == 0 &&
|
|
lstrcmp(pszVersion, TEXT("2.00.05.0053")) == 0)
|
|
{
|
|
dwVersionAttribs &= ~VS_FF_PRERELEASE; // Since 350883 got punted
|
|
}
|
|
}
|
|
|
|
wsprintf(pszAttributes, szCombineFmt,
|
|
(dwVersionAttribs & VS_FF_PRERELEASE ? szBeta : szFinal),
|
|
(dwVersionAttribs & VS_FF_DEBUG ? szDebug : szRetail));
|
|
if (pbBeta != NULL)
|
|
*pbBeta = (dwVersionAttribs & VS_FF_PRERELEASE) ? TRUE : FALSE;
|
|
if (pbDebug != NULL)
|
|
*pbDebug = (dwVersionAttribs & VS_FF_DEBUG) ? TRUE : FALSE;
|
|
}
|
|
}
|
|
}
|
|
if (pszLanguage != NULL)
|
|
{
|
|
if (VerQueryValue(&FileVersionBuffer, TEXT("\\VarFileInfo\\Translation"), (VOID**)&pdwCharSet, &cb)
|
|
&& pdwCharSet && cb)
|
|
{
|
|
wLanguage = LOWORD(*pdwCharSet);
|
|
lcid = MAKELCID(wLanguage, SORT_DEFAULT);
|
|
GetLocaleInfo(lcid, LOCALE_SENGLANGUAGE, pszLanguage, 100);
|
|
if (pszLanguageLocal != NULL)
|
|
{
|
|
GetLocaleInfo(lcid, LOCALE_SLANGUAGE, pszLanguageLocal, 100);
|
|
// Show "English", not "English (United States)". I can't
|
|
// find a better way to do this (such that it localizes properly)
|
|
TCHAR* pszSublanguage;
|
|
pszSublanguage = _tcsstr(pszLanguageLocal, TEXT(" ("));
|
|
if (pszSublanguage != NULL)
|
|
*pszSublanguage = '\0';
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
TCHAR* pszLeaf = _tcsrchr(pszFile, TEXT('\\'));
|
|
if( pszLeaf )
|
|
{
|
|
pszLeaf++;
|
|
if (lstrcmpi(pszLeaf, TEXT("vidx16.dll")) == 0)
|
|
{
|
|
if (pszVersion != NULL)
|
|
lstrcpy(pszVersion, TEXT("0.00.00.0000"));
|
|
if (pszAttributes != NULL)
|
|
wsprintf(pszAttributes, TEXT("%s %s"), szFinal, szRetail);
|
|
if (pszLanguage != NULL)
|
|
{
|
|
wLanguage = MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US);
|
|
lcid = MAKELCID(wLanguage, SORT_DEFAULT);
|
|
GetLocaleInfo(lcid, LOCALE_SENGLANGUAGE, pszLanguage, 100);
|
|
if (pszLanguageLocal != NULL)
|
|
{
|
|
GetLocaleInfo(lcid, LOCALE_SLANGUAGE, pszLanguageLocal, 100);
|
|
// Show "English", not "English (United States)". I can't
|
|
// find a better way to do this (such that it localizes properly)
|
|
TCHAR* pszSublanguage;
|
|
pszSublanguage = _tcsstr(pszLanguageLocal, TEXT(" ("));
|
|
if (pszSublanguage != NULL)
|
|
*pszSublanguage = '\0';
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
/****************************************************************************
|
|
*
|
|
* GetLanguageFromFile
|
|
*
|
|
****************************************************************************/
|
|
WORD GetLanguageFromFile(const TCHAR* pszFileName, const TCHAR* pszPath)
|
|
{
|
|
BYTE FileVersionBuffer[4096];
|
|
DWORD *pdwCharSet;
|
|
UINT cb;
|
|
DWORD dwHandle;
|
|
TCHAR szFileAndPath[MAX_PATH];
|
|
WORD wLanguage;
|
|
|
|
lstrcpy(szFileAndPath, pszPath);
|
|
lstrcat(szFileAndPath, TEXT("\\"));
|
|
lstrcat(szFileAndPath, pszFileName);
|
|
memset(&FileVersionBuffer, 0, sizeof FileVersionBuffer);
|
|
wLanguage = 0;
|
|
|
|
if (cb = GetFileVersionInfoSize(szFileAndPath, &dwHandle/*ignored*/))
|
|
{
|
|
cb = (cb <= sizeof FileVersionBuffer ? cb : sizeof FileVersionBuffer);
|
|
|
|
if (GetFileVersionInfo(szFileAndPath, 0, cb, &FileVersionBuffer))
|
|
{
|
|
pdwCharSet = 0;
|
|
|
|
if (VerQueryValue(&FileVersionBuffer, TEXT("\\VarFileInfo\\Translation"), (void**)&pdwCharSet, &cb)
|
|
&& pdwCharSet && cb)
|
|
{
|
|
wLanguage = LOWORD(*pdwCharSet);
|
|
}
|
|
}
|
|
}
|
|
return wLanguage;
|
|
}
|
|
|
|
|
|
struct DLSVERSION
|
|
{
|
|
DWORD dwVersionMS;
|
|
DWORD dwVersionLS;
|
|
};
|
|
|
|
#define FOURCC_VERS mmioFOURCC('v','e','r','s')
|
|
|
|
/****************************************************************************
|
|
*
|
|
* GetRiffFileVersion
|
|
*
|
|
****************************************************************************/
|
|
HRESULT GetRiffFileVersion(TCHAR* pszFile, TCHAR* pszVersion)
|
|
{
|
|
MMIOINFO mmio;
|
|
MMCKINFO mmck1;
|
|
MMCKINFO mmck2;
|
|
DLSVERSION dlsver;
|
|
HMMIO hDLS;
|
|
|
|
// DLS file has different version scheme since it's a riff file.
|
|
// So retrieve version info from 'vers' chunk.
|
|
|
|
ZeroMemory(&mmio, sizeof(MMIOINFO));
|
|
hDLS = mmioOpen(pszFile,&mmio,MMIO_READ);
|
|
if (hDLS == NULL)
|
|
{
|
|
return E_FAIL;
|
|
}
|
|
|
|
// read riff chunk
|
|
ZeroMemory(&mmck1,sizeof(MMCKINFO));
|
|
if (mmioDescend(hDLS,
|
|
&mmck1,
|
|
NULL,
|
|
MMIO_FINDRIFF) != MMSYSERR_NOERROR)
|
|
{
|
|
mmioClose(hDLS,0);
|
|
return E_FAIL;
|
|
}
|
|
ZeroMemory(&mmck2,sizeof(MMCKINFO));
|
|
mmck2.ckid = FOURCC_VERS;
|
|
if (mmioDescend(hDLS,
|
|
&mmck2,
|
|
&mmck1,
|
|
MMIO_FINDCHUNK) != MMSYSERR_NOERROR)
|
|
{
|
|
mmioClose(hDLS,0);
|
|
return E_FAIL;
|
|
}
|
|
if (mmioRead(hDLS,
|
|
(HPSTR)&dlsver,
|
|
sizeof(DLSVERSION)) != sizeof(DLSVERSION))
|
|
{
|
|
mmioClose(hDLS,0);
|
|
return E_FAIL;
|
|
}
|
|
|
|
wsprintf(pszVersion, TEXT("%d.%02d.%02d.%04d"),
|
|
HIWORD(dlsver.dwVersionMS),
|
|
LOWORD(dlsver.dwVersionMS),
|
|
HIWORD(dlsver.dwVersionLS),
|
|
LOWORD(dlsver.dwVersionLS));
|
|
mmioClose(hDLS,0);
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
/****************************************************************************
|
|
*
|
|
* FileIsSigned - use digital signature on all OSs
|
|
*
|
|
****************************************************************************/
|
|
VOID FileIsSigned(LPTSTR lpszFile, BOOL* pbSigned, BOOL* pbIsValid)
|
|
{
|
|
// Look for digital sig
|
|
if( !InitDigiSignData() )
|
|
{
|
|
if( pbSigned )
|
|
*pbSigned = FALSE;
|
|
|
|
if( pbIsValid )
|
|
*pbIsValid = FALSE;
|
|
|
|
return;
|
|
}
|
|
|
|
if( pbSigned )
|
|
*pbSigned = IsFileDigitallySigned(lpszFile);
|
|
if( pbIsValid )
|
|
*pbIsValid = TRUE;
|
|
}
|
|
|
|
|
|
// 5/12/97(RichGr): From Eric's dsetup16.c.
|
|
// * 14-sep-95 ericeng directdraw signed tests, drivers failing dll tests are removed from list
|
|
/****************************************************************************
|
|
*
|
|
* FileIsSignedOld
|
|
*
|
|
****************************************************************************/
|
|
BOOL FileIsSignedOld(LPTSTR lpszFile)
|
|
{
|
|
typedef struct tagIMAGE_DOS_HEADER // DOS .EXE header
|
|
{
|
|
WORD e_magic; // Magic number
|
|
WORD e_cblp; // Bytes on last page of file
|
|
WORD e_cp; // Pages in file
|
|
WORD e_crlc; // Relocations
|
|
WORD e_cparhdr; // Size of header in paragraphs
|
|
WORD e_minalloc; // Minimum extra paragraphs needed
|
|
WORD e_maxalloc; // Maximum extra paragraphs needed
|
|
WORD e_ss; // Initial (relative) SS value
|
|
WORD e_sp; // Initial SP value
|
|
WORD e_csum; // Checksum
|
|
WORD e_ip; // Initial IP value
|
|
WORD e_cs; // Initial (relative) CS value
|
|
WORD e_lfarlc; // File address of relocation table
|
|
WORD e_ovno; // Overlay number
|
|
WORD e_res[4]; // Reserved words
|
|
WORD e_oemid; // OEM identifier (for e_oeminfo)
|
|
WORD e_oeminfo; // OEM information; e_oemid specific
|
|
WORD e_res2[10]; // Reserved words
|
|
LONG e_lfanew; // File address of new exe header
|
|
} IMAGE_DOS_HEADER, * PIMAGE_DOS_HEADER, FAR* LPIMAGE_DOS_HEADER;
|
|
|
|
typedef struct tagIMAGE_OS2_HEADER // OS/2 .EXE header
|
|
{
|
|
WORD ne_magic; // Magic number
|
|
CHAR ne_ver; // Version number
|
|
CHAR ne_rev; // Revision number
|
|
WORD ne_enttab; // Offset of Entry Table
|
|
WORD ne_cbenttab; // Number of bytes in Entry Table
|
|
LONG ne_crc; // Checksum of whole file
|
|
WORD ne_flags; // Flag word
|
|
WORD ne_autodata; // Automatic data segment number
|
|
WORD ne_heap; // Initial heap allocation
|
|
WORD ne_stack; // Initial stack allocation
|
|
LONG ne_csip; // Initial CS:IP setting
|
|
LONG ne_sssp; // Initial SS:SP setting
|
|
WORD ne_cseg; // Count of file segments
|
|
WORD ne_cmod; // Entries in Module Reference Table
|
|
WORD ne_cbnrestab; // Size of non-resident name table
|
|
WORD ne_segtab; // Offset of Segment Table
|
|
WORD ne_rsrctab; // Offset of Resource Table
|
|
WORD ne_restab; // Offset of resident name table
|
|
WORD ne_modtab; // Offset of Module Reference Table
|
|
WORD ne_imptab; // Offset of Imported Names Table
|
|
LONG ne_nrestab; // Offset of Non-resident Names Table
|
|
WORD ne_cmovent; // Count of movable entries
|
|
WORD ne_align; // Segment alignment shift count
|
|
WORD ne_cres; // Count of resource segments
|
|
BYTE ne_exetyp; // Target Operating system
|
|
BYTE ne_flagsothers; // Other .EXE flags
|
|
WORD ne_pretthunks; // offset to return thunks
|
|
WORD ne_psegrefbytes; // offset to segment ref. bytes
|
|
WORD ne_swaparea; // Minimum code swap area size
|
|
WORD ne_expver; // Expected Windows version number
|
|
} IMAGE_OS2_HEADER, * PIMAGE_OS2_HEADER, FAR* LPIMAGE_OS2_HEADER;
|
|
|
|
typedef struct tagWINSTUB
|
|
{
|
|
IMAGE_DOS_HEADER idh;
|
|
BYTE rgb[14];
|
|
} WINSTUB, * PWINSTUB, FAR* LPWINSTUB;
|
|
|
|
typedef struct tagFILEINFO
|
|
{
|
|
BYTE cbInfo[0x120];
|
|
} FILEINFO, * PFILEINFO, FAR* LPFILEINFO;
|
|
|
|
|
|
|
|
FILE * pf;
|
|
int nRC;
|
|
FILEINFO fi;
|
|
LPIMAGE_DOS_HEADER lpmz;
|
|
// LPIMAGE_OS2_HEADER lpne;
|
|
BYTE cbInfo[9+32+2];
|
|
BOOL IsSigned = FALSE;
|
|
|
|
static WINSTUB winstub = {
|
|
{
|
|
IMAGE_DOS_SIGNATURE, /* magic */
|
|
0, /* bytes on last page - varies */
|
|
0, /* pages in file - varies */
|
|
0, /* relocations */
|
|
4, /* paragraphs in header */
|
|
1, /* min allocation */
|
|
0xFFFF, /* max allocation */
|
|
0, /* initial SS */
|
|
0xB8, /* initial SP */
|
|
0, /* checksum (ha!) */
|
|
0, /* initial IP */
|
|
0, /* initial CS */
|
|
0x40, /* lfarlc */
|
|
0, /* overlay number */
|
|
{ 0, 0, 0, 0}, /* reserved */
|
|
0, /* oem id */
|
|
0, /* oem info */
|
|
0, /* compiler bug */
|
|
{ 0}, /* reserved */
|
|
0x80, /* lfanew */
|
|
},
|
|
{
|
|
0x0E, 0x1F, 0xBA, 0x0E, 0x00, 0xB4, 0x09, 0xCD,
|
|
0x21, 0xB8, 0x01, 0x4C, 0xCD, 0x21,
|
|
}
|
|
};
|
|
|
|
pf = _tfopen(lpszFile, TEXT("rb"));
|
|
if (pf==0)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
nRC = fread(&fi, sizeof(BYTE), sizeof(FILEINFO), pf);
|
|
if (nRC != sizeof(FILEINFO))
|
|
{
|
|
goto FileIsSigned_exit;
|
|
}
|
|
|
|
lpmz = (LPIMAGE_DOS_HEADER)(&fi);
|
|
// lpne = (LPIMAGE_OS2_HEADER)((WORD)&fi + 0x80);
|
|
|
|
winstub.idh.e_cblp = lpmz->e_cblp;
|
|
winstub.idh.e_cp = lpmz->e_cp;
|
|
|
|
if (memcmp(&fi, &winstub, sizeof(winstub)) == 0)
|
|
{
|
|
goto FileIsSigned_exit;
|
|
}
|
|
|
|
// if (lpne->ne_magic == IMAGE_OS2_SIGNATURE ||
|
|
// lpne->ne_magic == IMAGE_VXD_SIGNATURE ||
|
|
// lpne->ne_magic == IMAGE_NT_SIGNATURE)
|
|
// {
|
|
// DPF(0, "Found a match in the OS2 header");
|
|
// }
|
|
// else
|
|
// {
|
|
// DPF(0, "Didn't meet second criteria!!!");
|
|
// goto FileIsSigned_exit;
|
|
// }
|
|
|
|
memcpy(cbInfo, &((PWINSTUB)(&fi)->cbInfo)->rgb[14], sizeof(cbInfo));
|
|
|
|
if ( (cbInfo[4] != ' ' ) || // space
|
|
(cbInfo[8] != ' ' ) || // space
|
|
(cbInfo[9+32] != '\n') || // return
|
|
(cbInfo[9+32+1] != '$' ) ) // Dollar Sign
|
|
{
|
|
goto FileIsSigned_exit;
|
|
}
|
|
|
|
cbInfo[4] = 0;
|
|
cbInfo[8] = 0;
|
|
|
|
if ( (strcmp((const char*)&cbInfo[0], "Cert") != 0) ||
|
|
(strcmp((const char*)&cbInfo[5], "DX2") != 0) )
|
|
{
|
|
goto FileIsSigned_exit;
|
|
}
|
|
|
|
IsSigned=TRUE;
|
|
|
|
FileIsSigned_exit:
|
|
|
|
fclose(pf);
|
|
|
|
return IsSigned;
|
|
}
|
|
|
|
|
|
/****************************************************************************
|
|
*
|
|
* InitDigiSignData
|
|
*
|
|
****************************************************************************/
|
|
BOOL InitDigiSignData(VOID)
|
|
{
|
|
TCHAR szPath[MAX_PATH];
|
|
|
|
if( s_dsd.bInitialized )
|
|
return TRUE;
|
|
if( s_dsd.bFailed )
|
|
return FALSE;
|
|
|
|
ZeroMemory(&s_dsd, sizeof(s_dsd));
|
|
|
|
GetSystemDirectory(szPath, MAX_PATH);
|
|
lstrcat(szPath, TEXT("\\mscat32.dll"));
|
|
s_dsd.hInstMsCat32 = LoadLibrary(szPath);
|
|
if (s_dsd.hInstMsCat32 == NULL)
|
|
{
|
|
s_dsd.bFailed = TRUE;
|
|
return FALSE;
|
|
}
|
|
|
|
s_dsd.CryptCATAdminAcquireContext = (PfnCryptCATAdminAcquireContext)GetProcAddress(s_dsd.hInstMsCat32, "CryptCATAdminAcquireContext");
|
|
if (s_dsd.CryptCATAdminAcquireContext == NULL)
|
|
{
|
|
s_dsd.bFailed = TRUE;
|
|
return FALSE;
|
|
}
|
|
|
|
s_dsd.CryptCATAdminReleaseContext = (PfnCryptCATAdminReleaseContext)GetProcAddress(s_dsd.hInstMsCat32, "CryptCATAdminReleaseContext");
|
|
if (s_dsd.CryptCATAdminReleaseContext == NULL)
|
|
{
|
|
s_dsd.bFailed = TRUE;
|
|
return FALSE;
|
|
}
|
|
|
|
s_dsd.CryptCATAdminReleaseCatalogContext = (PfnCryptCATAdminReleaseCatalogContext)GetProcAddress(s_dsd.hInstMsCat32, "CryptCATAdminReleaseCatalogContext");
|
|
if (s_dsd.CryptCATAdminReleaseCatalogContext == NULL)
|
|
{
|
|
s_dsd.bFailed = TRUE;
|
|
return FALSE;
|
|
}
|
|
|
|
s_dsd.CryptCATCatalogInfoFromContext = (PfnCryptCATCatalogInfoFromContext)GetProcAddress(s_dsd.hInstMsCat32, "CryptCATCatalogInfoFromContext");
|
|
if (s_dsd.CryptCATCatalogInfoFromContext == NULL)
|
|
{
|
|
s_dsd.bFailed = TRUE;
|
|
return FALSE;
|
|
}
|
|
|
|
s_dsd.CryptCATAdminEnumCatalogFromHash = (PfnCryptCATAdminEnumCatalogFromHash)GetProcAddress(s_dsd.hInstMsCat32, "CryptCATAdminEnumCatalogFromHash");
|
|
if (s_dsd.CryptCATAdminEnumCatalogFromHash == NULL)
|
|
{
|
|
s_dsd.bFailed = TRUE;
|
|
return FALSE;
|
|
}
|
|
|
|
s_dsd.IsCatalogFile = (PfnIsCatalogFile)GetProcAddress(s_dsd.hInstMsCat32, "IsCatalogFile");
|
|
if (s_dsd.IsCatalogFile == NULL)
|
|
{
|
|
s_dsd.bFailed = TRUE;
|
|
return FALSE;
|
|
}
|
|
|
|
s_dsd.CryptCATAdminCalcHashFromFileHandle = (PfnCryptCATAdminCalcHashFromFileHandle)GetProcAddress(s_dsd.hInstMsCat32, "CryptCATAdminCalcHashFromFileHandle");
|
|
if (s_dsd.CryptCATAdminCalcHashFromFileHandle == NULL)
|
|
{
|
|
s_dsd.bFailed = TRUE;
|
|
return FALSE;
|
|
}
|
|
|
|
if (!s_dsd.CryptCATAdminAcquireContext(&s_dsd.hCatAdmin, NULL, 0))
|
|
{
|
|
s_dsd.bFailed = TRUE;
|
|
return FALSE;
|
|
}
|
|
|
|
GetSystemDirectory(szPath, MAX_PATH);
|
|
lstrcat(szPath, TEXT("\\wintrust.dll"));
|
|
s_dsd.hInstWinTrust = LoadLibrary(szPath);
|
|
if (s_dsd.hInstWinTrust == NULL)
|
|
{
|
|
s_dsd.bFailed = TRUE;
|
|
return FALSE;
|
|
}
|
|
|
|
s_dsd.WinVerifyTrust = (PfnWinVerifyTrust)GetProcAddress(s_dsd.hInstWinTrust, "WinVerifyTrust");
|
|
if (s_dsd.WinVerifyTrust == NULL)
|
|
{
|
|
s_dsd.bFailed = TRUE;
|
|
return FALSE;
|
|
}
|
|
|
|
GetSystemDirectory(szPath, MAX_PATH);
|
|
lstrcat(szPath, TEXT("\\crypt32.dll"));
|
|
s_dsd.hInstCrypt32 = LoadLibrary(szPath);
|
|
if (s_dsd.hInstCrypt32 == NULL)
|
|
{
|
|
s_dsd.bFailed = TRUE;
|
|
return FALSE;
|
|
}
|
|
|
|
s_dsd.CertFreeCertificateContext = (PfnCertFreeCertificateContext)GetProcAddress(s_dsd.hInstCrypt32, "CertFreeCertificateContext");
|
|
if (s_dsd.CertFreeCertificateContext == NULL)
|
|
{
|
|
s_dsd.bFailed = TRUE;
|
|
return FALSE;
|
|
}
|
|
|
|
s_dsd.bFailed = FALSE;
|
|
s_dsd.bInitialized = TRUE;
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
/****************************************************************************
|
|
*
|
|
* ReleaseDigiSignData
|
|
*
|
|
****************************************************************************/
|
|
VOID ReleaseDigiSignData(VOID)
|
|
{
|
|
if( s_dsd.CryptCATAdminReleaseContext && s_dsd.hCatAdmin )
|
|
s_dsd.CryptCATAdminReleaseContext(s_dsd.hCatAdmin,0);
|
|
if (s_dsd.hInstMsCat32 != NULL)
|
|
FreeLibrary(s_dsd.hInstMsCat32);
|
|
if (s_dsd.hInstWinTrust != NULL)
|
|
FreeLibrary(s_dsd.hInstWinTrust);
|
|
if (s_dsd.hInstCrypt32 != NULL)
|
|
FreeLibrary(s_dsd.hInstCrypt32);
|
|
ZeroMemory(&s_dsd, sizeof(s_dsd));
|
|
}
|
|
|
|
|
|
/****************************************************************************
|
|
*
|
|
* IsFileDigitallySigned
|
|
*
|
|
****************************************************************************/
|
|
BOOL IsFileDigitallySigned(TCHAR* pszFile)
|
|
{
|
|
if (!s_dsd.bInitialized)
|
|
return FALSE;
|
|
|
|
TCHAR lpFileName[MAX_PATH];
|
|
TCHAR lpDirName[MAX_PATH];
|
|
TCHAR* pch;
|
|
lstrcpy(lpDirName, pszFile);
|
|
CharLowerBuff(lpDirName, lstrlen(lpDirName));
|
|
pch = _tcsrchr(lpDirName, TEXT('\\'));
|
|
// 22670: There *should* be a backslash in pszFile, but cope if it isn't
|
|
if (pch == NULL)
|
|
{
|
|
lstrcpy(lpFileName, pszFile);
|
|
GetCurrentDirectory(MAX_PATH, lpDirName);
|
|
}
|
|
else
|
|
{
|
|
lstrcpy(lpFileName, pch + 1);
|
|
*pch = TEXT('\0');
|
|
}
|
|
if (_tcsstr(lpDirName, TEXT("\\")) == NULL)
|
|
lstrcat(lpDirName, TEXT("\\"));
|
|
|
|
return VerifyFileNode(lpFileName, lpDirName);
|
|
}
|
|
|
|
|
|
/****************************************************************************
|
|
*
|
|
* VerifyFileNode
|
|
*
|
|
****************************************************************************/
|
|
BOOL VerifyFileNode(TCHAR* lpFileName, TCHAR* lpDirName)
|
|
{
|
|
const DWORD HASH_SIZE = 100;
|
|
HANDLE hFile;
|
|
BOOL bRet;
|
|
HCATINFO hCatInfo = NULL;
|
|
HCATINFO PrevCat;
|
|
WINTRUST_DATA WinTrustData;
|
|
WINTRUST_CATALOG_INFO WinTrustCatalogInfo;
|
|
DRIVER_VER_INFO VerInfo;
|
|
GUID guidSubSystemDriver = DRIVER_ACTION_VERIFY;
|
|
HRESULT hRes;
|
|
DWORD cbHash = HASH_SIZE;
|
|
BYTE szHash[HASH_SIZE];
|
|
LPBYTE lpHash = szHash;
|
|
CATALOG_INFO CatInfo;
|
|
#ifndef UNICODE
|
|
WCHAR UnicodeKey[MAX_PATH];
|
|
#endif
|
|
BOOL bSigned = FALSE;
|
|
TCHAR szFullPath[MAX_PATH];
|
|
|
|
wsprintf(szFullPath, TEXT("%s\\%s"), lpDirName, lpFileName);
|
|
|
|
//
|
|
// Get the handle to the file, so we can call CryptCATAdminCalcHashFromFileHandle
|
|
//
|
|
hFile = CreateFile( szFullPath,
|
|
GENERIC_READ,
|
|
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
|
NULL,
|
|
OPEN_EXISTING,
|
|
FILE_ATTRIBUTE_NORMAL,
|
|
NULL);
|
|
if (hFile == INVALID_HANDLE_VALUE)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
// Initialize the hash buffer
|
|
ZeroMemory(lpHash, HASH_SIZE);
|
|
|
|
// Generate the hash from the file handle and store it in lpHash
|
|
if (!s_dsd.CryptCATAdminCalcHashFromFileHandle(hFile, &cbHash, lpHash, 0))
|
|
{
|
|
//
|
|
// If we couldn't generate a hash, it might be an individually signed catalog.
|
|
// If it's a catalog, zero out lpHash and cbHash so we know there's no hash to check.
|
|
//
|
|
if (s_dsd.IsCatalogFile(hFile, NULL))
|
|
{
|
|
lpHash = NULL;
|
|
cbHash = 0;
|
|
}
|
|
else // If it wasn't a catalog, we'll bail and this file will show up as unscanned.
|
|
{
|
|
CloseHandle(hFile);
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
// Close the file handle
|
|
CloseHandle(hFile);
|
|
|
|
//
|
|
// Now we have the file's hash. Initialize the structures that
|
|
// will be used later on in calls to WinVerifyTrust.
|
|
//
|
|
ZeroMemory(&WinTrustData, sizeof(WINTRUST_DATA));
|
|
WinTrustData.cbStruct = sizeof(WINTRUST_DATA);
|
|
WinTrustData.dwUIChoice = WTD_UI_NONE;
|
|
WinTrustData.fdwRevocationChecks = WTD_REVOKE_NONE;
|
|
WinTrustData.dwUnionChoice = WTD_CHOICE_CATALOG;
|
|
WinTrustData.dwStateAction = WTD_STATEACTION_AUTO_CACHE;
|
|
WinTrustData.pPolicyCallbackData = (LPVOID)&VerInfo;
|
|
|
|
ZeroMemory(&VerInfo, sizeof(DRIVER_VER_INFO));
|
|
VerInfo.cbStruct = sizeof(DRIVER_VER_INFO);
|
|
|
|
OSVERSIONINFO osvi;
|
|
ZeroMemory(&osvi, sizeof(osvi));
|
|
osvi.dwOSVersionInfoSize = sizeof(osvi);
|
|
if (GetVersionEx(&osvi))
|
|
{
|
|
VerInfo.dwPlatform = osvi.dwPlatformId;
|
|
VerInfo.dwVersion = osvi.dwMajorVersion;
|
|
VerInfo.sOSVersionLow.dwMajor = osvi.dwMajorVersion;
|
|
VerInfo.sOSVersionLow.dwMinor = osvi.dwMinorVersion;
|
|
VerInfo.sOSVersionHigh.dwMajor = osvi.dwMajorVersion;
|
|
VerInfo.sOSVersionHigh.dwMinor = osvi.dwMinorVersion;
|
|
}
|
|
|
|
WinTrustData.pCatalog = &WinTrustCatalogInfo;
|
|
|
|
ZeroMemory(&WinTrustCatalogInfo, sizeof(WINTRUST_CATALOG_INFO));
|
|
WinTrustCatalogInfo.cbStruct = sizeof(WINTRUST_CATALOG_INFO);
|
|
WinTrustCatalogInfo.pbCalculatedFileHash = lpHash;
|
|
WinTrustCatalogInfo.cbCalculatedFileHash = cbHash;
|
|
#ifdef UNICODE
|
|
WinTrustCatalogInfo.pcwszMemberTag = lpFileName;
|
|
#else
|
|
MultiByteToWideChar(CP_ACP, 0, lpFileName, -1, UnicodeKey, MAX_PATH);
|
|
WinTrustCatalogInfo.pcwszMemberTag = UnicodeKey;
|
|
#endif
|
|
|
|
//
|
|
// Now we try to find the file hash in the catalog list, via CryptCATAdminEnumCatalogFromHash
|
|
//
|
|
PrevCat = NULL;
|
|
hCatInfo = s_dsd.CryptCATAdminEnumCatalogFromHash(s_dsd.hCatAdmin, lpHash, cbHash, 0, &PrevCat);
|
|
|
|
//
|
|
// We want to cycle through the matching catalogs until we find one that matches both hash and member tag
|
|
//
|
|
bRet = FALSE;
|
|
while(hCatInfo && !bRet)
|
|
{
|
|
ZeroMemory(&CatInfo, sizeof(CATALOG_INFO));
|
|
CatInfo.cbStruct = sizeof(CATALOG_INFO);
|
|
if(s_dsd.CryptCATCatalogInfoFromContext(hCatInfo, &CatInfo, 0))
|
|
{
|
|
WinTrustCatalogInfo.pcwszCatalogFilePath = CatInfo.wszCatalogFile;
|
|
|
|
// Now verify that the file is an actual member of the catalog.
|
|
hRes = s_dsd.WinVerifyTrust(NULL, &guidSubSystemDriver, &WinTrustData);
|
|
if (hRes == ERROR_SUCCESS)
|
|
{
|
|
/*
|
|
#ifdef UNICODE
|
|
GetFullPathName(CatInfo.wszCatalogFile, MAX_PATH, szBuffer, &lpFilePart);
|
|
#else
|
|
WideCharToMultiByte(CP_ACP, 0, CatInfo.wszCatalogFile, -1, szBuffer, sizeof(szBuffer), NULL, NULL);
|
|
GetFullPathName(szBuffer, MAX_PATH, szBuffer, &lpFilePart);
|
|
#endif
|
|
lpFileNode->lpCatalog = (LPTSTR)MALLOC((lstrlen(lpFilePart) + 1) * sizeof(TCHAR));
|
|
lstrcpy(lpFileNode->lpCatalog, lpFilePart);
|
|
*/
|
|
if (VerInfo.pcSignerCertContext != NULL)
|
|
{
|
|
s_dsd.CertFreeCertificateContext(VerInfo.pcSignerCertContext);
|
|
VerInfo.pcSignerCertContext = NULL;
|
|
}
|
|
bRet = TRUE;
|
|
}
|
|
}
|
|
|
|
if (!bRet)
|
|
{
|
|
// The hash was in this catalog, but the file wasn't a member... so off to the next catalog
|
|
PrevCat = hCatInfo;
|
|
hCatInfo = s_dsd.CryptCATAdminEnumCatalogFromHash(s_dsd.hCatAdmin, lpHash, cbHash, 0, &PrevCat);
|
|
}
|
|
}
|
|
|
|
if (!hCatInfo)
|
|
{
|
|
//
|
|
// If it wasn't found in the catalogs, check if the file is individually signed.
|
|
//
|
|
bRet = VerifyIsFileSigned(lpFileName, (PDRIVER_VER_INFO) &VerInfo);
|
|
if (bRet)
|
|
{
|
|
// If so, mark the file as being signed.
|
|
bSigned = TRUE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// The file was verified in the catalogs, so mark it as signed and free the catalog context.
|
|
bSigned = TRUE;
|
|
s_dsd.CryptCATAdminReleaseCatalogContext(s_dsd.hCatAdmin, hCatInfo, 0);
|
|
}
|
|
/*
|
|
if (lpFileNode->bSigned)
|
|
{
|
|
#ifdef UNICODE
|
|
lpFileNode->lpVersion = MALLOC((lstrlen(VerInfo.wszVersion) + 1) * sizeof(TCHAR));
|
|
lstrcpy(lpFileNode->lpVersion, VerInfo.wszVersion);
|
|
lpFileNode->lpSignedBy = MALLOC((lstrlen(VerInfo.wszSignedBy) + 1) * sizeof(TCHAR));
|
|
lstrcpy(lpFileNode->lpSignedBy, VerInfo.wszSignedBy);
|
|
#else
|
|
WideCharToMultiByte(CP_ACP, 0, VerInfo.wszVersion, -1, szBuffer, sizeof(szBuffer), NULL, NULL);
|
|
lpFileNode->lpVersion = (LPTSTR)MALLOC((lstrlen(szBuffer) + 1) * sizeof(TCHAR));
|
|
lstrcpy(lpFileNode->lpVersion, szBuffer);
|
|
WideCharToMultiByte(CP_ACP, 0, VerInfo.wszSignedBy, -1, szBuffer, sizeof(szBuffer), NULL, NULL);
|
|
lpFileNode->lpSignedBy = (LPTSTR)MALLOC((lstrlen(szBuffer) + 1) * sizeof(TCHAR));
|
|
lstrcpy(lpFileNode->lpSignedBy, szBuffer);
|
|
#endif
|
|
}
|
|
*/
|
|
return bSigned;
|
|
}
|
|
|
|
|
|
/****************************************************************************
|
|
*
|
|
* VerifyIsFileSigned
|
|
*
|
|
****************************************************************************/
|
|
BOOL VerifyIsFileSigned(LPTSTR pcszMatchFile, PDRIVER_VER_INFO lpVerInfo)
|
|
{
|
|
HRESULT hRes;
|
|
WINTRUST_DATA WinTrustData;
|
|
WINTRUST_FILE_INFO WinTrustFile;
|
|
GUID guidOSVerCheck = DRIVER_ACTION_VERIFY;
|
|
GUID guidPublishedSoftware = WINTRUST_ACTION_GENERIC_VERIFY_V2;
|
|
|
|
ZeroMemory(&WinTrustData, sizeof(WINTRUST_DATA));
|
|
WinTrustData.cbStruct = sizeof(WINTRUST_DATA);
|
|
WinTrustData.dwUIChoice = WTD_UI_NONE;
|
|
WinTrustData.fdwRevocationChecks = WTD_REVOKE_NONE;
|
|
WinTrustData.dwUnionChoice = WTD_CHOICE_FILE;
|
|
WinTrustData.dwStateAction = WTD_STATEACTION_AUTO_CACHE;
|
|
WinTrustData.pFile = &WinTrustFile;
|
|
WinTrustData.pPolicyCallbackData = (LPVOID)lpVerInfo;
|
|
|
|
ZeroMemory(lpVerInfo, sizeof(DRIVER_VER_INFO));
|
|
lpVerInfo->cbStruct = sizeof(DRIVER_VER_INFO);
|
|
|
|
ZeroMemory(&WinTrustFile, sizeof(WINTRUST_FILE_INFO));
|
|
WinTrustFile.cbStruct = sizeof(WINTRUST_FILE_INFO);
|
|
|
|
#ifndef UNICODE
|
|
WCHAR wszFileName[MAX_PATH];
|
|
MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, pcszMatchFile, -1, (LPWSTR)&wszFileName, MAX_PATH);
|
|
WinTrustFile.pcwszFilePath = wszFileName;
|
|
#else
|
|
WinTrustFile.pcwszFilePath = pcszMatchFile;
|
|
#endif
|
|
|
|
hRes = s_dsd.WinVerifyTrust(NULL, &guidOSVerCheck, &WinTrustData);
|
|
if (hRes != ERROR_SUCCESS)
|
|
hRes = s_dsd.WinVerifyTrust(NULL, &guidPublishedSoftware, &WinTrustData);
|
|
|
|
if (lpVerInfo->pcSignerCertContext != NULL)
|
|
{
|
|
s_dsd.CertFreeCertificateContext(lpVerInfo->pcSignerCertContext);
|
|
lpVerInfo->pcSignerCertContext = NULL;
|
|
}
|
|
|
|
return (hRes == ERROR_SUCCESS);
|
|
}
|
|
|
|
|
|
/****************************************************************************
|
|
*
|
|
* DiagnoseDxFiles
|
|
*
|
|
****************************************************************************/
|
|
VOID DiagnoseDxFiles(SysInfo* pSysInfo, FileInfo* pDxComponentsFileInfoFirst,
|
|
FileInfo* pDxWinComponentsFileInfoFirst)
|
|
{
|
|
FileInfo* pFileInfo;
|
|
TCHAR szHighest[50];
|
|
TCHAR szDXVersion[50];
|
|
BOOL bNT = BIsPlatformNT();
|
|
BOOL bWin2k = BIsWin2k();
|
|
BOOL bIA64 = BIsIA64();
|
|
FLOAT fDXVersion = 0.0f;
|
|
BOOL bDX5 = FALSE;
|
|
BOOL bDX6 = FALSE; // 6.x
|
|
BOOL bDX60 = FALSE; // 6.0
|
|
BOOL bDX61 = FALSE; // 6.1
|
|
BOOL bDX7 = FALSE; // 7.x
|
|
BOOL bDX70 = FALSE; // 7.0
|
|
BOOL bDX71 = FALSE; // 7.1
|
|
BOOL bDX8 = FALSE; // 8.x
|
|
BOOL bDX80 = FALSE; // 8.0
|
|
BOOL bDX81 = FALSE; // 8.1
|
|
BOOL b64BitDxDiag = BIsDxDiag64Bit();
|
|
TCHAR szMissing[200];
|
|
TCHAR szInWindows[200];
|
|
TCHAR szOld[200];
|
|
TCHAR szDebug[200];
|
|
TCHAR szBeta[200];
|
|
TCHAR szFmt[300];
|
|
TCHAR szMessage[300];
|
|
LONG lwNumInWindows;
|
|
LONG lwNumMissing;
|
|
LONG lwNumOld;
|
|
LONG lwNumDebug;
|
|
LONG lwNumBeta;
|
|
TCHAR szListContinuer[30];
|
|
TCHAR szListEtc[30];
|
|
BOOL bVersionWarnings = TRUE;
|
|
BOOL bWinsockWarning = FALSE;
|
|
|
|
// Find highest version number in list
|
|
szHighest[0] = '\0';
|
|
for (pFileInfo = pDxComponentsFileInfoFirst; pFileInfo != NULL;
|
|
pFileInfo = pFileInfo->m_pFileInfoNext)
|
|
{
|
|
if (pFileInfo->m_bIgnoreVersionInfo)
|
|
continue;
|
|
|
|
// ddrawex.dll and dxapi.sys have wacky version numbers, so ignore them
|
|
if (lstrcmpi(pFileInfo->m_szName, TEXT("ddrawex.dll")) == 0 ||
|
|
lstrcmpi(pFileInfo->m_szName, TEXT("dxapi.sys")) == 0)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
// Bug 18892: dplayx.dll and dpmodemx.dll can have wacky version numbers if
|
|
// DPlay 6.0a is installed over DX 6.0
|
|
if (lstrcmpi(pFileInfo->m_szName, TEXT("dplayx.dll")) == 0 &&
|
|
lstrcmpi(pFileInfo->m_szVersion, TEXT("4.06.02.0363")) == 0)
|
|
{
|
|
continue;
|
|
}
|
|
if (lstrcmpi(pFileInfo->m_szName, TEXT("dpmodemx.dll")) == 0 &&
|
|
lstrcmpi(pFileInfo->m_szVersion, TEXT("4.06.02.0356")) == 0)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
// DPlay 6.1a: dplay files can have higher version numbers if
|
|
// DPlay 6.1a is installed over DX 6.0 (or DX 6.1)
|
|
if (lstrcmpi(pFileInfo->m_szVersion, TEXT("4.06.03.0518")) == 0 &&
|
|
(lstrcmpi(pFileInfo->m_szName, TEXT("dplayx.dll")) == 0 ||
|
|
lstrcmpi(pFileInfo->m_szName, TEXT("dpmodemx.dll")) == 0 ||
|
|
lstrcmpi(pFileInfo->m_szName, TEXT("dpwsockx.dll")) == 0 ||
|
|
lstrcmpi(pFileInfo->m_szName, TEXT("dplaysvr.exe")) == 0))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if (lstrcmp(pFileInfo->m_szVersion, pSysInfo->m_szDxDiagVersion) > 0)
|
|
{
|
|
// Bug 21291: Do not complain about file version newer than DxDiag itself
|
|
continue;
|
|
}
|
|
|
|
if (lstrcmp(szHighest, pFileInfo->m_szVersion) < 0)
|
|
lstrcpy(szHighest, pFileInfo->m_szVersion);
|
|
}
|
|
|
|
if (bNT)
|
|
lstrcpy(szDXVersion, pSysInfo->m_szDirectXVersion);
|
|
else
|
|
lstrcpy(szDXVersion, szHighest);
|
|
|
|
// Determine DX version
|
|
DWORD dwMajor;
|
|
DWORD dwMinor;
|
|
DWORD dwRevision;
|
|
DWORD dwBuild;
|
|
_stscanf(szDXVersion, TEXT("%d.%d.%d.%d"), &dwMajor, &dwMinor, &dwRevision, &dwBuild);
|
|
if (dwMinor < 6)
|
|
bDX5 = TRUE;
|
|
else if (dwMinor < 7 && dwRevision < 2)
|
|
bDX60 = TRUE;
|
|
else if (dwMinor < 7)
|
|
bDX61 = TRUE;
|
|
else if (dwMinor < 8 && dwRevision < 1)
|
|
bDX70 = TRUE;
|
|
else if (dwMinor < 8)
|
|
bDX71 = TRUE;
|
|
else if (dwMinor == 8 && dwRevision < 1)
|
|
bDX80 = TRUE;
|
|
else if (dwMinor >= 8)
|
|
bDX81 = TRUE;
|
|
|
|
// Calc DX ver
|
|
fDXVersion = (float) dwMinor + (float) (dwRevision/10.0f);
|
|
|
|
// Is this DX6?
|
|
bDX6 = bDX60 || bDX61;
|
|
|
|
// Is this DX7?
|
|
bDX7 = bDX70 || bDX71;
|
|
|
|
// Is this DX8?
|
|
bDX8 = bDX80 || bDX81;
|
|
|
|
lwNumInWindows = 0;
|
|
lwNumMissing = 0;
|
|
lwNumOld = 0;
|
|
lwNumDebug = 0;
|
|
lwNumBeta = 0;
|
|
LoadString(NULL, IDS_LISTCONTINUER, szListContinuer, 30);
|
|
LoadString(NULL, IDS_LISTETC, szListEtc, 30);
|
|
|
|
for (pFileInfo = pDxWinComponentsFileInfoFirst; pFileInfo != NULL;
|
|
pFileInfo = pFileInfo->m_pFileInfoNext)
|
|
{
|
|
pFileInfo->m_bProblem = TRUE;
|
|
lwNumInWindows++;
|
|
if (lwNumInWindows == 1)
|
|
{
|
|
lstrcpy(szInWindows, pFileInfo->m_szName);
|
|
}
|
|
else if (lwNumInWindows < 4)
|
|
{
|
|
lstrcat(szInWindows, szListContinuer);
|
|
lstrcat(szInWindows, pFileInfo->m_szName);
|
|
}
|
|
else if (lwNumInWindows < 5)
|
|
{
|
|
lstrcat(szInWindows, szListEtc);
|
|
}
|
|
}
|
|
|
|
for (pFileInfo = pDxComponentsFileInfoFirst; pFileInfo != NULL;
|
|
pFileInfo = pFileInfo->m_pFileInfoNext)
|
|
{
|
|
if (!pFileInfo->m_bExists && !pFileInfo->m_bOptional)
|
|
{
|
|
// A missing file is a problem unless it's optional, OR...
|
|
// (on NT): it's optional on NT
|
|
// (on IA64): it's not on IA64
|
|
// (on IA64): we're running 32-bit dxdiag and its optional on WOW
|
|
// if file hasn't shipped yet on this DX version
|
|
// if file stopped shipping on or after this DX version
|
|
if (bNT && pFileInfo->m_bOptionalOnNT)
|
|
{
|
|
}
|
|
else if (bIA64 && pFileInfo->m_bNotIA64)
|
|
{
|
|
}
|
|
else if (bIA64 && !b64BitDxDiag && pFileInfo->m_bOptionalOnWOW64)
|
|
{
|
|
}
|
|
else if (fDXVersion+0.05f < pFileInfo->m_fStartShipAt)
|
|
{
|
|
}
|
|
else if (fDXVersion+0.05f >= pFileInfo->m_fStopShipAt)
|
|
{
|
|
}
|
|
else
|
|
{
|
|
pFileInfo->m_bProblem = TRUE;
|
|
LoadString(NULL, IDS_FILEMISSING, pFileInfo->m_szVersion, 50);
|
|
lwNumMissing++;
|
|
if (lwNumMissing == 1)
|
|
{
|
|
lstrcpy(szMissing, pFileInfo->m_szName);
|
|
}
|
|
else if (lwNumMissing < 4)
|
|
{
|
|
lstrcat(szMissing, szListContinuer);
|
|
lstrcat(szMissing, pFileInfo->m_szName);
|
|
}
|
|
else if (lwNumMissing < 5)
|
|
{
|
|
lstrcat(szMissing, szListEtc);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!pFileInfo->m_bExists)
|
|
continue;
|
|
|
|
if( BIsWin95() )
|
|
{
|
|
if( lstrcmpi(pFileInfo->m_szName, TEXT("wsock32.dll")) )
|
|
{
|
|
if( IsBadWin95Winsock( pFileInfo ) )
|
|
bWinsockWarning = TRUE;
|
|
}
|
|
}
|
|
|
|
// If DX6 or later, flag any dx5 only files as
|
|
// obsolete (needing to be deleted)
|
|
// manbugs 16765: don't complain about these files, just don't list them
|
|
if (!bDX5 && (pFileInfo->m_fStopShipAt == 6.0f))
|
|
{
|
|
pFileInfo->m_bProblem = TRUE;
|
|
pFileInfo->m_bObsolete = TRUE;
|
|
continue; // don't complain about these files for any other reason
|
|
}
|
|
|
|
if (bVersionWarnings && lstrcmp(szHighest, pFileInfo->m_szVersion) != 0)
|
|
{
|
|
if( pFileInfo->m_bIgnoreVersionInfo )
|
|
{
|
|
// Don't warn on files that have m_bIgnoreVersionInfo set
|
|
}
|
|
else if( _tcsstr(pFileInfo->m_szVersion, TEXT("5.01.2600.0000")) != NULL )
|
|
{
|
|
// Allow 5.01.2600.0000 in SP1
|
|
}
|
|
else if( bDX81 && ( _tcsstr(pFileInfo->m_szVersion, TEXT("4.08.00.0400")) != NULL ||
|
|
_tcsstr(pFileInfo->m_szVersion, TEXT("5.01.2258.0400")) != NULL ) )
|
|
{
|
|
// Bug 48732: If szHighest is 4.08.00.05xx and
|
|
// pFileInfo->m_szVersion is 4.08.00.0400 its OK
|
|
}
|
|
else if( bWin2k && (
|
|
(lstrcmpi(pFileInfo->m_szName, TEXT("d3drm.dll")) == 0 && lstrcmpi(pFileInfo->m_szVersion, TEXT("5.00.2134.0001")) == 0) ||
|
|
(lstrcmpi(pFileInfo->m_szName, TEXT("d3dxof.dll")) == 0 && lstrcmpi(pFileInfo->m_szVersion, TEXT("5.00.2135.0001")) == 0) ||
|
|
(lstrcmpi(pFileInfo->m_szName, TEXT("d3dpmesh.dll")) == 0 && lstrcmpi(pFileInfo->m_szVersion, TEXT("5.00.2134.0001")) == 0)
|
|
)
|
|
)
|
|
{
|
|
}
|
|
else if( bDX71 && _tcsstr(pFileInfo->m_szVersion, TEXT("4.07.00.07")) != NULL )
|
|
{
|
|
// Bug 114753: If szHighest is 4.07.01.xxxx and
|
|
// pFileInfo->m_szVersion is 4.07.00.0700 its OK (for now).
|
|
}
|
|
else if (!bNT && (bDX60 || bDX61) && CompareString(LOCALE_SYSTEM_DEFAULT, 0,
|
|
pFileInfo->m_szVersion, 4, TEXT("4.05"), 4) == CSTR_EQUAL &&
|
|
( lstrcmpi(pFileInfo->m_szName, TEXT("dsound.dll")) == 0 ||
|
|
lstrcmpi(pFileInfo->m_szName, TEXT("dsound.vxd")) == 0 ||
|
|
lstrcmpi(pFileInfo->m_szName, TEXT("dinput.dll")) == 0 ||
|
|
lstrcmpi(pFileInfo->m_szName, TEXT("dinput.vxd")) == 0 ||
|
|
lstrcmpi(pFileInfo->m_szName, TEXT("vjoyd.vxd")) == 0 ||
|
|
lstrcmpi(pFileInfo->m_szName, TEXT("msanalog.vxd")) == 0 ||
|
|
lstrcmpi(pFileInfo->m_szName, TEXT("joy.cpl")) == 0 ||
|
|
lstrcmpi(pFileInfo->m_szName, TEXT("gcdef.dll")) == 0 ||
|
|
lstrcmpi(pFileInfo->m_szName, TEXT("gchand.dll")) == 0))
|
|
{
|
|
// If Win9x DX6.x, dsound and dinput are allowed to be 4.05.xx.xxxx
|
|
// CompareString is used rather than lstrcmp only because we
|
|
// only want to look at the first four characters of the string
|
|
|
|
// Don't report these as version problems
|
|
}
|
|
else if (!bNT && bDX7 && CompareString(LOCALE_SYSTEM_DEFAULT, 0,
|
|
pFileInfo->m_szVersion, 4, TEXT("4.05"), 4) == CSTR_EQUAL &&
|
|
(lstrcmpi(pFileInfo->m_szName, TEXT("dinput.dll")) == 0 ||
|
|
lstrcmpi(pFileInfo->m_szName, TEXT("dinput.vxd")) == 0 ||
|
|
lstrcmpi(pFileInfo->m_szName, TEXT("joy.cpl")) == 0 ||
|
|
lstrcmpi(pFileInfo->m_szName, TEXT("gchand.dll")) == 0 ||
|
|
lstrcmpi(pFileInfo->m_szName, TEXT("gcdef.dll")) == 0 ||
|
|
lstrcmpi(pFileInfo->m_szName, TEXT("vjoyd.vxd")) == 0 ||
|
|
lstrcmpi(pFileInfo->m_szName, TEXT("msanalog.vxd")) == 0))
|
|
{
|
|
// 21470: On DX7, these input files still exist on Win95,
|
|
// and they stay at DX5 level.
|
|
}
|
|
else if ( !bNT &&
|
|
(lstrcmpi(pFileInfo->m_szName, TEXT("msjstick.drv")) == 0 && lstrcmpi(pFileInfo->m_szVersion, TEXT("4.00.00.0950")) == 0) ||
|
|
(lstrcmpi(pFileInfo->m_szName, TEXT("vjoyd.vxd")) == 0 && lstrcmpi(pFileInfo->m_szVersion, TEXT("4.05.00.0155")) == 0)
|
|
)
|
|
{
|
|
// 34687: These stays at the dx5 level.
|
|
}
|
|
else if (!bNT && (lstrcmpi(pFileInfo->m_szName, TEXT("ddrawex.dll")) == 0 ||
|
|
lstrcmpi(pFileInfo->m_szName, TEXT("dxapi.sys")) == 0))
|
|
{
|
|
// Ignore ddrawex.dll and dxapi.sys on Win9x because they have weird version numbers:
|
|
}
|
|
else if (lstrcmpi(pFileInfo->m_szName, TEXT("dplayx.dll")) == 0 &&
|
|
lstrcmpi(pFileInfo->m_szVersion, TEXT("4.06.02.0363")) == 0)
|
|
{
|
|
// Bug 18892: work around DPlay 6.0a
|
|
}
|
|
else if (lstrcmpi(pFileInfo->m_szName, TEXT("dpmodemx.dll")) == 0 &&
|
|
lstrcmpi(pFileInfo->m_szVersion, TEXT("4.06.02.0356")) == 0)
|
|
{
|
|
// Bug 18892: work around DPlay 6.0a
|
|
}
|
|
else if (lstrcmpi(pFileInfo->m_szVersion, TEXT("4.06.03.0518")) == 0 &&
|
|
(lstrcmpi(pFileInfo->m_szName, TEXT("dplayx.dll")) == 0 ||
|
|
lstrcmpi(pFileInfo->m_szName, TEXT("dpmodemx.dll")) == 0 ||
|
|
lstrcmpi(pFileInfo->m_szName, TEXT("dpwsockx.dll")) == 0 ||
|
|
lstrcmpi(pFileInfo->m_szName, TEXT("dplaysvr.exe")) == 0))
|
|
{
|
|
// DPlay 6.1a: dplay files can have higher version numbers if
|
|
// DPlay 6.1a is installed over DX 6.0 (or DX 6.1)
|
|
}
|
|
else if (lstrcmpi(pFileInfo->m_szName, TEXT("dxsetup.exe")) == 0 ||
|
|
lstrcmpi(pFileInfo->m_szName, TEXT("dsetup.dll")) == 0 ||
|
|
lstrcmpi(pFileInfo->m_szName, TEXT("dsetup16.dll")) == 0 ||
|
|
lstrcmpi(pFileInfo->m_szName, TEXT("dsetup32.dll")) == 0 ||
|
|
lstrcmpi(pFileInfo->m_szName, TEXT("directx.cpl")) == 0)
|
|
{
|
|
// Bug 18540: Don't complain if dsetup/cpl files are out of date because
|
|
// some updates (OSR) don't update the setup/cpl files which may exist from
|
|
// another (SDK) installation
|
|
}
|
|
else if (!bNT && lstrcmpi(pFileInfo->m_szVersion, TEXT("4.06.02.0436")) == 0 &&
|
|
(lstrcmpi(pFileInfo->m_szName, TEXT("d3drm.dll")) == 0 ||
|
|
lstrcmpi(pFileInfo->m_szName, TEXT("d3dxof.dll")) == 0 ||
|
|
lstrcmpi(pFileInfo->m_szName, TEXT("d3dpmesh.dll")) == 0 ||
|
|
lstrcmpi(pFileInfo->m_szName, TEXT("dplayx.dll")) == 0 ||
|
|
lstrcmpi(pFileInfo->m_szName, TEXT("dpmodemx.dll")) == 0 ||
|
|
lstrcmpi(pFileInfo->m_szName, TEXT("dpwsockx.dll")) == 0 ||
|
|
lstrcmpi(pFileInfo->m_szName, TEXT("dplaysvr.exe")) == 0))
|
|
{
|
|
// On DX 6.1a, the RM and DPlay files stay at 4.06.02.0436. No problemo.
|
|
}
|
|
else if (lstrcmp(pFileInfo->m_szVersion, pSysInfo->m_szDxDiagVersion) > 0)
|
|
{
|
|
// Bug 21291: Do not complain about file version newer than DxDiag itself
|
|
}
|
|
else
|
|
{
|
|
pFileInfo->m_bProblem = TRUE;
|
|
lwNumOld++;
|
|
if (lwNumOld == 1)
|
|
{
|
|
lstrcpy(szOld, pFileInfo->m_szName);
|
|
}
|
|
else if (lwNumOld < 4)
|
|
{
|
|
lstrcat(szOld, szListContinuer);
|
|
lstrcat(szOld, pFileInfo->m_szName);
|
|
}
|
|
else if (lwNumOld < 5)
|
|
{
|
|
lstrcat(szOld, szListEtc);
|
|
}
|
|
}
|
|
} // end if (bVersionWarnings && lstrcmp(szHighest, pFileInfo->m_szVersion) != 0)
|
|
|
|
if (pFileInfo->m_bBeta && !pFileInfo->m_bIgnoreBeta)
|
|
{
|
|
pFileInfo->m_bProblem = TRUE;
|
|
lwNumBeta++;
|
|
if (lwNumBeta == 1)
|
|
{
|
|
lstrcpy(szBeta, pFileInfo->m_szName);
|
|
}
|
|
else if (lwNumBeta < 4)
|
|
{
|
|
lstrcat(szBeta, szListContinuer);
|
|
lstrcat(szBeta, pFileInfo->m_szName);
|
|
}
|
|
else if (lwNumBeta < 5)
|
|
{
|
|
lstrcat(szBeta, szListEtc);
|
|
}
|
|
}
|
|
|
|
if (pFileInfo->m_bDebug && !pFileInfo->m_bIgnoreDebug)
|
|
{
|
|
pFileInfo->m_bProblem = TRUE;
|
|
lwNumDebug++;
|
|
if (lwNumDebug == 1)
|
|
{
|
|
lstrcpy(szDebug, pFileInfo->m_szName);
|
|
}
|
|
else if (lwNumDebug < 4)
|
|
{
|
|
lstrcat(szDebug, szListContinuer);
|
|
lstrcat(szDebug, pFileInfo->m_szName);
|
|
}
|
|
else if (lwNumDebug < 5)
|
|
{
|
|
lstrcat(szDebug, szListEtc);
|
|
}
|
|
}
|
|
}
|
|
|
|
BOOL bShouldReinstall = FALSE;
|
|
|
|
_tcscpy(pSysInfo->m_szDXFileNotes, TEXT("") );
|
|
_tcscpy(pSysInfo->m_szDXFileNotesEnglish, TEXT("") );
|
|
|
|
if (lwNumInWindows > 0)
|
|
{
|
|
if (lwNumInWindows == 1)
|
|
LoadString(NULL, IDS_INWINDOWSFMT1, szFmt, 300);
|
|
else
|
|
LoadString(NULL, IDS_INWINDOWSFMT2, szFmt, 300);
|
|
wsprintf(szMessage, szFmt, szInWindows);
|
|
_tcscat(pSysInfo->m_szDXFileNotes, szMessage);
|
|
|
|
if (lwNumInWindows == 1)
|
|
LoadString(NULL, IDS_INWINDOWSFMT1_ENGLISH, szFmt, 300);
|
|
else
|
|
LoadString(NULL, IDS_INWINDOWSFMT2_ENGLISH, szFmt, 300);
|
|
wsprintf(szMessage, szFmt, szInWindows);
|
|
_tcscat(pSysInfo->m_szDXFileNotesEnglish, szMessage);
|
|
}
|
|
|
|
if (lwNumMissing > 0)
|
|
{
|
|
if (lwNumMissing == 1)
|
|
LoadString(NULL, IDS_MISSINGFMT1, szFmt, 300);
|
|
else
|
|
LoadString(NULL, IDS_MISSINGFMT2, szFmt, 300);
|
|
wsprintf(szMessage, szFmt, szMissing);
|
|
_tcscat(pSysInfo->m_szDXFileNotes, szMessage);
|
|
|
|
if (lwNumMissing == 1)
|
|
LoadString(NULL, IDS_MISSINGFMT1_ENGLISH, szFmt, 300);
|
|
else
|
|
LoadString(NULL, IDS_MISSINGFMT2_ENGLISH, szFmt, 300);
|
|
wsprintf(szMessage, szFmt, szMissing);
|
|
_tcscat(pSysInfo->m_szDXFileNotesEnglish, szMessage);
|
|
|
|
bShouldReinstall = TRUE;
|
|
}
|
|
|
|
if (lwNumOld > 0)
|
|
{
|
|
if (lwNumOld == 1)
|
|
LoadString(NULL, IDS_OLDFMT1, szFmt, 300);
|
|
else
|
|
LoadString(NULL, IDS_OLDFMT2, szFmt, 300);
|
|
wsprintf(szMessage, szFmt, szOld);
|
|
_tcscat(pSysInfo->m_szDXFileNotes, szMessage);
|
|
|
|
if (lwNumOld == 1)
|
|
LoadString(NULL, IDS_OLDFMT1_ENGLISH, szFmt, 300);
|
|
else
|
|
LoadString(NULL, IDS_OLDFMT2_ENGLISH, szFmt, 300);
|
|
wsprintf(szMessage, szFmt, szOld);
|
|
_tcscat(pSysInfo->m_szDXFileNotesEnglish, szMessage);
|
|
|
|
bShouldReinstall = TRUE;
|
|
}
|
|
|
|
if (lwNumBeta > 0)
|
|
{
|
|
if (lwNumBeta == 1)
|
|
LoadString(NULL, IDS_BETAFMT1, szFmt, 300);
|
|
else
|
|
LoadString(NULL, IDS_BETAFMT2, szFmt, 300);
|
|
wsprintf(szMessage, szFmt, szBeta);
|
|
_tcscat(pSysInfo->m_szDXFileNotes, szMessage);
|
|
|
|
if (lwNumBeta == 1)
|
|
LoadString(NULL, IDS_BETAFMT1_ENGLISH, szFmt, 300);
|
|
else
|
|
LoadString(NULL, IDS_BETAFMT2_ENGLISH, szFmt, 300);
|
|
wsprintf(szMessage, szFmt, szBeta);
|
|
_tcscat(pSysInfo->m_szDXFileNotesEnglish, szMessage);
|
|
|
|
bShouldReinstall = TRUE;
|
|
}
|
|
|
|
if (lwNumDebug > 0)
|
|
{
|
|
if (lwNumDebug == 1)
|
|
LoadString(NULL, IDS_DEBUGFMT1, szFmt, 300);
|
|
else
|
|
LoadString(NULL, IDS_DEBUGFMT2, szFmt, 300);
|
|
wsprintf(szMessage, szFmt, szDebug);
|
|
_tcscat( pSysInfo->m_szDXFileNotes, szMessage);
|
|
|
|
if (lwNumDebug == 1)
|
|
LoadString(NULL, IDS_DEBUGFMT1_ENGLISH, szFmt, 300);
|
|
else
|
|
LoadString(NULL, IDS_DEBUGFMT2_ENGLISH, szFmt, 300);
|
|
wsprintf(szMessage, szFmt, szDebug);
|
|
_tcscat( pSysInfo->m_szDXFileNotesEnglish, szMessage);
|
|
|
|
//bShouldReinstall = TRUE;
|
|
}
|
|
|
|
if( bWinsockWarning )
|
|
{
|
|
LoadString(NULL, IDS_WINSOCK_WARN, szMessage, 300);
|
|
_tcscat( pSysInfo->m_szDXFileNotes, szMessage);
|
|
|
|
LoadString(NULL, IDS_WINSOCK_WARN_ENGLISH, szMessage, 300);
|
|
_tcscat( pSysInfo->m_szDXFileNotesEnglish, szMessage);
|
|
}
|
|
|
|
if( bShouldReinstall )
|
|
{
|
|
BOOL bTellUser = FALSE;
|
|
|
|
// Figure out if the user can install DirectX
|
|
if( BIsPlatform9x() )
|
|
bTellUser = TRUE;
|
|
else if( BIsWin2k() && bDX8 )
|
|
bTellUser = TRUE;
|
|
|
|
if( bTellUser )
|
|
{
|
|
LoadString(NULL, IDS_REINSTALL_DX, szMessage, 300);
|
|
_tcscat( pSysInfo->m_szDXFileNotes, szMessage);
|
|
|
|
LoadString(NULL, IDS_REINSTALL_DX_ENGLISH, szMessage, 300);
|
|
_tcscat( pSysInfo->m_szDXFileNotesEnglish, szMessage);
|
|
}
|
|
}
|
|
|
|
if (lwNumMissing == 0 && lwNumOld == 0 &&
|
|
lwNumBeta == 0 && lwNumDebug == 0 && lwNumInWindows == 0)
|
|
{
|
|
LoadString(NULL, IDS_NOPROBLEM, szMessage, 300);
|
|
_tcscat(pSysInfo->m_szDXFileNotes, szMessage);
|
|
|
|
LoadString(NULL, IDS_NOPROBLEM_ENGLISH, szMessage, 300);
|
|
_tcscat(pSysInfo->m_szDXFileNotesEnglish, szMessage);
|
|
}
|
|
}
|
|
|
|
|
|
/****************************************************************************
|
|
*
|
|
* IsBadWin95Winsock
|
|
*
|
|
****************************************************************************/
|
|
BOOL IsBadWin95Winsock( FileInfo* pFileInfo )
|
|
{
|
|
typedef int (PASCAL* LPWSASTARTUP)(IN WORD wVersionRequired, OUT LPWSADATA lpWSAData);
|
|
typedef int (PASCAL* LPWSACLEANUP)(void);
|
|
|
|
BOOL bReturn = FALSE;
|
|
TCHAR szPath[MAX_PATH];
|
|
HINSTANCE hInstWSock;
|
|
LPWSASTARTUP pWSAStartup = NULL;
|
|
LPWSACLEANUP pWSACleanup = NULL;
|
|
|
|
GetSystemDirectory(szPath, MAX_PATH);
|
|
lstrcat(szPath, TEXT("\\wsock32.dll"));
|
|
hInstWSock = LoadLibrary(szPath);
|
|
if (hInstWSock != NULL)
|
|
{
|
|
pWSAStartup = (LPWSASTARTUP)GetProcAddress(hInstWSock, "WSAStartup");
|
|
pWSACleanup = (LPWSACLEANUP)GetProcAddress(hInstWSock, "WSACleanup");
|
|
if (pWSAStartup != NULL && pWSACleanup != NULL)
|
|
{
|
|
WORD wVersionRequested;
|
|
WSADATA wsaData;
|
|
int err;
|
|
wVersionRequested = MAKEWORD( 2, 2 );
|
|
|
|
err = pWSAStartup( wVersionRequested, &wsaData );
|
|
if ( err == 0 )
|
|
{
|
|
if ( LOBYTE( wsaData.wVersion ) == 2 &&
|
|
HIBYTE( wsaData.wVersion ) == 2 )
|
|
{
|
|
FILETIME fileTimeGoodWinsock;
|
|
SYSTEMTIME systemTimeGoodWinsock;
|
|
ULARGE_INTEGER ulGoodWinsock;
|
|
ULARGE_INTEGER ulCurrentWinsock;
|
|
|
|
ZeroMemory( &systemTimeGoodWinsock, sizeof(SYSTEMTIME) );
|
|
systemTimeGoodWinsock.wYear = 1998;
|
|
systemTimeGoodWinsock.wMonth = 2;
|
|
systemTimeGoodWinsock.wDay = 6;
|
|
systemTimeGoodWinsock.wHour = 14;
|
|
systemTimeGoodWinsock.wMinute = 18;
|
|
systemTimeGoodWinsock.wSecond = 00;
|
|
|
|
SystemTimeToFileTime( &systemTimeGoodWinsock, &fileTimeGoodWinsock );
|
|
|
|
ulCurrentWinsock.LowPart = pFileInfo->m_FileTime.dwLowDateTime;
|
|
ulCurrentWinsock.HighPart = pFileInfo->m_FileTime.dwHighDateTime;
|
|
ulGoodWinsock.LowPart = fileTimeGoodWinsock.dwLowDateTime;
|
|
ulGoodWinsock.HighPart = fileTimeGoodWinsock.dwHighDateTime;
|
|
|
|
if( ulCurrentWinsock.QuadPart < ulGoodWinsock.QuadPart )
|
|
{
|
|
bReturn = TRUE;
|
|
}
|
|
}
|
|
|
|
pWSACleanup();
|
|
}
|
|
}
|
|
}
|
|
|
|
FreeLibrary(hInstWSock);
|
|
|
|
return bReturn;
|
|
}
|