Windows2003-3790/multimedia/directx/dinput/dx8/dll/diport.c
2020-09-30 16:53:55 +02:00

1912 lines
56 KiB
C

/*****************************************************************************
*
* DIPort.c
*
* Copyright (c) 1996 Microsoft Corporation. All Rights Reserved.
*
* Abstract:
*
* Support functions for Gameport/Serialport enumeration.
*
* Contents:
*
*
*
*****************************************************************************/
#include "dinputpr.h"
/*
* We can reuse some code from diHidEnm.c
*/
#define DIPort_GetDevicePath(hdev, pdid, didd, dinf) \
DIHid_GetDevicePath(hdev, pdid, didd, dinf)
#define DIPort_GetDeviceInstanceId(hdev, pdinf, tszId) \
DIHid_GetDeviceInstanceId(hdev, pdinf, tszId)
#define DIPort_GetInstanceGUID(hk, lpguid) \
DIHid_GetInstanceGUID(hk, lpguid)
#define DIPort_GetRegistryProperty(ptszId, dwProperty, pdiph) \
DIHid_GetRegistryProperty(ptszId, dwProperty, pdiph)
/*****************************************************************************
*
* The sqiffle for this file.
*
*****************************************************************************/
#undef sqfl
#define sqfl sqflPort
/*****************************************************************************
*
* @doc INTERNAL
*
* @global PBUSDEVICE | g_pBusDevice |
*
* List of known GamePort/SerialPort devices.
*
*****************************************************************************/
static BUSDEVICE g_pBusDevice[] =
{
{
D(TEXT("GamePort Bus") comma)
NULL,
&GUID_GAMEENUM_BUS_ENUMERATOR,
0x0,
IOCTL_GAMEENUM_EXPOSE_HARDWARE,
IOCTL_GAMEENUM_REMOVE_HARDWARE,
IOCTL_GAMEENUM_PORT_DESC,
IOCTL_GAMEENUM_PORT_PARAMETERS,
IOCTL_GAMEENUM_EXPOSE_SIBLING,
IOCTL_GAMEENUM_REMOVE_SELF,
IDS_STDGAMEPORT,
JOY_HWS_ISGAMEPORTBUS
},
/***************
No defination for serial port devices yet !
{
D(TEXT("SerialPort Bus") comma )
NULL,
&GUID_SERENUM_BUS_ENUMERATOR,
0x0,
IOCTL_SERIALENUM_EXPOSE_HARDWARE,
IOCTL_SERIALENUM_REMOVE_HARDWARE,
IOCTL_SERIALENUM_PORT_DESC,
IOCTL_SERIALENUM_PORT_PARAMETERS,
IOCTL_SERIALENUM_EXPOSE_SIBLING,
IOCTL_SERIALENUM_REMOVE_SELF,
IDS_STDSERIALPORT,
JOY_HWS_ISSERIALPORTBUS
},
****************/
};
#pragma BEGIN_CONST_DATA
/*****************************************************************************
*
* @doc INTERNAL
*
* @func BOOL INTERNAL | SearchDevTree |
*
* Helper routine that searches the device tree for
* a desired device device.
*
* @parm IN DEVINST | dnStart |
* Starting point for the search.
*
* @parm IN DEVINST | dnSeek |
* The device instance we are looking for.
*
* @parm IN PULONG | pRecurse |
* To limit the number of recursions.
*
* @returns BOOL
* True on success.
*
*****************************************************************************/
CONFIGRET INTERNAL
SearchDevTree
(
DEVINST dnStart,
DEVINST dnSeek,
PUINT pRecurse
)
{
#define MAX_RECURSION ( 4 )
CONFIGRET cr;
EnterProcI(SearchDevTree, (_"xxx", dnStart, dnSeek, pRecurse));
cr = CR_SUCCESS;
for( *pRecurse = 0x0; *pRecurse < MAX_RECURSION && cr == CR_SUCCESS; (*pRecurse)++)
{
cr = CM_Get_Parent(&dnSeek, dnSeek, 0 );
if( dnStart == dnSeek )
{
break;
}
}
if( dnStart != dnSeek )
{
cr = CR_NO_SUCH_DEVNODE;
}
#undef MAX_RECURSION
#if 0 // Using Recursion
if( *pRecurse > MAX_RECURSION )
{
return CR_NO_SUCH_DEVNODE;
}
if( dnSeek == dnStart )
{
return CR_SUCCESS;
}
do
{
DEVINST dnNode;
cr = CM_Get_Child(&dnNode, dnStart, 0 );
if( cr == CR_SUCCESS )
{
CAssertF(CR_SUCCESS == 0x0 );
if( CR_SUCCESS == SearchDevTree(dnNode, dnSeek, pRecurse) )
{
return cr;
}
}
cr = CM_Get_Sibling(&dnStart, dnStart, 0);
}while( cr == CR_SUCCESS );
#endif // No recursion
return cr;
}
/*****************************************************************************
*
* @doc INTERNAL
*
* @func PBUSDEVICEINFO | pbdiFromphdi |
*
* Locates Gameport/Serialport information given a device instance of
* one of its children.
* Returns NULL if the device instance is not a child of
* any known gameports/serialports
*
* Internal Routine, parameters already validated.
*
* The DLL critical must be held across the call; once the
* critical section is released, the returned pointer becomes
* invalid.
*
* @parm IN PHIDDEVICEINFO | phdi |
*
* Address of a HIDDEVICEINFO structure
*
* @returns
*
* Pointer to the <t BUSDEVICEINFO> that describes
* the parent bus.
*
*****************************************************************************/
PBUSDEVICEINFO INTERNAL
pbdiFromphdi
(
IN PHIDDEVICEINFO phdi
)
{
PBUSDEVICEINFO pbdi_Found;
PBUSDEVICE pBusDevice;
int iBusType;
EnterProcI(pbdiFromphdi, (_"x", phdi));
AssertF(InCrit());
AssertF(phdi != NULL );
pbdi_Found = NULL;
for( iBusType = 0x0, pBusDevice = g_pBusDevice;
iBusType < cA(g_pBusDevice) && pbdi_Found == NULL;
iBusType++, pBusDevice++ )
{
HDEVINFO hdev;
/*
* Now talk to SetupApi to get info about the device.
*/
hdev = SetupDiCreateDeviceInfoList(NULL, NULL);
if(hdev != INVALID_HANDLE_VALUE )
{
SP_DEVINFO_DATA dinf_hid;
ZeroX(dinf_hid);
dinf_hid.cbSize = cbX(SP_DEVINFO_DATA);
/* Get SP_DEVINFO_DATA for the HID device */
if( pBusDevice->pbdl != NULL &&
phdi!= NULL &&
SetupDiOpenDeviceInfo(hdev, phdi->ptszId, NULL, 0, &dinf_hid))
{
int igdi;
PBUSDEVICEINFO pbdi;
SP_DEVINFO_DATA dinf_bus;
ZeroX(dinf_bus);
dinf_bus.cbSize = cbX(SP_DEVINFO_DATA);
/*
* Loop through all known gameports/serialports and look for a gameport/serialport
* that is a parent of the HID device
*/
for(igdi = 0, pbdi = pBusDevice->pbdl->rgbdi;
igdi < pBusDevice->pbdl->cgbi && pbdi_Found == NULL ;
igdi++, pbdi++)
{
if(SetupDiOpenDeviceInfo(hdev, pbdi->ptszId, NULL, 0, &dinf_bus))
{
ULONG Recurse = 0x0;
if( CR_SUCCESS == SearchDevTree(dinf_bus.DevInst, dinf_hid.DevInst, &Recurse) )
{
pbdi_Found = pbdi;
break;
}
}
}
}
SetupDiDestroyDeviceInfoList(hdev);
}
}
ExitProcX((UINT_PTR)pbdi_Found);
return pbdi_Found;
}
/*****************************************************************************
*
* @doc INTERNAL
*
* @func PBUSDEVICEINFO | pbdiFromGUID |
*
* Locates Gameport/Serialport information given a device instance of
* one of its children.
* Returns NULL if the device instance is not a child of
* any known gameports/serialports
*
* Internal Routine, parameters already validated.
*
* The DLL critical must be held across the call; once the
* critical section is released, the returned pointer becomes
* invalid.
*
* @parm IN PCGUID | pguid |
*
* The instance GUID to be located.
*
* @returns
*
* Pointer to the <t BUSDEVICEINFO> that describes
* the parent bus.
*
*****************************************************************************/
PBUSDEVICEINFO EXTERNAL
pbdiFromGUID
(
IN PCGUID pguid
)
{
PBUSDEVICEINFO pbdi_Found;
PBUSDEVICE pBusDevice;
int iBusType;
EnterProcI(pbdiFromGUID, (_"G", &pguid));
AssertF(InCrit());
pbdi_Found = NULL;
for( iBusType = 0x0, pBusDevice = g_pBusDevice;
iBusType < cA(g_pBusDevice) && pbdi_Found == NULL;
iBusType++, pBusDevice++ )
{
/*
* Loop through all known gameports/serialports and look for a gameport/serialport
* that is a parent of the HID device
*/
PBUSDEVICEINFO pbdi;
int igdi;
for(igdi = 0, pbdi = pBusDevice->pbdl->rgbdi;
igdi < pBusDevice->pbdl->cgbi && pbdi_Found == NULL ;
igdi++, pbdi++)
{
if( IsEqualGUID(pguid, &pbdi->guid) )
{
pbdi_Found = pbdi;
}
}
}
ExitProcX((UINT_PTR)pbdi_Found);
return pbdi_Found;
}
/*****************************************************************************
*
* @doc INTERNAL
*
* @func PHIDDEVICEINFO | phdiFrompbdi |
*
* Locates a HID device attached to a given Gameport/Serialport
* Returns NULL if no devices are currently attached to a known port.
*
* Internal Routine, parameters already validated.
*
* The DLL critical must be held across the call; once the
* critical section is released, the returned pointer becomes
* invalid.
*
* @parm IN PBUSDEVICEINFO | pbdi |
*
* Address of the <t BUSDEVICEINFO> structure that
* describes the gameport/serialport.
*
* @returns
*
* Pointer to one of the <t HIDDEVICEINFO> that describes
* the device. ( Gamport may have multiple devices attached ).
*
*****************************************************************************/
PHIDDEVICEINFO INTERNAL
phdiFrompbdi
(
IN PBUSDEVICEINFO pbdi
)
{
PHIDDEVICEINFO phdi_Found;
HDEVINFO hdev;
EnterProcI(phdiFrompbdi, (_"x", pbdi));
AssertF(InCrit());
AssertF(pbdi != NULL );
/* Enumurate the HID devices */
DIHid_BuildHidList(TRUE);
phdi_Found = NULL;
/*
* Now talk to SetupApi to get info about the device.
*/
hdev = SetupDiCreateDeviceInfoList(NULL, NULL);
if(hdev != INVALID_HANDLE_VALUE)
{
SP_DEVINFO_DATA dinf_bus;
dinf_bus.cbSize = cbX(SP_DEVINFO_DATA);
if( pbdi != NULL && SetupDiOpenDeviceInfo(hdev, pbdi->ptszId, NULL, 0, &dinf_bus))
{
int ihdi;
PHIDDEVICEINFO phdi;
SP_DEVINFO_DATA dinf_hid;
dinf_hid.cbSize = cbX(SP_DEVINFO_DATA);
if( g_phdl )
{
for(ihdi = 0, phdi = g_phdl->rghdi ;
ihdi < g_phdl->chdi && phdi_Found == NULL ;
ihdi++, phdi++)
{
if(SetupDiOpenDeviceInfo(hdev, phdi->ptszId, NULL, 0, &dinf_hid))
{
ULONG Recurse = 0x0;
if(CR_SUCCESS == SearchDevTree(dinf_bus.DevInst, dinf_hid.DevInst, &Recurse) )
{
phdi_Found = phdi;
}
}
}
}
}
SetupDiDestroyDeviceInfoList(hdev);
}
ExitProcX((UINT_PTR)phdi_Found);
return phdi_Found;
}
/*****************************************************************************
*
* @doc EXTERNAL
*
* @func PPORTDEVICEINFO | pbdiFromJoyId |
*
* Locates Gameport/Serialport information given a device id of
* a joystick .
*
* Returns NULL if the device instance is not a child of
* any known gameports/serialports
*
* Internal Routine, parameters already validated.
*
* The DLL critical must be held across the call; once the
* critical section is released, the returned pointer becomes
* invalid.
*
* @parm IN int | idJoy |
*
* The Joystick ID of the child device that will be associated
* to a known gameport/serialport.
*
* @returns
*
* Pointer to the <t BUSDEVICEINFO> that describes
* the device.
*
*****************************************************************************/
PBUSDEVICEINFO EXTERNAL
pbdiFromJoyId
(
IN int idJoy
)
{
GUID guid;
HRESULT hres;
PBUSDEVICEINFO pbdi;
EnterProcI(pbdiFromJoyId, (_"x", idJoy));
AssertF(InCrit());
pbdi = NULL;
/* Find the GUID that corresponds to the Joystick ID */
hres = hResIdJoypInstanceGUID_WDM(idJoy, &guid);
#ifndef WINNT
if( FAILED(hres) ) {
hres = hResIdJoypInstanceGUID_95(idJoy, &guid);
}
#endif
if( SUCCEEDED(hres) )
{
PHIDDEVICEINFO phdi;
phdi = phdiFindHIDInstanceGUID(&guid);
if( phdi != NULL )
{
pbdi = pbdiFromphdi(phdi);
}
}
ExitProcX((UINT_PTR)pbdi);
return pbdi;
}
/*****************************************************************************
*
* @doc INTERNAL
*
* @func BOOL | DIBusDevice_Expose |
*
* Attaches a gameport/serialport device to the Gameport/SerialPort Bus
*
* @parm IN PBUSDEVICEINFO | pbdi |
* Address of a BUSDEVICEINFO structure.
*
* @parm IN OUT PBUS_REGDATA | pRegData |
* Gameport/Serialport specific data. The Handle to the opened device
* is returned in this structure
*
*
* @returns
* BOOL. True indicates success.
*
*****************************************************************************/
HRESULT EXTERNAL
DIBusDevice_Expose
(
IN PBUSDEVICEINFO pbdi,
IN OUT PBUS_REGDATA pRegData
)
{
HRESULT hres;
BOOL frc;
PHIDDEVICEINFO phdi;
EnterProcI(DIBusDevice_Expose, (_ "pp", pbdi, pRegData));
AssertF(DllInCrit() );
AssertF(pbdi!= NULL );
phdi = phdiFrompbdi(pbdi);
if( pRegData && pRegData->dwSize != cbX(*pRegData) )
{
hres = E_INVALIDARG;
} else if( phdi != NULL )
{
hres = E_ACCESSDENIED;
} else
{
HANDLE hf;
BUS_REGDATA RegDataTest;
/* There is a weird condition where the HID device does not appear on a previous
* Add, (drivers not loaded, user cancelled loading of some files, etc
* In such cases we need to tell GameEnum to remove the device before proceeding
* any further
*/
if( pbdi->fAttached || pRegData->hHardware != NULL )
{
DIBusDevice_Remove(pbdi);
}
AssertF(pbdi->fAttached == FALSE);
// Change for Windows bug 575181 -- make sure we can write to the registry
// before we expose the device; otherwise we might not be able to remove it!
ZeroMemory(&RegDataTest, cbX(RegDataTest));
RegDataTest.dwSize = cbX(RegDataTest);
if (FAILED(DIBusDevice_SetRegData(pbdi->hk, &RegDataTest)))
{
// We couldn't write to the registy; return E_ACCESSDENIED
hres = E_ACCESSDENIED;
}
else
{
// Open a File handle to the gameport/serialport device so we can send it IOCTLS
hf = CreateFile(pbdi->pdidd->DevicePath,
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE,
0, /* no SECURITY_ATTRIBUTES */
OPEN_EXISTING,
0, /* attributes */
0); /* template */
if( hf != INVALID_HANDLE_VALUE )
{
DWORD cbRc;
GAMEENUM_PORT_DESC Desc;
Desc.Size = cbX(Desc) ;
Sleep(50); //need sleep a while to wait for the device is ready to accept commands.
/* Get the gameport bus properties */
frc = DeviceIoControl (hf,
pbdi->pBusDevice->ioctl_DESC,
&Desc, cbX(Desc),
&Desc, cbX(Desc),
&cbRc, NULL);
if( frc && cbRc == cbX(Desc) )
{
PGAMEENUM_EXPOSE_HARDWARE pExpose;
DWORD cbExpose;
cbExpose = cbX(*pExpose) + cbX(pRegData->wszHardwareId);
hres = AllocCbPpv( cbExpose, & pExpose);
if( SUCCEEDED(hres ) )
{
typedef struct _OEMDATA
{
ULONG uVID_uPID;
ULONG joy_hws_dwFlags;
ULONG dwFlags1;
ULONG Reserved;
} OEMDATA, *POEMDATA;
POEMDATA pOemData = (POEMDATA)(&pExpose->OemData);
CAssertF(2*sizeof(*pOemData) == sizeof(pExpose->OemData))
pOemData->uVID_uPID = MAKELONG(pRegData->uVID, pRegData->uPID);
pOemData->joy_hws_dwFlags = pRegData->hws.dwFlags;
pOemData->dwFlags1 = pRegData->dwFlags1;
/*
* Make sure only known analog devices cause the
* compatible hardware ID to be exposed.
* This is done so that no in-box drivers will match for
* an unsupported digital joystick so users will be
* prompted to use an unsigned IHV driver rather than
* silently loading the generic analog joystick driver.
*/
if( ( pRegData->dwFlags1 & JOYTYPE_ANALOGCOMPAT )
|| ( ( pRegData->uVID == MSFT_SYSTEM_VID )
&& ( ( pRegData->uPID & 0xff00 ) == MSFT_SYSTEM_PID ) ) )
{
pExpose->Flags = GAMEENUM_FLAG_COMPATIDCTRL;
}
else
{
pExpose->Flags = GAMEENUM_FLAG_COMPATIDCTRL | GAMEENUM_FLAG_NOCOMPATID ;
}
pExpose->Size = cbX(*pExpose) ;
pExpose->PortHandle = Desc.PortHandle;
pExpose->NumberJoysticks = pRegData->nJoysticks;
pRegData->nAxes = 2;
if( pExpose->NumberJoysticks != 2 )
{
AssertF( pExpose->NumberJoysticks == 1);
if( pRegData->hws.dwFlags & JOY_HWS_HASZ )
{
pRegData->nAxes++;
}
if( pRegData->hws.dwFlags & JOY_HWS_HASR )
{
pRegData->nAxes++;
}
pExpose->NumberButtons = (USHORT)pRegData->hws.dwNumButtons;
}
else
{
pOemData++;
pOemData->uVID_uPID = MAKELONG(pRegData->uVID, pRegData->uPID);
pOemData->joy_hws_dwFlags = JOY_HWS_XISJ2X | JOY_HWS_YISJ2Y;
pExpose->NumberButtons = 2;
}
pExpose->NumberAxis = pRegData->nAxes;
/*
* The SideWinder driver uses the OEMData field in a
* sibling expose to pass internal data (this ptrs) from
* one instance to another. Since these fields are
* supposed to be for the OEMData we have a Flags1 field
* to allow the data to be zeroed for a DInput expose for
* drivers that don't want the normal data.
*/
if ( pRegData->dwFlags1 & JOYTYPE_ZEROGAMEENUMOEMDATA )
{
ZeroBuf(pExpose->OemData, sizeof(pExpose->OemData) );
}
CopyMemory(pExpose->HardwareIDs, pRegData->wszHardwareId, cbX(pRegData->wszHardwareId) );
Sleep(50);
if( frc = DeviceIoControl (hf,
pbdi->pBusDevice->ioctl_EXPOSE,
pExpose, cbExpose,
pExpose, cbExpose,
&cbRc, NULL )
&& cbRc == cbExpose )
{
PVOID hHardwareOld = pRegData->hHardware;
pbdi->fAttached = TRUE;
pRegData->hHardware = pExpose->HardwareHandle;
DIBusDevice_SetRegData(pbdi->hk, pRegData);
/*
* If we have dealt with this device before then the hHardwareOld
* will be non null, and we have sufficient reason to believe that the
* expose will succeed.
*
* This test needs to be removed to fix manbug: 39554.
* For new created device, we need wait for a while to let phdi be ready.
*
*/
//if(hHardwareOld)
{
int i;
for(i = 0; (i < 20) && (phdiFrompbdi(pbdi) == NULL); i++ )
{
Sleep(50);
}
}
} else // DeviceIOControl (EXPOSE) Failed
{
hres = E_FAIL;
SquirtSqflPtszV(sqfl | sqflError,
TEXT("%S: IOCTL_PORTENUM_EXPOSE_HARDWARE failed ")
TEXT("Error = %d"),
s_szProc, GetLastError());
}
FreePpv(&pExpose);
} else // Alloc failed
{
SquirtSqflPtszV(sqfl | sqflError,
TEXT("%S: AllocCbPpv failed "),
s_szProc);
}
} else // IOCTL FAILED
{
hres = E_FAIL;
SquirtSqflPtszV(sqfl | sqflError,
TEXT("%S: IOCTL_PORTENUM_PORT_DESC failed ")
TEXT("Error = %d"),
s_szProc, GetLastError());
}
CloseHandle(hf);
} else
{
hres = E_FAIL;
SquirtSqflPtszV(sqfl | sqflError,
TEXT("%S: CreateFile(%s) failed ")
TEXT("Error = %d"),
s_szProc, pbdi->pdidd->DevicePath, GetLastError());
}
}
}
ExitBenignProcX(hres);
return hres;
}
/*****************************************************************************
*
* @doc INTERNAL
*
* @func BOOL | DIBusDevice_Remove |
*
* Removes the FDO for a gameport/serialport device.
*
* @parm IN HANDLE | hf |
* Handle to the GamePort/SerialPort Bus device file object
*
* @parm IN PPORT_REGDATA | pRegData |
* Structure that contains registry data. What we need from here is the
* handle to the hardware.
*
* @returns
* BOOL. True for success.
*
*****************************************************************************/
HRESULT INTERNAL
DIBusDevice_Remove
(
IN PBUSDEVICEINFO pbdi
)
{
HRESULT hres;
BUS_REGDATA RegData;
EnterProcI(DIBus_Remove, (_ "p", pbdi));
hres = DIBusDevice_GetRegData(pbdi->hk, &RegData);
//
// Delete our registry goo, so this device
// will not show up on subsequent reboots
//
DIBusDevice_SetRegData(pbdi->hk, NULL);
if( SUCCEEDED(hres) )
{
HANDLE hf;
BOOL frc;
// Open a File handle to the gameport/serialport device so we can send it IOCTLS
hf = CreateFile(pbdi->pdidd->DevicePath,
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE,
0, /* no SECURITY_ATTRIBUTES */
OPEN_EXISTING,
0, /* attributes */
0); /* template */
if( hf != INVALID_HANDLE_VALUE )
{
DWORD cbRc;
GAMEENUM_REMOVE_HARDWARE Remove;
Remove.Size = cbX(Remove);
Remove.HardwareHandle = RegData.hHardware;
frc = DeviceIoControl (hf,
pbdi->pBusDevice->ioctl_REMOVE,
&Remove, cbX(Remove),
&Remove, cbX(Remove),
&cbRc, NULL) ;
if( frc && cbRc == cbX(Remove) )
{
pbdi->fAttached = FALSE;
} else // DeviceIoControl ( REMOVE_HARDWARE ) Failed
{
hres = E_FAIL;
SquirtSqflPtszV(sqfl | sqflError,
TEXT("%S: DeviceIOControl(REMOVE_HARDWARE) failed ")
TEXT("Error = %d"),
s_szProc, GetLastError());
}
CloseHandle(hf);
}
}
ExitBenignOleProc();
return hres;
}
/*****************************************************************************
*
* @doc INTERNAL
*
* @func HRESULT | DIPort_SetRegData |
*
* Sets up registry data under the $hk$/Config subkey for the gameport
* device.
*
* @parm IN HKEY | hk |
* A handle to the parent key where the registry data will be written.
*
* @parm IN PGAMEPORT_REGDATA | pRegData |
* Pointer to a structure containing data to be written to the registry.
*
* @returns
* BOOL. True for success
*
*****************************************************************************/
HRESULT INTERNAL
DIBusDevice_SetRegData
(
IN HKEY hk,
IN PBUS_REGDATA pRegData
)
{
LONG lrc;
HRESULT hres = S_OK;
EnterProcI(DIPort_SetRegData, (_ "xpx", hk, pRegData ));
if( pRegData != NULL )
{
if( ( lrc = RegSetValueEx(hk, TEXT("Config"), 0, REG_BINARY,
(PV) (pRegData), cbX(*pRegData)) ) == ERROR_SUCCESS )
{
hres = S_OK;
} else // RegSetValueEx FAILED
{
hres = E_FAIL;
SquirtSqflPtszV(sqfl | sqflError,
TEXT("%S: RegSetValueEx() failed ")
TEXT("Error = %d"),
s_szProc, lrc);
}
} else
{
lrc = RegDeleteValue(hk, TEXT("Config"));
}
ExitOleProc();
return (hres);
}
/*****************************************************************************
*
* @doc INTERNAL
*
* @func HRESULT | DIPort_GetRegData |
*
* Gets registry data from the $hk$/Config subkey for the gameport
* device.
*
* @parm IN HKEY | hk |
* A handle to the parent key where the registry.
*
* @parm IN PGAMEPORT_REGDATA | pRegData |
* Address of a pointer to the structure where the registry data
* will be read into.
*
* @returns
* HRESULT
*****************************************************************************/
HRESULT INTERNAL
DIBusDevice_GetRegData
(
IN HKEY hk,
OUT PBUS_REGDATA pRegData
)
{
LONG lRc;
DWORD cb;
HRESULT hres;
EnterProcI(DIPort_GetRegData, (_ "xpx", hk, pRegData ));
cb = cbX(*pRegData);
lRc = RegQueryValueEx( hk, TEXT("Config"), 0, 0 , (PV)(pRegData), &cb );
if( lRc == ERROR_SUCCESS && pRegData->dwSize == cbX(*pRegData ) )
{
hres = S_OK;
} else
{
DIBusDevice_SetRegData(hk, NULL );
ZeroX(*pRegData);
hres = E_FAIL;
SquirtSqflPtszV(sqfl | sqflBenign,
TEXT("%S: RegQueryValueEx(Config) failed ")
TEXT("Error = %d, ( pRegData->cbSize(%d) == cbX(*pRegData)(%d)) "),
s_szProc, lRc, pRegData->dwSize, cbX(*pRegData) );
}
ExitBenignOleProc();
return ( hres ) ;
}
/*****************************************************************************
*
* @doc INTERNAL
*
* @func void | DIBus_BuildListEntry |
*
* Builds a single entry in the list of GAMEPORT/SERIALPORT devices.
*
* @parm HDEVINFO | hdev |
*
* Device list being enumerated.
*
* @parm PSP_DEVICE_INTERFACE_DATA | pdid |
*
* Describes the device that was enumerated.
*
* @returns
*
* Nonzero on success.
*
*****************************************************************************/
BOOL INTERNAL
DIBusDevice_BuildListEntry
(
HDEVINFO hdev,
PSP_DEVICE_INTERFACE_DATA pdid,
PBUSDEVICE pBusDevice
)
{
BOOL fRc = TRUE;
//HKEY hkDev;
HKEY hkDin;
PBUSDEVICEINFO pbdi;
PBUSDEVICELIST pbdl;
PSP_DEVICE_INTERFACE_DETAIL_DATA pdidd;
BOOL fAlreadyExist;
HRESULT hres;
EnterProcI(DIBus_BuildListEntry, (_ "xp", hdev, pdid));
pbdl = pBusDevice->pbdl;
fAlreadyExist = FALSE;
/* GetDevicePath is expecting a NULL */
pdidd = NULL;
if( DIPort_GetDevicePath(hdev, pdid, &pdidd, NULL) )
{
int ibdi;
//Check whether the device has been in the list
for( ibdi = 0; ibdi < pbdl->cgbi; ibdi++)
{
if( pbdl->rgbdi[ibdi].pdidd )
{
if( lstrcmp( pdidd->DevicePath, pbdl->rgbdi[ibdi].pdidd->DevicePath ) == 0 )
{
//already in the list
fAlreadyExist = TRUE;
break;
}
}
}
FreePpv(&pdidd);
}
if( fAlreadyExist == TRUE )
{
fRc = TRUE;
} else
{
/*
* Make sure there is room for this device in the list.
* Grow by doubling.
*/
if( pbdl->cgbi >= pbdl->cgbiAlloc)
{
/*
* Assert that we never ask for zero bytes here
*/
AssertF( cbGdlCbdi( pbdl->cgbiAlloc * 2) );
hres = ReallocCbPpv( cbGdlCbdi( pbdl->cgbiAlloc * 2), &pBusDevice->pbdl );
if( FAILED(hres) )
{
SquirtSqflPtszV(sqfl | sqflError,
TEXT("%S: Realloc failed"), s_szProc);
fRc = FALSE;
goto done;
}
/*
* Prefix warns (Win:170673) that pBusDevice->pbdl could be zero
* if we asked for zero bytes above but the size requested cannot
* be zero so this has been asserted. Note the fix for (W:45084)
* was incorrect so it has been removed.
*/
pbdl = pBusDevice->pbdl;
pbdl->cgbiAlloc *= 2;
}
AssertF( pbdl->cgbi < pbdl->cgbiAlloc);
pbdi = &pbdl->rgbdi[pbdl->cgbi];
pbdi->pBusDevice = pBusDevice;
pbdi->hk = 0;
pbdi->idJoy = JOY_BOGUSID;
/*
* Open the registry key for the device so we can obtain
* auxiliary information.
*/
{
//Open our own reg key under MediaProperties/DirectInput,
//creating it if necessary.
hres = hresMumbleKeyEx(HKEY_LOCAL_MACHINE,
REGSTR_PATH_DITYPEPROP,
DI_KEY_ALL_ACCESS,
REG_OPTION_NON_VOLATILE,
&hkDin);
if (SUCCEEDED(hres))
{
//Create the Gameports reg key
HKEY hkGameports;
hres = hresMumbleKeyEx(hkDin,
TEXT("Gameports"),
DI_KEY_ALL_ACCESS,
REG_OPTION_NON_VOLATILE,
&hkGameports);
if (SUCCEEDED(hres))
{
//Create a reg key corresponding to the instance number.
//Since we do this for every gameport enumerated, the number in the list
//indicates the instance number.
TCHAR tszInst[3];
wsprintf(tszInst, TEXT("%u"), pbdl->cgbi);
hres = hresMumbleKeyEx(hkGameports,
tszInst,
DI_KEY_ALL_ACCESS,
REG_OPTION_NON_VOLATILE,
&pbdi->hk);
if(SUCCEEDED(hres))
{
SP_DEVINFO_DATA dinf;
dinf.cbSize = cbX(SP_DEVINFO_DATA);
/*
* Get the instance GUID and the path to
* the GAMEPORT/SERIALPORT device so we can talk to it.
*/
if(DIPort_GetDevicePath(hdev, pdid, &pbdi->pdidd, &dinf) &&
DIPort_GetDeviceInstanceId(hdev, &dinf, &pbdi->ptszId) &&
DIPort_GetInstanceGUID(pbdi->hk, &pbdi->guid) )
{
HANDLE hf;
hf = CreateFile(pbdi->pdidd->DevicePath,
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE,
0, /* no SECURITY_ATTRIBUTES */
OPEN_EXISTING,
0, /* attributes */
0); /* template */
if( hf != INVALID_HANDLE_VALUE )
{
BUS_REGDATA RegData;
ZeroX(RegData);
CloseHandle(hf);
// Bump up the counter
fRc = TRUE;
pbdl->cgbi++;
hres = DIBus_InitId(pBusDevice->pbdl);
if( SUCCEEDED(hres) )
{
hres = DIBusDevice_GetRegData(pbdi->hk, &RegData);
}
if( SUCCEEDED(hres) )
{
/* There is a pathological case which can cause endless bluescreen's
* If the HID driver causes a bluescreen, and we keep reattaching
* it, we are sunk !!
* To guard against this possiblity we reattach a device on reboot
* only if we are sure that it succeeded the first time around
*/
if( RegData.fAttachOnReboot == FALSE )
{
DIBusDevice_Remove(pbdi);
SquirtSqflPtszV(sqfl | sqflError,
TEXT("%S: DIPortDevice_Expose FAILED, ")
TEXT("Driver did not load property the first time around "),
s_szProc);
} else if( pbdi->fAttached == FALSE )
{
hres = DIBusDevice_Expose( pbdi, &RegData );
if( SUCCEEDED( hres ) || hres == E_ACCESSDENIED )
{
pbdi->fAttached = TRUE;
} else
{
SquirtSqflPtszV(sqfl | sqflError,
TEXT("%S: DIPortDevice_Expose FAILED ")
TEXT("hres = %d"),
s_szProc, hres);
}
}
}
} else
{
fRc = FALSE;
SquirtSqflPtszV(sqfl | sqflError,
TEXT("%S: CreateFile(%s) failed ")
TEXT("Error = %d"),
s_szProc, pbdi->pdidd->DevicePath, GetLastError());
}
} else
{
SquirtSqflPtszV(sqfl | sqflError,
TEXT("%S: Unable to get device path"),
s_szProc);
pbdi->hk = 0x0;
fRc = FALSE;
}
/*
* If we failed, then free the goo we already got.
*/
if(!fRc)
{
if( pbdi->hk )
RegCloseKey(pbdi->hk);
pbdi->hk = 0;
FreePpv(&pbdi->pdidd);
FreePpv(&pbdi->ptszId);
fRc = FALSE;
}
} else
{
SquirtSqflPtszV(sqfl | sqflError,
TEXT("%S: RegCreateKeyEx failed on Instance, error "),
s_szProc);
fRc = FALSE;
}
RegCloseKey(hkGameports);
} else // RegCreateKeyEx FAILED
{
SquirtSqflPtszV(sqfl | sqflError,
TEXT("%S: RegCreateKeyEx failed on Gameports, error "),
s_szProc);
fRc = FALSE;
}
RegCloseKey(hkDin);
}
else
{
SquirtSqflPtszV(sqfl | sqflError,
TEXT("%S: RegOpenKeyEx failed on DirectInput"),
s_szProc);
fRc = FALSE;
}
}
}
done:;
ExitProcF(fRc);
return fRc;
}
/*****************************************************************************
*
* @doc EXTERNAL
*
* @func void | DIPort_EmptyList |
*
* Empty the list of GAMEPORT/SERIALPORT devices.
*
* This function must be called under the DLL critical section.
*
*****************************************************************************/
void INTERNAL
DIBus_EmptyList
(
PBUSDEVICELIST *ppbdl
)
{
PBUSDEVICELIST pbdl = *ppbdl;
AssertF(InCrit());
if( pbdl )
{
int igdi;
for(igdi = 0; igdi < pbdl->cgbi; igdi++)
{
FreePpv(&pbdl->rgbdi[igdi].pdidd);
FreePpv(&pbdl->rgbdi[igdi].ptszId);
if( pbdl->rgbdi[igdi].hk)
{
RegCloseKey( pbdl->rgbdi[igdi].hk);
}
}
/*
* We invalidated all the pointers, so make sure
* nobody looks at them.
*/
pbdl->cgbi = 0;
FreePpv(&pbdl);
*ppbdl = NULL;
}
}
void EXTERNAL
DIBus_FreeMemory()
{
int iBusType;
PBUSDEVICE pBusDevice;
for( iBusType = 0x0, pBusDevice = g_pBusDevice;
iBusType < cA(g_pBusDevice);
iBusType++, pBusDevice++ )
{
DIBus_EmptyList(&pBusDevice->pbdl);
}
}
/*****************************************************************************
*
* @doc EXTERNAL
*
* @func void | DIPort_InitId |
*
* Initializes Joystick IDs for JoyConfig and legacy APIs
* Store the joystick IDs the registry under the %%DirectX/JOYID key.
*
*****************************************************************************/
#undef PORTID_BOGUS
#define PORTID_BOGUS ( 0xffffffff )
HRESULT EXTERNAL
DIBus_InitId(PBUSDEVICELIST pbdl)
{
HRESULT hres = FALSE;
LONG lRc;
DWORD cb;
int igdi;
BOOL fNeedId;
BOOL rfPortId[cgbiMax]; /* Bool Array for to determine which IDs are in use */
PBUSDEVICEINFO pbdi;
EnterProcI(DIBus_InitId, (_ ""));
fNeedId = FALSE;
AssertF(DllInCrit());
ZeroX(rfPortId );
if( pbdl != NULL )
{
/* Iterate over to find used IDs */
for( igdi = 0, pbdi = pbdl->rgbdi ;
igdi < pbdl->cgbi ;
igdi++, pbdi++ )
{
pbdi->idPort = PORTID_BOGUS; // Default
cb = cbX(pbdi->idPort);
if( ( lRc = RegQueryValueEx(pbdi->hk, TEXT("ID"),
0, 0, (PV)&pbdi->idPort, &cb) == ERROR_SUCCESS ) )
{
if( rfPortId[pbdi->idPort] // Collision in GameId
|| pbdi->idPort > cgbiMax ) // Wrror
{
pbdi->idPort = PORTID_BOGUS;
fNeedId = TRUE;
} else // Valid idPort
{
rfPortId[pbdi->idPort] = TRUE;
}
} else // RegQueryValue("ID") does not exist
{
fNeedId = TRUE;
}
}
if( fNeedId )
{
/*
* We have Examined all GamePort/SerialPort Ids found used IDs
* and determined some device needs an Id
*/
/* Iterate to assign unused Id's */
for( igdi = 0, pbdi = pbdl->rgbdi;
igdi < pbdl->cgbi ;
igdi++, pbdi++ )
{
if( pbdi->idPort == PORTID_BOGUS )
{
/* Get an Unused ID */
for( pbdi->idPort = 0x0;
pbdi->idPort < cgbiMax;
pbdi->idPort++ )
{
if( rfPortId[pbdi->idPort] == FALSE )
break;
}
rfPortId[pbdi->idPort] = TRUE;
if( lRc = RegSetValueEx(pbdi->hk, TEXT("ID"), 0, REG_BINARY,
(PV)&pbdi->idPort, cbX(pbdi->idPort)) == ERROR_SUCCESS )
{
} else
{
SquirtSqflPtszV(sqfl | sqflError,
TEXT("%S: RegSetValueEx(JOYID) FAILED ")
TEXT("Error = %d"),
s_szProc, lRc);
hres = FALSE;
}
}
}
}
}
ExitOleProc();
return hres;
}
/*****************************************************************************
*
* @doc INTERNAL
*
* @func void | DIBus_CheckList |
*
* Check the list of HID devices and free any that cannot be opened
*
* This function must be called under the DLL critical section.
*
*****************************************************************************/
void INTERNAL
DIBus_CheckList(PBUSDEVICELIST pbdl)
{
HANDLE hf;
AssertF(InCrit());
/*
* Free all the information of the device that cannot be opened
*/
if(pbdl)
{
int ibdi;
PBUSDEVICEINFO pbdi;
for(ibdi = 0, pbdl->cgbi = 0; ibdi < pbdl->cgbiAlloc; ibdi++)
{
pbdi = &pbdl->rgbdi[ibdi];
if( pbdi && pbdi->pdidd )
{
/*
* Open the device
*/
hf = CreateFile(pbdi->pdidd->DevicePath,
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE,
0, /* no SECURITY_ATTRIBUTES */
OPEN_EXISTING,
0, /* attributes */
0); /* template */
if(hf == INVALID_HANDLE_VALUE)
{
FreePpv(&pbdi->pdidd);
FreePpv(&pbdi->ptszId);
if(pbdi->hk)
{
RegCloseKey(pbdi->hk);
}
ZeroX( pbdi );
} else
{
pbdl->cgbi++;
CloseHandle(hf);
}
}
}
//re-order the existing devices, put them at the front of the hid list.
for(ibdi = 0; ibdi < pbdl->cgbi; ibdi++)
{
if( !pbdl->rgbdi[ibdi].pdidd )
{
int ibdi2;
//find the existing device from the biggest index in the hid list.
for( ibdi2 = pbdl->cgbiAlloc; ibdi2 >= ibdi+1; ibdi2-- )
{
if( pbdl->rgbdi[ibdi2].pdidd )
{
memcpy( &pbdl->rgbdi[ibdi], &pbdl->rgbdi[ibdi2], sizeof(BUSDEVICEINFO) );
ZeroX( pbdl->rgbdi[ibdi2] );
}
}
}
}
}
return;
}
/*****************************************************************************
*
* @doc EXTERNAL
*
* @func void | DIBus_BuildList |
*
* Builds the list of GAMEPORT/SERIALPORT devices.
*
* @parm BOOL | fForce |
*
* If nonzero, we force a rebuild of the GAMEPORT/SERIALPORT list.
* Otherwise, we rebuild only if the list hasn't
* been rebuilt recently.
*
*****************************************************************************/
#define MSREBUILDRATE 20000 /* Twenty seconds */
ULONG EXTERNAL
DIBus_BuildList( IN BOOL fForce )
{
HRESULT hres;
PBUSDEVICE pBusDevice;
ULONG cDevices;
int iBusType;
DWORD dwTickCount;
EnterProcI(DIBus_BuildList, (_ "u", fForce));
DllEnterCrit();
/*
* Decide whether or not to rebuild once (don't want to half rebuild)
*/
dwTickCount = GetTickCount();
// Force implies a complete rebuild of the list.
if(fForce)
{
DIBus_FreeMemory();
}
DIHid_BuildHidList(fForce);
hres = S_OK;
for( cDevices = iBusType = 0x0, pBusDevice = g_pBusDevice;
iBusType < cA(g_pBusDevice);
iBusType++, pBusDevice++ )
{
PBUSDEVICELIST pbdl;
pbdl = pBusDevice->pbdl;
if( HidD_GetHidGuid && /* HID support */
( fForce || /* Forcing rebuild, or */
pBusDevice->tmLastRebuild == 0 || /* Never built before, or */
dwTickCount - pBusDevice->tmLastRebuild > MSREBUILDRATE )
)
{
HDEVINFO hdev;
/* delete devices that disappeared since we last looked */
DIBus_CheckList(pbdl);
hdev = SetupDiGetClassDevs((LPGUID)pBusDevice->pcGuid, 0, 0,
DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
if(hdev != INVALID_HANDLE_VALUE)
{
/*
* There is no way to query the number of devices.
* You just have to keep incrementing until you run out.
*
* If we already have a pbdl, then re-use it. Else, create
* a new one. Alloc up to the minimum starting point.
*/
if( pBusDevice->pbdl == NULL )
{
/*
* Prefix warns that we leak this memory (mb:34688) but
* we keep a reference in our global list so we can free
* the memory when we're done with it.
*/
hres = AllocCbPpv(cbGdlCbdi(cgbiInit), &pBusDevice->pbdl );
if(SUCCEEDED(hres))
{
pbdl = pBusDevice->pbdl;
pbdl->cgbi = 0;
pbdl->cgbiAlloc = cgbiInit;
}
}
if( SUCCEEDED(hres) )
{
int idev;
/*
* To avoid infinite looping on
* internal *boo-boo's*, break on any
* error once we have tried more than
* cgbiMax devices, since that's the most
* GAMEPORT/SERIALPORT will ever give us.
*/
for(idev = 0; idev < cgbiMax; idev++)
{
SP_DEVICE_INTERFACE_DATA did;
AssertF( pbdl->cgbi <= pbdl->cgbiAlloc);
/*
* Note, pnp.c doesn't initialize this so we have to
*/
did.cbSize = cbX(did);
if(SetupDiEnumDeviceInterfaces(hdev, 0, (LPGUID)pBusDevice->pcGuid,
idev, &did))
{
if(DIBusDevice_BuildListEntry(hdev, &did, &g_pBusDevice[iBusType] ))
{
//pbdl->cgbi++;
} else
{
/* Skip erroneous items */
SquirtSqflPtszV(sqfl | sqflError,
TEXT("DIBus_BuildListEntry ")
TEXT("failed?"));
}
} else
if(GetLastError() == ERROR_NO_MORE_ITEMS)
{
break;
} else
{
/* Skip erroneous items */
SquirtSqflPtszV(sqfl | sqflError,
TEXT("SetupDiEnumDeviceInterface ")
TEXT("failed? le=%d"), GetLastError());
}
}
}
SetupDiDestroyDeviceInfoList(hdev);
pBusDevice->tmLastRebuild = GetTickCount();
}
}
if(pbdl) { cDevices += pbdl->cgbi; }
}
/* New gameport devices may be exposed. Pick them up too */
DIHid_BuildHidList(FALSE);
DllLeaveCrit();
ExitProc();
return (cDevices);
}
PBUSDEVICELIST EXTERNAL
pbdlFromGUID
(
IN PCGUID pcGuid
)
{
PBUSDEVICELIST pbdl_Found = NULL;
PBUSDEVICE pBusDevice;
int iBusType;
for( iBusType = 0x0, pBusDevice = g_pBusDevice;
iBusType < cA(g_pBusDevice);
iBusType++, pBusDevice++ )
{
if( IsEqualGUID(pBusDevice->pcGuid, pcGuid) )
{
pbdl_Found = pBusDevice->pbdl;
break;
}
}
return pbdl_Found;
}
/*****************************************************************************
*
* @doc INTERNAL
*
* @func HRESULT | DIBusDevice_ExposeEx |
*
* Attache a HID device to all available ports.
*
* @parm IN HANDLE | hf |
* Handle the the Gameport/SerialPort File object
*
* @parm IN OUT PBUS_REGDATA | pRegData |
* Gameport/Serialport specific data. The Handle to the opened device
* is returned in this structure
*
*
* @returns
* BOOL. True indicates success.
*
*****************************************************************************/
HRESULT EXTERNAL
DIBusDevice_ExposeEx
(
IN PBUSDEVICELIST pbdl,
IN PBUS_REGDATA pRegData
)
{
HRESULT hres = DIERR_DEVICENOTREG;
EnterProcI(DIBusDevice_ExposeEx, (_ "xx", pbdl, pRegData));
/*
* The return code a little strange for this function
* If the Expose succeeds for any gameport then
* we will return that error code.
* If the expose fails for all gameports,
* then we will return the amalgam of
* all the error codes.
*/
if( pbdl->cgbi != 0x0 )
{
HRESULT hres1 = DIERR_DEVICENOTREG;
int ibdi;
hres = S_OK;
for( ibdi = 0x0; ibdi < pbdl->cgbi; ibdi++)
{
HRESULT hres0;
PBUSDEVICEINFO pbdi;
hres0 = DIERR_DEVICENOTREG;
pbdi = &(pbdl->rgbdi[ibdi]);
if( pbdi->fAttached == FALSE )
{
pbdi->fDeleteIfNotConnected = TRUE;
hres0 = DIBusDevice_Expose(pbdi, pRegData);
if( FAILED(hres0) )
{
hres |= hres0;
} else
{
hres1 = hres0;
}
} else {
hres = DIERR_DEVICEFULL;
}
}
if(SUCCEEDED(hres1))
{
hres = hres1;
}
}
ExitOleProc();
return hres;
}
/*****************************************************************************
*
* @doc INTERNAL
*
* @func HRESULT | DIBusDevice_GetTypeInfo |
*
* Gets typeinfo for bus device.
*
* @parm IN PCGUID | pcguid |
* GUID that identifies the gameport
*
* @parm OUT LPDIJOTYPEINFO | pjti |
* Typeinfo stuct filled in by this function
*
* @parm IN DWORD | fl |
* Flags that specify what fields to fill out.
*
* @returns
* HRESULT.
*
*****************************************************************************/
HRESULT EXTERNAL
DIBusDevice_GetTypeInfo
(
PCGUID pcguid,
LPDIJOYTYPEINFO pjti,
DWORD fl
)
{
HRESULT hres;
PBUSDEVICEINFO pbdi;
EnterProcI(DIBusDevice_GetTypeInfo, (_ "Gp", pcguid, pjti));
hres = E_FAIL;
DllEnterCrit();
if( NULL != ( pbdi = pbdiFromGUID(pcguid) ) )
{
DIPROPSTRING dips;
if(fl & DITC_REGHWSETTINGS)
{
pjti->hws.dwFlags = pbdi->pBusDevice->dwJOY_HWS_ISPORTBUS | JOY_HWS_AUTOLOAD ;
pjti->hws.dwNumButtons = MAKELONG( pbdi->idPort, 0x0 );
}
if( fl & DITC_CLSIDCONFIG )
{
pjti->clsidConfig = pbdi->guid;
}
if(fl & DITC_DISPLAYNAME)
{
if(FAILED( hres = DIPort_GetRegistryProperty(pbdi->ptszId, SPDRP_FRIENDLYNAME, &dips.diph) ) )
{
if( FAILED( hres = DIPort_GetRegistryProperty(pbdi->ptszId, SPDRP_DEVICEDESC, &dips.diph) ) )
{
SquirtSqflPtszV(sqfl | sqflError,
TEXT("%S: No device name | friendly name for gameport %d "),
s_szProc, pbdi->idPort);
}
}
if( SUCCEEDED(hres) )
{
/*
* Prefix warns (Wi:228282) that dips.wsz could be
* uninitialized however one of the above GetRegistryProperty
* functions has succeeded leaving a worst case of a NULL
* terminator having been copied there.
*/
lstrcpyW(pjti->wszDisplayName, dips.wsz);
}
}
#ifndef WINNT
if(fl & DITC_CALLOUT)
{
ZeroX(pjti->wszCallout);
}
#endif
if(fl & DITC_HARDWAREID)
{
ZeroX(pjti->wszHardwareId);
}
if( fl & DITC_FLAGS1 )
{
pjti->dwFlags1 = 0x0;
}
hres = S_OK;
} else
{
hres = E_FAIL;
SquirtSqflPtszV(sqfl | sqflError,
TEXT("%S: GUID not a port GUID "),
s_szProc);
}
DllLeaveCrit();
ExitProcX(hres);
return hres;
}
HRESULT EXTERNAL DIPort_SnapTypes(LPWSTR *ppwszz)
{
LONG cDevices;
HRESULT hres = E_FAIL;
cDevices = DIBus_BuildList(FALSE);
if( cDevices)
{
DllEnterCrit();
hres = AllocCbPpv(cbCwch( cDevices * MAX_JOYSTRING) , ppwszz);
if( SUCCEEDED(hres) )
{
int iBusType, igdi;
PBUSDEVICE pBusDevice;
LPWSTR pwsz = *ppwszz;
for(iBusType = 0x0, pBusDevice = g_pBusDevice;
iBusType < 1;
iBusType++, pBusDevice++ )
{
PBUSDEVICEINFO pbdi;
for(igdi = 0, pbdi = pBusDevice->pbdl->rgbdi;
igdi < pBusDevice->pbdl->cgbi;
igdi++, pbdi++)
{
TCHAR tszGuid[MAX_JOYSTRING];
NameFromGUID(tszGuid, &pbdi->guid);
#ifdef UNICODE
lstrcpyW(pwsz, &tszGuid[ctchNamePrefix]);
pwsz += lstrlenW(pwsz) + 1;
#else
TToU(pwsz, cA(pwsz), &tszGuid[ctchNamePrefix]);
pwsz += lstrlenW(pwsz) + 1;
#endif
}
}
*pwsz = L'\0'; /* Make it ZZ */
}
DllLeaveCrit();
}
return hres;
}