1182 lines
37 KiB
C
1182 lines
37 KiB
C
/*==========================================================================;
|
|
*
|
|
* Copyright (C) 1994-1997 Microsoft Corporation. All Rights Reserved.
|
|
*
|
|
* File: drvinfo.c
|
|
* Content: DirectDraw driver info implementation
|
|
*@@BEGIN_MSINTERNAL
|
|
* History:
|
|
* Date By Reason
|
|
* ==== == ======
|
|
* 17-jun-98 jeffno initial implementation, after michael lyons and toddla
|
|
* 14-jun-99 mregen return WHQL certification level -- postponed
|
|
*@@END_MSINTERNAL
|
|
*
|
|
***************************************************************************/
|
|
|
|
#include "ddrawpr.h"
|
|
|
|
#include <tchar.h>
|
|
#include <stdio.h>
|
|
#include <wincrypt.h>
|
|
#include <wintrust.h>
|
|
#include <softpub.h>
|
|
#include <mscat.h>
|
|
|
|
|
|
|
|
//========================================================================
|
|
//
|
|
// just some handy forward declarations
|
|
//
|
|
DWORD GetWHQLLevel(LPTSTR lpszDriver, LPSTR lpszWin9xDriver);
|
|
DWORD IsFileDigitallySigned(LPTSTR lpszDriver);
|
|
BOOL FileIsSignedOld(LPTSTR lpszFile);
|
|
|
|
//
|
|
// These functions are defined in mscat.h. They are not available on win95,
|
|
// so we have to use LoadLibrary to load mscat32.dll and wincrypt.dll
|
|
//
|
|
typedef HCATINFO WINAPI funcCryptCATAdminEnumCatalogFromHash(HCATADMIN hCatAdmin,
|
|
BYTE *pbHash,
|
|
DWORD cbHash,
|
|
DWORD dwFlags,
|
|
HCATINFO *phPrevCatInfo);
|
|
typedef BOOL WINAPI funcCryptCATAdminCalcHashFromFileHandle(HANDLE hFile,
|
|
DWORD *pcbHash,
|
|
BYTE *pbHash,
|
|
DWORD dwFlags);
|
|
typedef HANDLE WINAPI funcCryptCATOpen(LPWSTR pwszFileName,
|
|
DWORD fdwOpenFlags,
|
|
HCRYPTPROV hProv,
|
|
DWORD dwPublicVersion,
|
|
DWORD dwEncodingType);
|
|
typedef BOOL WINAPI funcCryptCATClose(IN HANDLE hCatalog);
|
|
typedef CRYPTCATATTRIBUTE * WINAPI funcCryptCATGetCatAttrInfo(HANDLE hCatalog,
|
|
LPWSTR pwszReferenceTag);
|
|
typedef BOOL WINAPI funcCryptCATAdminAcquireContext(HCATADMIN *phCatAdmin,
|
|
GUID *pgSubsystem,
|
|
DWORD dwFlags);
|
|
typedef BOOL WINAPI funcCryptCATAdminReleaseContext(HCATADMIN hCatAdmin,
|
|
DWORD dwFlags);
|
|
typedef BOOL WINAPI funcCryptCATAdminReleaseCatalogContext(HCATADMIN hCatAdmin,
|
|
HCATINFO hCatInfo,
|
|
DWORD dwFlags);
|
|
typedef BOOL WINAPI funcCryptCATCatalogInfoFromContext(HCATINFO hCatInfo,
|
|
CATALOG_INFO *psCatInfo,
|
|
DWORD dwFlags);
|
|
|
|
typedef CRYPTCATATTRIBUTE * WINAPI funcCryptCATEnumerateCatAttr(HCATINFO hCatalog,
|
|
CRYPTCATATTRIBUTE *lpCat);
|
|
|
|
|
|
//
|
|
// function defined in wincrypt.dll
|
|
//
|
|
typedef LONG WINAPI funcWinVerifyTrust(HWND hwnd, GUID *pgActionID,
|
|
LPVOID pWVTData);
|
|
|
|
//
|
|
// our storage for the mscat32/wincrypt dll loader
|
|
//
|
|
typedef struct tagCatApi {
|
|
BOOL bInitialized;
|
|
HINSTANCE hLibMSCat;
|
|
HINSTANCE hLibWinTrust;
|
|
HCATADMIN hCatAdmin;
|
|
funcCryptCATClose *pCryptCATClose;
|
|
funcCryptCATGetCatAttrInfo *pCryptCATGetCatAttrInfo;
|
|
funcCryptCATOpen *pCryptCATOpen;
|
|
funcCryptCATAdminEnumCatalogFromHash *pCryptCATAdminEnumCatalogFromHash;
|
|
funcCryptCATAdminCalcHashFromFileHandle *pCryptCATAdminCalcHashFromFileHandle;
|
|
funcCryptCATAdminAcquireContext *pCryptCATAdminAcquireContext;
|
|
funcCryptCATAdminReleaseContext *pCryptCATAdminReleaseContext;
|
|
funcCryptCATAdminReleaseCatalogContext *pCryptCATAdminReleaseCatalogContext;
|
|
funcCryptCATCatalogInfoFromContext *pCryptCATCatalogInfoFromContext;
|
|
funcCryptCATEnumerateCatAttr *pCryptCATEnumerateCatAttr;
|
|
funcWinVerifyTrust *pWinVerifyTrust;
|
|
} CATAPI,* LPCATAPI;
|
|
|
|
//========================================================================
|
|
//
|
|
// some helper functions to open/close crypt API
|
|
//
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "InitCATAPI"
|
|
|
|
|
|
BOOL InitCATAPI(LPCATAPI lpCatApi)
|
|
{
|
|
UINT uiOldErrorMode;
|
|
HINSTANCE hLibMSCat;
|
|
HINSTANCE hLibWinTrust;
|
|
|
|
DDASSERT(lpCatApi!=NULL);
|
|
ZeroMemory(lpCatApi, sizeof(CATAPI));
|
|
|
|
// already initialized by ZeroMemory
|
|
// lpCatApi->bInitialized=FALSE:
|
|
|
|
uiOldErrorMode=SetErrorMode(SEM_NOOPENFILEERRORBOX);
|
|
hLibMSCat=LoadLibrary("mscat32.dll");
|
|
hLibWinTrust=LoadLibrary("wintrust.dll");
|
|
|
|
if (hLibMSCat!=NULL &&
|
|
hLibWinTrust!=NULL)
|
|
{
|
|
lpCatApi->pCryptCATOpen=(funcCryptCATOpen *)
|
|
GetProcAddress (hLibMSCat, "CryptCATOpen");
|
|
lpCatApi->pCryptCATClose=(funcCryptCATClose *)
|
|
GetProcAddress (hLibMSCat, "CryptCATClose");
|
|
lpCatApi->pCryptCATGetCatAttrInfo=(funcCryptCATGetCatAttrInfo *)
|
|
GetProcAddress (hLibMSCat, "CryptCATGetCatAttrInfo");
|
|
lpCatApi->pCryptCATAdminCalcHashFromFileHandle=(funcCryptCATAdminCalcHashFromFileHandle*)
|
|
GetProcAddress (hLibMSCat, "CryptCATAdminCalcHashFromFileHandle");
|
|
lpCatApi->pCryptCATAdminEnumCatalogFromHash=(funcCryptCATAdminEnumCatalogFromHash*)
|
|
GetProcAddress (hLibMSCat, "CryptCATAdminEnumCatalogFromHash");
|
|
lpCatApi->pCryptCATAdminAcquireContext=(funcCryptCATAdminAcquireContext*)
|
|
GetProcAddress (hLibMSCat, "CryptCATAdminAcquireContext");
|
|
lpCatApi->pCryptCATAdminReleaseContext=(funcCryptCATAdminReleaseContext*)
|
|
GetProcAddress (hLibMSCat, "CryptCATAdminReleaseContext");
|
|
lpCatApi->pCryptCATAdminReleaseCatalogContext=(funcCryptCATAdminReleaseCatalogContext*)
|
|
GetProcAddress (hLibMSCat, "CryptCATAdminReleaseCatalogContext");
|
|
lpCatApi->pCryptCATCatalogInfoFromContext=(funcCryptCATCatalogInfoFromContext*)
|
|
GetProcAddress (hLibMSCat, "CryptCATCatalogInfoFromContext");
|
|
lpCatApi->pCryptCATEnumerateCatAttr=(funcCryptCATEnumerateCatAttr*)
|
|
GetProcAddress (hLibMSCat, "CryptCATEnumerateCatAttr");
|
|
lpCatApi->pWinVerifyTrust=(funcWinVerifyTrust*)
|
|
GetProcAddress (hLibWinTrust,"WinVerifyTrust");
|
|
|
|
if (lpCatApi->pCryptCATOpen!=NULL &&
|
|
lpCatApi->pCryptCATClose!=NULL &&
|
|
lpCatApi->pCryptCATGetCatAttrInfo!=NULL &&
|
|
lpCatApi->pCryptCATAdminCalcHashFromFileHandle!=NULL &&
|
|
lpCatApi->pCryptCATAdminEnumCatalogFromHash!=NULL &&
|
|
lpCatApi->pCryptCATAdminAcquireContext!=NULL &&
|
|
lpCatApi->pCryptCATAdminReleaseContext!=NULL &&
|
|
lpCatApi->pCryptCATAdminReleaseCatalogContext!=NULL &&
|
|
lpCatApi->pCryptCATCatalogInfoFromContext!=NULL &&
|
|
lpCatApi->pCryptCATEnumerateCatAttr !=NULL &&
|
|
lpCatApi->pWinVerifyTrust!=NULL
|
|
)
|
|
{
|
|
if ((*lpCatApi->pCryptCATAdminAcquireContext)(&lpCatApi->hCatAdmin,NULL,0))
|
|
{
|
|
lpCatApi->hLibMSCat=hLibMSCat;
|
|
lpCatApi->hLibWinTrust=hLibWinTrust;
|
|
lpCatApi->bInitialized=TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!lpCatApi->bInitialized)
|
|
{
|
|
FreeLibrary(hLibMSCat);
|
|
FreeLibrary(hLibWinTrust);
|
|
}
|
|
|
|
SetErrorMode(uiOldErrorMode);
|
|
|
|
return lpCatApi->bInitialized;
|
|
}
|
|
|
|
BOOL ReleaseCATAPI(LPCATAPI lpCatApi)
|
|
{
|
|
DDASSERT(lpCatApi!=NULL);
|
|
|
|
if (lpCatApi->bInitialized)
|
|
{
|
|
(*lpCatApi->pCryptCATAdminReleaseContext)(lpCatApi->hCatAdmin, 0);
|
|
|
|
FreeLibrary(lpCatApi->hLibMSCat);
|
|
FreeLibrary(lpCatApi->hLibWinTrust);
|
|
ZeroMemory(lpCatApi, sizeof(CATAPI));
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
//========================================================================
|
|
//
|
|
// _strstr
|
|
//
|
|
// String-in-string function, written to avoid RTL inclusion necessity.
|
|
//
|
|
//========================================================================
|
|
char *_strstr(char *s1, char *s2)
|
|
{
|
|
if (s1 && s2)
|
|
{
|
|
while (*s1)
|
|
{
|
|
char *p1=s1;
|
|
char *p2=s2;
|
|
|
|
while (*p2 && (*p1==*p2))
|
|
{
|
|
p1++;
|
|
p2++;
|
|
}
|
|
if (*p2==0)
|
|
return s1;
|
|
|
|
s1++;
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
//***&&*%**!!ing c runtime
|
|
|
|
DWORD _atoi(char * p)
|
|
{
|
|
DWORD dw=0;
|
|
while ((*p >= '0' && *p <= '9') || (*p >= 'A' && *p <= 'F') || (*p >= 'A' && *p <= 'F'))
|
|
{
|
|
dw = dw*16;
|
|
if (*p >= 'a')
|
|
dw += *p-'a' + 10;
|
|
else if (*p >= 'A')
|
|
dw += *p-'A' + 10;
|
|
else
|
|
dw += *p-'0';
|
|
|
|
p++;
|
|
}
|
|
return dw;
|
|
}
|
|
|
|
char *FindLast(char * s, char c)
|
|
{
|
|
char * pFound=0;
|
|
if (s)
|
|
{
|
|
while (*s)
|
|
{
|
|
if (*s == c)
|
|
pFound = s;
|
|
s++;
|
|
}
|
|
}
|
|
return pFound;
|
|
}
|
|
|
|
//========================================================================
|
|
// hard-coded vendor IDs
|
|
//========================================================================
|
|
#define VEN_3DFX "VEN_121A"
|
|
#define VEN_3DFXVOODOO1 "VEN_121A&DEV_0001"
|
|
#define VEN_POWERVR "VEN_1033"
|
|
|
|
#ifdef WIN95
|
|
|
|
void GetFileVersionData (D3DADAPTER_IDENTIFIER8* pDI)
|
|
{
|
|
void * buffer;
|
|
VS_FIXEDFILEINFO * verinfo;
|
|
DWORD dwSize;
|
|
DWORD dwHi,dwLo;
|
|
|
|
//Failure means 0 returned
|
|
pDI->DriverVersion.HighPart = 0;
|
|
pDI->DriverVersion.LowPart = 0;
|
|
|
|
dwSize = GetFileVersionInfoSize (pDI->Driver, 0);
|
|
|
|
if (!dwSize)
|
|
{
|
|
return;
|
|
}
|
|
|
|
buffer=MemAlloc(dwSize);
|
|
if (!buffer)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (!GetFileVersionInfo(pDI->Driver, 0, dwSize, buffer))
|
|
{
|
|
MemFree(buffer);
|
|
return;
|
|
}
|
|
|
|
if (!VerQueryValue(buffer, "\\", (void **)&verinfo, (UINT *)&dwSize))
|
|
{
|
|
MemFree(buffer);
|
|
return;
|
|
}
|
|
|
|
pDI->DriverVersion.HighPart = verinfo->dwFileVersionMS;
|
|
pDI->DriverVersion.LowPart = verinfo->dwFileVersionLS;
|
|
|
|
MemFree(buffer);
|
|
}
|
|
|
|
extern HRESULT _GetDriverInfoFromRegistry(char *szClass, char *szClassNot, char *szVendor, D3DADAPTER_IDENTIFIER8* pDI, char *szDeviceID);
|
|
|
|
/*
|
|
* following are all the 9x-specific version functions
|
|
*/
|
|
void GetHALName(char* pDriverName, D3DADAPTER_IDENTIFIER8* pDI)
|
|
{
|
|
pDI->Driver[0] = '\0';
|
|
D3D8GetHALName(pDriverName, pDI->Driver);
|
|
}
|
|
|
|
|
|
BOOL CheckPowerVR(D3DADAPTER_IDENTIFIER8* pDI)
|
|
{
|
|
#if 0
|
|
BOOL bFound=FALSE;
|
|
HKEY hKey;
|
|
DWORD dwSize;
|
|
DWORD dwType;
|
|
|
|
if (pdrv->dwFlags & DDRAWI_SECONDARYDRIVERLOADED)
|
|
{
|
|
/*
|
|
* Any secondary driver information in the registry at all? (assert this is true)
|
|
*/
|
|
if (ERROR_SUCCESS == RegOpenKey(HKEY_LOCAL_MACHINE,
|
|
REGSTR_PATH_SECONDARY,
|
|
&hKey))
|
|
{
|
|
/*
|
|
* Extract the name of the secondary driver's DLL. (assert this works)
|
|
*/
|
|
dwSize = sizeof(pDI->di.szDriver) - 1;
|
|
if (ERROR_SUCCESS == RegQueryValueEx(hKey,
|
|
REGSTR_VALUE_SECONDARY_DRIVERNAME,
|
|
NULL,
|
|
&dwType,
|
|
pDI->di.szDriver,
|
|
&dwSize))
|
|
{
|
|
if (REG_SZ == dwType)
|
|
{
|
|
GetFileVersionData(pDI);
|
|
}
|
|
}
|
|
RegCloseKey(hKey);
|
|
}
|
|
|
|
if (SUCCEEDED(_GetDriverInfoFromRegistry(NULL, "Display", VEN_POWERVR, pDI)))
|
|
{
|
|
//got PVR data...
|
|
bFound = TRUE;
|
|
}
|
|
}
|
|
return bFound;
|
|
#endif
|
|
return TRUE;
|
|
}
|
|
|
|
HRESULT Check3Dfx (D3DADAPTER_IDENTIFIER8* pDI)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
char szDeviceID[MAX_DDDEVICEID_STRING];
|
|
|
|
if (FAILED(_GetDriverInfoFromRegistry(NULL, "Display", VEN_3DFX, pDI, szDeviceID)))
|
|
{
|
|
DPF_ERR("Couldn't get registry data for this device");
|
|
hr = E_FAIL;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
HRESULT GetDriverInfoFromRegistry(char *szClass, char *szClassNot, char *szVendor, D3DADAPTER_IDENTIFIER8* pDI, char *szDeviceID)
|
|
{
|
|
return _GetDriverInfoFromRegistry(szClass, szClassNot, szVendor, pDI, szDeviceID);
|
|
}
|
|
|
|
|
|
/*
|
|
* Given a DISPLAY_DEVICE, get driver name
|
|
* NOTE::: THIS FUNCTION NUKES THE DISPLAY_DEVICE.DeviceKey STRING!!!!
|
|
*/
|
|
void GetWin9XDriverName(DISPLAY_DEVICEA * pdd, LPSTR pDrvName)
|
|
{
|
|
HKEY hKey;
|
|
|
|
lstrcat(pdd->DeviceKey, "\\DEFAULT");
|
|
if (ERROR_SUCCESS == RegOpenKeyEx(
|
|
HKEY_LOCAL_MACHINE,
|
|
pdd->DeviceKey,
|
|
0,
|
|
KEY_QUERY_VALUE ,
|
|
&hKey))
|
|
{
|
|
DWORD dwSize = MAX_DDDEVICEID_STRING;
|
|
DWORD dwType = 0;
|
|
|
|
RegQueryValueEx(hKey,
|
|
TEXT("drv"),
|
|
NULL,
|
|
&dwType,
|
|
pDrvName,
|
|
&dwSize);
|
|
|
|
RegCloseKey(hKey);
|
|
}
|
|
}
|
|
|
|
#else //win95
|
|
|
|
|
|
HRESULT Check3Dfx(D3DADAPTER_IDENTIFIER8* pDI)
|
|
{
|
|
return E_FAIL;
|
|
}
|
|
|
|
HRESULT GetDriverInfoFromRegistry(char *szClass, char *szClassNot, char *szVendor, D3DADAPTER_IDENTIFIER8* pDI, char *szDeviceID)
|
|
{
|
|
return E_FAIL;
|
|
}
|
|
|
|
/*
|
|
* Given a DISPLAY_DEVICE, get driver name, assuming winnt5
|
|
* NOTE::: THIS FUNCTION NUKES THE DISPLAY_DEVICE.DeviceKey STRING!!!!
|
|
*/
|
|
void GetNTDriverNameAndVersion(DISPLAY_DEVICEA * pdd, D3DADAPTER_IDENTIFIER8* pDI)
|
|
{
|
|
HKEY hKey;
|
|
void* buffer;
|
|
DWORD dwSize;
|
|
VS_FIXEDFILEINFO* verinfo;
|
|
|
|
//
|
|
// old style to determine display driver...returns name of miniport!
|
|
//
|
|
|
|
char * pTemp;
|
|
|
|
// The device key has the form blah\blah\services\<devicekey>\DeviceN
|
|
// So we back up one node:
|
|
if ((pTemp = FindLast(pdd->DeviceKey,'\\')))
|
|
{
|
|
char * pTempX;
|
|
char cOld=*pTemp;
|
|
*pTemp = 0;
|
|
|
|
//If we back up one node, we'll have the registry key under which the driver is stored. Let's use that!
|
|
if ((pTempX = FindLast(pdd->DeviceKey,'\\')))
|
|
{
|
|
lstrcpyn(pDI->Driver, pTemp+1, sizeof(pDI->Driver));
|
|
//ATTENTION No point getting version data without a filname:
|
|
//We need a new service or something to get the used display driver name
|
|
//GetFileVersionData(pDI);
|
|
}
|
|
|
|
*pTemp=cOld;
|
|
}
|
|
|
|
//
|
|
// we can find the display driver in a registry key
|
|
//
|
|
// note: InstalledDisplayDrivers can contain several entries
|
|
// to display drivers Since there is no way to find out which
|
|
// one is the active one, we always return the first as being
|
|
// the display driver!
|
|
//
|
|
if (ERROR_SUCCESS == RegOpenKeyEx(
|
|
HKEY_LOCAL_MACHINE,
|
|
pdd->DeviceKey+18,
|
|
0,
|
|
KEY_QUERY_VALUE ,
|
|
&hKey))
|
|
{
|
|
DWORD dwSize = sizeof(pDI->Driver);
|
|
DWORD dwType = 0;
|
|
if (ERROR_SUCCESS == RegQueryValueEx(hKey,
|
|
TEXT("InstalledDisplayDrivers"),
|
|
NULL,
|
|
&dwType,
|
|
pDI->Driver,
|
|
&dwSize))
|
|
{
|
|
lstrcat(pDI->Driver, TEXT(".dll"));
|
|
}
|
|
|
|
RegCloseKey(hKey);
|
|
}
|
|
|
|
// We have the name, now get the version
|
|
|
|
pDI->DriverVersion.HighPart = 0;
|
|
pDI->DriverVersion.LowPart = 0;
|
|
|
|
dwSize=GetFileVersionInfoSize(pDI->Driver, 0);
|
|
if (dwSize == 0)
|
|
return;
|
|
|
|
buffer = MemAlloc(dwSize);
|
|
if (buffer == NULL)
|
|
return;
|
|
|
|
if (!GetFileVersionInfo(pDI->Driver, 0, dwSize, buffer))
|
|
{
|
|
MemFree(buffer);
|
|
return;
|
|
}
|
|
|
|
if (!VerQueryValue(buffer, "\\", (void **)&verinfo, (UINT *)&dwSize))
|
|
{
|
|
MemFree(buffer);
|
|
return;
|
|
}
|
|
|
|
pDI->DriverVersion.HighPart = verinfo->dwFileVersionMS;
|
|
pDI->DriverVersion.LowPart = verinfo->dwFileVersionLS;
|
|
|
|
MemFree(buffer);
|
|
}
|
|
#endif //win95
|
|
|
|
|
|
|
|
void GenerateIdentifier(D3DADAPTER_IDENTIFIER8* pDI)
|
|
{
|
|
LPDWORD pdw;
|
|
|
|
CopyMemory(&pDI->DeviceIdentifier, &CLSID_DirectDraw, sizeof(pDI->DeviceIdentifier));
|
|
|
|
//The device IDs get XORed into the whole GUID with the vendor and device ID in the
|
|
//first two DWORDs so they don't get XORed with anything else. This makes it
|
|
DDASSERT(sizeof(GUID) >= 4*sizeof(DWORD));
|
|
pdw = (LPDWORD) &pDI->DeviceIdentifier;
|
|
pdw[0] ^= pDI->VendorId;
|
|
pdw[1] ^= pDI->DeviceId;
|
|
pdw[2] ^= pDI->SubSysId;
|
|
pdw[3] ^= pDI->Revision;
|
|
|
|
// The driver version gets XORed into the last two DWORDs of the GUID:
|
|
pdw[2] ^= pDI->DriverVersion.LowPart;
|
|
pdw[3] ^= pDI->DriverVersion.HighPart;
|
|
}
|
|
|
|
|
|
void ParseDeviceId(D3DADAPTER_IDENTIFIER8* pDI, char *szDeviceID)
|
|
{
|
|
char * p;
|
|
|
|
DPF(5,"Parsing %s",szDeviceID);
|
|
|
|
pDI->VendorId = 0;
|
|
pDI->DeviceId = 0;
|
|
pDI->SubSysId = 0;
|
|
pDI->Revision = 0;
|
|
|
|
if (p =_strstr(szDeviceID, "VEN_"))
|
|
pDI->VendorId = _atoi(p + 4);
|
|
|
|
if (p = _strstr(szDeviceID, "DEV_"))
|
|
pDI->DeviceId = _atoi(p + 4);
|
|
|
|
if (p = _strstr(szDeviceID, "SUBSYS_"))
|
|
pDI->SubSysId = _atoi(p + 7);
|
|
|
|
if (p = _strstr(szDeviceID, "REV_"))
|
|
pDI->Revision = _atoi(p + 4);
|
|
}
|
|
|
|
|
|
|
|
void GetAdapterInfo(char* pDriverName, D3DADAPTER_IDENTIFIER8* pDI, BOOL bDisplayDriver, BOOL bGuidOnly, BOOL bDriverName)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
int n;
|
|
DISPLAY_DEVICEA dd;
|
|
BOOL bFound;
|
|
char szDeviceID[MAX_DDDEVICEID_STRING];
|
|
#ifndef WINNT
|
|
static char szWin9xName[MAX_DDDEVICEID_STRING];
|
|
#endif
|
|
|
|
memset(pDI, 0, sizeof(*pDI));
|
|
szDeviceID[0] = 0;
|
|
#ifndef WINNT
|
|
|
|
// On Win9X, it's pretty expensive to get the driver name, so we
|
|
// only want to get it when we really need it
|
|
|
|
szWin9xName[0] = '\0';
|
|
if (bDriverName)
|
|
{
|
|
GetHALName(pDriverName, pDI);
|
|
GetFileVersionData(pDI);
|
|
}
|
|
#endif
|
|
|
|
// If it's a 3dfx, it's easy
|
|
|
|
if (!bDisplayDriver)
|
|
{
|
|
hr = Check3Dfx(pDI);
|
|
}
|
|
else
|
|
{
|
|
// Not a 3dfx. Next step: Figure out which display device we
|
|
// really are and get description string for it
|
|
|
|
ZeroMemory(&dd, sizeof(dd));
|
|
dd.cb = sizeof(dd);
|
|
|
|
bFound=FALSE;
|
|
|
|
for(n=0; xxxEnumDisplayDevicesA(NULL, n, &dd, 0); n++)
|
|
{
|
|
if (0 == _stricmp(dd.DeviceName, pDriverName))
|
|
{
|
|
// Found the device. Now we can get some data for it.
|
|
|
|
lstrcpyn(pDI->Description, dd.DeviceString, sizeof(pDI->Description));
|
|
lstrcpyn(szDeviceID, dd.DeviceID, sizeof(szDeviceID));
|
|
|
|
bFound = TRUE;
|
|
|
|
#ifdef WINNT
|
|
GetNTDriverNameAndVersion(&dd,pDI);
|
|
#else
|
|
GetWin9XDriverName(&dd, szWin9xName);
|
|
if (pDI->Driver[0] == '\0')
|
|
{
|
|
lstrcpyn(pDI->Driver, szWin9xName, sizeof(pDI->Driver));
|
|
}
|
|
#endif
|
|
|
|
break;
|
|
}
|
|
|
|
ZeroMemory(&dd, sizeof(dd));
|
|
dd.cb = sizeof(dd);
|
|
}
|
|
|
|
if (!bFound)
|
|
{
|
|
// Didn't find it: xxxEnumDisplayDevices failed, i.e. we're on 9x or NT4,
|
|
|
|
if (FAILED(GetDriverInfoFromRegistry("Display", NULL, NULL, pDI, szDeviceID)))
|
|
{
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
ParseDeviceId(pDI, szDeviceID);
|
|
|
|
// Finally, for the primary only, check if a PowerVR is in and functioning
|
|
#if 0
|
|
if (0 == (dwFlags & DDGDI_GETHOSTIDENTIFIER))
|
|
{
|
|
if (IsVGADevice(pdrv->cDriverName) && CheckPowerVR(pDI))
|
|
{
|
|
ParseDeviceId(pDI, szDeviceID);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
// Munge driver version and ID into the identifier GUID.
|
|
|
|
GenerateIdentifier(pDI);
|
|
|
|
// Now get the WHQL level
|
|
|
|
if (!bGuidOnly)
|
|
{
|
|
#ifdef WINNT
|
|
pDI->WHQLLevel = GetWHQLLevel((LPTSTR)pDI->Driver, NULL);
|
|
#else
|
|
pDI->WHQLLevel = GetWHQLLevel((LPTSTR)pDI->Driver, szWin9xName);
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
pDI->WHQLLevel = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
* Voodoo1GoodToGo
|
|
*
|
|
* The Voodoo 1 driver will succeed the CreateDC call on Voodoo 2, Voodoo 3,
|
|
* or Banshee hardware, but if we use the driver beyond that it will hang
|
|
* the hardware. This is a work around to not enumerate a Voodoo 1
|
|
* driver if the hardware isn't there.
|
|
*
|
|
* To our knowledge, only two guids were ever used to enumerate Voodoo1
|
|
* hardware, so we will look for those guids and assume that anything else
|
|
* doesn't need to be checked.
|
|
*/
|
|
BOOL Voodoo1GoodToGo(GUID * pGuid)
|
|
{
|
|
D3DADAPTER_IDENTIFIER8 DI;
|
|
|
|
if (IsEqualIID(pGuid, &guidVoodoo1A) || IsEqualIID(pGuid, &guidVoodoo1B))
|
|
{
|
|
#ifdef WIN95
|
|
char szDeviceID[MAX_DDDEVICEID_STRING];
|
|
|
|
/*
|
|
* Now search the hardware enum key to see if Voodoo 1 hardware exists
|
|
*/
|
|
if (FAILED(_GetDriverInfoFromRegistry(NULL, "Display", VEN_3DFXVOODOO1, &DI, szDeviceID)))
|
|
{
|
|
return FALSE;
|
|
}
|
|
#else
|
|
return FALSE;
|
|
#endif
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
#ifndef WINNT
|
|
/****************************************************************************
|
|
*
|
|
* FileIsSignedOld
|
|
*
|
|
* find win95 style of signature
|
|
*
|
|
****************************************************************************/
|
|
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;
|
|
|
|
|
|
FILEINFO fi;
|
|
int nRC;
|
|
LPIMAGE_DOS_HEADER lpmz;
|
|
LPIMAGE_OS2_HEADER lpne;
|
|
BYTE cbInfo[9+32+2];
|
|
BOOL IsSigned = FALSE;
|
|
OFSTRUCT OpenStruct;
|
|
HFILE hFile;
|
|
|
|
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,
|
|
}
|
|
};
|
|
|
|
OpenStruct.cBytes = sizeof(OpenStruct);
|
|
lstrcpyn(OpenStruct.szPathName, lpszFile, OFS_MAXPATHNAME);
|
|
hFile = OpenFile(lpszFile, &OpenStruct, OF_READ);
|
|
if (hFile == HFILE_ERROR)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
nRC = 0;
|
|
ReadFile((HANDLE) hFile, (LPVOID)&fi, sizeof(FILEINFO), &nRC, NULL);
|
|
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;
|
|
}
|
|
|
|
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:
|
|
|
|
_lclose(hFile);
|
|
|
|
return IsSigned;
|
|
}
|
|
#endif
|
|
|
|
|
|
/*
|
|
* GetWHQLLevel - On Win95, look for old stamp only. On Win2000, use digital
|
|
* signature only. On Win98, look for old stamp first, then digital signature
|
|
* if no old stamp.
|
|
*
|
|
* return 0 -- unsigned or uncertified
|
|
* return 1 -- driver certified
|
|
* return 1997 -- driver certified, PC97 compliant...
|
|
* return 1998...
|
|
*
|
|
*
|
|
* arguments:
|
|
*
|
|
* lpszDriver----Path of driver file
|
|
*
|
|
*/
|
|
|
|
DWORD GetWHQLLevel(LPTSTR lpszDriver, LPSTR lpszWin9xDriver)
|
|
{
|
|
TCHAR szTmp[MAX_PATH];
|
|
DWORD dwWhqlLevel = 0;
|
|
|
|
// here we should rather call
|
|
if (GetSystemDirectory(szTmp, MAX_PATH-lstrlen(lpszDriver)-2)==0)
|
|
return 0;
|
|
|
|
lstrcat(szTmp, TEXT("\\"));
|
|
lstrcat(szTmp, lpszDriver);
|
|
_tcslwr(szTmp);
|
|
|
|
//
|
|
// Look for a digital signature
|
|
//
|
|
dwWhqlLevel = IsFileDigitallySigned(szTmp);
|
|
if (dwWhqlLevel != 0)
|
|
{
|
|
return dwWhqlLevel;
|
|
}
|
|
|
|
|
|
#ifndef WINNT
|
|
|
|
// It wasn't digitally signed, but it may still have been signed
|
|
// the old way. On Win9X, however, lpszDriver actually contains the
|
|
// 32 bit HAL name rather than the display driver, but we typically only
|
|
// signed the display driver, so we should use lpszWin9xDriver.
|
|
|
|
if (lpszWin9xDriver[0] != '\0')
|
|
{
|
|
GetSystemDirectory(szTmp, MAX_PATH-lstrlen(lpszWin9xDriver)-2);
|
|
lstrcat(szTmp, TEXT("\\"));
|
|
lstrcat(szTmp, lpszWin9xDriver);
|
|
}
|
|
else
|
|
{
|
|
GetSystemDirectory(szTmp, MAX_PATH-lstrlen(lpszDriver)-2);
|
|
lstrcat(szTmp, TEXT("\\"));
|
|
lstrcat(szTmp, lpszDriver);
|
|
}
|
|
|
|
if (FileIsSignedOld(szTmp))
|
|
{
|
|
return 1;
|
|
}
|
|
#endif
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
DWORD IsFileDigitallySigned(LPTSTR lpszDriver)
|
|
{
|
|
DWORD dwWHQLLevel=0; // default, driver not certified
|
|
CATAPI catapi;
|
|
WCHAR *lpFileName;
|
|
DRIVER_VER_INFO VerInfo;
|
|
TCHAR szBuffer[50];
|
|
LPSTR lpAttr;
|
|
#ifndef UNICODE
|
|
WCHAR wszDriver[MAX_PATH];
|
|
MultiByteToWideChar(CP_ACP, 0, lpszDriver, -1, wszDriver, MAX_PATH);
|
|
lpFileName = wcsrchr(wszDriver, TEXT('\\'));
|
|
if (lpFileName==NULL)
|
|
{
|
|
lpFileName = wszDriver;
|
|
}
|
|
else
|
|
{
|
|
lpFileName++;
|
|
}
|
|
#else
|
|
lpFileName = _tcsrchr(lpszDriver, TEXT('\\'));
|
|
if (lpFileName==NULL) lpFileName = lpszDriver;
|
|
#endif
|
|
|
|
|
|
//
|
|
// try to load and initialize the mscat32.dll and wintrust.dll
|
|
// these dlls are not available on win95
|
|
//
|
|
if (InitCATAPI(&catapi))
|
|
{
|
|
HANDLE hFile;
|
|
DWORD cbHashSize=0;
|
|
BYTE *pbHash;
|
|
BOOL bResult;
|
|
|
|
//
|
|
// create a handle to our driver, because cat api wants handle to file
|
|
//
|
|
hFile = CreateFile(lpszDriver,
|
|
GENERIC_READ,
|
|
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
|
0,
|
|
OPEN_EXISTING,
|
|
FILE_ATTRIBUTE_NORMAL,
|
|
0
|
|
);
|
|
|
|
if (hFile!=INVALID_HANDLE_VALUE)
|
|
{
|
|
// first query hash size...
|
|
bResult=(*catapi.pCryptCATAdminCalcHashFromFileHandle)(hFile,
|
|
&cbHashSize,
|
|
NULL,
|
|
0);
|
|
pbHash=NULL;
|
|
if (bResult)
|
|
{
|
|
// allocate hash
|
|
pbHash = MemAlloc(cbHashSize);
|
|
}
|
|
|
|
if (pbHash!=NULL)
|
|
{
|
|
HCATINFO hPrevCat=NULL;
|
|
HANDLE hCatalog=NULL;
|
|
WINTRUST_DATA WinTrustData;
|
|
WINTRUST_CATALOG_INFO WinTrustCatalogInfo;
|
|
GUID guidSubSystemDriver = DRIVER_ACTION_VERIFY;
|
|
CRYPTCATATTRIBUTE *lpCat = NULL;
|
|
|
|
//
|
|
// Now get the hash for our file
|
|
//
|
|
|
|
bResult=(*catapi.pCryptCATAdminCalcHashFromFileHandle)(hFile,
|
|
&cbHashSize,
|
|
pbHash,
|
|
0);
|
|
|
|
if (bResult)
|
|
{
|
|
hCatalog=(*catapi.pCryptCATAdminEnumCatalogFromHash)(
|
|
catapi.hCatAdmin,
|
|
pbHash,
|
|
cbHashSize,
|
|
0,
|
|
&hPrevCat);
|
|
}
|
|
|
|
//
|
|
// 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);
|
|
|
|
WinTrustData.pCatalog = &WinTrustCatalogInfo;
|
|
|
|
ZeroMemory(&WinTrustCatalogInfo, sizeof(WINTRUST_CATALOG_INFO));
|
|
WinTrustCatalogInfo.cbStruct = sizeof(WINTRUST_CATALOG_INFO);
|
|
WinTrustCatalogInfo.pbCalculatedFileHash = pbHash;
|
|
WinTrustCatalogInfo.cbCalculatedFileHash = cbHashSize;
|
|
WinTrustCatalogInfo.pcwszMemberTag = lpFileName;
|
|
|
|
while (hCatalog)
|
|
{
|
|
CATALOG_INFO CatInfo;
|
|
|
|
ZeroMemory(&CatInfo, sizeof(CATALOG_INFO));
|
|
CatInfo.cbStruct = sizeof(CATALOG_INFO);
|
|
if ((*catapi.pCryptCATCatalogInfoFromContext)(hCatalog, &CatInfo, 0))
|
|
{
|
|
HRESULT hRes;
|
|
|
|
WinTrustCatalogInfo.pcwszCatalogFilePath = CatInfo.wszCatalogFile;
|
|
|
|
// Now verify that the file is an actual member of the catalog.
|
|
hRes = (*catapi.pWinVerifyTrust)
|
|
(NULL, &guidSubSystemDriver, &WinTrustData);
|
|
|
|
if (hRes == ERROR_SUCCESS)
|
|
{
|
|
//
|
|
// Our driver is certified! Now see if the cat
|
|
// info contains the WHQL level
|
|
//
|
|
CRYPTCATATTRIBUTE *lpCat = NULL;
|
|
HANDLE hCat;
|
|
|
|
dwWHQLLevel=1; // return "certified"
|
|
|
|
hCat = (*catapi.pCryptCATOpen)(CatInfo.wszCatalogFile, (DWORD)CRYPTCAT_OPEN_EXISTING, (HCRYPTPROV)NULL, 0, 0);
|
|
lpCat = (*catapi.pCryptCATGetCatAttrInfo) (hCat, L"KV_DISPLAY");
|
|
if (lpCat != NULL)
|
|
{
|
|
WideCharToMultiByte(CP_ACP, 0, (PUSHORT)lpCat->pbValue, -1, szBuffer, 50, NULL, NULL);
|
|
|
|
// The value looks like "1:yyyy-mm-dd".
|
|
|
|
lpAttr = _strstr(szBuffer, ":");
|
|
lpAttr++;
|
|
lpAttr[4] = '\0';
|
|
dwWHQLLevel = atoi(lpAttr) * 0x10000;
|
|
lpAttr[7] = '\0';
|
|
dwWHQLLevel |= atoi(&lpAttr[5]) * 0x100;
|
|
dwWHQLLevel |= atoi(&lpAttr[8]);
|
|
}
|
|
|
|
(*catapi.pCryptCATClose)(hCat);
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
// iterate through catalogs...
|
|
//
|
|
hPrevCat=hCatalog;
|
|
hCatalog=(*catapi.pCryptCATAdminEnumCatalogFromHash)(
|
|
catapi.hCatAdmin,
|
|
pbHash,
|
|
cbHashSize,
|
|
0,
|
|
&hPrevCat);
|
|
}
|
|
|
|
//
|
|
// we might have to free a catalog context!
|
|
//
|
|
if (hCatalog)
|
|
{
|
|
(*catapi.pCryptCATAdminReleaseCatalogContext)
|
|
(catapi.hCatAdmin, hCatalog, 0);
|
|
}
|
|
|
|
//
|
|
// free hash
|
|
//
|
|
MemFree(pbHash);
|
|
|
|
}
|
|
|
|
CloseHandle(hFile);
|
|
}
|
|
}
|
|
|
|
ReleaseCATAPI(&catapi);
|
|
|
|
return dwWHQLLevel;
|
|
}
|