Source code of Windows XP (NT5)
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.
 
 
 
 
 
 

890 lines
36 KiB

/****************************************************************************
*
* File: inptinfo.cpp
* Project: DxDiag (DirectX Diagnostic Tool)
* Author: Mike Anderson ([email protected])
* Purpose: Gather information about input devices on this machine
*
* (C) Copyright 1998 Microsoft Corp. All rights reserved.
*
****************************************************************************/
#define DIRECTINPUT_VERSION 0x0800
#include <tchar.h>
#include <Windows.h>
#include <regstr.h>
#include <mmsystem.h>
#include <stdio.h>
#include <hidclass.h>
#include <setupapi.h>
#include <cfgmgr32.h>
#include <dinput.h>
#include "mmddk.h"
#include "reginfo.h"
#include "sysinfo.h" // for BIsPlatformNT
#include "inptinfo.h"
#include "fileinfo.h"
#include "resource.h"
static HRESULT Get9xInputDeviceInfo(InputInfo* pInputInfo);
static HRESULT GetNTInputDeviceInfo(InputInfo* pInputInfo);
static VOID GetJoystickTypeDesc(DWORD dwType, TCHAR* pszDesc);
static HRESULT CheckRegistry(InputInfo* pInputInfo, RegError** ppRegErrorFirst);
/****************************************************************************
*
* GetInputInfo
*
****************************************************************************/
HRESULT GetInputInfo(InputInfo** ppInputInfo)
{
HRESULT hr;
*ppInputInfo = new InputInfo;
if (*ppInputInfo == NULL)
return E_OUTOFMEMORY;
ZeroMemory(*ppInputInfo, sizeof(InputInfo));
(*ppInputInfo)->m_bNT = BIsPlatformNT();
if ((*ppInputInfo)->m_bNT)
{
if (FAILED(hr = GetNTInputDeviceInfo(*ppInputInfo)))
return hr;
}
else
{
if (FAILED(hr = Get9xInputDeviceInfo(*ppInputInfo)))
return hr;
}
if (FAILED(hr = CheckRegistry(*ppInputInfo, &(*ppInputInfo)->m_pRegErrorFirst)))
return hr;
return S_OK;
}
// Have to do the LoadLibrary/GetProcAddress thing for dinput.dll and setupapi.dll:
typedef HRESULT (WINAPI* PfnDirectInputCreateA)(HINSTANCE hinst, DWORD dwVersion, LPDIRECTINPUTA *ppDI, LPUNKNOWN punkOuter);
typedef HRESULT (WINAPI* PfnDirectInputCreateW)(HINSTANCE hinst, DWORD dwVersion, LPDIRECTINPUTW *ppDI, LPUNKNOWN punkOuter);
typedef WINSETUPAPI HDEVINFO (WINAPI* PfnSetupDiGetClassDevsA)(IN CONST GUID *ClassGuid, IN PCSTR Enumerator, IN HWND hwndParent, IN DWORD Flags);
typedef WINSETUPAPI HDEVINFO (WINAPI* PfnSetupDiGetClassDevsW)(IN CONST GUID *ClassGuid, IN PCWSTR Enumerator, IN HWND hwndParent, IN DWORD Flags);
typedef WINSETUPAPI BOOL (WINAPI* PfnSetupDiEnumDeviceInterfaces)(IN HDEVINFO DeviceInfoSet, IN PSP_DEVINFO_DATA DeviceInfoData, IN CONST GUID *InterfaceClassGuid, IN DWORD MemberIndex, OUT PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData);
typedef WINSETUPAPI BOOL (WINAPI* PfnSetupDiGetDeviceInterfaceDetailA)(IN HDEVINFO DeviceInfoSet, IN PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData, OUT PSP_DEVICE_INTERFACE_DETAIL_DATA_A DeviceInterfaceDetailData, IN DWORD DeviceInterfaceDetailDataSize, OUT PDWORD RequiredSize, OUT PSP_DEVINFO_DATA DeviceInfoData);
typedef WINSETUPAPI BOOL (WINAPI* PfnSetupDiGetDeviceInterfaceDetailW)(IN HDEVINFO DeviceInfoSet, IN PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData, OUT PSP_DEVICE_INTERFACE_DETAIL_DATA_W DeviceInterfaceDetailData, IN DWORD DeviceInterfaceDetailDataSize, OUT PDWORD RequiredSize, OUT PSP_DEVINFO_DATA DeviceInfoData);
typedef WINSETUPAPI BOOL (WINAPI* PfnSetupDiDestroyDeviceInfoList)(IN HDEVINFO DeviceInfoSet);
typedef CMAPI CONFIGRET (WINAPI* PfnCM_Get_Parent)(OUT PDEVINST pdnDevInst, IN DEVINST dnDevInst, IN ULONG ulFlags);
typedef CMAPI CONFIGRET (WINAPI* PfnCM_Get_DevNode_Status)(OUT PULONG pulStatus, OUT PULONG pulProblemNumber, IN DEVINST dnDevInst, IN ULONG ulFlags);
typedef CMAPI CONFIGRET (WINAPI* PfnCM_Get_DevNode_Registry_PropertyW)(IN DEVINST dnDevInst, IN ULONG ulProperty, OUT PULONG pulRegDataType, OPTIONAL OUT PVOID Buffer, OPTIONAL IN OUT PULONG pulLength, IN ULONG ulFlags);
typedef CMAPI CONFIGRET (WINAPI* PfnCM_Get_DevNode_Registry_PropertyA)(IN DEVINST dnDevInst, IN ULONG ulProperty, OUT PULONG pulRegDataType, OPTIONAL OUT PVOID Buffer, OPTIONAL IN OUT PULONG pulLength, IN ULONG ulFlags);
/****************************************************************************
*
* GetNTInputDeviceInfo
*
****************************************************************************/
HRESULT GetNTInputDeviceInfo(InputInfo* pInputInfo)
{
HINSTANCE hInstDInput = NULL;
HINSTANCE hInstSetupApi = NULL;
LPDIRECTINPUT pDI = NULL;
GUID guidHid;
HDEVINFO hdev = NULL;
SP_DEVICE_INTERFACE_DETAIL_DATA* pdidd;
InputDeviceInfoNT* pInputDeviceInfoNTNew;
PfnCM_Get_Parent FnCM_Get_Parent = NULL;
PfnCM_Get_DevNode_Status FnCM_Get_DevNode_Status = NULL;
PfnSetupDiEnumDeviceInterfaces FnSetupDiEnumDeviceInterfaces = NULL;
PfnSetupDiDestroyDeviceInfoList FnSetupDiDestroyDeviceInfoList = NULL;
#ifdef UNICODE
PfnDirectInputCreateW FnDirectInputCreate = NULL;
PfnCM_Get_DevNode_Registry_PropertyW FnCM_Get_DevNode_Registry_Property = NULL;
PfnSetupDiGetClassDevsW FnSetupDiGetClassDevs = NULL;
PfnSetupDiGetDeviceInterfaceDetailW FnSetupDiGetDeviceInterfaceDetail = NULL;
#else
PfnDirectInputCreateA FnDirectInputCreate = NULL;
PfnCM_Get_DevNode_Registry_PropertyA FnCM_Get_DevNode_Registry_Property = NULL;
PfnSetupDiGetClassDevsA FnSetupDiGetClassDevs = NULL;
PfnSetupDiGetDeviceInterfaceDetailA FnSetupDiGetDeviceInterfaceDetail = NULL;
#endif
// Apparently one must initialize DInput before enumerating HID devices
hInstDInput = LoadLibrary(TEXT("dinput.dll"));
if (hInstDInput == NULL)
goto LEnd;
#ifdef UNICODE
FnDirectInputCreate = (PfnDirectInputCreateW)GetProcAddress(hInstDInput, "DirectInputCreateW");
if (FnDirectInputCreate == NULL)
goto LEnd;
#else
FnDirectInputCreate = (PfnDirectInputCreateA)GetProcAddress(hInstDInput, "DirectInputCreateA");
if (FnDirectInputCreate == NULL)
goto LEnd;
#endif
if (SUCCEEDED(FnDirectInputCreate(NULL, 0x0300, &pDI, NULL)))
pDI->Release(); // immediately drop DI interface; we don't actually use it
hInstSetupApi = LoadLibrary(TEXT("setupapi.dll"));
if (hInstSetupApi == NULL)
goto LEnd;
FnCM_Get_Parent = (PfnCM_Get_Parent)GetProcAddress(hInstSetupApi, "CM_Get_Parent");
if (FnCM_Get_Parent == NULL)
goto LEnd;
FnCM_Get_DevNode_Status = (PfnCM_Get_DevNode_Status)GetProcAddress(hInstSetupApi, "CM_Get_DevNode_Status");
if (FnCM_Get_DevNode_Status == NULL)
goto LEnd;
FnSetupDiEnumDeviceInterfaces = (PfnSetupDiEnumDeviceInterfaces)GetProcAddress(hInstSetupApi, "SetupDiEnumDeviceInterfaces");
if (FnSetupDiEnumDeviceInterfaces == NULL)
goto LEnd;
FnSetupDiDestroyDeviceInfoList = (PfnSetupDiDestroyDeviceInfoList)GetProcAddress(hInstSetupApi, "SetupDiDestroyDeviceInfoList");
if (FnSetupDiDestroyDeviceInfoList == NULL)
goto LEnd;
#ifdef UNICODE
FnCM_Get_DevNode_Registry_Property = (PfnCM_Get_DevNode_Registry_PropertyW)GetProcAddress(hInstSetupApi, "CM_Get_DevNode_Registry_PropertyW");
if (FnCM_Get_DevNode_Registry_Property == NULL)
goto LEnd;
FnSetupDiGetClassDevs = (PfnSetupDiGetClassDevsW)GetProcAddress(hInstSetupApi, "SetupDiGetClassDevsW");
if (FnSetupDiGetClassDevs == NULL)
goto LEnd;
FnSetupDiGetDeviceInterfaceDetail = (PfnSetupDiGetDeviceInterfaceDetailW)GetProcAddress(hInstSetupApi, "SetupDiGetDeviceInterfaceDetailW");
if (FnSetupDiGetDeviceInterfaceDetail == NULL)
goto LEnd;
#else
FnCM_Get_DevNode_Registry_Property = (PfnCM_Get_DevNode_Registry_PropertyA)GetProcAddress(hInstSetupApi, "CM_Get_DevNode_Registry_PropertyA");
if (FnCM_Get_DevNode_Registry_Property == NULL)
goto LEnd;
FnSetupDiGetClassDevs = (PfnSetupDiGetClassDevsA)GetProcAddress(hInstSetupApi, "SetupDiGetClassDevsA");
if (FnSetupDiGetClassDevs == NULL)
goto LEnd;
FnSetupDiGetDeviceInterfaceDetail = (PfnSetupDiGetDeviceInterfaceDetailA)GetProcAddress(hInstSetupApi, "SetupDiGetDeviceInterfaceDetailA");
if (FnSetupDiGetDeviceInterfaceDetail == NULL)
goto LEnd;
#endif
guidHid = GUID_CLASS_INPUT;
hdev = FnSetupDiGetClassDevs(&guidHid, 0, 0, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
if (hdev == INVALID_HANDLE_VALUE || hdev == NULL)
return E_FAIL;
int idev;
// There is no way to query the number of devices.
// You just have to keep incrementing until you run out.
// To avoid infinite looping on internal errors, break on any
// error once we have tried more than chdiMax devices, since that's the most
// HID will ever give us. 64 is a resonable value for chidMax. It is the
// max allowed USB/HID devices.
for (idev = 0; idev < 64/*chdiMax*/; idev++)
{
SP_DEVICE_INTERFACE_DATA did;
did.cbSize = sizeof(did);
if (!FnSetupDiEnumDeviceInterfaces(hdev, 0, &guidHid, idev, &did))
{
if(GetLastError() == ERROR_NO_MORE_ITEMS)
break;
else
continue;
}
/*
* Ask for the required size then allocate it then fill it.
*
* Note that we don't need to free the memory on the failure
* path; our caller will do the necessary memory freeing.
*
* Sigh. Windows NT and Windows 98 implement
* SetupDiGetDeviceInterfaceDetail differently if you are
* querying for the buffer size.
*
* Windows 98 returns FALSE, and GetLastError() returns
* ERROR_INSUFFICIENT_BUFFER.
*
* Windows NT returns TRUE.
*
* So we allow the cases either where the call succeeds or
* the call fails with ERROR_INSUFFICIENT_BUFFER.
*/
SP_DEVINFO_DATA dinf;
DWORD cbRequired;
if (FnSetupDiGetDeviceInterfaceDetail(hdev, &did, 0, 0, &cbRequired, 0) ||
GetLastError() == ERROR_INSUFFICIENT_BUFFER)
{
pdidd = (SP_DEVICE_INTERFACE_DETAIL_DATA*)(new BYTE[cbRequired]);
if (pdidd == NULL)
continue;
ZeroMemory(pdidd, cbRequired);
pdidd->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
dinf.cbSize = sizeof(dinf);
if (!FnSetupDiGetDeviceInterfaceDetail(hdev, &did, pdidd, cbRequired, &cbRequired, &dinf))
{
delete pdidd;
continue;
}
delete pdidd;
DEVINST dinst;
if (CR_SUCCESS != FnCM_Get_Parent(&dinst, dinf.DevInst, 0))
continue;
pInputDeviceInfoNTNew = new InputDeviceInfoNT;
if (pInputDeviceInfoNTNew == NULL)
return E_OUTOFMEMORY;
ZeroMemory(pInputDeviceInfoNTNew, sizeof(InputDeviceInfoNT));
if (pInputInfo->m_pInputDeviceInfoNTFirst == NULL)
{
pInputInfo->m_pInputDeviceInfoNTFirst = pInputDeviceInfoNTNew;
}
else
{
InputDeviceInfoNT* pInputDeviceInfoNT;
for (pInputDeviceInfoNT = pInputInfo->m_pInputDeviceInfoNTFirst;
pInputDeviceInfoNT->m_pInputDeviceInfoNTNext != NULL;
pInputDeviceInfoNT = pInputDeviceInfoNT->m_pInputDeviceInfoNTNext)
{
}
pInputDeviceInfoNT->m_pInputDeviceInfoNTNext = pInputDeviceInfoNTNew;
}
CONFIGRET cr;
TCHAR sz[200];
ULONG ulLength;
ulLength = 200;
cr = FnCM_Get_DevNode_Registry_Property(dinst, CM_DRP_DEVICEDESC,
NULL, (BYTE*)pInputDeviceInfoNTNew->m_szName, &ulLength, NULL);
// Friendly name is preferably to device desc, but is often (always?) missing
ulLength = 200;
cr = FnCM_Get_DevNode_Registry_Property(dinst, CM_DRP_FRIENDLYNAME,
NULL, (BYTE*)sz, &ulLength, NULL);
if (cr == CR_SUCCESS)
lstrcpy(pInputDeviceInfoNTNew->m_szName, sz);
ulLength = 200;
cr = FnCM_Get_DevNode_Registry_Property(dinst, CM_DRP_MFG,
NULL, (BYTE*)pInputDeviceInfoNTNew->m_szProvider, &ulLength, NULL);
ulLength = 200;
cr = FnCM_Get_DevNode_Registry_Property(dinst, CM_DRP_HARDWAREID,
NULL, (BYTE*)pInputDeviceInfoNTNew->m_szId, &ulLength, NULL);
cr = FnCM_Get_DevNode_Status(&pInputDeviceInfoNTNew->m_dwStatus, &pInputDeviceInfoNTNew->m_dwProblem, dinst, 0);
DEVINST dinstPort;
if (CR_SUCCESS != FnCM_Get_Parent(&dinstPort, dinst, 0))
continue;
ulLength = 200;
cr = FnCM_Get_DevNode_Registry_Property(dinstPort, CM_DRP_DEVICEDESC,
NULL, (BYTE*)pInputDeviceInfoNTNew->m_szPortName, &ulLength, NULL);
// Friendly name is preferably to device desc, but is often (always?) missing
ulLength = 200;
cr = FnCM_Get_DevNode_Registry_Property(dinstPort, CM_DRP_FRIENDLYNAME,
NULL, (BYTE*)sz, &ulLength, NULL);
if (cr == CR_SUCCESS)
lstrcpy(pInputDeviceInfoNTNew->m_szPortName, sz);
ulLength = 200;
cr = FnCM_Get_DevNode_Registry_Property(dinstPort, CM_DRP_MFG,
NULL, (BYTE*)pInputDeviceInfoNTNew->m_szPortProvider, &ulLength, NULL);
ulLength = 200;
cr = FnCM_Get_DevNode_Registry_Property(dinstPort, CM_DRP_HARDWAREID,
NULL, (BYTE*)pInputDeviceInfoNTNew->m_szPortId, &ulLength, NULL);
cr = FnCM_Get_DevNode_Status(&pInputDeviceInfoNTNew->m_dwPortStatus, &pInputDeviceInfoNTNew->m_dwPortProblem, dinstPort, 0);
}
}
LEnd:
if (hdev != NULL)
FnSetupDiDestroyDeviceInfoList(hdev);
if (hInstSetupApi != NULL)
FreeLibrary(hInstSetupApi);
if (hInstDInput != NULL)
FreeLibrary(hInstDInput);
return S_OK;
}
/****************************************************************************
*
* Get9xInputDeviceInfo
*
****************************************************************************/
HRESULT Get9xInputDeviceInfo(InputInfo* pInputInfo)
{
DWORD dwDevNum;
JOYCAPS jc;
HKEY hkBase;
HKEY hkDrv;
HKEY hkData;
JOYREGHWCONFIG jhwc;
DWORD dwBufferLen;
INT i;
TCHAR szKey[256];
TCHAR szOEMKey[256];
HKEY hkOEMBase;
HKEY hkOEMData;
TCHAR szOEMName[256];
TCHAR szOEMCallout[256];
InputDeviceInfo* pInputDeviceInfoNew;
InputDeviceInfo* pInputDeviceInfo;
TCHAR szPath[MAX_PATH];
TCHAR sz[200];
dwDevNum = (DWORD)-1;
if (JOYERR_NOERROR == joyGetDevCaps(dwDevNum, &jc, sizeof jc))
{
if ((ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE, REGSTR_PATH_JOYCONFIG, 0, KEY_READ, &hkBase))
&& (ERROR_SUCCESS == RegOpenKeyEx(hkBase, jc.szRegKey, 0, KEY_READ, &hkDrv))
&& (ERROR_SUCCESS == RegOpenKeyEx(hkDrv, REGSTR_KEY_JOYCURR, 0, KEY_READ, &hkData)))
{
for (i = 0; i < 20; i++)
{
wsprintf(szKey, REGSTR_VAL_JOYNCONFIG, i + 1);
dwBufferLen = sizeof JOYREGHWCONFIG;
if (ERROR_SUCCESS == RegQueryValueEx(hkData, szKey, 0, NULL, (LPBYTE)&jhwc, &dwBufferLen))
{
// Skip devices whose type is JOY_HW_NONE.
if (jhwc.dwType == JOY_HW_NONE)
continue;
pInputDeviceInfoNew = new InputDeviceInfo;
if (pInputDeviceInfoNew == NULL)
return E_OUTOFMEMORY;
ZeroMemory(pInputDeviceInfoNew, sizeof(InputDeviceInfo));
if (pInputInfo->m_pInputDeviceInfoFirst == NULL)
{
pInputInfo->m_pInputDeviceInfoFirst = pInputDeviceInfoNew;
}
else
{
for (pInputDeviceInfo = pInputInfo->m_pInputDeviceInfoFirst;
pInputDeviceInfo->m_pInputDeviceInfoNext != NULL;
pInputDeviceInfo = pInputDeviceInfo->m_pInputDeviceInfoNext)
{
}
pInputDeviceInfo->m_pInputDeviceInfoNext = pInputDeviceInfoNew;
}
pInputDeviceInfoNew->m_dwUsageSettings = jhwc.dwUsageSettings;
wsprintf(pInputDeviceInfoNew->m_szSettings, TEXT("0x%08x"), jhwc.dwUsageSettings);
if (JOY_US_PRESENT & jhwc.dwUsageSettings)
{
LoadString(NULL, IDS_JOYSTICKPRESENT, sz, 200);
lstrcat(pInputDeviceInfoNew->m_szSettings, sz);
}
// Try reading an OEM name
wsprintf(szKey, REGSTR_VAL_JOYNOEMNAME, i + 1);
dwBufferLen = sizeof szOEMKey;
szOEMKey[0] = 0;
szOEMName[0] = 0;
if (ERROR_SUCCESS == RegQueryValueEx(hkData, szKey, 0, NULL, (LPBYTE)szOEMKey, &dwBufferLen))
{
hkOEMBase = 0;
hkOEMData = 0;
// If there is an OEM name, look in the PrivateProperties to find out
// the name of the device as shown in the control panel applet.
if((szOEMKey[0] != 0)
&& (ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE, REGSTR_PATH_JOYOEM, 0, KEY_READ, &hkOEMBase))
&& (ERROR_SUCCESS == RegOpenKeyEx(hkOEMBase, szOEMKey, 0, KEY_READ, &hkOEMData))
&& (ERROR_SUCCESS == RegQueryValueEx(hkOEMData, REGSTR_VAL_JOYOEMNAME, 0, NULL, NULL, &dwBufferLen))
&& dwBufferLen)
{
dwBufferLen = sizeof szOEMName;
RegQueryValueEx(hkOEMData, REGSTR_VAL_JOYOEMNAME, 0, NULL, (LPBYTE)szOEMName, &dwBufferLen);
}
if (hkOEMData)
RegCloseKey(hkOEMData);
}
if (hkOEMBase)
RegCloseKey(hkOEMBase);
if (szOEMName[0] != 0)
lstrcpy(pInputDeviceInfoNew->m_szDeviceName, szOEMName);
else
GetJoystickTypeDesc(jhwc.dwType, pInputDeviceInfoNew->m_szDeviceName);
wsprintf(szKey, REGSTR_VAL_JOYNOEMCALLOUT, i + 1);
dwBufferLen = sizeof szOEMCallout;
if (ERROR_SUCCESS == RegQueryValueEx(hkData, szKey, 0, NULL, (LPBYTE)&szOEMCallout, &dwBufferLen))
{
lstrcpy(pInputDeviceInfoNew->m_szDriverName, szOEMCallout);
GetSystemDirectory(szPath, MAX_PATH);
lstrcat(szPath, TEXT("\\"));
lstrcat(szPath, szOEMCallout);
GetFileVersion(szPath, pInputDeviceInfoNew->m_szDriverVersion,
pInputDeviceInfoNew->m_szDriverAttributes, pInputDeviceInfoNew->m_szDriverLanguageLocal, pInputDeviceInfoNew->m_szDriverLanguage,
&pInputDeviceInfoNew->m_bBeta, &pInputDeviceInfoNew->m_bDebug);
GetFileDateAndSize(szPath, pInputDeviceInfoNew->m_szDriverDateLocal, pInputDeviceInfoNew->m_szDriverDate, &pInputDeviceInfoNew->m_numBytes);
FileIsSigned(szPath, &pInputDeviceInfoNew->m_bDriverSigned, &pInputDeviceInfoNew->m_bDriverSignedValid);
}
else
{
LoadString(NULL, IDS_DEFAULT, pInputDeviceInfoNew->m_szDriverName, 100);
}
}
}
}
}
return S_OK;
}
/****************************************************************************
*
* GetJoystickTypeDesc
*
****************************************************************************/
VOID GetJoystickTypeDesc(DWORD dwType, TCHAR* pszDesc)
{
LONG ids;
switch(dwType)
{
case JOY_HW_NONE:
ids = IDS_JOY_HW_NONE;
break;
case JOY_HW_CUSTOM:
ids = IDS_JOY_HW_CUSTOM;
break;
case JOY_HW_2A_2B_GENERIC:
ids = IDS_JOY_HW_2A_2B_GENERIC;
break;
case JOY_HW_2A_4B_GENERIC:
ids = IDS_JOY_HW_2A_4B_GENERIC;
break;
case JOY_HW_2B_GAMEPAD:
ids = IDS_JOY_HW_2B_GAMEPAD;
break;
case JOY_HW_2B_FLIGHTYOKE:
ids = IDS_JOY_HW_2B_FLIGHTYOKE;
break;
case JOY_HW_2B_FLIGHTYOKETHROTTLE:
ids = IDS_JOY_HW_2B_FLIGHTYOKETHROTTLE;
break;
case JOY_HW_3A_2B_GENERIC:
ids = IDS_JOY_HW_3A_2B_GENERIC;
break;
case JOY_HW_3A_4B_GENERIC:
ids = IDS_JOY_HW_3A_4B_GENERIC;
break;
case JOY_HW_4B_GAMEPAD:
ids = IDS_JOY_HW_4B_GAMEPAD;
break;
case JOY_HW_4B_FLIGHTYOKE:
ids = IDS_JOY_HW_4B_FLIGHTYOKE;
break;
case JOY_HW_4B_FLIGHTYOKETHROTTLE:
ids = IDS_JOY_HW_4B_FLIGHTYOKETHROTTLE;
break;
default:
ids = IDS_JOY_UNKNOWN;
break;
}
LoadString(NULL, ids, pszDesc, 60);
}
/****************************************************************************
*
* GetInputDriverInfo
*
****************************************************************************/
HRESULT GetInputDriverInfo(InputInfo* pInputInfo)
{
HKEY hkBase;
HKEY hkDrv;
HKEY hkMedia;
HKEY hkMediaDriver;
DWORD dwIndex = 0;
TCHAR szName[100];
DWORD dwNameSize;
TCHAR szClass[100];
DWORD dwClassSize;
InputDriverInfo* pInputDriverInfoNew;
InputDriverInfo* pInputDriverInfo;
DWORD dwBufferLen;
TCHAR szActive[10];
TCHAR szSubMediaKey[10];
if (ERROR_SUCCESS != RegOpenKeyEx(HKEY_LOCAL_MACHINE, REGSTR_PATH_JOYCONFIG, 0, KEY_READ, &hkBase))
return S_OK; // This key doesn't exist on NT, so exit silently for now.
dwNameSize = 100;
dwClassSize = 100;
while (ERROR_SUCCESS == RegEnumKeyEx(hkBase, dwIndex, szName,
&dwNameSize, NULL, szClass, &dwClassSize, NULL))
{
if (szName[dwNameSize - 1] == '>' &&
szName[dwNameSize - 6] == '<')
{
// It's a driver
pInputDriverInfoNew = new InputDriverInfo;
if (pInputDriverInfoNew == NULL)
return E_OUTOFMEMORY;
ZeroMemory(pInputDriverInfoNew, sizeof(InputDriverInfo));
if (pInputInfo->m_pInputDriverInfoFirst == NULL)
{
pInputInfo->m_pInputDriverInfoFirst = pInputDriverInfoNew;
}
else
{
for (pInputDriverInfo = pInputInfo->m_pInputDriverInfoFirst;
pInputDriverInfo->m_pInputDriverInfoNext != NULL;
pInputDriverInfo = pInputDriverInfo->m_pInputDriverInfoNext)
{
}
pInputDriverInfo->m_pInputDriverInfoNext = pInputDriverInfoNew;
}
lstrcpy(pInputDriverInfoNew->m_szRegKey, szName);
// Read info from reg key
if (ERROR_SUCCESS != RegOpenKeyEx(hkBase, szName, 0, KEY_READ, &hkDrv))
return E_FAIL;
dwBufferLen = 100;
RegQueryValueEx(hkDrv, TEXT("DeviceID"), 0, NULL, (LPBYTE)pInputDriverInfoNew->m_szDeviceID, &dwBufferLen);
dwBufferLen = 10;
RegQueryValueEx(hkDrv, TEXT("Active"), 0, NULL, (LPBYTE)szActive, &dwBufferLen);
if (lstrcmp(szActive, TEXT("1")) == 0)
pInputDriverInfoNew->m_bActive = TRUE;
dwBufferLen = 100;
RegQueryValueEx(hkDrv, TEXT("Driver"), 0, NULL, (LPBYTE)pInputDriverInfoNew->m_szDriver16, &dwBufferLen);
RegCloseKey(hkDrv);
// Open corresponding key under Services\Class\Media and read more info
lstrcpy(szSubMediaKey, &szName[dwNameSize - 5]);
szSubMediaKey[4] = '\0';
if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE, REGSTR_PATH_CLASS TEXT("\\") REGSTR_KEY_MEDIA_CLASS, 0, KEY_READ, &hkMedia))
{
if (ERROR_SUCCESS == RegOpenKeyEx(hkMedia, szSubMediaKey, 0, KEY_READ, &hkMediaDriver))
{
dwBufferLen = 100;
RegQueryValueEx(hkMediaDriver, TEXT("MatchingDeviceId"), 0, NULL, (LPBYTE)pInputDriverInfoNew->m_szMatchingDeviceID, &dwBufferLen);
dwBufferLen = 100;
RegQueryValueEx(hkMediaDriver, TEXT("Driver"), 0, NULL, (LPBYTE)pInputDriverInfoNew->m_szDriver32, &dwBufferLen);
RegCloseKey(hkMediaDriver);
}
RegCloseKey(hkMedia);
}
}
dwNameSize = 100;
dwClassSize = 100;
dwIndex++;
}
RegCloseKey(hkBase);
return S_OK;
}
/****************************************************************************
*
* CheckRegistry
*
****************************************************************************/
HRESULT CheckRegistry(InputInfo* pInputInfo, RegError** ppRegErrorFirst)
{
HRESULT hr;
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)
{
_stscanf(szVersion, TEXT("%d.%d.%d.%d"), &dwMajor, &dwMinor, &dwRevision, &dwBuild);
}
}
// No registry checking on DX versions before DX7
if (dwMinor < 7)
return S_OK;
// 34644: check for poll flags
DWORD dwData = 0;
DWORD dwSize = sizeof(dwData);
DWORD dwType;
if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE, TEXT("System\\CurrentControlSet\\control\\MediaProperties\\PrivateProperties\\Joystick\\OEM\\Standard Gameport"),
0, KEY_READ, &hkey))
{
RegQueryValueEx(hkey, TEXT("PollFlags"), NULL, &dwType, (BYTE *)&dwData, &dwSize);
RegCloseKey(hkey);
}
pInputInfo->m_bPollFlags = ( dwData == 0x00000001 );
// From dinput.inf:
if (FAILED(hr = CheckRegString(ppRegErrorFirst, HKCR, TEXT("CLSID\\{25E609E0-B259-11CF-BFC7-444553540000}"), TEXT(""), TEXT("*"))))
return hr;
if (FAILED(hr = CheckRegString(ppRegErrorFirst, HKCR, TEXT("CLSID\\{25E609E0-B259-11CF-BFC7-444553540000}\\InProcServer32"), TEXT(""), TEXT("dinput.dll"), CRF_LEAF)))
return hr;
if (FAILED(hr = CheckRegString(ppRegErrorFirst, HKCR, TEXT("CLSID\\{25E609E0-B259-11CF-BFC7-444553540000}\\InprocServer32"), TEXT("ThreadingModel"), TEXT("Both"))))
return hr;
if (FAILED(hr = CheckRegString(ppRegErrorFirst, HKCR, TEXT("CLSID\\{25E609E1-B259-11CF-BFC7-444553540000}"), TEXT(""), TEXT("*"))))
return hr;
if (FAILED(hr = CheckRegString(ppRegErrorFirst, HKCR, TEXT("CLSID\\{25E609E1-B259-11CF-BFC7-444553540000}\\InProcServer32"), TEXT(""), TEXT("dinput.dll"), CRF_LEAF)))
return hr;
if (FAILED(hr = CheckRegString(ppRegErrorFirst, HKCR, TEXT("CLSID\\{25E609E1-B259-11CF-BFC7-444553540000}\\InprocServer32"), TEXT("ThreadingModel"), TEXT("Both"))))
return hr;
if (!BIsPlatformNT())
{
if (FAILED(hr = CheckRegString(ppRegErrorFirst, HKCR, TEXT("CLSID\\{92187326-72B4-11d0-A1AC-0000F8026977}"), TEXT(""), TEXT("*"))))
return hr;
if (FAILED(hr = CheckRegString(ppRegErrorFirst, HKCR, TEXT("CLSID\\{92187326-72B4-11d0-A1AC-0000F8026977}\\ProgID"), TEXT(""), TEXT("*"))))
return hr;
// Bug 119850: gchand.dll doesn't need to be on any DX7 OS.
// if (FAILED(hr = CheckRegString(ppRegErrorFirst, HKCR, TEXT("CLSID\\{92187326-72B4-11d0-A1AC-0000F8026977}\\InProcHandler32"), TEXT(""), TEXT("gchand.dll"), CRF_LEAF)))
// return hr;
if (FAILED(hr = CheckRegString(ppRegErrorFirst, HKCR, TEXT("CLSID\\{92187326-72B4-11d0-A1AC-0000F8026977}\\InProcServer32"), TEXT(""), TEXT("gcdef.dll"), CRF_LEAF)))
return hr;
if (FAILED(hr = CheckRegString(ppRegErrorFirst, HKCR, TEXT("CLSID\\{92187326-72B4-11d0-A1AC-0000F8026977}\\InprocServer32"), TEXT("ThreadingModel"), TEXT("Apartment"))))
return hr;
}
return S_OK;
}
/****************************************************************************
*
* DestroyInputInfo
*
****************************************************************************/
VOID DestroyInputInfo(InputInfo* pInputInfo)
{
if( pInputInfo )
{
DestroyReg( &pInputInfo->m_pRegErrorFirst );
InputDeviceInfo* pInputDeviceInfo;
InputDeviceInfo* pInputDeviceInfoNext;
for (pInputDeviceInfo = pInputInfo->m_pInputDeviceInfoFirst; pInputDeviceInfo != NULL;
pInputDeviceInfo = pInputDeviceInfoNext)
{
pInputDeviceInfoNext = pInputDeviceInfo->m_pInputDeviceInfoNext;
delete pInputDeviceInfo;
}
InputDeviceInfoNT* pInputDeviceNTInfo;
InputDeviceInfoNT* pInputDeviceNTInfoNext;
for (pInputDeviceNTInfo = pInputInfo->m_pInputDeviceInfoNTFirst; pInputDeviceNTInfo != NULL;
pInputDeviceNTInfo = pInputDeviceNTInfoNext)
{
pInputDeviceNTInfoNext = pInputDeviceNTInfo->m_pInputDeviceInfoNTNext;
delete pInputDeviceNTInfo;
}
InputDriverInfo* pInputDriverInfo;
InputDriverInfo* pInputDriverInfoNext;
for (pInputDriverInfo = pInputInfo->m_pInputDriverInfoFirst; pInputDriverInfo != NULL;
pInputDriverInfo = pInputDriverInfoNext)
{
pInputDriverInfoNext = pInputDriverInfo->m_pInputDriverInfoNext;
delete pInputDriverInfo;
}
delete pInputInfo;
}
}
/****************************************************************************
*
* DiagnoseInput
*
****************************************************************************/
VOID DiagnoseInput(SysInfo* pSysInfo, InputInfo* pInputInfo)
{
InputDeviceInfo* pInputDeviceInfo;
InputDeviceInfoNT* pInputDeviceInfoNT;
TCHAR szDebug[200];
TCHAR szBeta[200];
LONG lwNumDebug;
LONG lwNumBeta;
TCHAR szListContinuer[30];
TCHAR szListEtc[30];
TCHAR szFmt[300];
TCHAR szMessage[300];
BOOL bProblem = FALSE;
if( pInputInfo == NULL )
return;
lwNumDebug = 0;
lwNumBeta = 0;
LoadString(NULL, IDS_LISTCONTINUER, szListContinuer, 30);
LoadString(NULL, IDS_LISTETC, szListEtc, 30);
for (pInputDeviceInfo = pInputInfo->m_pInputDeviceInfoFirst; pInputDeviceInfo != NULL;
pInputDeviceInfo = pInputDeviceInfo->m_pInputDeviceInfoNext)
{
if (pInputDeviceInfo->m_bBeta)
{
pInputDeviceInfo->m_bProblem = TRUE;
bProblem = TRUE;
lwNumBeta++;
if (lwNumBeta == 1)
{
lstrcpy(szBeta, pInputDeviceInfo->m_szDriverName);
}
else if (lwNumBeta < 4)
{
lstrcat(szBeta, szListContinuer);
lstrcat(szBeta, pInputDeviceInfo->m_szDriverName);
}
else if (lwNumBeta < 5)
{
lstrcat(szBeta, szListEtc);
}
}
if (pInputDeviceInfo->m_bDebug)
{
pInputDeviceInfo->m_bProblem = TRUE;
bProblem = TRUE;
lwNumDebug++;
if (lwNumDebug == 1)
{
lstrcpy(szDebug, pInputDeviceInfo->m_szDriverName);
}
else if (lwNumDebug < 4)
{
lstrcat(szDebug, szListContinuer);
lstrcat(szDebug, pInputDeviceInfo->m_szDriverName);
}
else if (lwNumDebug < 5)
{
lstrcat(szDebug, szListEtc);
}
}
}
_tcscpy( pSysInfo->m_szInputNotes, TEXT("") );
_tcscpy( pSysInfo->m_szInputNotesEnglish, TEXT("") );
for (pInputDeviceInfoNT = pInputInfo->m_pInputDeviceInfoNTFirst; pInputDeviceInfoNT != NULL;
pInputDeviceInfoNT = pInputDeviceInfoNT->m_pInputDeviceInfoNTNext)
{
if (pInputDeviceInfoNT->m_dwProblem != 0)
{
bProblem = TRUE;
pInputDeviceInfoNT->m_bProblem = TRUE;
LoadString(NULL, IDS_INPUTDEVPROBLEMFMT, szFmt, 300);
wsprintf(szMessage, szFmt, pInputDeviceInfoNT->m_szName, pInputDeviceInfoNT->m_dwProblem);
_tcscat( pSysInfo->m_szInputNotes, szMessage );
LoadString(NULL, IDS_INPUTDEVPROBLEMFMT_ENGLISH, szFmt, 300);
wsprintf(szMessage, szFmt, pInputDeviceInfoNT->m_szName, pInputDeviceInfoNT->m_dwProblem);
_tcscat( pSysInfo->m_szInputNotesEnglish, szMessage );
}
if (pInputDeviceInfoNT->m_dwPortProblem != 0)
{
bProblem = TRUE;
pInputDeviceInfoNT->m_bProblem = TRUE;
LoadString(NULL, IDS_INPUTPORTPROBLEMFMT, szFmt, 300);
wsprintf(szMessage, szFmt, pInputDeviceInfoNT->m_szPortName, pInputDeviceInfoNT->m_dwPortProblem);
_tcscat( pSysInfo->m_szInputNotes, szMessage );
LoadString(NULL, IDS_INPUTPORTPROBLEMFMT_ENGLISH, szFmt, 300);
wsprintf(szMessage, szFmt, pInputDeviceInfoNT->m_szPortName, pInputDeviceInfoNT->m_dwPortProblem);
_tcscat( pSysInfo->m_szInputNotesEnglish, szMessage );
}
}
if (lwNumBeta > 0)
{
if (lwNumBeta == 1)
LoadString(NULL, IDS_BETADRIVERFMT1, szFmt, 300);
else
LoadString(NULL, IDS_BETADRIVERFMT2, szFmt, 300);
wsprintf(szMessage, szFmt, szBeta);
_tcscat( pSysInfo->m_szInputNotes, szMessage );
if (lwNumBeta == 1)
LoadString(NULL, IDS_BETADRIVERFMT1_ENGLISH, szFmt, 300);
else
LoadString(NULL, IDS_BETADRIVERFMT2_ENGLISH, szFmt, 300);
wsprintf(szMessage, szFmt, szBeta);
_tcscat( pSysInfo->m_szInputNotesEnglish, szMessage );
}
if (lwNumDebug > 0)
{
if (lwNumDebug == 1)
LoadString(NULL, IDS_DEBUGDRIVERFMT1, szFmt, 300);
else
LoadString(NULL, IDS_DEBUGDRIVERFMT2, szFmt, 300);
wsprintf(szMessage, szFmt, szDebug);
_tcscat( pSysInfo->m_szInputNotes, szMessage );
if (lwNumDebug == 1)
LoadString(NULL, IDS_DEBUGDRIVERFMT1_ENGLISH, szFmt, 300);
else
LoadString(NULL, IDS_DEBUGDRIVERFMT2_ENGLISH, szFmt, 300);
wsprintf(szMessage, szFmt, szDebug);
_tcscat( pSysInfo->m_szInputNotesEnglish, szMessage );
}
if (pInputInfo->m_pInputDeviceInfoFirst == NULL &&
pInputInfo->m_pInputDeviceInfoNTFirst == NULL)
{
LoadString(NULL, IDS_NOINPUT, szMessage, 300);
_tcscat( pSysInfo->m_szInputNotes, szMessage );
LoadString(NULL, IDS_NOINPUT_ENGLISH, szMessage, 300);
_tcscat( pSysInfo->m_szInputNotesEnglish, szMessage );
}
if (pInputInfo->m_pRegErrorFirst != NULL)
{
bProblem = TRUE;
LoadString(NULL, IDS_REGISTRYPROBLEM, szMessage, 300);
_tcscat( pSysInfo->m_szInputNotes, szMessage );
LoadString(NULL, IDS_REGISTRYPROBLEM_ENGLISH, szMessage, 300);
_tcscat( pSysInfo->m_szInputNotesEnglish, szMessage );
}
if (!bProblem)
{
LoadString(NULL, IDS_NOPROBLEM, szMessage, 300);
_tcscat( pSysInfo->m_szInputNotes, szMessage );
LoadString(NULL, IDS_NOPROBLEM_ENGLISH, szMessage, 300);
_tcscat( pSysInfo->m_szInputNotesEnglish, szMessage );
}
}