You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1756 lines
69 KiB
1756 lines
69 KiB
/****************************************************************************
|
|
*
|
|
* File: dispinfo.cpp
|
|
* Project: DxDiag (DirectX Diagnostic Tool)
|
|
* Author: Mike Anderson ([email protected])
|
|
* Purpose: Gather information about the display(s) on this machine
|
|
*
|
|
* (C) Copyright 1998-1999 Microsoft Corp. All rights reserved.
|
|
*
|
|
****************************************************************************/
|
|
|
|
#include <tchar.h>
|
|
#include <Windows.h>
|
|
#define COMPILE_MULTIMON_STUBS // for multimon.h
|
|
#include <multimon.h>
|
|
#define DIRECTDRAW_VERSION 5 // run on DX5 and later versions
|
|
#include <ddraw.h>
|
|
#include <d3d.h>
|
|
#include <stdio.h>
|
|
#include "sysinfo.h" // for BIsPlatformNT
|
|
#include "reginfo.h"
|
|
#include "dispinfo.h"
|
|
#include "dispinfo8.h"
|
|
#include "fileinfo.h" // for GetFileVersion
|
|
#include "sysinfo.h"
|
|
#include "resource.h"
|
|
|
|
|
|
// Taken from DirectDraw's ddcreate.c
|
|
// This is the first GUID of secondary display devices
|
|
static const GUID DisplayGUID =
|
|
{0x67685559,0x3106,0x11d0,{0xb9,0x71,0x0,0xaa,0x0,0x34,0x2f,0x9f}};
|
|
|
|
typedef HRESULT (WINAPI* LPDIRECTDRAWCREATE)(GUID FAR *lpGUID,
|
|
LPDIRECTDRAW FAR *lplpDD, IUnknown FAR *pUnkOuter);
|
|
|
|
static VOID GetRegDisplayInfo9x(DisplayInfo* pDisplayInfo);
|
|
static VOID GetRegDisplayInfoNT(DisplayInfo* pDisplayInfo);
|
|
static HRESULT GetDirectDrawInfo(LPDIRECTDRAWCREATE pDDCreate, DisplayInfo* pDisplayInfo);
|
|
static HRESULT CALLBACK EnumDevicesCallback(GUID* pGuid, LPSTR pszDesc, LPSTR pszName,
|
|
D3DDEVICEDESC* pd3ddevdesc1, D3DDEVICEDESC* pd3ddevdesc2, VOID* pvContext);
|
|
static BOOL FindDevice(INT iDevice, TCHAR* pszDeviceClass, TCHAR* pszDeviceClassNot, TCHAR* pszHardwareKey);
|
|
static BOOL GetDeviceValue(TCHAR* pszHardwareKey, TCHAR* pszKey, TCHAR* pszValue, BYTE *buf, DWORD cbbuf);
|
|
static HRESULT CheckRegistry(RegError** ppRegErrorFirst);
|
|
static BOOL CALLBACK MonitorEnumProc( HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcMonitor, LPARAM dwData );
|
|
static VOID GetRegDisplayInfoWhistler(DisplayInfo* pDisplayInfo, TCHAR* szKeyVideo, TCHAR* szKeyImage );
|
|
static VOID GetRegDisplayInfoWin2k(DisplayInfo* pDisplayInfo, TCHAR* szKeyVideo, TCHAR* szKeyImage );
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
*
|
|
* GetBasicDisplayInfo - Get minimal info on each display
|
|
*
|
|
****************************************************************************/
|
|
HRESULT GetBasicDisplayInfo(DisplayInfo** ppDisplayInfoFirst)
|
|
{
|
|
DisplayInfo* pDisplayInfo;
|
|
DisplayInfo* pDisplayInfoNew;
|
|
|
|
TCHAR szHardwareKey[MAX_PATH];
|
|
TCHAR szDriver[MAX_PATH];
|
|
|
|
// Check OS version. Win95 cannot use EnumDisplayDevices; Win98/NT5 can:
|
|
if( BIsWinNT() || BIsWin3x() )
|
|
return S_OK; // NT4 and earlier and pre-Win95 not supported
|
|
|
|
if( BIsWin95() )
|
|
{
|
|
// Win95:
|
|
if (!FindDevice(0, TEXT("Display"), NULL, szHardwareKey))
|
|
return E_FAIL;
|
|
pDisplayInfoNew = new DisplayInfo;
|
|
if (pDisplayInfoNew == NULL)
|
|
return E_OUTOFMEMORY;
|
|
ZeroMemory(pDisplayInfoNew, sizeof(DisplayInfo));
|
|
*ppDisplayInfoFirst = pDisplayInfoNew;
|
|
pDisplayInfoNew->m_bCanRenderWindow = TRUE;
|
|
pDisplayInfoNew->m_hMonitor = NULL; // Win95 doesn't like multimon
|
|
lstrcpy(pDisplayInfoNew->m_szKeyDeviceID, szHardwareKey);
|
|
if (GetDeviceValue(szHardwareKey, NULL, TEXT("Driver"), (LPBYTE)szDriver, sizeof(szDriver)))
|
|
{
|
|
lstrcpy(pDisplayInfoNew->m_szKeyDeviceKey, TEXT("System\\CurrentControlSet\\Services\\Class\\"));
|
|
if( lstrlen(pDisplayInfoNew->m_szKeyDeviceKey) + lstrlen(szDriver) < 200 )
|
|
lstrcat(pDisplayInfoNew->m_szKeyDeviceKey, szDriver);
|
|
}
|
|
GetDeviceValue(szHardwareKey, NULL, TEXT("DeviceDesc"), (LPBYTE)pDisplayInfoNew->m_szDescription, sizeof(pDisplayInfoNew->m_szDescription));
|
|
|
|
HDC hdc;
|
|
hdc = GetDC(NULL);
|
|
if (hdc != NULL)
|
|
{
|
|
wsprintf(pDisplayInfoNew->m_szDisplayMode, TEXT("%d x %d (%d bit)"),
|
|
GetDeviceCaps(hdc, HORZRES), GetDeviceCaps(hdc, VERTRES), GetDeviceCaps(hdc, BITSPIXEL));
|
|
lstrcpy( pDisplayInfoNew->m_szDisplayModeEnglish, pDisplayInfoNew->m_szDisplayMode );
|
|
ReleaseDC(NULL, hdc);
|
|
pDisplayInfoNew->m_dwWidth = GetDeviceCaps(hdc, HORZRES);
|
|
pDisplayInfoNew->m_dwHeight = GetDeviceCaps(hdc, VERTRES);
|
|
pDisplayInfoNew->m_dwBpp = GetDeviceCaps(hdc, BITSPIXEL);
|
|
}
|
|
|
|
// On Win98 and NT, we get the monitor key through a call to EnumDisplayDevices.
|
|
// On Win95, we have to use the registry to get the monitor key.
|
|
HKEY hKey = NULL;
|
|
DWORD cbData;
|
|
TCHAR szKey[200];
|
|
ULONG ulType;
|
|
if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE, TEXT("Enum\\MONITOR\\DEFAULT_MONITOR\\0001"), 0, KEY_READ, &hKey))
|
|
{
|
|
cbData = sizeof szKey;
|
|
|
|
if (ERROR_SUCCESS == RegQueryValueEx(hKey, TEXT("Driver"), 0, &ulType, (LPBYTE)szKey, &cbData)
|
|
&& szKey[0])
|
|
{
|
|
lstrcpy(pDisplayInfoNew->m_szMonitorKey, TEXT("System\\CurrentControlSet\\Services\\Class\\"));
|
|
if( lstrlen(pDisplayInfoNew->m_szMonitorKey) + lstrlen(szKey) < 200 )
|
|
lstrcat(pDisplayInfoNew->m_szMonitorKey, szKey);
|
|
}
|
|
RegCloseKey(hKey);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Win98 / NT5:
|
|
LONG iDevice = 0;
|
|
DISPLAY_DEVICE dispdev;
|
|
DISPLAY_DEVICE dispdev2;
|
|
|
|
ZeroMemory(&dispdev, sizeof(dispdev));
|
|
dispdev.cb = sizeof(dispdev);
|
|
|
|
ZeroMemory(&dispdev2, sizeof(dispdev2));
|
|
dispdev2.cb = sizeof(dispdev2);
|
|
|
|
while (EnumDisplayDevices(NULL, iDevice, (DISPLAY_DEVICE*)&dispdev, 0))
|
|
{
|
|
// Mirroring drivers are for monitors that echo another display, so
|
|
// they should be ignored. NT5 seems to create a mirroring driver called
|
|
// "NetMeeting driver", and we definitely don't want that.
|
|
if (dispdev.StateFlags & DISPLAY_DEVICE_MIRRORING_DRIVER)
|
|
{
|
|
iDevice++;
|
|
continue;
|
|
}
|
|
|
|
// Skip devices that aren't attached since they cause problems
|
|
if ( (dispdev.StateFlags & DISPLAY_DEVICE_ATTACHED_TO_DESKTOP) == 0 )
|
|
{
|
|
iDevice++;
|
|
continue;
|
|
}
|
|
|
|
pDisplayInfoNew = new DisplayInfo;
|
|
if (pDisplayInfoNew == NULL)
|
|
return E_OUTOFMEMORY;
|
|
ZeroMemory(pDisplayInfoNew, sizeof(DisplayInfo));
|
|
if (*ppDisplayInfoFirst == NULL)
|
|
{
|
|
*ppDisplayInfoFirst = pDisplayInfoNew;
|
|
}
|
|
else
|
|
{
|
|
for (pDisplayInfo = *ppDisplayInfoFirst;
|
|
pDisplayInfo->m_pDisplayInfoNext != NULL;
|
|
pDisplayInfo = pDisplayInfo->m_pDisplayInfoNext)
|
|
{
|
|
}
|
|
pDisplayInfo->m_pDisplayInfoNext = pDisplayInfoNew;
|
|
}
|
|
pDisplayInfoNew->m_bCanRenderWindow = TRUE;
|
|
pDisplayInfoNew->m_guid = DisplayGUID;
|
|
pDisplayInfoNew->m_guid.Data1 += iDevice;
|
|
lstrcpy(pDisplayInfoNew->m_szDeviceName, dispdev.DeviceName);
|
|
lstrcpy(pDisplayInfoNew->m_szDescription, dispdev.DeviceString);
|
|
lstrcpy(pDisplayInfoNew->m_szKeyDeviceID, TEXT("Enum\\"));
|
|
lstrcat(pDisplayInfoNew->m_szKeyDeviceID, dispdev.DeviceID);
|
|
lstrcpy(pDisplayInfoNew->m_szKeyDeviceKey, dispdev.DeviceKey);
|
|
|
|
DEVMODE devmode;
|
|
ZeroMemory(&devmode, sizeof(devmode));
|
|
devmode.dmSize = sizeof(devmode);
|
|
|
|
if (EnumDisplaySettings(dispdev.DeviceName, ENUM_CURRENT_SETTINGS, &devmode))
|
|
{
|
|
pDisplayInfoNew->m_dwWidth = devmode.dmPelsWidth;
|
|
pDisplayInfoNew->m_dwHeight = devmode.dmPelsHeight;
|
|
pDisplayInfoNew->m_dwBpp = devmode.dmBitsPerPel;
|
|
wsprintf(pDisplayInfoNew->m_szDisplayMode, TEXT("%d x %d (%d bit)"),
|
|
devmode.dmPelsWidth, devmode.dmPelsHeight, devmode.dmBitsPerPel);
|
|
lstrcpy( pDisplayInfoNew->m_szDisplayModeEnglish, pDisplayInfoNew->m_szDisplayMode );
|
|
if (devmode.dmDisplayFrequency > 0)
|
|
{
|
|
TCHAR sz[50];
|
|
wsprintf(sz, TEXT(" (%dHz)"), devmode.dmDisplayFrequency);
|
|
lstrcat(pDisplayInfoNew->m_szDisplayMode, sz);
|
|
lstrcat(pDisplayInfoNew->m_szDisplayModeEnglish, sz);
|
|
pDisplayInfoNew->m_dwRefreshRate = devmode.dmDisplayFrequency;
|
|
}
|
|
}
|
|
|
|
// Call EnumDisplayDevices a second time to get monitor name and monitor key
|
|
if (EnumDisplayDevices(dispdev.DeviceName, 0, &dispdev2, 0))
|
|
{
|
|
lstrcpy(pDisplayInfoNew->m_szMonitorName, dispdev2.DeviceString);
|
|
lstrcpy(pDisplayInfoNew->m_szMonitorKey, dispdev2.DeviceKey);
|
|
}
|
|
|
|
// Try to figure out the m_hMonitor
|
|
pDisplayInfoNew->m_hMonitor = NULL;
|
|
EnumDisplayMonitors( NULL, NULL, MonitorEnumProc, (LPARAM) pDisplayInfoNew );
|
|
|
|
iDevice++;
|
|
}
|
|
}
|
|
|
|
// Now look for non-display devices (like 3dfx Voodoo):
|
|
HKEY hkey;
|
|
HKEY hkey2;
|
|
DWORD dwIndex;
|
|
TCHAR szName[MAX_PATH+1];
|
|
DWORD cb;
|
|
DWORD dwType;
|
|
|
|
if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE, TEXT("Hardware\\DirectDrawDrivers"), 0, KEY_READ, &hkey))
|
|
{
|
|
dwIndex = 0;
|
|
while (ERROR_SUCCESS == RegEnumKey(hkey, dwIndex, szName, MAX_PATH+1))
|
|
{
|
|
BOOL bGoodDevice = FALSE;
|
|
TCHAR szDriverName[200];
|
|
HDC hdc;
|
|
|
|
if (lstrcmp(szName, TEXT("3a0cfd01-9320-11cf-ac-a1-00-a0-24-13-c2-e2")) == 0 ||
|
|
lstrcmp(szName, TEXT("aba52f41-f744-11cf-b4-52-00-00-1d-1b-41-26")) == 0)
|
|
{
|
|
// 24940: It's a Voodoo1, which will succeed GetDC (and crash later) if
|
|
// no Voodoo1 is present but a Voodoo2 is. So instead of the GetDC test,
|
|
// see if a V1 is present in registry's CurrentConfig.
|
|
INT i;
|
|
for (i=0 ; ; i++)
|
|
{
|
|
TCHAR szDevice[MAX_DDDEVICEID_STRING];
|
|
if (FindDevice(i, NULL, TEXT("Display"), szDevice))
|
|
{
|
|
if (_tcsstr(szDevice, TEXT("VEN_121A&DEV_0001")) != NULL)
|
|
{
|
|
bGoodDevice = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// To confirm that this is a real active DD device, create a DC with it
|
|
if (ERROR_SUCCESS == RegOpenKeyEx(hkey, szName, 0, KEY_READ, &hkey2))
|
|
{
|
|
cb = 200;
|
|
if (ERROR_SUCCESS == RegQueryValueEx(hkey2, TEXT("DriverName"), NULL, &dwType,
|
|
(CONST LPBYTE)szDriverName, &cb) && cb > 0)
|
|
{
|
|
// I think the following "if" will always fail, but we're about to ship so
|
|
// I'm being paranoid and doing everything that DDraw does:
|
|
if (szDriverName[0] == '\\' && szDriverName[1] == '\\' && szDriverName[2] == '.')
|
|
hdc = CreateDC( NULL, szDriverName, NULL, NULL);
|
|
else
|
|
hdc = CreateDC( szDriverName, NULL, NULL, NULL);
|
|
if (hdc != NULL)
|
|
{
|
|
bGoodDevice = TRUE;
|
|
DeleteDC(hdc);
|
|
}
|
|
}
|
|
RegCloseKey(hkey2);
|
|
}
|
|
}
|
|
|
|
if (!bGoodDevice)
|
|
{
|
|
dwIndex++;
|
|
continue;
|
|
}
|
|
|
|
pDisplayInfoNew = new DisplayInfo;
|
|
if (pDisplayInfoNew == NULL)
|
|
return E_OUTOFMEMORY;
|
|
ZeroMemory(pDisplayInfoNew, sizeof(DisplayInfo));
|
|
if (*ppDisplayInfoFirst == NULL)
|
|
{
|
|
*ppDisplayInfoFirst = pDisplayInfoNew;
|
|
}
|
|
else
|
|
{
|
|
for (pDisplayInfo = *ppDisplayInfoFirst;
|
|
pDisplayInfo->m_pDisplayInfoNext != NULL;
|
|
pDisplayInfo = pDisplayInfo->m_pDisplayInfoNext)
|
|
{
|
|
}
|
|
pDisplayInfo->m_pDisplayInfoNext = pDisplayInfoNew;
|
|
}
|
|
pDisplayInfoNew->m_bCanRenderWindow = FALSE;
|
|
pDisplayInfoNew->m_hMonitor = NULL;
|
|
if( _stscanf(szName, TEXT("%08x-%04x-%04x-%02x-%02x-%02x-%02x-%02x-%02x-%02x-%02x"),
|
|
&pDisplayInfoNew->m_guid.Data1,
|
|
&pDisplayInfoNew->m_guid.Data2,
|
|
&pDisplayInfoNew->m_guid.Data3,
|
|
&pDisplayInfoNew->m_guid.Data4[0],
|
|
&pDisplayInfoNew->m_guid.Data4[1],
|
|
&pDisplayInfoNew->m_guid.Data4[2],
|
|
&pDisplayInfoNew->m_guid.Data4[3],
|
|
&pDisplayInfoNew->m_guid.Data4[4],
|
|
&pDisplayInfoNew->m_guid.Data4[5],
|
|
&pDisplayInfoNew->m_guid.Data4[6],
|
|
&pDisplayInfoNew->m_guid.Data4[7]) == 11 )
|
|
{
|
|
if (ERROR_SUCCESS == RegOpenKeyEx(hkey, szName, 0, KEY_READ, &hkey2))
|
|
{
|
|
cb = sizeof(pDisplayInfoNew->m_szDescription);
|
|
RegQueryValueEx(hkey2, TEXT("Description"), NULL, &dwType, (LPBYTE)pDisplayInfoNew->m_szDescription, &cb);
|
|
|
|
cb = sizeof(pDisplayInfoNew->m_szDriverName);
|
|
RegQueryValueEx(hkey2, TEXT("DriverName"), NULL, &dwType, (LPBYTE)pDisplayInfoNew->m_szDriverName, &cb);
|
|
|
|
RegCloseKey(hkey2);
|
|
}
|
|
}
|
|
|
|
dwIndex++;
|
|
}
|
|
RegCloseKey(hkey);
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
/****************************************************************************
|
|
*
|
|
* MonitorEnumProc
|
|
*
|
|
****************************************************************************/
|
|
BOOL CALLBACK MonitorEnumProc( HMONITOR hMonitor, HDC hdcMonitor,
|
|
LPRECT lprcMonitor, LPARAM dwData )
|
|
{
|
|
DisplayInfo* pDisplayInfoNew = (DisplayInfo*) dwData;
|
|
|
|
// Get the MONITORINFOEX for this HMONITOR
|
|
MONITORINFOEX monInfo;
|
|
ZeroMemory( &monInfo, sizeof(MONITORINFOEX) );
|
|
monInfo.cbSize = sizeof(MONITORINFOEX);
|
|
GetMonitorInfo( hMonitor, &monInfo );
|
|
|
|
// Compare the display device for this HMONITOR and the one
|
|
// we just enumed with EnumDisplayDevices
|
|
if( lstrcmp( monInfo.szDevice, pDisplayInfoNew->m_szDeviceName ) == 0 )
|
|
{
|
|
// If they match, then record the HMONITOR
|
|
pDisplayInfoNew->m_hMonitor = hMonitor;
|
|
return FALSE;
|
|
}
|
|
|
|
// Keep looking...
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
/****************************************************************************
|
|
*
|
|
* GetExtraDisplayInfo
|
|
*
|
|
****************************************************************************/
|
|
HRESULT GetExtraDisplayInfo(DisplayInfo* pDisplayInfoFirst)
|
|
{
|
|
HRESULT hr;
|
|
DisplayInfo* pDisplayInfo;
|
|
BOOL bDDAccelEnabled;
|
|
BOOL bD3DAccelEnabled;
|
|
BOOL bAGPEnabled;
|
|
BOOL bNT = BIsPlatformNT();
|
|
|
|
bDDAccelEnabled = IsDDHWAccelEnabled();
|
|
bD3DAccelEnabled = IsD3DHWAccelEnabled();
|
|
bAGPEnabled = IsAGPEnabled();
|
|
|
|
for (pDisplayInfo = pDisplayInfoFirst; pDisplayInfo != NULL;
|
|
pDisplayInfo = pDisplayInfo->m_pDisplayInfoNext)
|
|
{
|
|
if (bNT)
|
|
GetRegDisplayInfoNT(pDisplayInfo);
|
|
else
|
|
GetRegDisplayInfo9x(pDisplayInfo);
|
|
pDisplayInfo->m_bDDAccelerationEnabled = bDDAccelEnabled;
|
|
pDisplayInfo->m_b3DAccelerationEnabled = bD3DAccelEnabled;
|
|
pDisplayInfo->m_bAGPEnabled = bAGPEnabled;
|
|
|
|
if (FAILED(hr = CheckRegistry(&pDisplayInfo->m_pRegErrorFirst)))
|
|
return hr;
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
/****************************************************************************
|
|
*
|
|
* GetDDrawDisplayInfo
|
|
*
|
|
****************************************************************************/
|
|
HRESULT GetDDrawDisplayInfo(DisplayInfo* pDisplayInfoFirst)
|
|
{
|
|
HRESULT hr;
|
|
HRESULT hrRet = S_OK;
|
|
DisplayInfo* pDisplayInfo;
|
|
TCHAR szPath[MAX_PATH];
|
|
HINSTANCE hInstDDraw;
|
|
LPDIRECTDRAWCREATE pDDCreate;
|
|
|
|
GetSystemDirectory(szPath, MAX_PATH);
|
|
lstrcat(szPath, TEXT("\\ddraw.dll"));
|
|
hInstDDraw = LoadLibrary(szPath);
|
|
if (hInstDDraw == NULL)
|
|
return E_FAIL;
|
|
pDDCreate = (LPDIRECTDRAWCREATE)GetProcAddress(hInstDDraw, "DirectDrawCreate");
|
|
if (pDDCreate == NULL)
|
|
{
|
|
FreeLibrary(hInstDDraw);
|
|
return E_FAIL;
|
|
}
|
|
|
|
// Init D3D8 so we can use GetDX8AdapterInfo()
|
|
InitD3D8();
|
|
|
|
for (pDisplayInfo = pDisplayInfoFirst; pDisplayInfo != NULL;
|
|
pDisplayInfo = pDisplayInfo->m_pDisplayInfoNext)
|
|
{
|
|
pDisplayInfo->m_b3DAccelerationExists = FALSE; // until proven otherwise
|
|
if (FAILED(hr = GetDirectDrawInfo(pDDCreate, pDisplayInfo)))
|
|
hrRet = hr; // but keep going
|
|
}
|
|
|
|
// Cleanup the D3D8 library
|
|
CleanupD3D8();
|
|
|
|
FreeLibrary(hInstDDraw);
|
|
|
|
return hrRet;
|
|
}
|
|
|
|
|
|
/****************************************************************************
|
|
*
|
|
* DestroyDisplayInfo
|
|
*
|
|
****************************************************************************/
|
|
VOID DestroyDisplayInfo(DisplayInfo* pDisplayInfoFirst)
|
|
{
|
|
DisplayInfo* pDisplayInfo;
|
|
DisplayInfo* pDisplayInfoNext;
|
|
|
|
for (pDisplayInfo = pDisplayInfoFirst; pDisplayInfo != NULL;
|
|
pDisplayInfo = pDisplayInfoNext)
|
|
{
|
|
DestroyReg( &pDisplayInfo->m_pRegErrorFirst );
|
|
|
|
pDisplayInfoNext = pDisplayInfo->m_pDisplayInfoNext;
|
|
delete pDisplayInfo;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
*
|
|
* GetRegDisplayInfo9x - Uses the registry keys to get more info about a
|
|
* display adapter.
|
|
*
|
|
****************************************************************************/
|
|
VOID GetRegDisplayInfo9x(DisplayInfo* pDisplayInfo)
|
|
{
|
|
TCHAR szFullKey[200];
|
|
HKEY hkey;
|
|
DWORD cbData;
|
|
DWORD dwType;
|
|
|
|
// set to n/a by default
|
|
_tcscpy( pDisplayInfo->m_szMiniVddDate, TEXT("n/a") );
|
|
|
|
if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE, pDisplayInfo->m_szKeyDeviceID, 0, KEY_READ, &hkey))
|
|
{
|
|
cbData = sizeof(pDisplayInfo->m_szManufacturer);
|
|
RegQueryValueEx(hkey, TEXT("Mfg"), 0, &dwType, (LPBYTE)pDisplayInfo->m_szManufacturer, &cbData);
|
|
|
|
RegCloseKey(hkey);
|
|
}
|
|
|
|
if (pDisplayInfo->m_dwRefreshRate == 0)
|
|
{
|
|
wsprintf(szFullKey, TEXT("%s\\Modes\\%d\\%d,%d"), pDisplayInfo->m_szKeyDeviceKey,
|
|
pDisplayInfo->m_dwBpp, pDisplayInfo->m_dwWidth, pDisplayInfo->m_dwHeight);
|
|
if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE, szFullKey, 0, KEY_READ, &hkey))
|
|
{
|
|
TCHAR szRefresh[100];
|
|
TCHAR szRefresh2[100];
|
|
TCHAR szRefreshEnglish2[100];
|
|
cbData = sizeof(szRefresh);
|
|
if (ERROR_SUCCESS == RegQueryValueEx(hkey, TEXT("RefreshRate"), 0, &dwType, (LPBYTE)szRefresh, &cbData))
|
|
{
|
|
if( _stscanf(szRefresh, TEXT("%d"), &pDisplayInfo->m_dwRefreshRate) != 1 )
|
|
pDisplayInfo->m_dwRefreshRate = 0;
|
|
if (lstrcmp(szRefresh, TEXT("0")) == 0)
|
|
LoadString(NULL, IDS_DEFAULTREFRESH, szRefresh2, 100);
|
|
else if (lstrcmp(szRefresh, TEXT("-1")) == 0)
|
|
LoadString(NULL, IDS_OPTIMALREFRESH, szRefresh2, 100);
|
|
else
|
|
wsprintf(szRefresh2, TEXT("(%sHz)"), szRefresh);
|
|
lstrcat(pDisplayInfo->m_szDisplayMode, TEXT(" "));
|
|
lstrcat(pDisplayInfo->m_szDisplayMode, szRefresh2);
|
|
|
|
if (lstrcmp(szRefresh, TEXT("0")) == 0)
|
|
LoadString(NULL, IDS_DEFAULTREFRESH_ENGLISH, szRefreshEnglish2, 100);
|
|
else if (lstrcmp(szRefresh, TEXT("-1")) == 0)
|
|
LoadString(NULL, IDS_OPTIMALREFRESH_ENGLISH, szRefreshEnglish2, 100);
|
|
else
|
|
wsprintf(szRefreshEnglish2, TEXT("(%sHz)"), szRefresh);
|
|
lstrcat(pDisplayInfo->m_szDisplayModeEnglish, szRefreshEnglish2);
|
|
lstrcat(pDisplayInfo->m_szDisplayModeEnglish, TEXT(" "));
|
|
|
|
if (pDisplayInfo->m_dwRefreshRate == 0)
|
|
pDisplayInfo->m_dwRefreshRate = 1; // 23399: so it doesn't check again
|
|
}
|
|
RegCloseKey(hkey);
|
|
}
|
|
}
|
|
lstrcpy(szFullKey, pDisplayInfo->m_szKeyDeviceKey);
|
|
lstrcat(szFullKey, TEXT("\\DEFAULT"));
|
|
if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE, szFullKey, 0, KEY_READ, &hkey))
|
|
{
|
|
// If no specific refresh rate was listed for the current mode, report the
|
|
// default rate.
|
|
if (pDisplayInfo->m_dwRefreshRate == 0)
|
|
{
|
|
TCHAR szRefresh[100];
|
|
TCHAR szRefresh2[100];
|
|
TCHAR szRefreshEnglish2[100];
|
|
cbData = sizeof(szRefresh);
|
|
if (ERROR_SUCCESS == RegQueryValueEx(hkey, TEXT("RefreshRate"), 0, &dwType, (LPBYTE)szRefresh, &cbData))
|
|
{
|
|
if (lstrcmp(szRefresh, TEXT("0")) == 0)
|
|
LoadString(NULL, IDS_DEFAULTREFRESH, szRefresh2, 100);
|
|
else if (lstrcmp(szRefresh, TEXT("-1")) == 0)
|
|
LoadString(NULL, IDS_OPTIMALREFRESH, szRefresh2, 100);
|
|
else
|
|
wsprintf(szRefresh2, TEXT("(%sHz)"), szRefresh);
|
|
lstrcat(pDisplayInfo->m_szDisplayMode, TEXT(" "));
|
|
lstrcat(pDisplayInfo->m_szDisplayMode, szRefresh2);
|
|
|
|
if (lstrcmp(szRefresh, TEXT("0")) == 0)
|
|
LoadString(NULL, IDS_DEFAULTREFRESH_ENGLISH, szRefreshEnglish2, 100);
|
|
else if (lstrcmp(szRefresh, TEXT("-1")) == 0)
|
|
LoadString(NULL, IDS_OPTIMALREFRESH_ENGLISH, szRefreshEnglish2, 100);
|
|
else
|
|
wsprintf(szRefreshEnglish2, TEXT("(%sHz)"), szRefresh);
|
|
lstrcat(pDisplayInfo->m_szDisplayModeEnglish, szRefreshEnglish2);
|
|
lstrcat(pDisplayInfo->m_szDisplayModeEnglish, TEXT(" "));
|
|
|
|
if (pDisplayInfo->m_dwRefreshRate == 0)
|
|
pDisplayInfo->m_dwRefreshRate = 1; // 23399: so it doesn't check again
|
|
}
|
|
}
|
|
|
|
cbData = sizeof(pDisplayInfo->m_szDriverName);
|
|
RegQueryValueEx(hkey, TEXT("drv"), 0, &dwType, (LPBYTE)pDisplayInfo->m_szDriverName, &cbData);
|
|
if (lstrlen(pDisplayInfo->m_szDriverName) > 0)
|
|
{
|
|
TCHAR szPath[MAX_PATH];
|
|
GetSystemDirectory(szPath, MAX_PATH);
|
|
lstrcat(szPath, TEXT("\\"));
|
|
lstrcat(szPath, pDisplayInfo->m_szDriverName);
|
|
GetFileVersion(szPath, pDisplayInfo->m_szDriverVersion,
|
|
pDisplayInfo->m_szDriverAttributes, pDisplayInfo->m_szDriverLanguageLocal, pDisplayInfo->m_szDriverLanguage,
|
|
&pDisplayInfo->m_bDriverBeta, &pDisplayInfo->m_bDriverDebug);
|
|
FileIsSigned(szPath, &pDisplayInfo->m_bDriverSigned, &pDisplayInfo->m_bDriverSignedValid);
|
|
GetFileDateAndSize(szPath, pDisplayInfo->m_szDriverDateLocal, pDisplayInfo->m_szDriverDate, &pDisplayInfo->m_cbDriver);
|
|
}
|
|
|
|
cbData = sizeof(pDisplayInfo->m_szVdd);
|
|
RegQueryValueEx(hkey, TEXT("vdd"), 0, &dwType, (LPBYTE)pDisplayInfo->m_szVdd, &cbData);
|
|
|
|
cbData = sizeof(pDisplayInfo->m_szMiniVdd);
|
|
RegQueryValueEx(hkey, TEXT("minivdd"), 0, &dwType, (LPBYTE)pDisplayInfo->m_szMiniVdd, &cbData);
|
|
if (lstrlen(pDisplayInfo->m_szMiniVdd) > 0)
|
|
{
|
|
TCHAR szPath[MAX_PATH];
|
|
GetSystemDirectory(szPath, MAX_PATH);
|
|
lstrcat(szPath, TEXT("\\drivers\\"));
|
|
lstrcat(szPath, pDisplayInfo->m_szMiniVdd);
|
|
TCHAR szDateLocal[100];
|
|
GetFileDateAndSize( szPath, szDateLocal, pDisplayInfo->m_szMiniVddDate,
|
|
&pDisplayInfo->m_cbMiniVdd );
|
|
}
|
|
|
|
RegCloseKey(hkey);
|
|
}
|
|
lstrcpy(szFullKey, pDisplayInfo->m_szKeyDeviceKey);
|
|
lstrcat(szFullKey, TEXT("\\INFO"));
|
|
if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE, szFullKey, 0, KEY_READ, &hkey))
|
|
{
|
|
cbData = sizeof pDisplayInfo->m_szChipType;
|
|
RegQueryValueEx(hkey, TEXT("ChipType"), 0, &dwType, (LPBYTE)pDisplayInfo->m_szChipType, &cbData);
|
|
|
|
cbData = sizeof pDisplayInfo->m_szDACType;
|
|
RegQueryValueEx(hkey, TEXT("DACType"), 0, &dwType, (LPBYTE)pDisplayInfo->m_szDACType, &cbData);
|
|
|
|
cbData = sizeof pDisplayInfo->m_szRevision;
|
|
RegQueryValueEx(hkey, TEXT("Revision"), 0, &dwType, (LPBYTE)pDisplayInfo->m_szRevision, &cbData);
|
|
if (cbData > 0)
|
|
{
|
|
lstrcat(pDisplayInfo->m_szChipType, TEXT(" Rev "));
|
|
lstrcat(pDisplayInfo->m_szChipType, pDisplayInfo->m_szRevision);
|
|
}
|
|
|
|
RegCloseKey(hkey);
|
|
}
|
|
|
|
if (lstrlen(pDisplayInfo->m_szDriverVersion) == 0)
|
|
{
|
|
TCHAR szPath[MAX_PATH];
|
|
GetSystemDirectory(szPath, MAX_PATH);
|
|
lstrcat(szPath, TEXT("\\"));
|
|
lstrcat(szPath, pDisplayInfo->m_szDriverName);
|
|
lstrcat(szPath, TEXT(".drv"));
|
|
GetFileVersion(szPath, pDisplayInfo->m_szDriverVersion,
|
|
pDisplayInfo->m_szDriverAttributes, pDisplayInfo->m_szDriverLanguageLocal, pDisplayInfo->m_szDriverLanguage);
|
|
FileIsSigned(szPath, &pDisplayInfo->m_bDriverSigned, &pDisplayInfo->m_bDriverSignedValid);
|
|
GetFileDateAndSize(szPath, pDisplayInfo->m_szDriverDateLocal, pDisplayInfo->m_szDriverDate, &pDisplayInfo->m_cbDriver);
|
|
if (lstrlen(pDisplayInfo->m_szDriverVersion) != 0)
|
|
{
|
|
lstrcat(pDisplayInfo->m_szDriverName, TEXT(".drv"));
|
|
}
|
|
else
|
|
{
|
|
GetSystemDirectory(szPath, MAX_PATH);
|
|
lstrcat(szPath, TEXT("\\"));
|
|
lstrcat(szPath, pDisplayInfo->m_szDriverName);
|
|
lstrcat(szPath, TEXT("32.dll"));
|
|
GetFileVersion(szPath, pDisplayInfo->m_szDriverVersion,
|
|
pDisplayInfo->m_szDriverAttributes, pDisplayInfo->m_szDriverLanguageLocal, pDisplayInfo->m_szDriverLanguage);
|
|
FileIsSigned(szPath, &pDisplayInfo->m_bDriverSigned, &pDisplayInfo->m_bDriverSignedValid);
|
|
GetFileDateAndSize(szPath, pDisplayInfo->m_szDriverDateLocal, pDisplayInfo->m_szDriverDate, &pDisplayInfo->m_cbDriver);
|
|
if (lstrlen(pDisplayInfo->m_szDriverVersion) != 0)
|
|
{
|
|
lstrcat(pDisplayInfo->m_szDriverName, TEXT("32.dll"));
|
|
}
|
|
else
|
|
{
|
|
GetSystemDirectory(szPath, MAX_PATH);
|
|
lstrcat(szPath, TEXT("\\"));
|
|
lstrcat(szPath, pDisplayInfo->m_szDriverName);
|
|
lstrcat(szPath, TEXT(".dll"));
|
|
GetFileVersion(szPath, pDisplayInfo->m_szDriverVersion,
|
|
pDisplayInfo->m_szDriverAttributes, pDisplayInfo->m_szDriverLanguageLocal, pDisplayInfo->m_szDriverLanguage);
|
|
FileIsSigned(szPath, &pDisplayInfo->m_bDriverSigned, &pDisplayInfo->m_bDriverSignedValid);
|
|
GetFileDateAndSize(szPath, pDisplayInfo->m_szDriverDateLocal, pDisplayInfo->m_szDriverDate, &pDisplayInfo->m_cbDriver);
|
|
if (lstrlen(pDisplayInfo->m_szDriverVersion) != 0)
|
|
{
|
|
lstrcat(pDisplayInfo->m_szDriverName, TEXT(".dll"));
|
|
}
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
// Use monitor key to get monitor max resolution (and monitor name, if we don't have it yet)
|
|
if (lstrlen(pDisplayInfo->m_szMonitorKey) > 0)
|
|
{
|
|
if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE, pDisplayInfo->m_szMonitorKey, 0, KEY_READ, &hkey))
|
|
{
|
|
cbData = sizeof(pDisplayInfo->m_szMonitorMaxRes);
|
|
RegQueryValueEx(hkey, TEXT("MaxResolution"), 0, &dwType, (LPBYTE)pDisplayInfo->m_szMonitorMaxRes, &cbData);
|
|
if (lstrlen(pDisplayInfo->m_szMonitorName) == 0)
|
|
{
|
|
cbData = sizeof(pDisplayInfo->m_szMonitorName);
|
|
RegQueryValueEx(hkey, TEXT("DriverDesc"), 0, &dwType, (LPBYTE)pDisplayInfo->m_szMonitorName, &cbData);
|
|
}
|
|
RegCloseKey(hkey);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
*
|
|
* GetRegDisplayInfoNT - Uses the registry keys to get more info about a
|
|
* display adapter.
|
|
*
|
|
****************************************************************************/
|
|
VOID GetRegDisplayInfoNT(DisplayInfo* pDisplayInfo)
|
|
{
|
|
TCHAR* pch;
|
|
DWORD dwType;
|
|
DWORD cbData;
|
|
TCHAR szKeyVideo[MAX_PATH+1];
|
|
TCHAR szKeyImage[MAX_PATH+1];
|
|
TCHAR szKey[MAX_PATH+1];
|
|
TCHAR szName[MAX_PATH+1];
|
|
HKEY hkey;
|
|
HKEY hkeyInfo;
|
|
|
|
// set to n/a by default
|
|
_tcscpy( pDisplayInfo->m_szMiniVddDate, TEXT("n/a") );
|
|
|
|
// On NT, m_szKeyDeviceID isn't quite as specific as we need--must go
|
|
// one level further in the registry.
|
|
lstrcpy(szKey, TEXT("System\\CurrentControlSet\\"));
|
|
lstrcat(szKey, pDisplayInfo->m_szKeyDeviceID);
|
|
if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE, szKey, 0, KEY_READ, &hkey))
|
|
{
|
|
if (ERROR_SUCCESS == RegEnumKey(hkey, 0, szName, MAX_PATH+1))
|
|
{
|
|
if (ERROR_SUCCESS == RegOpenKeyEx(hkey, szName, 0, KEY_READ, &hkeyInfo))
|
|
{
|
|
cbData = sizeof(pDisplayInfo->m_szManufacturer);
|
|
RegQueryValueEx(hkeyInfo, TEXT("Mfg"), 0, &dwType, (LPBYTE)pDisplayInfo->m_szManufacturer, &cbData);
|
|
|
|
RegCloseKey(hkeyInfo);
|
|
}
|
|
}
|
|
RegCloseKey(hkey);
|
|
}
|
|
|
|
// Forked path due to bug 182866: dispinfo.cpp makes an invalid assumption
|
|
// about the structure of video key.
|
|
|
|
// szKey will be filled with where the video info is.
|
|
// either "\System\ControlSet001\Services\[Service]\Device0",
|
|
// or "\System\ControlSet001\Video\[GUID]\0000" depending on
|
|
// pDisplayInfo->m_szKeyDeviceKey
|
|
if( _tcsstr( pDisplayInfo->m_szKeyDeviceKey, TEXT("\\Services\\") ) != NULL )
|
|
GetRegDisplayInfoWin2k( pDisplayInfo, szKeyVideo, szKeyImage );
|
|
else
|
|
GetRegDisplayInfoWhistler( pDisplayInfo, szKeyVideo, szKeyImage );
|
|
|
|
if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE, szKeyVideo, 0, KEY_READ, &hkeyInfo))
|
|
{
|
|
WCHAR wszChipType[200];
|
|
WCHAR wszDACType[200];
|
|
TCHAR szDriver[200];
|
|
|
|
cbData = 200 * sizeof(WCHAR);
|
|
if (ERROR_SUCCESS == RegQueryValueEx(hkeyInfo, TEXT("HardwareInformation.ChipType"), 0, &dwType, (LPBYTE)wszChipType, &cbData))
|
|
{
|
|
#ifdef UNICODE
|
|
lstrcpy(pDisplayInfo->m_szChipType, wszChipType);
|
|
#else
|
|
WideCharToMultiByte(CP_ACP, 0, wszChipType, -1, pDisplayInfo->m_szChipType, 200, NULL, NULL);
|
|
#endif
|
|
}
|
|
|
|
cbData = 200 * sizeof(WCHAR);
|
|
if (ERROR_SUCCESS == RegQueryValueEx(hkeyInfo, TEXT("HardwareInformation.DacType"), 0, &dwType, (LPBYTE)wszDACType, &cbData))
|
|
{
|
|
#ifdef UNICODE
|
|
lstrcpy(pDisplayInfo->m_szDACType, wszDACType);
|
|
#else
|
|
WideCharToMultiByte(CP_ACP, 0, wszDACType, -1, pDisplayInfo->m_szDACType, 200, NULL, NULL);
|
|
#endif
|
|
}
|
|
|
|
DWORD dwDisplayMemory;
|
|
cbData = sizeof(dwDisplayMemory);
|
|
if (ERROR_SUCCESS == RegQueryValueEx(hkeyInfo, TEXT("HardwareInformation.MemorySize"), 0, &dwType, (LPBYTE)&dwDisplayMemory, &cbData))
|
|
{
|
|
// Round to nearest 512K:
|
|
dwDisplayMemory = ((dwDisplayMemory + (256 * 1024)) / (512 * 1024));
|
|
// So dwDisplayMemory is (number of bytes / 512K), which makes the
|
|
// following line easier.
|
|
wsprintf(pDisplayInfo->m_szDisplayMemory, TEXT("%d.%d MB"), dwDisplayMemory / 2,
|
|
(dwDisplayMemory % 2) * 5);
|
|
lstrcpy(pDisplayInfo->m_szDisplayMemoryEnglish, pDisplayInfo->m_szDisplayMemory );
|
|
}
|
|
|
|
cbData = 200;
|
|
if (ERROR_SUCCESS == RegQueryValueEx(hkeyInfo, TEXT("InstalledDisplayDrivers"), 0, &dwType, (LPBYTE)szDriver, &cbData))
|
|
{
|
|
_tcsncpy(pDisplayInfo->m_szDriverName, szDriver, 150);
|
|
pDisplayInfo->m_szDriverName[149] = 0;
|
|
lstrcat(pDisplayInfo->m_szDriverName, TEXT(".dll"));
|
|
TCHAR szPath[MAX_PATH];
|
|
GetSystemDirectory(szPath, MAX_PATH);
|
|
lstrcat(szPath, TEXT("\\"));
|
|
if( lstrlen(szPath) + lstrlen(pDisplayInfo->m_szDriverName) < MAX_PATH )
|
|
lstrcat(szPath, pDisplayInfo->m_szDriverName);
|
|
|
|
GetFileVersion(szPath, pDisplayInfo->m_szDriverVersion,
|
|
pDisplayInfo->m_szDriverAttributes, pDisplayInfo->m_szDriverLanguageLocal, pDisplayInfo->m_szDriverLanguage,
|
|
&pDisplayInfo->m_bDriverBeta, &pDisplayInfo->m_bDriverDebug);
|
|
FileIsSigned(szPath, &pDisplayInfo->m_bDriverSigned, &pDisplayInfo->m_bDriverSignedValid);
|
|
GetFileDateAndSize(szPath, pDisplayInfo->m_szDriverDateLocal, pDisplayInfo->m_szDriverDate, &pDisplayInfo->m_cbDriver);
|
|
}
|
|
RegCloseKey(hkeyInfo);
|
|
}
|
|
|
|
if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE, szKeyImage, 0, KEY_READ, &hkeyInfo))
|
|
{
|
|
TCHAR szImagePath[MAX_PATH];
|
|
cbData = MAX_PATH;
|
|
if (ERROR_SUCCESS == RegQueryValueEx(hkeyInfo, TEXT("ImagePath"), 0, &dwType, (LPBYTE)szImagePath, &cbData))
|
|
{
|
|
pch = _tcsrchr(szImagePath, TEXT('\\'));
|
|
if( pch != NULL )
|
|
{
|
|
lstrcpy(pDisplayInfo->m_szMiniVdd, pch + 1);
|
|
if (lstrlen(pDisplayInfo->m_szMiniVdd) > 0)
|
|
{
|
|
TCHAR szPath[MAX_PATH];
|
|
GetSystemDirectory(szPath, MAX_PATH);
|
|
lstrcat(szPath, TEXT("\\drivers\\"));
|
|
lstrcat(szPath, pDisplayInfo->m_szMiniVdd);
|
|
TCHAR szDateLocal[100];
|
|
GetFileDateAndSize( szPath, szDateLocal, pDisplayInfo->m_szMiniVddDate,
|
|
&pDisplayInfo->m_cbMiniVdd );
|
|
}
|
|
}
|
|
}
|
|
RegCloseKey(hkeyInfo);
|
|
}
|
|
|
|
// Use monitor key to get monitor max resolution (and monitor name, if we don't have it yet)
|
|
if (lstrlen(pDisplayInfo->m_szMonitorKey) > 18)
|
|
{
|
|
// Note: Have to skip first 18 characters of string because it's "Registry\Machine\"
|
|
if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE, pDisplayInfo->m_szMonitorKey + 18, 0, KEY_READ, &hkeyInfo))
|
|
{
|
|
cbData = sizeof(pDisplayInfo->m_szMonitorMaxRes);
|
|
RegQueryValueEx(hkeyInfo, TEXT("MaxResolution"), 0, &dwType, (LPBYTE)pDisplayInfo->m_szMonitorMaxRes, &cbData);
|
|
if (lstrlen(pDisplayInfo->m_szMonitorName) == 0)
|
|
{
|
|
cbData = sizeof(pDisplayInfo->m_szMonitorName);
|
|
RegQueryValueEx(hkeyInfo, TEXT("DriverDesc"), 0, &dwType, (LPBYTE)pDisplayInfo->m_szMonitorName, &cbData);
|
|
}
|
|
RegCloseKey(hkeyInfo);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/****************************************************************************
|
|
*
|
|
* GetRegDisplayInfoWhistler - Returns string location of video struct and
|
|
* ImageInfo info in registry
|
|
*
|
|
****************************************************************************/
|
|
VOID GetRegDisplayInfoWhistler(DisplayInfo* pDisplayInfo, TCHAR* szKeyVideo, TCHAR* szKeyImage )
|
|
{
|
|
TCHAR* pch;
|
|
TCHAR szKey[MAX_PATH];
|
|
DWORD dwType;
|
|
DWORD cbData;
|
|
HKEY hkeyService;
|
|
|
|
// m_szKeyDeviceKey will be something like
|
|
// "\Registry\Machine\System\ControlSet001\Video\[GUID]\0000",
|
|
// The "\Registry\Machine\" part is useless, so we skip past the
|
|
// first 18 characters in the string.
|
|
if( lstrlen(pDisplayInfo->m_szKeyDeviceKey) <= 18 )
|
|
{
|
|
lstrcpy( szKeyImage, TEXT("") );
|
|
lstrcpy( szKeyVideo, TEXT("") );
|
|
return;
|
|
}
|
|
|
|
lstrcpy(szKey, pDisplayInfo->m_szKeyDeviceKey + 18);
|
|
|
|
// Slice off the "\0000" and add "\Video" to get the service
|
|
pch = _tcsrchr(szKey, TEXT('\\'));
|
|
if (pch != NULL)
|
|
*pch = 0;
|
|
lstrcat(szKey, TEXT("\\Video\\"));
|
|
|
|
if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE, szKey, 0, KEY_READ, &hkeyService))
|
|
{
|
|
TCHAR szService[MAX_PATH];
|
|
cbData = MAX_PATH;
|
|
if (ERROR_SUCCESS == RegQueryValueEx(hkeyService, TEXT("Service"), 0, &dwType, (LPBYTE)szService, &cbData))
|
|
{
|
|
lstrcpy(szKeyImage, TEXT("System\\CurrentControlSet\\Services\\") );
|
|
if( lstrlen(szKeyImage) + lstrlen(szService) < MAX_PATH )
|
|
lstrcat(szKeyImage, szService);
|
|
}
|
|
|
|
RegCloseKey(hkeyService);
|
|
}
|
|
|
|
// return something like "\System\ControlSet001\Services\atirage\Device0".
|
|
lstrcpy(szKeyVideo, pDisplayInfo->m_szKeyDeviceKey + 18);
|
|
}
|
|
|
|
|
|
/****************************************************************************
|
|
*
|
|
* GetRegDisplayInfoWin2k - Returns string location of video struct and
|
|
* ImageInfo info in registry
|
|
*
|
|
****************************************************************************/
|
|
VOID GetRegDisplayInfoWin2k(DisplayInfo* pDisplayInfo, TCHAR* szKeyVideo, TCHAR* szKeyImage )
|
|
{
|
|
TCHAR* pch;
|
|
|
|
// m_szKeyDeviceKey will be something like
|
|
// "\Registry\Machine\System\ControlSet001\Services\atirage\Device0".
|
|
// The "\Registry\Machine\" part is useless, so we skip past the
|
|
// first 18 characters in the string.
|
|
if( lstrlen(pDisplayInfo->m_szKeyDeviceKey) <= 18 )
|
|
{
|
|
lstrcpy( szKeyImage, TEXT("") );
|
|
lstrcpy( szKeyVideo, TEXT("") );
|
|
return;
|
|
}
|
|
|
|
lstrcpy(szKeyImage, pDisplayInfo->m_szKeyDeviceKey + 18);
|
|
|
|
// Slice off the "\Device0" to get the miniport driver path
|
|
pch = _tcsrchr(szKeyImage, TEXT('\\'));
|
|
if (pch != NULL)
|
|
*pch = 0;
|
|
|
|
// return something like "\System\ControlSet001\Services\atirage\Device0".
|
|
lstrcpy(szKeyVideo, pDisplayInfo->m_szKeyDeviceKey + 18);
|
|
}
|
|
|
|
|
|
/****************************************************************************
|
|
*
|
|
* GetDirectDrawInfo
|
|
*
|
|
****************************************************************************/
|
|
HRESULT GetDirectDrawInfo(LPDIRECTDRAWCREATE pDDCreate, DisplayInfo* pDisplayInfo)
|
|
{
|
|
HRESULT hr;
|
|
LPDIRECTDRAW pdd = NULL;
|
|
GUID* pGUID;
|
|
DDCAPS ddcaps;
|
|
DWORD dwDisplayMemory;
|
|
|
|
if (pDisplayInfo->m_guid == GUID_NULL)
|
|
pGUID = NULL;
|
|
else
|
|
pGUID = &pDisplayInfo->m_guid;
|
|
|
|
if (FAILED(hr = pDDCreate(pGUID, &pdd, NULL)))
|
|
goto LFail;
|
|
|
|
ddcaps.dwSize = sizeof(ddcaps);
|
|
if (FAILED(hr = pdd->GetCaps(&ddcaps, NULL)))
|
|
goto LFail;
|
|
|
|
// If AGP is disabled, we won't be able to tell if AGP is supported because
|
|
// the flag will not be set. So in that case, assume that AGP is supported.
|
|
// If AGP is not disabled, check the existence of AGP and note that we are
|
|
// confident in the knowledge of whether AGP exists or not. I know, it's yucky.
|
|
if (pDisplayInfo->m_bAGPEnabled)
|
|
{
|
|
pDisplayInfo->m_bAGPExistenceValid = TRUE;
|
|
if (ddcaps.dwCaps2 & DDCAPS2_NONLOCALVIDMEM)
|
|
pDisplayInfo->m_bAGPExists = TRUE;
|
|
}
|
|
|
|
if( ddcaps.dwCaps & DDCAPS_NOHARDWARE )
|
|
pDisplayInfo->m_bNoHardware = TRUE;
|
|
else
|
|
pDisplayInfo->m_bNoHardware = FALSE;
|
|
|
|
// 28873: if( DDCAPS_NOHARDWARE && m_bDDAccelerationEnabled ) then GetAvailableVidMem is wrong.
|
|
if( pDisplayInfo->m_bNoHardware && pDisplayInfo->m_bDDAccelerationEnabled )
|
|
{
|
|
LoadString(NULL, IDS_NA, pDisplayInfo->m_szDisplayMemory, 100);
|
|
wsprintf(pDisplayInfo->m_szDisplayMemoryEnglish, TEXT("n/a") );
|
|
}
|
|
else
|
|
{
|
|
if (lstrlen(pDisplayInfo->m_szDisplayMemory) == 0)
|
|
{
|
|
// 26678: returns wrong vid mem for 2nd monitor, so ignore non-hardware devices
|
|
if( (ddcaps.dwCaps & DDCAPS_NOHARDWARE) == 0 )
|
|
{
|
|
// 24351: ddcaps.dwVidMemTotal sometimes includes AGP-accessible memory,
|
|
// which we don't want. So use GetAvailableVidMem whenever we can, and
|
|
// fall back to ddcaps.dwVidMemTotal if that's a problem.
|
|
dwDisplayMemory = 0;
|
|
LPDIRECTDRAW2 pdd2;
|
|
if (SUCCEEDED(pdd->QueryInterface(IID_IDirectDraw2, (VOID**)&pdd2)))
|
|
{
|
|
DDSCAPS ddscaps;
|
|
ddscaps.dwCaps = DDSCAPS_VIDEOMEMORY | DDSCAPS_LOCALVIDMEM;
|
|
pdd2->GetAvailableVidMem(&ddscaps, &dwDisplayMemory, NULL);
|
|
pdd2->Release();
|
|
}
|
|
if (dwDisplayMemory == 0)
|
|
{
|
|
dwDisplayMemory = ddcaps.dwVidMemTotal;
|
|
}
|
|
// Add GDI memory except on no-GDI cards (Voodoo-type cards)
|
|
if (pDisplayInfo->m_bCanRenderWindow)
|
|
{
|
|
DDSURFACEDESC ddsd;
|
|
ddsd.dwSize = sizeof(ddsd);
|
|
if (FAILED(hr = pdd->GetDisplayMode(&ddsd)))
|
|
goto LFail;
|
|
|
|
dwDisplayMemory += ddsd.dwWidth * ddsd.dwHeight *
|
|
(ddsd.ddpfPixelFormat.dwRGBBitCount / 8);
|
|
}
|
|
// Round to nearest 512K:
|
|
dwDisplayMemory = ((dwDisplayMemory + (256 * 1024)) / (512 * 1024));
|
|
// So dwDisplayMemory is (number of bytes / 512K), which makes the
|
|
// following line easier.
|
|
wsprintf(pDisplayInfo->m_szDisplayMemory, TEXT("%d.%d MB"), dwDisplayMemory / 2,
|
|
(dwDisplayMemory % 2) * 5);
|
|
lstrcpy(pDisplayInfo->m_szDisplayMemoryEnglish, pDisplayInfo->m_szDisplayMemory );
|
|
}
|
|
}
|
|
}
|
|
|
|
// 24427: Detect driver DDI version
|
|
// 24656: Also detect D3D acceleration without DDCAPS_3D, since that flag is
|
|
// sometimes sensitive to the current desktop color depth.
|
|
|
|
// First, see if DD/D3D are disabled, and if so, briefly re-enable them
|
|
BOOL bDDDisabled;
|
|
BOOL bD3DDisabled;
|
|
HKEY hkeyDD;
|
|
HKEY hkeyD3D;
|
|
DWORD dwSize;
|
|
DWORD dwType;
|
|
DWORD dwData;
|
|
|
|
bDDDisabled = FALSE;
|
|
bD3DDisabled = FALSE;
|
|
hkeyDD = NULL;
|
|
hkeyD3D = NULL;
|
|
if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE,
|
|
TEXT("SOFTWARE\\Microsoft\\DirectDraw"), 0, KEY_ALL_ACCESS, &hkeyDD))
|
|
{
|
|
dwSize = sizeof(dwData);
|
|
dwData = 0;
|
|
RegQueryValueEx(hkeyDD, TEXT("EmulationOnly"), NULL, &dwType, (BYTE *)&dwData, &dwSize);
|
|
if (dwData != 0)
|
|
{
|
|
bDDDisabled = TRUE;
|
|
// Re-enable DD
|
|
dwData = 0;
|
|
RegSetValueEx(hkeyDD, TEXT("EmulationOnly"), 0, REG_DWORD, (BYTE*)&dwData, sizeof(dwData));
|
|
}
|
|
// Note: don't close key yet
|
|
}
|
|
|
|
if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE,
|
|
TEXT("SOFTWARE\\Microsoft\\Direct3D\\Drivers"), 0, KEY_ALL_ACCESS, &hkeyD3D))
|
|
{
|
|
dwSize = sizeof(dwData);
|
|
dwData = 0;
|
|
RegQueryValueEx(hkeyD3D, TEXT("SoftwareOnly"), NULL, &dwType, (BYTE *)&dwData, &dwSize);
|
|
if (dwData != 0)
|
|
{
|
|
bD3DDisabled = TRUE;
|
|
// Re-enable D3D
|
|
dwData = 0;
|
|
RegSetValueEx(hkeyD3D, TEXT("SoftwareOnly"), 0, REG_DWORD, (BYTE*)&dwData, sizeof(dwData));
|
|
}
|
|
// Note: don't close key yet
|
|
}
|
|
|
|
LPDIRECT3D pd3d;
|
|
if (SUCCEEDED(pdd->QueryInterface(IID_IDirect3D, (VOID**)&pd3d)))
|
|
{
|
|
DWORD dwVersion = 0;
|
|
if (SUCCEEDED(pd3d->EnumDevices(EnumDevicesCallback, (VOID*)&dwVersion)))
|
|
{
|
|
pDisplayInfo->m_dwDDIVersion = dwVersion;
|
|
}
|
|
pd3d->Release();
|
|
}
|
|
|
|
// While were in this function wrapped with crash protection try to
|
|
// get adapter info from D3D8, and match it up with the DisplayInfo list.
|
|
// This will also tell us if m_dwDDIVersion==8.
|
|
GetDX8AdapterInfo(pDisplayInfo);
|
|
|
|
switch (pDisplayInfo->m_dwDDIVersion)
|
|
{
|
|
case 0:
|
|
wsprintf(pDisplayInfo->m_szDDIVersion, TEXT("Unknown"));
|
|
break;
|
|
case 7:
|
|
if( IsD3D8Working() )
|
|
wsprintf(pDisplayInfo->m_szDDIVersion, TEXT("7"));
|
|
else
|
|
wsprintf(pDisplayInfo->m_szDDIVersion, TEXT("7 (or higher)"));
|
|
break;
|
|
case 8:
|
|
wsprintf(pDisplayInfo->m_szDDIVersion, TEXT("8 (or higher)"));
|
|
break;
|
|
default:
|
|
wsprintf(pDisplayInfo->m_szDDIVersion, TEXT("%d"), pDisplayInfo->m_dwDDIVersion);
|
|
break;
|
|
}
|
|
|
|
if (pDisplayInfo->m_dwDDIVersion != 0)
|
|
pDisplayInfo->m_b3DAccelerationExists = TRUE;
|
|
|
|
// Re-disable DD and D3D, if necessary
|
|
dwData = 1;
|
|
if (bDDDisabled)
|
|
RegSetValueEx(hkeyDD, TEXT("EmulationOnly"), 0, REG_DWORD, (BYTE*)&dwData, sizeof(dwData));
|
|
if (bD3DDisabled)
|
|
RegSetValueEx(hkeyD3D, TEXT("SoftwareOnly"), 0, REG_DWORD, (BYTE*)&dwData, sizeof(dwData));
|
|
if (hkeyDD != NULL)
|
|
RegCloseKey(hkeyDD);
|
|
if (hkeyD3D != NULL)
|
|
RegCloseKey(hkeyD3D);
|
|
|
|
pdd->Release();
|
|
return S_OK;
|
|
LFail:
|
|
if (pdd != NULL)
|
|
pdd->Release();
|
|
return hr;
|
|
}
|
|
|
|
|
|
/****************************************************************************
|
|
*
|
|
* EnumDevicesCallback
|
|
*
|
|
****************************************************************************/
|
|
HRESULT CALLBACK EnumDevicesCallback(GUID* pGuid, LPSTR pszDesc, LPSTR pszName,
|
|
D3DDEVICEDESC* pd3ddevdesc1, D3DDEVICEDESC* pd3ddevdesc2, VOID* pvContext)
|
|
{
|
|
DWORD* pdwVersion = (DWORD*)pvContext;
|
|
DWORD dwDevCaps;
|
|
if (pd3ddevdesc1->dcmColorModel == D3DCOLOR_RGB)
|
|
{
|
|
dwDevCaps = pd3ddevdesc1->dwDevCaps;
|
|
if (dwDevCaps & D3DDEVCAPS_DRAWPRIMITIVES2EX)
|
|
*pdwVersion = 7;
|
|
else if (dwDevCaps & D3DDEVCAPS_DRAWPRIMITIVES2)
|
|
*pdwVersion = 6;
|
|
else if (dwDevCaps & D3DDEVCAPS_DRAWPRIMTLVERTEX)
|
|
*pdwVersion = 5;
|
|
else if (dwDevCaps & D3DDEVCAPS_FLOATTLVERTEX)
|
|
*pdwVersion = 3;
|
|
}
|
|
return D3DENUMRET_OK;
|
|
}
|
|
|
|
|
|
/****************************************************************************
|
|
*
|
|
* IsDDHWAccelEnabled
|
|
*
|
|
****************************************************************************/
|
|
BOOL IsDDHWAccelEnabled(VOID)
|
|
{
|
|
HKEY hkey;
|
|
DWORD dwSize;
|
|
DWORD dwType;
|
|
DWORD dwData;
|
|
BOOL bResult = TRUE;
|
|
|
|
if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE,
|
|
TEXT("SOFTWARE\\Microsoft\\DirectDraw"), 0, KEY_READ, &hkey))
|
|
{
|
|
dwSize = sizeof(dwData);
|
|
if (ERROR_SUCCESS == RegQueryValueEx(hkey, TEXT("EmulationOnly"), NULL, &dwType, (BYTE *)&dwData, &dwSize))
|
|
{
|
|
if (dwData != 0)
|
|
bResult = FALSE;
|
|
|
|
RegCloseKey(hkey);
|
|
}
|
|
}
|
|
|
|
return bResult;
|
|
}
|
|
|
|
|
|
/****************************************************************************
|
|
*
|
|
* IsD3DHWAccelEnabled
|
|
*
|
|
****************************************************************************/
|
|
BOOL IsD3DHWAccelEnabled(VOID)
|
|
{
|
|
HKEY hkey;
|
|
DWORD dwSize;
|
|
DWORD dwType;
|
|
DWORD dwData;
|
|
BOOL bIsD3DHWAccelEnabled = TRUE;
|
|
|
|
if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE,
|
|
TEXT("SOFTWARE\\Microsoft\\Direct3D\\Drivers"), 0, KEY_READ, &hkey))
|
|
{
|
|
dwSize = sizeof(dwData);
|
|
if (ERROR_SUCCESS == RegQueryValueEx(hkey, TEXT("SoftwareOnly"), NULL, &dwType, (BYTE *)&dwData, &dwSize))
|
|
{
|
|
if (dwData != 0)
|
|
bIsD3DHWAccelEnabled = FALSE;
|
|
|
|
RegCloseKey( hkey );
|
|
}
|
|
}
|
|
|
|
return bIsD3DHWAccelEnabled;
|
|
}
|
|
|
|
|
|
/****************************************************************************
|
|
*
|
|
* IsAGPEnabled
|
|
*
|
|
****************************************************************************/
|
|
BOOL IsAGPEnabled(VOID)
|
|
{
|
|
HKEY hkey;
|
|
DWORD dwSize;
|
|
DWORD dwType;
|
|
DWORD dwData;
|
|
BOOL bIsAGPEnabled = TRUE;
|
|
|
|
if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE,
|
|
TEXT("SOFTWARE\\Microsoft\\DirectDraw"), 0, KEY_READ, &hkey))
|
|
{
|
|
dwSize = sizeof(dwData);
|
|
if (ERROR_SUCCESS == RegQueryValueEx(hkey, TEXT("DisableAGPSupport"), NULL, &dwType, (BYTE *)&dwData, &dwSize))
|
|
{
|
|
if (dwData != 0)
|
|
bIsAGPEnabled = FALSE;
|
|
|
|
RegCloseKey( hkey );
|
|
}
|
|
}
|
|
|
|
return bIsAGPEnabled;
|
|
}
|
|
|
|
|
|
//
|
|
// GetDeviceValue
|
|
//
|
|
// read a value from the HW or SW of a PnP device
|
|
//
|
|
BOOL GetDeviceValue(TCHAR* pszHardwareKey, TCHAR* pszKey, TCHAR* pszValue, BYTE *buf, DWORD cbbuf)
|
|
{
|
|
HKEY hkeyHW;
|
|
HKEY hkeySW;
|
|
BOOL f = FALSE;
|
|
DWORD cb;
|
|
TCHAR szSoftwareKey[MAX_PATH];
|
|
|
|
*(DWORD*)buf = 0;
|
|
|
|
//
|
|
// open the HW key
|
|
//
|
|
if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, pszHardwareKey, 0, KEY_READ, &hkeyHW) == ERROR_SUCCESS)
|
|
{
|
|
//
|
|
// try to read the value from the HW key
|
|
//
|
|
*buf = 0;
|
|
cb = cbbuf;
|
|
if (RegQueryValueEx(hkeyHW, pszValue, NULL, NULL, buf, &cb) == ERROR_SUCCESS)
|
|
{
|
|
f = TRUE;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// now try the SW key
|
|
//
|
|
static TCHAR szSW[] = TEXT("System\\CurrentControlSet\\Services\\Class\\");
|
|
|
|
lstrcpy(szSoftwareKey, szSW);
|
|
cb = sizeof(szSoftwareKey) - sizeof(szSW);
|
|
TCHAR* sz = szSoftwareKey;
|
|
sz += lstrlen(szSW);
|
|
RegQueryValueEx(hkeyHW, TEXT("Driver"), NULL, NULL, (LPBYTE)sz, &cb);
|
|
|
|
if (pszKey)
|
|
{
|
|
lstrcat(szSoftwareKey, TEXT("\\"));
|
|
lstrcat(szSoftwareKey, pszKey);
|
|
}
|
|
|
|
if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, szSoftwareKey, 0, KEY_READ, &hkeySW) == ERROR_SUCCESS)
|
|
{
|
|
*buf = 0;
|
|
cb = cbbuf;
|
|
if (RegQueryValueEx(hkeySW, pszValue, NULL, NULL, buf, &cb) == ERROR_SUCCESS)
|
|
{
|
|
f = TRUE;
|
|
}
|
|
|
|
RegCloseKey(hkeySW);
|
|
}
|
|
}
|
|
|
|
RegCloseKey(hkeyHW);
|
|
}
|
|
|
|
return f;
|
|
}
|
|
|
|
//
|
|
// FindDevice
|
|
//
|
|
// enum the started PnP devices looking for a device of a particular class
|
|
//
|
|
// iDevice what device to return (0= first device, 1=second et)
|
|
// szDeviceClass what class device (ie "Display") NULL will match all
|
|
// szDeviceID buffer to return the hardware ID (MAX_PATH bytes)
|
|
//
|
|
// return TRUE if a device was found.
|
|
//
|
|
// example:
|
|
//
|
|
// for (int i=0; FindDevice(i, "Display", DeviceID); i++)
|
|
// {
|
|
// }
|
|
//
|
|
BOOL FindDevice(INT iDevice, TCHAR* pszDeviceClass, TCHAR* pszDeviceClassNot, TCHAR* pszHardwareKey)
|
|
{
|
|
HKEY hkeyPnP;
|
|
HKEY hkey;
|
|
DWORD n;
|
|
DWORD cb;
|
|
DWORD dw;
|
|
TCHAR ach[MAX_PATH+1];
|
|
|
|
if (RegOpenKeyEx(HKEY_DYN_DATA, TEXT("Config Manager\\Enum"), 0, KEY_READ, &hkeyPnP) != ERROR_SUCCESS)
|
|
return FALSE;
|
|
|
|
for (n=0; RegEnumKey(hkeyPnP, n, ach, MAX_PATH+1) == 0; n++)
|
|
{
|
|
static TCHAR szHW[] = TEXT("Enum\\");
|
|
|
|
if (RegOpenKey(hkeyPnP, ach, &hkey) != ERROR_SUCCESS)
|
|
continue;
|
|
|
|
lstrcpy(pszHardwareKey, szHW);
|
|
cb = MAX_PATH - sizeof(szHW);
|
|
RegQueryValueEx(hkey, TEXT("HardwareKey"), NULL, NULL, (BYTE*)pszHardwareKey + sizeof(szHW) - 1, &cb);
|
|
|
|
dw = 0;
|
|
cb = sizeof(dw);
|
|
RegQueryValueEx(hkey, TEXT("Problem"), NULL, NULL, (BYTE*)&dw, &cb);
|
|
RegCloseKey(hkey);
|
|
|
|
if (dw != 0) // if this device has a problem skip it
|
|
continue;
|
|
|
|
if (pszDeviceClass || pszDeviceClassNot)
|
|
{
|
|
GetDeviceValue(pszHardwareKey, NULL, TEXT("Class"), (BYTE*)ach, sizeof(ach));
|
|
|
|
if (pszDeviceClass && DXUtil_strcmpi(pszDeviceClass, ach) != 0)
|
|
continue;
|
|
|
|
if (pszDeviceClassNot && DXUtil_strcmpi(pszDeviceClassNot, ach) == 0)
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// we found a device, make sure it is the one the caller wants
|
|
//
|
|
if (iDevice-- == 0)
|
|
{
|
|
RegCloseKey(hkeyPnP);
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
RegCloseKey(hkeyPnP);
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
/****************************************************************************
|
|
*
|
|
* CheckRegistry
|
|
*
|
|
****************************************************************************/
|
|
HRESULT CheckRegistry(RegError** ppRegErrorFirst)
|
|
{
|
|
HRESULT hr;
|
|
HKEY HKLM = HKEY_LOCAL_MACHINE;
|
|
HKEY HKCR = HKEY_CLASSES_ROOT;
|
|
|
|
TCHAR szVersion[100];
|
|
HKEY hkey;
|
|
DWORD cbData;
|
|
ULONG ulType;
|
|
|
|
DWORD dwMajor = 0;
|
|
DWORD dwMinor = 0;
|
|
DWORD dwRevision = 0;
|
|
DWORD dwBuild = 0;
|
|
|
|
if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE, TEXT("Software\\Microsoft\\DirectX"),
|
|
0, KEY_READ, &hkey))
|
|
{
|
|
cbData = 100;
|
|
RegQueryValueEx(hkey, TEXT("Version"), 0, &ulType, (LPBYTE)szVersion, &cbData);
|
|
RegCloseKey(hkey);
|
|
if (lstrlen(szVersion) > 6 &&
|
|
lstrlen(szVersion) < 20)
|
|
{
|
|
if( _stscanf(szVersion, TEXT("%d.%d.%d.%d"), &dwMajor, &dwMinor, &dwRevision, &dwBuild) != 4 )
|
|
{
|
|
dwMajor = 0;
|
|
dwMinor = 0;
|
|
dwRevision = 0;
|
|
dwBuild = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
// No registry checking on DX versions before DX7
|
|
if (dwMinor < 7)
|
|
return S_OK;
|
|
|
|
// From ddraw.inf (compatibility hacks not included):
|
|
if (FAILED(hr = CheckRegString(ppRegErrorFirst, HKCR, TEXT("DirectDraw"), TEXT(""), TEXT("*"))))
|
|
return hr;
|
|
if (FAILED(hr = CheckRegString(ppRegErrorFirst, HKCR, TEXT("DirectDraw\\CLSID"), TEXT(""), TEXT("{D7B70EE0-4340-11CF-B063-0020AFC2CD35}"))))
|
|
return hr;
|
|
if (FAILED(hr = CheckRegString(ppRegErrorFirst, HKCR, TEXT("CLSID\\{D7B70EE0-4340-11CF-B063-0020AFC2CD35}"), TEXT(""), TEXT("*"))))
|
|
return hr;
|
|
if (FAILED(hr = CheckRegString(ppRegErrorFirst, HKCR, TEXT("CLSID\\{D7B70EE0-4340-11CF-B063-0020AFC2CD35}\\InprocServer32"), TEXT(""), TEXT("ddraw.dll"), CRF_LEAF)))
|
|
return hr;
|
|
if (FAILED(hr = CheckRegString(ppRegErrorFirst, HKCR, TEXT("CLSID\\{D7B70EE0-4340-11CF-B063-0020AFC2CD35}\\InprocServer32"), TEXT("ThreadingModel"), TEXT("Both"))))
|
|
return hr;
|
|
|
|
if (FAILED(hr = CheckRegString(ppRegErrorFirst, HKCR, TEXT("DirectDrawClipper"), TEXT(""), TEXT("*"))))
|
|
return hr;
|
|
if (FAILED(hr = CheckRegString(ppRegErrorFirst, HKCR, TEXT("DirectDrawClipper\\CLSID"), TEXT(""), TEXT("{593817A0-7DB3-11CF-A2DE-00AA00B93356}"))))
|
|
return hr;
|
|
if (FAILED(hr = CheckRegString(ppRegErrorFirst, HKCR, TEXT("CLSID\\{593817A0-7DB3-11CF-A2DE-00AA00B93356}"), TEXT(""), TEXT("*"))))
|
|
return hr;
|
|
if (FAILED(hr = CheckRegString(ppRegErrorFirst, HKCR, TEXT("CLSID\\{593817A0-7DB3-11CF-A2DE-00AA00B93356}\\InprocServer32"), TEXT(""), TEXT("ddraw.dll"), CRF_LEAF)))
|
|
return hr;
|
|
if (FAILED(hr = CheckRegString(ppRegErrorFirst, HKCR, TEXT("CLSID\\{593817A0-7DB3-11CF-A2DE-00AA00B93356}\\InprocServer32"), TEXT("ThreadingModel"), TEXT("Both"))))
|
|
return hr;
|
|
|
|
if (!BIsPlatformNT())
|
|
{
|
|
// We can't check for the following entry on Win2000 because it is missing.
|
|
if (FAILED(hr = CheckRegString(ppRegErrorFirst, HKCR, TEXT("CLSID\\{4FD2A832-86C8-11d0-8FCA-00C04FD9189D}"), TEXT(""), TEXT("*"))))
|
|
return hr;
|
|
}
|
|
if (FAILED(hr = CheckRegString(ppRegErrorFirst, HKCR, TEXT("CLSID\\{4FD2A832-86C8-11d0-8FCA-00C04FD9189D}\\InprocServer32"), TEXT(""), TEXT("ddrawex.dll"), CRF_LEAF)))
|
|
return hr;
|
|
if (FAILED(hr = CheckRegString(ppRegErrorFirst, HKCR, TEXT("CLSID\\{4FD2A832-86C8-11d0-8FCA-00C04FD9189D}\\InprocServer32"), TEXT("ThreadingModel"), TEXT("Both"))))
|
|
return hr;
|
|
|
|
|
|
// From d3d.inf:
|
|
TCHAR* pszHALKey = TEXT("Software\\Microsoft\\Direct3D\\Drivers\\Direct3D HAL");
|
|
BYTE bArrayHALGuid[] = { 0xe0, 0x3d, 0xe6, 0x84, 0xaa, 0x46, 0xcf, 0x11, 0x81, 0x6f, 0x00, 0x00, 0xc0, 0x20, 0x15, 0x6e };
|
|
TCHAR* pszRampKey = TEXT("Software\\Microsoft\\Direct3D\\Drivers\\Ramp Emulation");
|
|
BYTE bArrayRampGuid[] = { 0x20, 0x6b, 0x08, 0xf2, 0x9f, 0x25, 0xcf, 0x11, 0xa3, 0x1a, 0x00, 0xaa, 0x00, 0xb9, 0x33, 0x56 };
|
|
TCHAR* pszRGBKey = TEXT("Software\\Microsoft\\Direct3D\\Drivers\\RGB Emulation");
|
|
BYTE bArrayRGBGuid[] = { 0x60, 0x5c, 0x66, 0xa4, 0x73, 0x26, 0xcf, 0x11, 0xa3, 0x1a, 0x00, 0xaa, 0x00, 0xb9, 0x33, 0x56 };
|
|
|
|
if (FAILED(hr = CheckRegString(ppRegErrorFirst, HKLM, pszHALKey, TEXT("Base"), TEXT("hal"))))
|
|
return hr;
|
|
if (FAILED(hr = CheckRegString(ppRegErrorFirst, HKLM, pszHALKey, TEXT("Description"), TEXT("*"))))
|
|
return hr;
|
|
if (FAILED(hr = CheckRegBinary(ppRegErrorFirst, HKLM, pszHALKey, TEXT("GUID"), bArrayHALGuid, sizeof(bArrayHALGuid))))
|
|
return hr;
|
|
|
|
if (FAILED(hr = CheckRegString(ppRegErrorFirst, HKLM, pszRampKey, TEXT("Base"), TEXT("ramp"))))
|
|
return hr;
|
|
if (FAILED(hr = CheckRegString(ppRegErrorFirst, HKLM, pszRampKey, TEXT("Description"), TEXT("*"))))
|
|
return hr;
|
|
if (FAILED(hr = CheckRegBinary(ppRegErrorFirst, HKLM, pszRampKey, TEXT("GUID"), bArrayRampGuid, sizeof(bArrayRampGuid))))
|
|
return hr;
|
|
|
|
if (FAILED(hr = CheckRegString(ppRegErrorFirst, HKLM, pszRGBKey, TEXT("Base"), TEXT("rgb"))))
|
|
return hr;
|
|
if (FAILED(hr = CheckRegString(ppRegErrorFirst, HKLM, pszRGBKey, TEXT("Description"), TEXT("*"))))
|
|
return hr;
|
|
if (FAILED(hr = CheckRegBinary(ppRegErrorFirst, HKLM, pszRGBKey, TEXT("GUID"), bArrayRGBGuid, sizeof(bArrayRGBGuid))))
|
|
return hr;
|
|
|
|
if (FAILED(hr = CheckRegString(ppRegErrorFirst, HKLM, TEXT("Software\\Microsoft\\Direct3D\\DX6TextureEnumInclusionList\\16 bit Bump DuDv"), TEXT("ddpf"), TEXT("00080000 0 16 ff ff00 0 0"))))
|
|
return hr;
|
|
if (FAILED(hr = CheckRegString(ppRegErrorFirst, HKLM, TEXT("Software\\Microsoft\\Direct3D\\DX6TextureEnumInclusionList\\16 bit BumpLum DuDv"), TEXT("ddpf"), TEXT("000C0000 0 16 1f 3e0 fc00 0"))))
|
|
return hr;
|
|
if (FAILED(hr = CheckRegString(ppRegErrorFirst, HKLM, TEXT("Software\\Microsoft\\Direct3D\\DX6TextureEnumInclusionList\\16 bit Luminance Alpha"), TEXT("ddpf"), TEXT("00020001 0 16 ff 0 0 ff00"))))
|
|
return hr;
|
|
if (FAILED(hr = CheckRegString(ppRegErrorFirst, HKLM, TEXT("Software\\Microsoft\\Direct3D\\DX6TextureEnumInclusionList\\24 bit BumpLum DuDv"), TEXT("ddpf"), TEXT("000C0000 0 24 ff ff00 ff0000 0"))))
|
|
return hr;
|
|
if (FAILED(hr = CheckRegString(ppRegErrorFirst, HKLM, TEXT("Software\\Microsoft\\Direct3D\\DX6TextureEnumInclusionList\\8 bit Luminance"), TEXT("ddpf"), TEXT("00020000 0 8 ff 0 0 0"))))
|
|
return hr;
|
|
|
|
if (FAILED(hr = CheckRegString(ppRegErrorFirst, HKCR, TEXT("Direct3DRM"), TEXT(""), TEXT("*"))))
|
|
return hr;
|
|
if (FAILED(hr = CheckRegString(ppRegErrorFirst, HKCR, TEXT("Direct3DRM\\CLSID"), TEXT(""), TEXT("{4516EC41-8F20-11d0-9B6D-0000C0781BC3}"))))
|
|
return hr;
|
|
if (FAILED(hr = CheckRegString(ppRegErrorFirst, HKCR, TEXT("CLSID\\{4516EC41-8F20-11d0-9B6D-0000C0781BC3}"), TEXT(""), TEXT("*"))))
|
|
return hr;
|
|
if (FAILED(hr = CheckRegString(ppRegErrorFirst, HKCR, TEXT("CLSID\\{4516EC41-8F20-11d0-9B6D-0000C0781BC3}\\InprocServer32"), TEXT(""), TEXT("d3drm.dll"))))
|
|
return hr;
|
|
if (FAILED(hr = CheckRegString(ppRegErrorFirst, HKCR, TEXT("CLSID\\{4516EC41-8F20-11d0-9B6D-0000C0781BC3}\\InprocServer32"), TEXT("ThreadingModel"), TEXT("Both"))))
|
|
return hr;
|
|
|
|
if (FAILED(hr = CheckRegString(ppRegErrorFirst, HKCR, TEXT("DirectXFile"), TEXT(""), TEXT("*"))))
|
|
return hr;
|
|
if (FAILED(hr = CheckRegString(ppRegErrorFirst, HKCR, TEXT("DirectXFile\\CLSID"), TEXT(""), TEXT("{4516EC43-8F20-11D0-9B6D-0000C0781BC3}"))))
|
|
return hr;
|
|
if (FAILED(hr = CheckRegString(ppRegErrorFirst, HKCR, TEXT("CLSID\\{4516EC43-8F20-11D0-9B6D-0000C0781BC3}"), TEXT(""), TEXT("*"))))
|
|
return hr;
|
|
if (FAILED(hr = CheckRegString(ppRegErrorFirst, HKCR, TEXT("CLSID\\{4516EC43-8F20-11d0-9B6D-0000C0781BC3}\\InprocServer32"), TEXT(""), TEXT("d3dxof.dll"))))
|
|
return hr;
|
|
if (BIsPlatformNT())
|
|
{
|
|
// 23342: This setting is missing on Win9x.
|
|
if (FAILED(hr = CheckRegString(ppRegErrorFirst, HKCR, TEXT("CLSID\\{4516EC43-8F20-11d0-9B6D-0000C0781BC3}\\InprocServer32"), TEXT("ThreadingModel"), TEXT("Both"))))
|
|
return hr;
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
/****************************************************************************
|
|
*
|
|
* DiagnoseDisplay
|
|
*
|
|
****************************************************************************/
|
|
VOID DiagnoseDisplay(SysInfo* pSysInfo, DisplayInfo* pDisplayInfoFirst)
|
|
{
|
|
DisplayInfo* pDisplayInfo;
|
|
TCHAR sz[300];
|
|
TCHAR szEnglish[300];
|
|
TCHAR szFmt[300];
|
|
BOOL bShouldReinstall = FALSE;
|
|
|
|
for (pDisplayInfo = pDisplayInfoFirst; pDisplayInfo != NULL;
|
|
pDisplayInfo = pDisplayInfo->m_pDisplayInfoNext)
|
|
{
|
|
if (pDisplayInfo->m_bDDAccelerationEnabled)
|
|
{
|
|
if( pDisplayInfo->m_bNoHardware )
|
|
{
|
|
LoadString(NULL, IDS_ACCELUNAVAIL, sz, 100);
|
|
LoadString(NULL, IDS_ACCELUNAVAIL_ENGLISH, szEnglish, 100);
|
|
}
|
|
else
|
|
{
|
|
LoadString(NULL, IDS_ACCELENABLED, sz, 100);
|
|
LoadString(NULL, IDS_ACCELENABLED_ENGLISH, szEnglish, 100);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
LoadString(NULL, IDS_ACCELDISABLED, sz, 100);
|
|
LoadString(NULL, IDS_ACCELDISABLED_ENGLISH, szEnglish, 100);
|
|
}
|
|
|
|
_tcscpy( pDisplayInfo->m_szDDStatus, sz );
|
|
_tcscpy( pDisplayInfo->m_szDDStatusEnglish, szEnglish );
|
|
|
|
if (pDisplayInfo->m_b3DAccelerationExists)
|
|
{
|
|
if (pDisplayInfo->m_b3DAccelerationEnabled)
|
|
{
|
|
LoadString(NULL, IDS_ACCELENABLED, sz, 100);
|
|
LoadString(NULL, IDS_ACCELENABLED_ENGLISH, szEnglish, 100);
|
|
}
|
|
else
|
|
{
|
|
LoadString(NULL, IDS_ACCELDISABLED, sz, 100);
|
|
LoadString(NULL, IDS_ACCELDISABLED_ENGLISH, szEnglish, 100);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
LoadString(NULL, IDS_ACCELUNAVAIL, sz, 100);
|
|
LoadString(NULL, IDS_ACCELUNAVAIL_ENGLISH, szEnglish, 100);
|
|
}
|
|
_tcscpy( pDisplayInfo->m_szD3DStatus, sz );
|
|
_tcscpy( pDisplayInfo->m_szD3DStatusEnglish, szEnglish );
|
|
|
|
if ( (pDisplayInfo->m_bAGPExistenceValid && !pDisplayInfo->m_bAGPExists) ||
|
|
(!pDisplayInfo->m_bDDAccelerationEnabled) )
|
|
{
|
|
LoadString(NULL, IDS_ACCELUNAVAIL, sz, 100);
|
|
LoadString(NULL, IDS_ACCELUNAVAIL_ENGLISH, szEnglish, 100);
|
|
}
|
|
else
|
|
{
|
|
if (pDisplayInfo->m_bAGPEnabled)
|
|
{
|
|
LoadString(NULL, IDS_ACCELENABLED, sz, 100);
|
|
LoadString(NULL, IDS_ACCELENABLED_ENGLISH, szEnglish, 100);
|
|
}
|
|
else
|
|
{
|
|
LoadString(NULL, IDS_ACCELDISABLED, sz, 100);
|
|
LoadString(NULL, IDS_ACCELDISABLED_ENGLISH, szEnglish, 100);
|
|
}
|
|
}
|
|
_tcscpy( pDisplayInfo->m_szAGPStatus, sz );
|
|
_tcscpy( pDisplayInfo->m_szAGPStatusEnglish, szEnglish );
|
|
|
|
_tcscpy( pDisplayInfo->m_szNotes, TEXT("") );
|
|
_tcscpy( pDisplayInfo->m_szNotesEnglish, TEXT("") );
|
|
|
|
// Report any problems:
|
|
BOOL bProblem = FALSE;
|
|
if( pSysInfo->m_bNetMeetingRunning &&
|
|
!pDisplayInfo->m_b3DAccelerationExists )
|
|
{
|
|
LoadString(NULL, IDS_NETMEETINGWARN, szFmt, MAX_PATH);
|
|
wsprintf(sz, szFmt, pDisplayInfo->m_szDriverName);
|
|
_tcscat( pDisplayInfo->m_szNotes, sz );
|
|
|
|
LoadString(NULL, IDS_NETMEETINGWARN_ENGLISH, szFmt, MAX_PATH);
|
|
wsprintf(sz, szFmt, pDisplayInfo->m_szDriverName);
|
|
_tcscat( pDisplayInfo->m_szNotesEnglish, sz );
|
|
|
|
bProblem = TRUE;
|
|
}
|
|
|
|
if (pDisplayInfo->m_bDriverSignedValid && !pDisplayInfo->m_bDriverSigned)
|
|
{
|
|
LoadString(NULL, IDS_UNSIGNEDDRIVERFMT1, szFmt, MAX_PATH);
|
|
wsprintf(sz, szFmt, pDisplayInfo->m_szDriverName);
|
|
_tcscat( pDisplayInfo->m_szNotes, sz );
|
|
|
|
LoadString(NULL, IDS_UNSIGNEDDRIVERFMT1_ENGLISH, szFmt, MAX_PATH);
|
|
wsprintf(sz, szFmt, pDisplayInfo->m_szDriverName);
|
|
_tcscat( pDisplayInfo->m_szNotesEnglish, sz );
|
|
|
|
bProblem = TRUE;
|
|
}
|
|
|
|
if (pDisplayInfo->m_pRegErrorFirst != NULL)
|
|
{
|
|
LoadString(NULL, IDS_REGISTRYPROBLEM, sz, MAX_PATH);
|
|
_tcscat( pDisplayInfo->m_szNotes, sz );
|
|
|
|
LoadString(NULL, IDS_REGISTRYPROBLEM_ENGLISH, sz, MAX_PATH);
|
|
_tcscat( pDisplayInfo->m_szNotesEnglish, sz );
|
|
|
|
bProblem = TRUE;
|
|
bShouldReinstall = TRUE;
|
|
}
|
|
|
|
if( bShouldReinstall )
|
|
{
|
|
BOOL bTellUser = FALSE;
|
|
|
|
// Figure out if the user can install DirectX
|
|
if( BIsPlatform9x() )
|
|
bTellUser = TRUE;
|
|
else if( BIsWin2k() && pSysInfo->m_dwDirectXVersionMajor >= 8 )
|
|
bTellUser = TRUE;
|
|
|
|
if( bTellUser )
|
|
{
|
|
LoadString(NULL, IDS_REINSTALL_DX, sz, 300);
|
|
_tcscat( pDisplayInfo->m_szNotes, sz);
|
|
|
|
LoadString(NULL, IDS_REINSTALL_DX_ENGLISH, sz, 300);
|
|
_tcscat( pDisplayInfo->m_szNotesEnglish, sz);
|
|
}
|
|
}
|
|
|
|
if (!bProblem)
|
|
{
|
|
LoadString(NULL, IDS_NOPROBLEM, sz, MAX_PATH);
|
|
_tcscat( pDisplayInfo->m_szNotes, sz );
|
|
|
|
LoadString(NULL, IDS_NOPROBLEM_ENGLISH, sz, MAX_PATH);
|
|
_tcscat( pDisplayInfo->m_szNotesEnglish, sz );
|
|
}
|
|
|
|
// Report any DD test results:
|
|
if (pDisplayInfo->m_testResultDD.m_bStarted &&
|
|
!pDisplayInfo->m_testResultDD.m_bCancelled)
|
|
{
|
|
LoadString(NULL, IDS_DDRESULTS, sz, MAX_PATH);
|
|
_tcscat( pDisplayInfo->m_szNotes, sz );
|
|
_tcscat( pDisplayInfo->m_szNotes, pDisplayInfo->m_testResultDD.m_szDescription );
|
|
_tcscat( pDisplayInfo->m_szNotes, TEXT("\r\n") );
|
|
|
|
LoadString(NULL, IDS_DDRESULTS_ENGLISH, sz, MAX_PATH);
|
|
_tcscat( pDisplayInfo->m_szNotesEnglish, sz );
|
|
_tcscat( pDisplayInfo->m_szNotesEnglish, pDisplayInfo->m_testResultDD.m_szDescription );
|
|
_tcscat( pDisplayInfo->m_szNotesEnglish, TEXT("\r\n") );
|
|
}
|
|
else
|
|
{
|
|
LoadString(NULL, IDS_DDINSTRUCTIONS, sz, MAX_PATH);
|
|
_tcscat( pDisplayInfo->m_szNotes, sz );
|
|
|
|
LoadString(NULL, IDS_DDINSTRUCTIONS_ENGLISH, sz, MAX_PATH);
|
|
_tcscat( pDisplayInfo->m_szNotesEnglish, sz );
|
|
}
|
|
|
|
// Report any D3D test results:
|
|
TestResult* pTestResult;
|
|
if( pDisplayInfo->m_dwTestToDisplayD3D == 7 )
|
|
pTestResult = &pDisplayInfo->m_testResultD3D7;
|
|
else
|
|
pTestResult = &pDisplayInfo->m_testResultD3D8;
|
|
|
|
if (pTestResult->m_bStarted &&
|
|
!pTestResult->m_bCancelled)
|
|
{
|
|
LoadString(NULL, IDS_D3DRESULTS, sz, MAX_PATH);
|
|
_tcscat( pDisplayInfo->m_szNotes, sz );
|
|
_tcscat( pDisplayInfo->m_szNotes, pTestResult->m_szDescription );
|
|
_tcscat( pDisplayInfo->m_szNotes, TEXT("\r\n") );
|
|
|
|
LoadString(NULL, IDS_D3DRESULTS_ENGLISH, sz, MAX_PATH);
|
|
_tcscat( pDisplayInfo->m_szNotesEnglish, sz );
|
|
_tcscat( pDisplayInfo->m_szNotesEnglish, pTestResult->m_szDescription );
|
|
_tcscat( pDisplayInfo->m_szNotesEnglish, TEXT("\r\n") );
|
|
}
|
|
else
|
|
{
|
|
if( pDisplayInfo->m_b3DAccelerationExists &&
|
|
pDisplayInfo->m_b3DAccelerationEnabled )
|
|
{
|
|
LoadString(NULL, IDS_D3DINSTRUCTIONS, sz, MAX_PATH);
|
|
_tcscat( pDisplayInfo->m_szNotes, sz );
|
|
|
|
LoadString(NULL, IDS_D3DINSTRUCTIONS_ENGLISH, sz, MAX_PATH);
|
|
_tcscat( pDisplayInfo->m_szNotesEnglish, sz );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|