/**************************************************************************** * * Copyright (C) 2000, 2001 Microsoft Corporation. All Rights Reserved. * * Author: Tomislav Markoc, (tmarkoc), SDE * ****************************************************************************/ #include #include //UI only #include //UI only #define _INC_MMSYSTEM #define WINMMAPI DECLSPEC_IMPORT typedef UINT MMRESULT; /* error return code, 0 means no error */ /* call as if(err=xxxx(...)) Error(err); else */ // end of hack to avoid including mmsystem.h!!! #include #include #include #include #include #include #include #include #include #include #include #include "resource.h" #include "ifacesvr.h" #include "joyarray.h" using namespace std; #define NUMJOYDEVS 16//Max joy id-s. Why is this hardcoded? #define MAX_DEVICES 75 #define IDC_WHATSTHIS 400 #ifdef UNICODE #define String wstring #else #define String string #endif // !UNICODE #ifdef _CHECKED #define JOY_EXCEPTION(A) JoyException(_T(__FILE__),__LINE__,A) #else #define JOY_EXCEPTION(A) JoyException(A) #endif #define cA(a) (sizeof(a)/sizeof(a[0])) class JoyException:public exception { HRESULT m_hRes; #ifdef _CHECKED String m_SourceFile; DWORD m_dwLine; #endif public: HRESULT GetResult(){return m_hRes;}; JoyException( #ifdef _CHECKED LPCTSTR lpSourceFile,DWORD dwLine, #endif HRESULT hRes); }; JoyException::JoyException( #ifdef _CHECKED LPCTSTR lpSourceFile,DWORD dwLine, #endif HRESULT hRes) { m_hRes=hRes; #ifdef _CHECKED m_SourceFile=lpSourceFile; m_dwLine=dwLine; #endif } int __cdecl my_new_handler(size_t) { throw JOY_EXCEPTION(E_OUTOFMEMORY); return 0; } template class AutoRelease { p m_p; public: AutoRelease(){m_p=NULL;}; ~AutoRelease(){Clear();}; void Clear(){ ULONG nRef=-1; if(m_p) { nRef=m_p->Release();//If last ptr, nRef falls to 0. }; m_p=NULL;}; AutoRelease(const AutoRelease

&R) {m_p=R.m_p;m_p->AddRef();}; AutoRelease

&operator=(const AutoRelease

&R) {m_p=R.m_p;m_p->AddRef();return *this;}; AutoRelease

&operator=(p ptr) {m_p=ptr;if(m_p)m_p->AddRef();return *this;}; p operator->(){return m_p;}; operator p&(){return m_p;}; operator p*(){return &m_p;}; }; typedef AutoRelease LPDIRECTINPUT_AR; typedef AutoRelease LPDIRECTINPUTDEVICE_AR; typedef AutoRelease LPDIRECTINPUTJOYCONFIG_AR; template class AutoDeleteArray { p m_p; public: AutoDeleteArray(){m_p=NULL;}; AutoDeleteArray(const p P){m_p=P;}; ~AutoDeleteArray(){delete[] m_p;}; p operator=(const p P){m_p=P;return m_p;}; p operator->(){return m_p;}; operator p&(){return m_p;}; operator p*(){return &m_p;}; }; enum EStatus{EConnected,ENotConnected,EUnknown}; //ISSUE-2001/03/29-timgill Should use predefined NULLGUID const GUID NULLGUID; class CCore; class CDIDev { friend BOOL CALLBACK DIEnumDevicesProc( const DIDEVICEINSTANCE * lpddi,LPVOID pvRef); LPDIRECTINPUTDEVICE_AR m_pDID; DIDEVICEINSTANCE m_DIDevInst; DIDEVCAPS_DX3 m_DIDevCaps; DIJOYCONFIG m_DIJoyCfg; DWORD m_dwId; bool m_bInitialized; CCore *m_pCore; public: CDIDev(){m_bInitialized=false;}; DWORD Id(){return m_dwId;}; const GUID &InstGUID(){return m_DIDevInst.guidInstance;}; const GUID &PortGUID(){return m_DIJoyCfg.guidGameport;}; LPCTSTR InstName(){return m_DIDevInst.tszInstanceName;}; EStatus Status(){if(m_DIDevCaps.dwFlags&DIDC_ATTACHED)return EConnected;return ENotConnected;}; void Update(LPDIRECTINPUTJOYCONFIG8 pJoyCfg); HRESULT Rename(LPCTSTR pName); bool operator==(const GUID &G){if(InstGUID()==G)return true;return false;}; }; class CGprtDev { friend BOOL CALLBACK DIEnumJoyTypePr(LPCWSTR pwszTypeName,LPVOID pvRef); friend class CCore; String m_Name; DIJOYTYPEINFO m_Info; public: LPCTSTR TypeName(){return m_Name.data();}; LPCTSTR Name(){return m_Info.wszDisplayName;}; bool operator==(LPCTSTR pTypeName){if(m_Name==pTypeName)return true;return false;}; bool Rudder(){if(m_Info.hws.dwFlags&JOY_HWS_HASR)return true;return false;}; }; typedef list LISTDIDEV; typedef list LISTSTRING; typedef list LISTGPRTDEV; class CCore { friend HRESULT Properties(HMODULE hMod,HWND hWnd,CCore *pCore,DWORD dwId); friend BOOL CALLBACK DIEnumJoyTypePr(LPCWSTR pwszTypeName,LPVOID pvRef); friend class CDIDev; friend BOOL CALLBACK DIEnumDevicesProc(const DIDEVICEINSTANCE *lpddi,LPVOID pvRef); bool m_bAccess; bool m_bInitialized; virtual void UIUpdate(){}; LPDIRECTINPUT_AR m_pDI; LPDIRECTINPUTJOYCONFIG_AR m_pDIJoyCfg; int GetNextAvailableId(); bool FullJoyOemAccess(); public: LISTDIDEV m_ListDIDev; LISTSTRING m_GprtDrv; LISTGPRTDEV m_GprtBus; LISTGPRTDEV m_GprtDev; CCore(); void Initialize(HWND hWnd); void Update(); void UpdateType(); bool Access(){return m_bAccess;}; CDIDev *FindDIDev(GUID &G); HRESULT Remove(GUID &G); void Preferred(GUID &G); HRESULT AddDevice (LPCTSTR pTypeName,bool bRudder,LPCTSTR pGprtId,GUID &GOccupied); bool IsAutoDetectGprt(); bool IsAvailableVIDPID(String &VIDPIDName); bool DuplicateDeviceName(LPCTSTR pName); void AddCustomDevice(bool bJoy,bool bPad,bool bYoke,bool bCar, int nAxes,bool bZAxis,int nButtons,bool bHasPov,LPCTSTR pName, LPCTSTR pVIDPIDName); bool IsCustomDevice(LPCTSTR pTypeName); bool IsDeviceActive(LPCTSTR pTypeName); void DeleteType(LPCTSTR pTypeName); CGprtDev *FindGprtDev(LPCTSTR pTypeName); }; struct SEnumDev { LPDIRECTINPUT8 m_pDI; CCore *m_pCore; SEnumDev(LISTDIDEV &ListDIDev,LPDIRECTINPUT8 pDI,CCore *pCore) {m_pDI=pDI;m_pCore=pCore;}; }; /****************************************************************************** End of header ******************************************************************************/ /****************************************************************************** CDIDev ******************************************************************************/ HRESULT CDIDev::Rename(LPCTSTR pName) { if(!m_bInitialized) { throw JOY_EXCEPTION(E_FAIL); } if(!m_pCore->Access())return DIERR_INSUFFICIENTPRIVS; DIPROPSTRING DIPropString; ZeroMemory(&DIPropString,sizeof(DIPROPSTRING)); DIPropString.diph.dwSize=sizeof(DIPROPSTRING); DIPropString.diph.dwHeaderSize=sizeof(DIPROPHEADER); DIPropString.diph.dwHow=DIPH_DEVICE; wcsncpy(DIPropString.wsz,pName,MAX_PATH-1); DIPropString.wsz[MAX_PATH-1]=0; HRESULT hRes=m_pDID->SetProperty(DIPROP_INSTANCENAME,&DIPropString.diph); Update(m_pCore->m_pDIJoyCfg); return hRes; } void CDIDev::Update(LPDIRECTINPUTJOYCONFIG8 pJoyCfg) { HRESULT hRes=S_OK; ZeroMemory(&m_DIDevInst,sizeof(m_DIDevInst)); m_DIDevInst.dwSize=sizeof(m_DIDevInst); hRes=m_pDID->GetDeviceInfo(&m_DIDevInst); if(FAILED(hRes)) { throw JOY_EXCEPTION(hRes); } ZeroMemory(&m_DIDevCaps,sizeof(m_DIDevCaps)); m_DIDevCaps.dwSize=sizeof(m_DIDevCaps); hRes=m_pDID->GetCapabilities((LPDIDEVCAPS)&m_DIDevCaps); if(FAILED(hRes)) { throw JOY_EXCEPTION(hRes); } //Get Id. m_dwId=-1; DIPROPDWORD DIPropDW; ZeroMemory(&DIPropDW,sizeof(DIPropDW)); DIPropDW.diph.dwSize=sizeof(DIPROPDWORD); DIPropDW.diph.dwHeaderSize=sizeof(DIPROPHEADER); DIPropDW.diph.dwHow=DIPH_DEVICE; hRes=m_pDID->GetProperty(DIPROP_JOYSTICKID,&DIPropDW.diph); if(FAILED(hRes)) { throw JOY_EXCEPTION(hRes); } m_dwId=DIPropDW.dwData; //Get gameport. ZeroMemory(&m_DIJoyCfg,sizeof(m_DIJoyCfg)); m_DIJoyCfg.dwSize=sizeof(m_DIJoyCfg); hRes=pJoyCfg->GetConfig(m_dwId,&m_DIJoyCfg,DIJC_WDMGAMEPORT); if(FAILED(hRes)) { //throw JOY_EXCEPTION(hRes); } } /****************************************************************************** CCore ******************************************************************************/ BOOL CALLBACK DIEnumDevicesProc( const DIDEVICEINSTANCE *lpddi,LPVOID pvRef) { try { SEnumDev &ED=*(SEnumDev*)pvRef; CDIDev Dev; Dev.m_pCore=ED.m_pCore; HRESULT hRes=ED.m_pDI->CreateDevice(lpddi->guidInstance,Dev.m_pDID,NULL); if(FAILED(hRes)) { throw JOY_EXCEPTION(hRes); } Dev.Update(ED.m_pCore->m_pDIJoyCfg); Dev.m_bInitialized=true; ED.m_pCore->m_ListDIDev.push_back(Dev); } catch(JoyException E) { } catch(exception) { } return DIENUM_CONTINUE; } BOOL CALLBACK DIEnumJoyTypePr(LPCWSTR pwszTypeName,LPVOID pvRef) { try { HRESULT hRes=S_OK; String TN=pwszTypeName; SEnumDev &ED=*(SEnumDev*)pvRef; DIJOYTYPEINFO JoyInfo; ZeroMemory(&JoyInfo,sizeof(JoyInfo)); JoyInfo.dwSize=sizeof(JoyInfo); switch(ED.m_pCore->m_pDIJoyCfg->GetTypeInfo(pwszTypeName,&JoyInfo,DITC_REGHWSETTINGS)) { //Errors to continue with. case DIERR_NOTFOUND: return DIENUM_CONTINUE; //Errors to stop with. case DIERR_INVALIDPARAM: case DIERR_NOMOREITEMS: return DIENUM_STOP; } if(JoyInfo.hws.dwFlags&JOY_HWS_ISGAMEPORTBUS) { CGprtDev D; D.m_Name=TN; ZeroMemory(&D.m_Info,sizeof(D.m_Info)); D.m_Info.dwSize=sizeof(D.m_Info); DWORD dwFlags=DITC_CLSIDCONFIG|DITC_DISPLAYNAME; if(FAILED(ED.m_pCore->m_pDIJoyCfg->GetTypeInfo(D.m_Name.data(),&D.m_Info,dwFlags))) { throw JOY_EXCEPTION(hRes); } ED.m_pCore->m_GprtBus.push_back(D); } else if(!(JoyInfo.hws.dwFlags&JOY_HWS_AUTOLOAD)) { CGprtDev D; D.m_Name=TN; ZeroMemory(&D.m_Info,sizeof(D.m_Info)); D.m_Info.dwSize=sizeof(D.m_Info); DWORD dwFlags=DITC_REGHWSETTINGS|DITC_FLAGS1|DITC_HARDWAREID|DITC_CALLOUT|DITC_DISPLAYNAME; if(FAILED(ED.m_pCore->m_pDIJoyCfg->GetTypeInfo(D.m_Name.data(),&D.m_Info,dwFlags))) { throw JOY_EXCEPTION(hRes); } ED.m_pCore->m_GprtDev.push_back(D); } } catch(JoyException E) { } catch(exception) { } return DIENUM_CONTINUE; } CCore::CCore() { m_bAccess=false; m_bInitialized=false; } bool CCore::IsAutoDetectGprt() { if(!m_GprtDev.size())return false; if(m_GprtDev.front().m_Info.dwFlags1& JOYTYPE_NOAUTODETECTGAMEPORT)return false; return true; } int CCore::GetNextAvailableId() { if(!m_bInitialized)return -1; DIJOYCONFIG JoyCfg; ZeroMemory(&JoyCfg,sizeof(JoyCfg)); JoyCfg.dwSize=sizeof(JoyCfg); for(int i=0;iGetConfig(i,&JoyCfg,DIJC_REGHWCONFIGTYPE)) { case S_FALSE: case DIERR_NOMOREITEMS: case DIERR_NOTFOUND: case E_FAIL: return i; } } return -1; } bool CCore::FullJoyOemAccess() { LONG lRc; HKEY hk; bool bRc; lRc = RegOpenKeyEx(HKEY_LOCAL_MACHINE, REGSTR_PATH_JOYOEM, 0, KEY_ALL_ACCESS & ~WRITE_DAC & ~WRITE_OWNER, &hk); if( lRc == ERROR_SUCCESS ) { bRc = true; RegCloseKey(hk); } else { bRc = false; } return bRc; } HRESULT CCore::AddDevice(LPCTSTR pTypeName,bool bRudder,LPCTSTR pGprtId,GUID &GOccupied) { HRESULT hRes=S_OK; GOccupied=NULLGUID; if(!m_bInitialized)return E_FAIL; if(m_GprtDev.size()>=MAX_DEVICES)return E_FAIL; LISTGPRTDEV::iterator It; It=find(m_GprtDev.begin(),m_GprtDev.end(),pTypeName); if(It==m_GprtDev.end())return E_FAIL; CGprtDev *pGprtDev=&*It; int nId=GetNextAvailableId(); if(nId==-1)return DIERR_NOTFOUND; DIJOYCONFIG JoyCfg; ZeroMemory(&JoyCfg,sizeof(JoyCfg)); JoyCfg.dwSize=sizeof(JoyCfg); JoyCfg.hwc.hws=pGprtDev->m_Info.hws; JoyCfg.hwc.hws.dwFlags|=JOY_HWS_ISANALOGPORTDRIVER; if(bRudder) { JoyCfg.hwc.hws.dwFlags|=JOY_HWS_HASR; JoyCfg.hwc.dwUsageSettings|=JOY_US_HASRUDDER; } JoyCfg.hwc.dwUsageSettings|=JOY_US_PRESENT; //JoyCfg.hwc.dwType=nArrayID;WHY is this beeing set to index????????????????????????????????????????????????????????????????????????????????? wcsncpy(JoyCfg.wszCallout,pGprtDev->m_Info.wszCallout,sizeof(JoyCfg.wszCallout)/sizeof(JoyCfg.wszCallout[0])-1); wcsncpy(JoyCfg.wszType,pGprtDev->m_Name.data(),sizeof(JoyCfg.wszType)/sizeof(JoyCfg.wszType[0])-1); if(SUCCEEDED(hRes=m_pDIJoyCfg->Acquire())) { if(m_GprtBus.size()) { if(m_GprtBus.size()>1) { if(pGprtId) { String GId=pGprtId; LISTGPRTDEV::iterator It; It=find(m_GprtBus.begin(),m_GprtBus.end(),GId.data()); if(It!=m_GprtDev.end()) { JoyCfg.guidGameport=It->m_Info.clsidConfig; } } } else { JoyCfg.guidGameport=m_GprtBus.front().m_Info.clsidConfig; } } if(FAILED(hRes=m_pDIJoyCfg->SetConfig(nId,&JoyCfg,DIJC_REGHWCONFIGTYPE|DIJC_CALLOUT))) { m_pDIJoyCfg->Unacquire(); if(hRes==E_ACCESSDENIED) GOccupied=JoyCfg.guidGameport; return hRes; } else { //Fix #55524. if(SUCCEEDED(m_pDIJoyCfg->GetConfig(nId,&JoyCfg,DIJC_REGHWCONFIGTYPE))) { if(!(JoyCfg.hwc.dwUsageSettings&JOY_US_PRESENT)) { JoyCfg.hwc.dwUsageSettings|=JOY_US_PRESENT; JoyCfg.hwc.hwv.dwCalFlags|=0x80000000; JoyCfg.hwc.hws.dwFlags|=JOY_HWS_ISANALOGPORTDRIVER; m_pDIJoyCfg->SetConfig(nId,&JoyCfg,DIJC_REGHWCONFIGTYPE); } } //End of fix #55524. } m_pDIJoyCfg->Unacquire(); } Update(); UpdateType(); return hRes; } void CCore::Initialize(HWND hWnd) { if((LPDIRECTINPUTJOYCONFIG8)m_pDIJoyCfg) m_pDIJoyCfg->Release(); m_pDIJoyCfg=NULL; if((LPDIRECTINPUT8)m_pDI) m_pDI->Release(); m_pDI=NULL; HMODULE hM=GetModuleHandle(NULL); if(!hM) { throw JOY_EXCEPTION(E_FAIL); } HRESULT hRes=DirectInput8Create(hM,DIRECTINPUT_VERSION, IID_IDirectInput8,(LPVOID*)&m_pDI,NULL); if(FAILED(hRes)) { throw JOY_EXCEPTION(hRes); } hRes=m_pDI->QueryInterface(IID_IDirectInputJoyConfig8,(LPVOID*)&m_pDIJoyCfg); if(hRes!=DI_OK) { throw JOY_EXCEPTION(hRes); } hRes=m_pDIJoyCfg->SetCooperativeLevel(hWnd,DISCL_EXCLUSIVE|DISCL_BACKGROUND); if(hRes!=DI_OK) { throw JOY_EXCEPTION(hRes); } m_bAccess = FullJoyOemAccess(); m_bInitialized=true; } void CCore::Update() { HRESULT hRes; if(!m_bInitialized) { throw JOY_EXCEPTION(E_FAIL); } m_ListDIDev.clear(); SEnumDev ED(m_ListDIDev,m_pDI,this); hRes=m_pDI->EnumDevices(DI8DEVCLASS_GAMECTRL,DIEnumDevicesProc,&ED,DIEDFL_ALLDEVICES); if(FAILED(hRes)) { //EnumDevices goes wrong ; //throw JOY_EXCEPTION(hRes); } UIUpdate(); } void CCore::UpdateType() { if(!m_bInitialized) { throw JOY_EXCEPTION(E_FAIL); } m_GprtDrv.clear(); m_GprtBus.clear(); m_GprtDev.clear(); HRESULT hRes=S_OK; SEnumDev ED(m_ListDIDev,m_pDI,this); hRes=m_pDIJoyCfg->EnumTypes(DIEnumJoyTypePr,&ED); if(FAILED(hRes)) { throw JOY_EXCEPTION(hRes); } UIUpdate(); } CDIDev *CCore::FindDIDev(GUID &Guid) { LISTDIDEV::iterator It; It=find(m_ListDIDev.begin(),m_ListDIDev.end(),Guid); if(It==m_ListDIDev.end())return NULL; return &*It; } HRESULT CCore::Remove(GUID &Guid) { if(!m_bInitialized) { throw JOY_EXCEPTION(E_FAIL); } CDIDev *pDev=FindDIDev(Guid); if(!pDev)return E_FAIL; HRESULT hRes; if(FAILED(hRes=m_pDIJoyCfg->Acquire()))return hRes; if(FAILED(hRes=m_pDIJoyCfg->DeleteConfig(pDev->Id()))) { m_pDIJoyCfg->Unacquire(); return hRes; } m_pDIJoyCfg->SendNotify(); m_pDIJoyCfg->Unacquire(); return S_OK; } #define DIJC_ALL DIJC_REGHWCONFIGTYPE|DIJC_CALLOUT|DIJC_WDMGAMEPORT|DIJC_GAIN|DIJC_GUIDINSTANCE void CCore::Preferred(GUID &G) { if(!m_bInitialized) { throw JOY_EXCEPTION(E_FAIL); } //Set Id of preferred device to 0. //Find Id of device to be set to 0. CDIDev *pDev=FindDIDev(G); if(!pDev)return; int nId=pDev->Id(); if(nId==0)//Already preferred. return; if(SUCCEEDED(m_pDIJoyCfg->Acquire())) { //We could call SetConfig only once and DInput on NT or Whistler should //swap Id-s of two devices. However, it will not work if gameport device //is unplugged, so we still must swap by salling SetConfig twice. DIJOYCONFIG OldId0; ZeroMemory(&OldId0,sizeof(OldId0)); OldId0.dwSize=sizeof(OldId0); bool bOldId0=true; HRESULT hRes = m_pDIJoyCfg->GetConfig(0,&OldId0,DIJC_ALL); if(hRes==DIERR_NOTFOUND||hRes==S_FALSE) bOldId0=false; DIJOYCONFIG NewId0; ZeroMemory(&NewId0,sizeof(NewId0)); NewId0.dwSize=sizeof(NewId0); bool bNewId0=true; hRes=m_pDIJoyCfg->GetConfig(nId,&NewId0,DIJC_ALL); if(hRes==DIERR_NOTFOUND||hRes==S_FALSE) bNewId0=false; if(bOldId0) m_pDIJoyCfg->SetConfig(nId,&OldId0,DIJC_ALL); else //We must still delete because GetConfig could fail for other //reasons than device with Id 0 not present. m_pDIJoyCfg->DeleteConfig(0); if(bNewId0) m_pDIJoyCfg->SetConfig(0,&NewId0,DIJC_ALL); m_pDIJoyCfg->SendNotify(); m_pDIJoyCfg->Unacquire(); } Update(); } //Partialy copied from old joy.cpl. //I strongly suspect this is not documented anywhere. bool CCore::IsAvailableVIDPID(String &VIDPIDName) { if(!m_bInitialized) { throw JOY_EXCEPTION(E_FAIL); } HRESULT hRes=m_pDIJoyCfg->Acquire(); if(FAILED(hRes))throw JOY_EXCEPTION(hRes); //Make the VID/PID to compare from the following formula: //VID_045e&PID_100+JOY_HW_LASTENTRY to 100+JOY_HW_LASTENTRY+0xf TCHAR Type[18]; _tcsncpy(Type,_T("VID_045E&PID_0100"),18); Type[17] = 0; const WCHAR Lookup[]=_T("0123456789ABCDEF"); int i=JOY_HW_LASTENTRY; do { if(i<0x10) { Type[16]=Lookup[i]; } else { Type[15]=Lookup[1]; Type[16]=Lookup[i%0x10]; } i++; HKEY hKey; if(FAILED(m_pDIJoyCfg->OpenTypeKey(Type,KEY_READ,&hKey))) break; RegCloseKey(hKey); } while(i<(JOY_HW_LASTENTRY+0x11)); m_pDIJoyCfg->Unacquire(); if(i<0x1d) { VIDPIDName=Type; return true; } return false; } CGprtDev *CCore::FindGprtDev(LPCTSTR pTypeName) { if(!pTypeName)return NULL; if(!m_bInitialized) { throw JOY_EXCEPTION(E_FAIL); } for(LISTGPRTDEV::iterator It=m_GprtDev.begin(); It!=m_GprtDev.end();It++) { if(It->m_Name==pTypeName) return &(*It); } return NULL; } bool CCore::IsCustomDevice(LPCTSTR pTypeName) { if(!pTypeName)return false; if(!m_bInitialized) { throw JOY_EXCEPTION(E_FAIL); } if(pTypeName[0]==_T('#'))return false;//Standard type. CGprtDev *pDevType=FindGprtDev(pTypeName); if(!pDevType) //This should never happend, but just in case. throw JOY_EXCEPTION(E_FAIL); if(!pDevType->m_Info.wszHardwareId[0]) { if(!pDevType->m_Info.wszCallout[0]) return true; } else { TCHAR AnalogRoot[]=_T("gameport\\vid_045e&pid_01"); //Test if it is predefined custom. Do not delete. TCHAR C=pDevType->m_Info.wszHardwareId[(sizeof(AnalogRoot)/ sizeof(AnalogRoot[0]))-1]; if((C==_T('f'))||(C==_T('F'))) return false; //Now test if it is custom. if(!_tcsnicmp(pDevType->m_Info.wszHardwareId,AnalogRoot, (sizeof(AnalogRoot)/sizeof(AnalogRoot[0]))-1)) return true; } return false; } void CCore::DeleteType(LPCTSTR pTypeName) { if(!pTypeName)return; if(!m_bInitialized) { throw JOY_EXCEPTION(E_FAIL); } HRESULT hRes=m_pDIJoyCfg->Acquire(); if(FAILED(hRes))throw JOY_EXCEPTION(hRes); m_pDIJoyCfg->DeleteType(pTypeName); m_pDIJoyCfg->Unacquire(); UpdateType(); } bool CCore::IsDeviceActive(LPCTSTR pTypeName) { if(!pTypeName)return false; if(!m_bInitialized) { throw JOY_EXCEPTION(E_FAIL); } for(LISTDIDEV::iterator It=m_ListDIDev.begin(); It!=m_ListDIDev.end();It++) { DIJOYCONFIG JoyCfg; ZeroMemory(&JoyCfg,sizeof(JoyCfg)); JoyCfg.dwSize=sizeof(JoyCfg); if(SUCCEEDED(m_pDIJoyCfg->GetConfig(It->Id(),&JoyCfg, DIJC_REGHWCONFIGTYPE))) { if(!_tcscmp(JoyCfg.wszType,pTypeName)) return true; } } return false; } bool CCore::DuplicateDeviceName(LPCTSTR pName) { if(!m_bInitialized) { throw JOY_EXCEPTION(E_FAIL); } for(LISTGPRTDEV::iterator It=m_GprtDev.begin(); It!=m_GprtDev.end();It++) { if(!_tcsncmp(pName,It->Name(), (sizeof(It->m_Info.wszDisplayName)/ sizeof(It->m_Info.wszDisplayName[0]))-1)) return true; } return false; } void CCore::AddCustomDevice(bool bJoy,bool bPad,bool bYoke,bool bCar, int nAxes,bool bZAxis,int nButtons,bool bHasPov,LPCTSTR pName, LPCTSTR pVIDPIDName) { if(!m_bInitialized) { throw JOY_EXCEPTION(E_FAIL); } String VIDPIDName=_T("GamePort\\"); VIDPIDName+=pVIDPIDName; HRESULT hRes=m_pDIJoyCfg->Acquire(); if(FAILED(hRes))throw JOY_EXCEPTION(hRes); DIJOYTYPEINFO JTI; ZeroMemory(&JTI,sizeof(JTI)); JTI.dwSize=sizeof(JTI); int nCh=sizeof(JTI.wszDisplayName)/ sizeof(JTI.wszDisplayName[0]); _tcsncpy(JTI.wszDisplayName,pName,nCh); JTI.wszDisplayName[nCh-1]=0; JTI.hws.dwNumButtons=nButtons; if(nAxes==3) { if(bZAxis) JTI.hws.dwFlags|=JOY_HWS_HASZ; else JTI.hws.dwFlags|=JOY_HWS_HASR; } else if(nAxes==4) { JTI.hws.dwFlags|=JOY_HWS_HASR|JOY_HWS_HASZ; } if(bHasPov) JTI.hws.dwFlags|=JOY_HWS_HASPOV|JOY_HWS_POVISBUTTONCOMBOS; if(!bJoy) { if(bPad) { JTI.hws.dwFlags|=JOY_HWS_ISGAMEPAD; } else if(bCar) { JTI.hws.dwFlags|=JOY_HWS_ISCARCTRL; } else { JTI.hws.dwFlags|=JOY_HWS_ISYOKE; } } nCh=sizeof(JTI.wszHardwareId)/ sizeof(JTI.wszHardwareId[0]); _tcsncpy(JTI.wszHardwareId,VIDPIDName.data(),nCh); JTI.wszDisplayName[nCh-1]=0; hRes=m_pDIJoyCfg->SetTypeInfo(pVIDPIDName,&JTI, DITC_DISPLAYNAME|DITC_CLSIDCONFIG| DITC_REGHWSETTINGS|DITC_HARDWAREID,NULL); m_pDIJoyCfg->Unacquire(); if(FAILED(hRes))throw JOY_EXCEPTION(hRes); UpdateType(); } /****************************************************************************** UI ******************************************************************************/ /****************************************************************************** UI header ******************************************************************************/ class CDlgProcHandler//this is not in CDlg because we want to reuse for property sheets... { protected: HWND m_hWnd; HMODULE m_hModule; static INT_PTR CALLBACK DialogProc (HWND hwndDlg,UINT uMsg,WPARAM wParam,LPARAM lParam); virtual INT_PTR DialogProc(UINT uMsg,WPARAM wParam,LPARAM lParam); virtual BOOL InitDialog(HWND hFocus,LPARAM lParam){return TRUE;}; virtual BOOL Timer(WPARAM wTimerID){return FALSE;}; virtual INT_PTR Command(WORD wNotifyCode,WORD wID,HWND hwndCtl); virtual INT_PTR Notify(int idCtrl,LPNMHDR pnmh){return 0;}; HWND HDlgItem(int nIDDlgItem){return GetDlgItem(m_hWnd,nIDDlgItem);}; public: CDlgProcHandler(){m_hWnd=NULL;m_hModule=NULL;}; }; class CDlg:public CDlgProcHandler { protected: virtual INT_PTR DialogProc(UINT uMsg,WPARAM wParam,LPARAM lParam); virtual INT_PTR Command(WORD wNotifyCode,WORD wID,HWND hwndCtl); public: int Dlg(WORD wID,HMODULE hModule,HWND hParent); }; int CDlg::Dlg(WORD wID,HMODULE hModule,HWND hParent) { m_hModule=hModule; return DialogBoxParam(hModule,MAKEINTRESOURCE(wID),hParent, CDlgProcHandler::DialogProc,(LPARAM)this); } typedef list LISTGUID; class CMainDlg; class CPreferredDlg:public CDlg { LISTGUID m_ListCtrl; bool m_bBlockUpdate; CCore *m_pCore; CMainDlg *m_pMainDlg; virtual BOOL InitDialog(HWND hFocus,LPARAM lParam); virtual INT_PTR Command(WORD wNotifyCode,WORD wID,HWND hwndCtl); void Preferred(); INT_PTR Notify(int idCtrl,LPNMHDR pnmh); public: CPreferredDlg(CMainDlg *pMainDlg,CCore *pCore) {m_pMainDlg=pMainDlg;m_pCore=pCore;m_bBlockUpdate=false;}; void Update(); }; class CAddDlg:public CDlg { CCore *m_pCore; // CMainDlg *m_pMainDlg; LISTSTRING m_ListCtrl; LISTSTRING m_GprtListCtrl; bool m_bBlockUpdate; BOOL InitDialog(HWND hFocus,LPARAM lParam); INT_PTR Command(WORD wNotifyCode,WORD wID,HWND hwndCtl); void AddDev(); INT_PTR DialogProc(UINT uMsg,WPARAM wParam,LPARAM lParam); public: CAddDlg(/*CMainDlg *pMainDlg,*/CCore *pCore) {/*m_pMainDlg=pMainDlg;*/m_pCore=pCore;m_bBlockUpdate=false;}; void Update(); }; class CCustomDlg:public CDlg { CCore *m_pCore; String m_VIDPIDName; BOOL InitDialog(HWND hFocus,LPARAM lParam); INT_PTR Command(WORD wNotifyCode,WORD wID,HWND hwndCtl); public: CCustomDlg(CCore *pCore){m_pCore=pCore;}; LPCTSTR GetVIDPIDName(){return m_VIDPIDName.data();}; }; class CMainDlg:public CDlg { LISTGUID m_ListCtrl; bool m_bBlockUpdate; CCore *m_pCore; CPreferredDlg *m_pPrefDlg; CAddDlg *m_pAddDlg; bool m_bEditingName; virtual BOOL InitDialog(HWND hFocus,LPARAM lParam); virtual BOOL Timer(WPARAM wTimerID); virtual INT_PTR Command(WORD wNotifyCode,WORD wID,HWND hwndCtl); INT_PTR DialogProc(UINT uMsg,WPARAM wParam,LPARAM lParam); INT_PTR Notify(int idCtrl,LPNMHDR pnmh); void Remove(); void Prop(); protected: CMainDlg(){m_pCore=NULL;m_bBlockUpdate=false;m_pPrefDlg=NULL;m_pAddDlg=NULL;m_bEditingName=false;}; void ConnectUI(CCore *pCore){m_pCore=pCore;}; void Update(); void CoreUpdate(); }; class CUpdate { bool *m_pbBlockUpdate; public: CUpdate(bool *pbBlockUpdate) {m_pbBlockUpdate=pbBlockUpdate;*m_pbBlockUpdate=true;}; ~CUpdate(){*m_pbBlockUpdate=false;}; }; /****************************************************************************** End of UI header ******************************************************************************/ #define DEVICE_COLUMN 0 #define STATUS_COLUMN 1 LPTSTR Insert1String(LPCTSTR pS,LPCTSTR pI) { LPTSTR pR=new TCHAR[_tcslen(pS)+_tcslen(pI)+1]; wsprintf(pR,pS,pI); return pR; } LPTSTR Insert2Strings(LPCTSTR pS,LPCTSTR pI1,LPCTSTR pI2) { LPTSTR pR=new TCHAR[_tcslen(pS)+_tcslen(pI1)+_tcslen(pI2)+1]; wsprintf(pR,pS,pI1,pI2); return pR; } void MessageBox(HWND hWnd,HINSTANCE hInstance,UINT uTitleID,UINT uMsgID) { TCHAR Title[128]; TCHAR Msg[256]; LoadString(hInstance,uTitleID, Title, cA(Title)); LoadString(hInstance,uMsgID, Msg, cA(Msg)); UINT uRTL = (GetWindowLongPtr(hWnd,GWL_EXSTYLE) & WS_EX_LAYOUTRTL) ? MB_RTLREADING : 0; MessageBox(hWnd,Msg,Title,MB_ICONHAND|MB_OK|MB_APPLMODAL|uRTL); } void LVSetItem(HWND hCtrl,int nItem,int nSubItem, LPCTSTR lpStr) { LVITEM Item; ZeroMemory(&Item,sizeof(Item)); Item.mask=LVIF_TEXT; Item.iItem=nItem; Item.iSubItem=nSubItem; Item.cchTextMax=lstrlen(lpStr); Item.pszText=(LPTSTR)lpStr; SendMessage(hCtrl,LVM_SETITEM,0,(LPARAM)(const LPLVITEM)&Item); } void LVInsertItem(HWND hCtrl,int nItem,int nSubItem,LPCTSTR lpStr,LPARAM lData) { LVITEM Item; ZeroMemory(&Item,sizeof(Item)); Item.mask=LVIF_TEXT|LVIF_PARAM; Item.iItem=nItem; Item.cchTextMax=lstrlen(lpStr); Item.pszText=(LPTSTR)lpStr; Item.lParam=lData; SendMessage(hCtrl,LVM_INSERTITEM,0,(LPARAM)(const LPLVITEM)&Item); } void *LVGetItemDataPtr(HWND hCtrl,int nItem) { LVITEM Item; ZeroMemory(&Item,sizeof(LVITEM)); Item.mask=LVIF_PARAM; Item.iItem=nItem; if(SendMessage(hCtrl,LVM_GETITEM,0,(LPARAM)(LPLVITEM)&Item)) return(void*)Item.lParam; return NULL; } const GUID &LVGetItemGUID(HWND hCtrl,int nItem) { if(nItem<0)return NULLGUID; GUID *pG=(GUID*)LVGetItemDataPtr(hCtrl,nItem); if(pG)return *pG; return NULLGUID; } int LVFindGUIDIndex(HWND hCtrl,GUID &G) { int nCnt=ListView_GetItemCount(hCtrl); for(int i=0;im_hWnd=hwndDlg; } if( pH->m_hWnd == hwndDlg ) { return pH->DialogProc(uMsg,wParam,lParam); } } return FALSE; } catch(JoyException E) { if(pH) { if(uMsg==WM_INITDIALOG) { EndDialog(pH->m_hWnd,IDCANCEL); } } } catch(...) { if(pH && !IsBadReadPtr(pH, sizeof(CDlgProcHandler))) { EndDialog(pH->m_hWnd, IDCANCEL); } //should report error here, and keep going. } if(uMsg==WM_INITDIALOG) { return TRUE; } return FALSE; } /****************************************************************************** CDlg ******************************************************************************/ INT_PTR CDlg::Command(WORD wNotifyCode,WORD wID,HWND hwndCtl) { switch(wID) { case IDOK: if(!(wNotifyCode&~1)) EndDialog(m_hWnd,IDOK); return 0; case IDCANCEL: if(!(wNotifyCode&~1)) EndDialog(m_hWnd,IDCANCEL); return 0; } return CDlgProcHandler::Command(wNotifyCode,wID,hwndCtl); }; INT_PTR CDlg::DialogProc(UINT uMsg,WPARAM wParam,LPARAM lParam) { switch(uMsg) { case WM_CLOSE: EndDialog(m_hWnd,0); return 0; } return CDlgProcHandler::DialogProc(uMsg,wParam,lParam); } /****************************************************************************** Main dialog CMainDlg ******************************************************************************/ void CMainDlg::Remove() { { if(!m_pCore->Access()) { MessageBox(m_hWnd,m_hModule,IDS_USER_MODE_TITLE,IDS_USER_MODE); return; } HWND hListCtrl=HDlgItem(IDC_LIST_DEVICE); if(hListCtrl) { int nSelDev=LVGetSel(hListCtrl); if(nSelDev<0)return; GUID G=LVGetItemGUID(hListCtrl,nSelDev); CDIDev *pDev=m_pCore->FindDIDev(G); if(!pDev) { return; } TCHAR AreSure[256]; LoadString(m_hModule,IDS_GEN_AREYOUSURE, AreSure, cA(AreSure)); LPTSTR pT = Insert1String(AreSure,pDev->InstName()); lstrcpy(AreSure, pT); delete[] pT; TCHAR Title[128]; LoadString(m_hModule,IDS_GEN_AREYOUSURE_TITLE, Title, cA(Title)); UINT uRTL = (GetWindowLongPtr(m_hWnd,GWL_EXSTYLE) & WS_EX_LAYOUTRTL) ? MB_RTLREADING : 0; if(IDYES!=MessageBox(m_hWnd,AreSure,Title,MB_ICONQUESTION|MB_YESNO|MB_APPLMODAL|uRTL)) { return; } if(m_pCore->Remove(G)==DIERR_UNSUPPORTED) { MessageBox(m_hWnd,m_hModule,IDS_GEN_AREYOUSURE_TITLE,IDS_GEN_NO_REMOVE_USB); } } } CoreUpdate(); } void OnHelp(LPHELPINFO pHelpInfo,HINSTANCE hInstance) { TCHAR FileName[256]; LoadString(hInstance,IDS_HELPFILENAME, FileName, cA(FileName)); if(pHelpInfo->iContextType==HELPINFO_WINDOW) WinHelp((HWND)pHelpInfo->hItemHandle,FileName,HELP_WM_HELP,(ULONG_PTR)gaHelpIDs); } INT_PTR CMainDlg::DialogProc(UINT uMsg,WPARAM wParam,LPARAM lParam) { switch(uMsg) { case WM_ACTIVATEAPP: CoreUpdate(); return 0; /* case WM_POWERBROADCAST: switch( wParam ) { return 0; case PBT_APMSUSPEND: // Suspend operation! KillTimer(hDlg, ID_MYTIMER); break; case PBT_APMRESUMESUSPEND: case PBT_APMRESUMECRITICAL: // Resume operation! SetActive(hDlg); break; } break;return 0;*/ case WM_DEVICECHANGE: CoreUpdate(); return 0; case WM_HELP: OnHelp((LPHELPINFO)lParam,m_hModule); return 0; /* nFlags &= ~ON_PAGE; KillTimer(hDlg, ID_MYTIMER); OnContextMenu(wParam, lParam); nFlags |= ON_PAGE; SetTimer(hDlg, ID_MYTIMER, POLLRATE, 0); return(1); return 0;??? */ case WM_SYSCOLORCHANGE: { HWND hListCtrl=HDlgItem(IDC_LIST_DEVICE); if(hListCtrl) { SendMessage(hListCtrl,WM_SYSCOLORCHANGE,0,0); } } return 0; } return CDlg::DialogProc(uMsg,wParam,lParam); } void CMainDlg::Prop() { HWND hListCtrl=HDlgItem(IDC_LIST_DEVICE); if(hListCtrl) { int nSelDev=LVGetSel(hListCtrl); if(nSelDev<0)return; GUID G=LVGetItemGUID(hListCtrl,nSelDev); CDIDev *pDev=m_pCore->FindDIDev(G); //ISSUE-2001/03/29-timgill internal error;SHOULD ASSERT HERE if(!pDev)return; //need to kill the timer before launching property sheet - see Whistler bug 260145 for details KillTimer(m_hWnd,1); switch(Properties(m_hModule,m_hWnd,m_pCore,pDev->Id())) { case E_NOINTERFACE: MessageBox(m_hWnd,m_hModule,IDS_INTERNAL_ERROR,IDS_NO_DIJOYCONFIG); break; default://Not handled for now or ever? break; }; //now update and re-set the timer m_pCore->Update(); SetTimer(m_hWnd,1,5000,NULL); } } INT_PTR CMainDlg::Command(WORD wNotifyCode,WORD wID,HWND hwndCtl) { switch(wID) { case IDC_BTN_ADV: if(!m_pCore->Access()) { MessageBox(m_hWnd,m_hModule,IDS_USER_MODE_TITLE,IDS_USER_MODE); } else { if(!m_pPrefDlg) { CPreferredDlg PrefDlg(this,m_pCore); m_pPrefDlg=&PrefDlg; PrefDlg.Dlg(IDD_ADV_CHANGE,m_hModule,m_hWnd); m_pPrefDlg=NULL; } } return 0; case IDC_BTN_REMOVE: Remove(); return 0; case IDC_BTN_ADD: if(!m_pCore->Access()) { MessageBox(m_hWnd,m_hModule,IDS_USER_MODE_TITLE,IDS_USER_MODE); } else { if(!m_pAddDlg) { CAddDlg AddDlg(m_pCore); m_pAddDlg=&AddDlg; AddDlg.Dlg(IDD_ADD,m_hModule,m_hWnd); m_pAddDlg=NULL; } } return 0; case IDC_BTN_TSHOOT: { TCHAR ExeBuff[MAX_PATH]; if( GetWindowsDirectory(ExeBuff,MAX_PATH) ) { TCHAR CmdBuff[256]; LoadString(m_hModule,IDS_TSHOOT_CMD, CmdBuff, cA(CmdBuff)); STARTUPINFO Si; PROCESS_INFORMATION Pi; ZeroMemory(&Si,sizeof(Si)); ZeroMemory(&Pi,sizeof(Pi)); Si.cb=sizeof(Si); // ISSUE-2000/12/20-MarcAnd Quick Fix to use HSS // In other places where HSS is used, STARTF_FORCEONFEEDBACK is not set // Changed IDS_TSHOOT_CMD from: "hh.exe joy.chm" // to "explorer.exe hcp://help/tshoot/tsInputDev.htm" // Need to make this OS specific to allow backprop to Win2k (or further) Si.dwFlags=STARTF_USESHOWWINDOW|STARTF_FORCEONFEEDBACK; Si.wShowWindow=SW_NORMAL; ExeBuff[MAX_PATH-1]=0; String Exe=ExeBuff; String Cmd=CmdBuff; if(Exe[Exe.size()-1]!=_T('\\')) { Exe+=_T('\\'); } Exe+=_T("explorer.exe"); Cmd=_T("\"")+Exe+_T("\"")+_T(" ")+Cmd; if(CreateProcess(Exe.data(),(LPTSTR)Cmd.data(),0,0,0,0,0,0,&Si,&Pi)) { CloseHandle(Pi.hThread); CloseHandle(Pi.hProcess); } } else { // something is wrong when calling GetWindowsDirectory ; } } return 0; case IDC_BTN_PROPERTIES: Prop(); return 0; } return CDlg::Command(wNotifyCode,wID,hwndCtl); }; INT_PTR CMainDlg::Notify(int idCtrl,LPNMHDR pnmh) { switch(pnmh->code ) { /* Keeping this just in case someone changes his/her mind soon. case LVN_BEGINLABELEDIT: { HWND hListCtrl=HDlgItem(IDC_LIST_DEVICE); if(!hListCtrl)return TRUE; if(!m_pCore->Access())return TRUE; PostMessage((HWND)::SendMessage(hListCtrl,LVM_GETEDITCONTROL,0,0),EM_SETLIMITTEXT,MAX_PATH-1,0); m_bEditingName=true; return(FALSE); } case LVN_ENDLABELEDIT: { m_bEditingName=false; HWND hListCtrl=HDlgItem(IDC_LIST_DEVICE); if(!hListCtrl) { CoreUpdate(); return FALSE; } HWND hCtrl=(HWND)SendMessage(hListCtrl,LVM_GETEDITCONTROL,0,0); if(hCtrl) { if(SendMessage(hCtrl,EM_GETMODIFY,0,0)) { int nLen=lstrlen(((NMLVDISPINFO*)pnmh)->item.pszText); if((nLen>(MAX_PATH-1))||(nLen==0)) MessageBeep(MB_ICONHAND); //Make sure the name is usable. else if(_tcschr(((NMLVDISPINFO*)pnmh)->item.pszText,TEXT('\\'))) MessageBox(m_hWnd,m_hModule,IDS_INVALID_NAME_TITLE,IDS_INVALID_NAME); else { int nSelDev=LVGetSel(hListCtrl); GUID SelGUID=LVGetItemGUID(hListCtrl,nSelDev); CDIDev *pSelDev=m_pCore->FindDIDev(SelGUID); if(SUCCEEDED(pSelDev->Rename(((NMLVDISPINFO *)pnmh)->item.pszText))) { CoreUpdate(); return TRUE; } else { MessageBox(m_hWnd,m_hModule,IDS_NO_RENAME_TITLE,IDS_NO_RENAME); } } } } CoreUpdate(); return FALSE; }*/ case LVN_KEYDOWN: switch(((LV_KEYDOWN*)pnmh)->wVKey) { case VK_DELETE: Remove(); return 0; case VK_F5: CoreUpdate(); return 0; } return 0; case LVN_ITEMCHANGED: if(!(((LPNMLISTVIEW)pnmh)->uOldState&LVIS_SELECTED)&& (((LPNMLISTVIEW)pnmh)->uNewState&LVIS_SELECTED)&& (((LPNMLISTVIEW)pnmh)->uChanged&LVIF_STATE)) Update(); return 0; case NM_DBLCLK: switch(idCtrl) { case IDC_LIST_DEVICE: Prop(); return 0; } return 0; } return 0; } void CMainDlg::CoreUpdate() { m_pCore->Update(); //KillTimer so if UI is updated for some other reason than WM_TIMER timer will be reset. //make sure nothing can fail between KillTimer and SetTimer. KillTimer(m_hWnd,1); SetTimer(m_hWnd,1,5000,NULL); } BOOL CMainDlg::InitDialog(HWND hFocus,LPARAM lParam) { SetTimer(m_hWnd,1,5000,NULL); m_pCore->Initialize(m_hWnd); //#wi315410. we need to decide... // m_pCore->UpdateType(); HWND hListCtrl=HDlgItem(IDC_LIST_DEVICE); if(hListCtrl) { SendMessage(hListCtrl,LVM_SETEXTENDEDLISTVIEWSTYLE,0,LVS_EX_FULLROWSELECT); RECT R; GetClientRect(hListCtrl,&R); int nWidth=(R.right>>2)*3; LVInsertColumn(hListCtrl,DEVICE_COLUMN,IDS_GEN_DEVICE_HEADING,nWidth,m_hModule); LVInsertColumn(hListCtrl,STATUS_COLUMN,IDS_GEN_STATUS_HEADING,R.right-nWidth,m_hModule); } CoreUpdate(); return TRUE; } BOOL CMainDlg::Timer(WPARAM wTimerID) { CoreUpdate(); return FALSE; } void CMainDlg::Update() { if(m_pPrefDlg)m_pPrefDlg->Update(); if(m_bEditingName)return;//Do not update this dialog when editing name. if(m_bBlockUpdate)return;//Some actions may send notify messages which then Update and overflow stack. CUpdate U(&m_bBlockUpdate); int nSelDev=-1; GUID SelGUID=NULLGUID; HWND hListCtrl=HDlgItem(IDC_LIST_DEVICE); if(hListCtrl) { nSelDev=LVGetSel(hListCtrl); SelGUID=LVGetItemGUID(hListCtrl,nSelDev); SendMessage(hListCtrl,WM_SETREDRAW,(WPARAM)FALSE,0); SendMessage(hListCtrl,LVM_DELETEALLITEMS,0,0); m_ListCtrl.clear();//Must be behind LVM_DELETEALLITEMS int nIndex=0; for(LISTDIDEV::iterator It=m_pCore->m_ListDIDev.begin(); It!=m_pCore->m_ListDIDev.end();It++) { GUID G=It->InstGUID(); m_ListCtrl.push_back(G); LVInsertItem(hListCtrl,nIndex,DEVICE_COLUMN, It->InstName(),(LPARAM)&m_ListCtrl.back()); TCHAR Status[256]; if(It->Status()==ENotConnected) { LoadString(m_hModule,IDS_GEN_STATUS_NOTCONNECTED, Status, cA(Status)); } else if(It->Status()==EConnected) { LoadString(m_hModule,IDS_GEN_STATUS_OK, Status, cA(Status)); } else { LoadString(m_hModule,IDS_GEN_STATUS_UNKNOWN, Status, cA(Status)); } LVSetItem(hListCtrl,nIndex,STATUS_COLUMN,Status); nIndex++; } nSelDev=LVFindGUIDIndex(hListCtrl,SelGUID); if(nSelDev>=0) { LVSetSel(hListCtrl,nSelDev); } else LVSetSel(hListCtrl,0); nSelDev=LVGetSel(hListCtrl); SendMessage(hListCtrl,WM_SETREDRAW,(WPARAM)TRUE,0); InvalidateRect(hListCtrl,NULL,TRUE); SelGUID=LVGetItemGUID(hListCtrl,nSelDev); } CDIDev *pSelDev=m_pCore->FindDIDev(SelGUID); //#wi315410. we need to decide... // HWND hAddBtn=HDlgItem(IDC_BTN_ADD); // if(hAddBtn) // { // BOOL bE=(m_pCore->m_GprtBus.size()>0)?TRUE:FALSE; // EnableWindow(hAddBtn,bE); // } HWND hRemBtn=HDlgItem(IDC_BTN_REMOVE); if(hRemBtn) { BOOL bE=(nSelDev>=0)?TRUE:FALSE; EnableWindow(hRemBtn,bE); } HWND hPropBtn=HDlgItem(IDC_BTN_PROPERTIES); if(hPropBtn) { BOOL bE=FALSE; if((nSelDev>=0)&&pSelDev) if(pSelDev->Status()==EConnected) bE=TRUE; EnableWindow(hPropBtn,bE); } } /****************************************************************************** Add dialog ******************************************************************************/ int CBGetCurSel(HWND hCtrl) { int i=ComboBox_GetCurSel(hCtrl); if(i==CB_ERR) i=-1; return i; } int CBGetCnt(HWND hCtrl) { int i=ComboBox_GetCount(hCtrl); if(i==CB_ERR) i=0; return i; } const GUID &CBGetItemGUID(HWND hCtrl,int iIndex) { LRESULT p=ComboBox_GetItemData(hCtrl,iIndex); if(p==CB_ERR)return NULLGUID; if(p) return *(GUID*)p; return NULLGUID; } int CBFindGUIDIndex(HWND hCtrl,const GUID &G) { int nCnt=ComboBox_GetCount(hCtrl); if(nCnt==CB_ERR)return -1; for(int i=0;idata(); return NULL; } int CBFindTypeNameIndex(HWND hCtrl,LPCTSTR pTypeName) { int nCnt=ComboBox_GetCount(hCtrl); if(nCnt==CB_ERR)return -1; String TN; if(pTypeName) TN=pTypeName; for(int i=0;idata(); return NULL; } int LBFindTypeNameIndex(HWND hCtrl,LPCTSTR pTypeName) { int nCnt=ListBox_GetCount(hCtrl); if(nCnt==LB_ERR)return -1; String TN; if(pTypeName) TN=pTypeName; for(int i=0;iUpdateType(); Update(); return TRUE; } void CAddDlg::Update() { if(m_bBlockUpdate)return;//Some actions may send notify messages which then Update and overflow stack. CUpdate U(&m_bBlockUpdate); if(!m_hWnd)return; //Update device list. int nSelDev=-1; String TypeName; HWND hListCtrl=HDlgItem(IDC_DEVICE_LIST); if(hListCtrl) { int nTopIndex=ListBox_GetTopIndex(hListCtrl); nSelDev=LBGetCurSel(hListCtrl); LPCTSTR pTypeName=LBGetItemTypeName(hListCtrl,nSelDev); if(pTypeName)TypeName=pTypeName; SetWindowRedraw(hListCtrl,FALSE); ListBox_ResetContent(hListCtrl); m_ListCtrl.clear();//Must be behind ListBox_ResetContent for(LISTGPRTDEV::iterator It=m_pCore->m_GprtDev.begin(); It!=m_pCore->m_GprtDev.end();It++) { String S=It->TypeName(); m_ListCtrl.push_back(S); int nIndex=ListBox_AddString(hListCtrl,It->Name()); ListBox_SetItemData(hListCtrl,nIndex,&m_ListCtrl.back()); } nSelDev=LBFindTypeNameIndex(hListCtrl,TypeName.data()); if(nSelDev>=0) ListBox_SetCurSel(hListCtrl,nSelDev); else ListBox_SetCurSel(hListCtrl,0); ListBox_SetTopIndex(hListCtrl,nTopIndex); SetWindowRedraw(hListCtrl,TRUE); InvalidateRect(hListCtrl,NULL,TRUE); nSelDev=LBGetCurSel(hListCtrl); } HWND hRudder=HDlgItem(IDC_JOY1HASRUDDER); if(hRudder) { BOOL bE=FALSE; if(nSelDev>=0) { LPCTSTR pTypeName=LBGetItemTypeName(hListCtrl,nSelDev); if(pTypeName) { LISTGPRTDEV::iterator It; It=find(m_pCore->m_GprtDev.begin(),m_pCore->m_GprtDev.end(),pTypeName); if(It!=m_pCore->m_GprtDev.end()) bE=It->Rudder()?FALSE:TRUE; } } EnableWindow(hRudder,bE); } //Update gameport list. nSelDev=-1; TypeName; HWND hListCtrlTitle=HDlgItem(IDC_GAMEPORT); hListCtrl=HDlgItem(IDC_GAMEPORTLIST); if(hListCtrl&&hListCtrlTitle) { SetWindowRedraw(hListCtrl,FALSE); SetWindowPos(hListCtrl,NULL,NULL,NULL,NULL,NULL, SWP_NOMOVE|SWP_NOSIZE|SWP_NOZORDER|SWP_HIDEWINDOW); //How many gameports. Gameport list only if more than 1. if(m_pCore->m_GprtBus.size()>1) { ShowWindow(hListCtrlTitle,SW_SHOWNA); nSelDev=CBGetCurSel(hListCtrl); LPCTSTR pTypeName=CBGetItemTypeName(hListCtrl,nSelDev); if(pTypeName)TypeName=pTypeName; ComboBox_ResetContent(hListCtrl); m_GprtListCtrl.clear();//Must be behind ComboBox_ResetContent for(LISTGPRTDEV::iterator It=m_pCore->m_GprtBus.begin(); It!=m_pCore->m_GprtBus.end();It++) { String S=It->TypeName(); m_GprtListCtrl.push_back(S); int nIndex=ComboBox_AddString(hListCtrl,It->Name()); ComboBox_SetItemData(hListCtrl,nIndex,&m_GprtListCtrl.back()); } nSelDev=CBFindTypeNameIndex(hListCtrl,TypeName.data()); if(nSelDev>=0) ComboBox_SetCurSel(hListCtrl,nSelDev); else ComboBox_SetCurSel(hListCtrl,0); SetWindowPos(hListCtrl,NULL,NULL,NULL,NULL,NULL, SWP_NOMOVE|SWP_NOSIZE|SWP_NOZORDER|SWP_SHOWWINDOW); } else { ShowWindow(hListCtrlTitle,SW_HIDE); } SetWindowRedraw(hListCtrl,TRUE); InvalidateRect(hListCtrl,NULL,TRUE); } HWND hCustomBtn=HDlgItem(IDC_CUSTOM); if(hCustomBtn) { BOOL bE=(m_pCore->m_GprtDev.size()m_GprtBus.front().TypeName(); } if(pTypeName&&pGprtTypeName) { GUID GOccupied=NULLGUID; HRESULT hRes=m_pCore->AddDevice(pTypeName,Button_GetCheck(hRudder)?true:false,pGprtTypeName,GOccupied); if(!SUCCEEDED(hRes)) switch(hRes) { case E_FAIL: break; case E_ACCESSDENIED: if(GOccupied!=NULLGUID) { //Find device which occupies the port. for(LISTDIDEV::iterator It=m_pCore->m_ListDIDev.begin();It!=m_pCore->m_ListDIDev.end();It++) { if(It->PortGUID()==GOccupied) { TCHAR Title[128]; LoadString(m_hModule,IDS_ADD_PORT_OCCUPIED, Title, cA(Title)); TCHAR Msg[256]; LoadString(m_hModule,IDS_ADD_PORT_MSGFORMAT, Msg, cA(Msg)); //Get gameport name. LPCTSTR pBus=_T(" "); LISTGPRTDEV::iterator It; It=find(m_pCore->m_GprtBus.begin(),m_pCore->m_GprtBus.end(),pGprtTypeName); if(It!=m_pCore->m_GprtBus.end()) pBus=It->Name(); //Get device name. LPCTSTR pDev=_T(" "); LISTDIDEV::iterator ItDN; for(ItDN=m_pCore->m_ListDIDev.begin();ItDN!=m_pCore->m_ListDIDev.end();ItDN++) if(ItDN->PortGUID()==GOccupied)break; if(ItDN!=m_pCore->m_ListDIDev.end()) pDev=ItDN->InstName(); LPTSTR pT = Insert2Strings(Msg,pDev,pBus); lstrcpy(Msg, pT); delete[] pT; UINT uRTL = (GetWindowLongPtr(m_hWnd,GWL_EXSTYLE) & WS_EX_LAYOUTRTL) ? MB_RTLREADING : 0; MessageBox(m_hWnd,Msg,Title,MB_ICONHAND|MB_OK|MB_APPLMODAL|uRTL); break; } } } break; case DIERR_DEVICEFULL: MessageBox(m_hWnd,m_hModule,IDS_GAMEPORT_OCCUPIED_TITLE,IDS_GAMEPORT_OCCUPIED); break; case DIERR_NOTFOUND: MessageBox(m_hWnd,m_hModule,IDS_NO_IDS_TITLE,IDS_NO_IDS); break; case DIERR_DEVICENOTREG: MessageBox(m_hWnd,m_hModule,IDS_NO_GAMENUM_TITLE,IDS_NO_GAMENUM); break; } } } EndDialog(m_hWnd,IDOK); } INT_PTR CAddDlg::Command(WORD wNotifyCode,WORD wID,HWND hwndCtl) { switch(wID) { case IDOK: AddDev(); return 0; case IDC_CUSTOM: { CCustomDlg CustomDlg(m_pCore); if(CustomDlg.Dlg(IDD_CUSTOM,m_hModule,m_hWnd)==IDOK) { Update(); //Now select new custom device in this dialog box. HWND hListCtrl=HDlgItem(IDC_DEVICE_LIST); if(hListCtrl) { int nSelDev=LBFindTypeNameIndex(hListCtrl,CustomDlg.GetVIDPIDName()); if(nSelDev>=0) { ListBox_SetCurSel(hListCtrl,nSelDev); } } } } return 0; case IDC_DEVICE_LIST: switch(wNotifyCode) { case LBN_DBLCLK: AddDev(); return 0; case LBN_SELCHANGE: Update(); return 0; } return 0; } return CDlg::Command(wNotifyCode,wID,hwndCtl); } INT_PTR CAddDlg::DialogProc(UINT uMsg,WPARAM wParam,LPARAM lParam) { switch(uMsg) { case WM_VKEYTOITEM: if(LOWORD(wParam)==VK_DELETE) { HWND hListCtrl=HDlgItem(IDC_DEVICE_LIST); if(hListCtrl) { int nSelDev=LBGetCurSel(hListCtrl); LPCTSTR pTypeName=LBGetItemTypeName(hListCtrl,nSelDev); if(pTypeName) { if(m_pCore->IsCustomDevice(pTypeName)) { if(!m_pCore->IsDeviceActive(pTypeName)) { CGprtDev *pDev=m_pCore->FindGprtDev(pTypeName); if(!pDev) { //This should never happend, but just in case. throw JOY_EXCEPTION(E_FAIL); } TCHAR S[128]; LoadString(m_hModule,IDS_GEN_AREYOUSURE, S, cA(S)); LPTSTR pT = Insert1String(S,pDev->Name()); lstrcpy(S, pT); delete[] pT; TCHAR Title[128]; LoadString(m_hModule,IDS_GEN_AREYOUSURE_TITLE, Title, cA(Title)); UINT uRTL = (GetWindowLongPtr(m_hWnd,GWL_EXSTYLE) & WS_EX_LAYOUTRTL) ? MB_RTLREADING : 0; if(MessageBox(m_hWnd,S,Title, MB_ICONQUESTION|MB_YESNO|MB_APPLMODAL|uRTL)==IDYES) { m_pCore->DeleteType(pTypeName); } } else { MessageBox(m_hWnd,m_hModule,IDS_GEN_AREYOUSURE_TITLE,IDS_NO_REMOVE); } } } } } else return -1; return 0; } return CDlg::DialogProc(uMsg,wParam,lParam); } /****************************************************************************** Custom dialog ******************************************************************************/ #define MAX_ANALOG_BUTTONS 4 #define MIN_ANALOG_AXIS 2 #define MAX_ANALOG_AXIS 4 #define MAX_STR_LEN 255 BOOL CCustomDlg::InitDialog(HWND hFocus,LPARAM lParam) { if(!m_pCore->IsAvailableVIDPID(m_VIDPIDName)) { MessageBox(m_hWnd,m_hModule,IDS_NO_NAME_TITLE,IDS_NOAVAILABLEVIDPID); EndDialog(m_hWnd,IDCANCEL); return TRUE; } HWND hButtons=HDlgItem(IDC_COMBO_BUTTONS); if(hButtons) { for(int i=0;i<=MAX_ANALOG_BUTTONS;i++) { TCHAR Str[32]; _sntprintf(Str,32,_T("%d"),i); Str[31]=0; ComboBox_InsertString(hButtons,i,Str); } ComboBox_SetCurSel(hButtons,MAX_ANALOG_BUTTONS); } HWND hAxis=HDlgItem(IDC_COMBO_AXIS); if(hAxis) { for(int i=MIN_ANALOG_AXIS;i<=MAX_ANALOG_AXIS;i++) { TCHAR Str[32]; _sntprintf(Str,32,_T("%d"),i); Str[31]=0; ComboBox_InsertString(hAxis,i-MIN_ANALOG_AXIS,Str); } ComboBox_SetCurSel(hAxis,0); } HWND hSpecJoy=HDlgItem(IDC_SPECIAL_JOYSTICK); if(hSpecJoy) Button_SetCheck(hSpecJoy,BST_CHECKED); HWND hEdit=HDlgItem(IDC_EDIT_NAME); if(hEdit) Edit_LimitText(hEdit,MAX_STR_LEN); HWND hHasZAxis=HDlgItem(IDC_HASZAXIS); if(hHasZAxis) Button_SetCheck(hHasZAxis,BST_CHECKED); return TRUE; } INT_PTR CCustomDlg::Command(WORD wNotifyCode,WORD wID,HWND hwndCtl) { switch(wID) { case IDOK: { HWND hJoy=HDlgItem(IDC_SPECIAL_JOYSTICK); HWND hYoke=HDlgItem(IDC_SPECIAL_YOKE); HWND hPad=HDlgItem(IDC_SPECIAL_PAD); HWND hCar=HDlgItem(IDC_SPECIAL_AUTO); HWND hAxis=HDlgItem(IDC_COMBO_AXIS); HWND hRudder=HDlgItem(IDC_HASRUDDER); HWND hZAxis=HDlgItem(IDC_HASZAXIS); HWND hButtons=HDlgItem(IDC_COMBO_BUTTONS); HWND hPov=HDlgItem(IDS_CUSTOM_HASPOV); HWND hEdit=HDlgItem(IDC_EDIT_NAME); if(hJoy&& hYoke&& hPad&& hCar&& hAxis&& hRudder&& hZAxis&& hButtons&& hPov&& hEdit)//Possible internal error. { TCHAR *pStr=NULL; bool bErr=false; int nLen=Edit_LineLength(hEdit,0);//Possible internal error. if(!nLen) { bErr=true; MessageBox(m_hWnd,m_hModule,IDS_NO_NAME_TITLE,IDS_NO_NAME); } else { pStr=new TCHAR[nLen+1]; if (pStr == NULL) return 0; //Internal error if(GetDlgItemText(m_hWnd,IDC_EDIT_NAME,pStr,nLen+1)!=nLen) return 0;//Internal error. if(_tcschr(pStr,_T('\\'))) { bErr=true; MessageBox(m_hWnd,m_hModule,IDS_NO_NAME_TITLE,IDS_INVALID_NAME); } else { if(m_pCore->DuplicateDeviceName(pStr)) { bErr=true; MessageBox(m_hWnd,m_hModule,IDS_NO_NAME_TITLE,IDS_DUPLICATE_TYPE); } } } if(bErr)//User entered invalid text for name. { SetFocus(m_hWnd); SetFocus(hEdit); Edit_SetSel(hEdit,0,-1); return 0; } m_pCore->AddCustomDevice( (Button_GetCheck(hJoy)==BST_CHECKED)?true:false, (Button_GetCheck(hPad)==BST_CHECKED)?true:false, (Button_GetCheck(hYoke)==BST_CHECKED)?true:false, (Button_GetCheck(hCar)==BST_CHECKED)?true:false, ComboBox_GetCurSel(hAxis)+MIN_ANALOG_AXIS, (Button_GetCheck(hZAxis)==BST_CHECKED)?true:false, ComboBox_GetCurSel(hButtons), (Button_GetCheck(hPov)==BST_CHECKED)?true:false, pStr, m_VIDPIDName.data()); if( pStr ) { delete[] pStr; } } } EndDialog(m_hWnd,IDOK); return 0; case IDC_COMBO_AXIS: if(wNotifyCode==CBN_SELCHANGE) { HWND hAxis=HDlgItem(IDC_COMBO_AXIS); if(hAxis) { UINT uShow=SWP_NOMOVE|SWP_NOSIZE|SWP_NOZORDER; if((ComboBox_GetCurSel(hAxis)+MIN_ANALOG_AXIS)==3)//If 3 axis selected. uShow|=SWP_SHOWWINDOW; else uShow|=SWP_HIDEWINDOW; HWND hHasZAxis=HDlgItem(IDC_HASZAXIS); if(hHasZAxis) { SetWindowPos(hHasZAxis,NULL,NULL,NULL,NULL,NULL,uShow); } HWND hHasRudder=HDlgItem(IDC_HASRUDDER); if(hHasRudder) { SetWindowPos(hHasRudder,NULL,NULL,NULL,NULL,NULL,uShow); } } } return 0; } return CDlg::Command(wNotifyCode,wID,hwndCtl); } /****************************************************************************** Preferred dialog ******************************************************************************/ void CPreferredDlg::Preferred() { HWND hListCtrl=HDlgItem(IDC_CHANGE_LIST); if(hListCtrl) { int nSelDev=CBGetCurSel(hListCtrl); GUID SelGUID=CBGetItemGUID(hListCtrl,nSelDev); if(SelGUID!=NULLGUID) m_pCore->Preferred(SelGUID); } EndDialog(m_hWnd,IDOK); } INT_PTR CPreferredDlg::Command(WORD wNotifyCode,WORD wID,HWND hwndCtl) { switch(wID) { case IDOK: Preferred(); return 0; } if(wNotifyCode==CBN_CLOSEUP) { Update(); return 0; } return CDlg::Command(wNotifyCode,wID,hwndCtl); } BOOL CPreferredDlg::InitDialog(HWND hFocus,LPARAM lParam) { Update(); HWND hListCtrl=HDlgItem(IDC_CHANGE_LIST); if(hListCtrl) { for(LISTDIDEV::iterator It=m_pCore->m_ListDIDev.begin(); It!=m_pCore->m_ListDIDev.end();It++) { if(It->Id()==0) { int nSelDev=CBFindGUIDIndex(hListCtrl,It->InstGUID()); if(nSelDev>=0) ComboBox_SetCurSel(hListCtrl,nSelDev); break; } } } return TRUE; } void CPreferredDlg::Update() { if(m_bBlockUpdate)return;//Some actions may send notify messages which then Update and overflow stack. CUpdate U(&m_bBlockUpdate); if(!m_hWnd)return; int nSelDev=-1; GUID SelGUID=NULLGUID; HWND hListCtrl=HDlgItem(IDC_CHANGE_LIST); if(hListCtrl) { if(ComboBox_GetDroppedState(hListCtrl))return;//No update when selecting preferred. int nCount=CBGetCnt(hListCtrl); nSelDev=CBGetCurSel(hListCtrl); SelGUID=CBGetItemGUID(hListCtrl,nSelDev); SetWindowRedraw(hListCtrl,FALSE); ComboBox_ResetContent(hListCtrl); m_ListCtrl.clear();//Must be behind ComboBox_ResetContent. int nId0Index=-1;//Index of preferred device. for(LISTDIDEV::iterator It=m_pCore->m_ListDIDev.begin(); It!=m_pCore->m_ListDIDev.end();It++) { GUID G=It->InstGUID(); m_ListCtrl.push_back(G); int nIndex=ComboBox_AddString(hListCtrl,It->InstName()); ComboBox_SetItemData(hListCtrl,nIndex,&m_ListCtrl.back()); if(It->Id()==0) nId0Index=nIndex; } int nNoneIndex=-1; if(nId0Index<0)//Only if there is no preferred device. { TCHAR None[256]; LoadString(m_hModule,IDS_NONE, None, cA(None)); nNoneIndex=ComboBox_AddString(hListCtrl,None); } if((!nCount)||//First update during init. (SelGUID==NULLGUID))//Or none is selected. { if(nId0Index>=0)//Preferred device was added. ComboBox_SetCurSel(hListCtrl,nId0Index); else//There is no preferred device. ComboBox_SetCurSel(hListCtrl,nNoneIndex); } else//List was not empty before update. Select same thing. { nSelDev=CBFindGUIDIndex(hListCtrl,SelGUID); if(nSelDev>=0) ComboBox_SetCurSel(hListCtrl,nSelDev); else//Selected device removed. { if(nId0Index>=0)//Then select original preferred device. ComboBox_SetCurSel(hListCtrl,nId0Index); else//Select none. ComboBox_SetCurSel(hListCtrl,nNoneIndex); } } SetWindowRedraw(hListCtrl,TRUE); InvalidateRect(hListCtrl,NULL,TRUE); } } INT_PTR CPreferredDlg::Notify(int idCtrl,LPNMHDR pnmh) { // switch(pnmh->code) // { /*case LVN_KEYDOWN: switch(((LV_KEYDOWN*)pnmh)->wVKey) { case VK_F5: CoreUpdate(); return 0; } return 0; case LVN_ITEMCHANGED: Update(); return 0;*/ /* case NM_DBLCLK: switch(pnmh->idFrom) { case IDC_CHANGE_LIST: Preferred(); return 0; } return 0;*/ // } return 0; } /****************************************************************************** Connect UI and core ******************************************************************************/ class CCP:public CCore,public CMainDlg { virtual void UIUpdate(){CMainDlg::Update();}; public: CCP(){ConnectUI((CCore*)this);}; }; /****************************************************************************** Entry point. ******************************************************************************/ #define MUTEX_NAME _T("$$$MS_GameControllers_Cpl$$$") void Core(HANDLE hModule,HWND hWnd) { static HWND hPrevHwnd=NULL; static HANDLE hMutex=CreateMutex(NULL,TRUE,MUTEX_NAME); if(GetLastError()==ERROR_ALREADY_EXISTS) { SetForegroundWindow(hPrevHwnd); } else { hPrevHwnd=hWnd; _PNH _old_handler; _old_handler = _set_new_handler(my_new_handler); if( SHFusionInitializeFromModuleID((HMODULE)hModule,124) ) { // While not initializing would only cause theming to be inactive, // a failure to initialize indicates a much worse problem so since // PREFIX warns (656863) that the return needs to be tested, abort // if the initialization fails. try { CCP CP; CP.Dlg(IDD_CPANEL,(HMODULE)hModule,hWnd); } catch(JoyException E) { } catch(exception) { } SHFusionUninitialize(); } _set_new_handler(_old_handler); ReleaseMutex(hMutex); CloseHandle(hMutex); } } /****************************************************************************** Propertiy ******************************************************************************/ class CoInit { HRESULT m_hRes; public: ~CoInit() { if(SUCCEEDED(m_hRes)) { CoFreeUnusedLibraries();//Free gcdef.dll. CoUninitialize(); } }; CoInit(){m_hRes=CoInitialize(NULL);}; operator HRESULT(){return m_hRes;}; }; typedef HPROPSHEETPAGE *LPHPROPSHEETPAGE; typedef AutoDeleteArray LPHPROPSHEETPAGE_ADAR; //FUN! FUN! FUN! FUN! //This is certain funny code written by some other, quite funny people, //so I will put it in the funny code section at the end of the otherwise //serious file. //tmarkoc cleaned it up. No more memory/interface/freelib leaks, alloc failures handled, no unneccessary allocations. /* #ifndef PPVOID typedef LPVOID* PPVOID; #endif //WHAT IS THIS FOR???????????????????????????????????????????????????????? class CDIGameCntrlPropSheet : public IDIGameCntrlPropSheet { private: DWORD m_cProperty_refcount; public: CDIGameCntrlPropSheet(void); ~CDIGameCntrlPropSheet(void); // IUnknown methods STDMETHODIMP QueryInterface(REFIID, PPVOID); STDMETHODIMP_(ULONG) AddRef(void); STDMETHODIMP_(ULONG) Release(void); // CImpIServerProperty methods STDMETHODIMP GetSheetInfo(LPDIGCSHEETINFO *lpSheetInfo); STDMETHODIMP GetPageInfo (LPDIGCPAGEINFO *lpPageInfo ); STDMETHODIMP SetID(USHORT nID); STDMETHODIMP_(USHORT) GetID(void); };*/ //typedef CDIGameCntrlPropSheet *LPCDIGAMECNTRLPROPSHEET; typedef IDIGameCntrlPropSheet *LPCDIGAMECNTRLPROPSHEET; typedef AutoRelease LPCDIGAMECNTRLPROPSHEET_AR; HRESULT Properties(HMODULE hMod,HWND hWnd,CCore *pCore,DWORD dwId) { // ASSERT(IsWindow(hWnd)); CLSID clsidPropSheet=CLSID_LegacyServer; //Get type name. DIJOYCONFIG DIJoyCfg; ZeroMemory(&DIJoyCfg,sizeof(DIJoyCfg)); DIJoyCfg.dwSize=sizeof(DIJoyCfg); if(SUCCEEDED(pCore->m_pDIJoyCfg->GetConfig(dwId,&DIJoyCfg,DIJC_REGHWCONFIGTYPE|DIJC_CALLOUT))) { //Get the clsidConfig. DIJOYTYPEINFO DIJoyType; ZeroMemory(&DIJoyType,sizeof(DIJoyType)); DIJoyType.dwSize=sizeof(DIJoyType); if(SUCCEEDED(pCore->m_pDIJoyCfg->GetTypeInfo(DIJoyCfg.wszType,&DIJoyType,DITC_CLSIDCONFIG|DITC_REGHWSETTINGS|DITC_FLAGS1))) { if((DIJoyType.clsidConfig!=GUID_NULL)&& !(DIJoyType.dwFlags1&JOYTYPE_DEFAULTPROPSHEET)) clsidPropSheet=DIJoyType.clsidConfig; } } int nStartPage=(clsidPropSheet==CLSID_LegacyServer)?1:0; if(nStartPage>MAX_PAGES) return(DIGCERR_STARTPAGETOOLARGE); CoInit CI;//CoInitialize(NULL); Auto CoFreeUnusedLibraries();CoUninitialize();. LPCDIGAMECNTRLPROPSHEET_AR fnInterface; if(SUCCEEDED(CI)) { IClassFactory* pCF; if(SUCCEEDED(CoGetClassObject(clsidPropSheet,CLSCTX_INPROC_SERVER,NULL,IID_IClassFactory,(LPVOID*)&pCF))) { pCF->CreateInstance(NULL,IID_IDIGameCntrlPropSheet,(LPVOID*)&fnInterface); pCF->Release(); } else { //reset to legacy server clsidPropSheet=CLSID_LegacyServer; nStartPage=1; if(SUCCEEDED(CoGetClassObject(clsidPropSheet,CLSCTX_INPROC_SERVER,NULL,IID_IClassFactory,(LPVOID*)&pCF))) { pCF->CreateInstance(NULL,IID_IDIGameCntrlPropSheet,(LPVOID*)&fnInterface); pCF->Release(); } } } if(*((PVOID *)&fnInterface) == NULL) { return(E_NOINTERFACE); } //Send device Id to the property sheet. fnInterface->SetID(dwId); LPDIGCSHEETINFO pServerSheet=NULL; //Get the property sheet info from the server. if(FAILED(fnInterface->GetSheetInfo(&pServerSheet))) { return(E_FAIL); } //Verify data from server. if(pServerSheet->nNumPages==0) return(DIGCERR_NUMPAGESZERO); else if((pServerSheet->nNumPages>MAX_PAGES)||(pServerSheet->nNumPagesGetPageInfo(&pServerPage))) { return(E_FAIL); } // Allocate memory for the pages. LPHPROPSHEETPAGE_ADAR pPages=new HPROPSHEETPAGE[pServerSheet->nNumPages]; if(*((PVOID *)&pPages) == NULL) return(E_OUTOFMEMORY); ZeroMemory((LPHPROPSHEETPAGE)pPages,sizeof(HPROPSHEETPAGE)*pServerSheet->nNumPages); // Allocate memory for the header! PROPSHEETHEADER SH; ZeroMemory(&SH,sizeof(SH)); SH.dwSize=sizeof(SH); SH.hwndParent= hWnd; SH.hInstance=pServerPage[0].hInstance; if(pServerSheet->fSheetIconFlag) { if(pServerSheet->lpwszSheetIcon) { //Check to see if you are an INT or a WSTR. if(HIWORD((INT_PTR)pServerSheet->lpwszSheetIcon)) { //You are a string. SH.pszIcon=pServerSheet->lpwszSheetIcon; } else SH.pszIcon=(LPCTSTR)(pServerSheet->lpwszSheetIcon); SH.dwFlags=PSH_USEICONID; } else return(DIGCERR_NOICON); } //Do we have a sheet caption? if(pServerSheet->lpwszSheetCaption) { SH.pszCaption=pServerSheet->lpwszSheetCaption; SH.dwFlags|=PSH_PROPTITLE; } SH.nPages=pServerSheet->nNumPages; SH.nStartPage=nStartPage; //Set the property pages inofrmation into the header. SH.phpage=(LPHPROPSHEETPAGE)pPages; //Sheet stuff is done.Now do the pages. PROPSHEETPAGE PropPage; ZeroMemory(&PropPage,sizeof(PropPage)); PropPage.dwSize=sizeof(PropPage); //Fill up each page. int nIndex=0; do { //Assign the things that there are not questionable. PropPage.lParam=pServerPage[nIndex].lParam; PropPage.hInstance=pServerPage[nIndex].hInstance; // Add the title. if(pServerPage[nIndex].lpwszPageTitle) { PropPage.dwFlags=PSP_USETITLE; //Check to see if you are a string. if(HIWORD((INT_PTR)pServerPage[nIndex].lpwszPageTitle)) { PropPage.pszTitle=pServerPage[nIndex].lpwszPageTitle; } else PropPage.pszTitle=(LPTSTR)pServerPage[nIndex].lpwszPageTitle; } else PropPage.pszTitle=NULL; //If icon is required go ahead and add it. if(pServerPage[nIndex].fIconFlag) { PropPage.dwFlags|=PSP_USEICONID; //Check to see if you are an INT or a String. if(HIWORD((INT_PTR)pServerPage[nIndex].lpwszPageIcon)) { //You're a string. PropPage.pszIcon=pServerPage[nIndex].lpwszPageIcon; } else PropPage.pszIcon=(LPCTSTR)(pServerPage[nIndex].lpwszPageIcon); } //If a pre - post processing call back proc is required go ahead and add it. if(pServerPage[nIndex].fProcFlag) { if(pServerPage[nIndex].fpPrePostProc) { PropPage.dwFlags|=PSP_USECALLBACK; PropPage.pfnCallback=(LPFNPSPCALLBACK)pServerPage[nIndex].fpPrePostProc; } else return(DIGCERR_NOPREPOSTPROC); } //And the essential "dialog" proc. if(pServerPage[nIndex].fpPageProc) PropPage.pfnDlgProc=pServerPage[nIndex].fpPageProc; else return(DIGCERR_NODLGPROC); //Assign the dialog template. if(HIWORD((INT_PTR)pServerPage[nIndex].lpwszTemplate)) { PropPage.pszTemplate=pServerPage[nIndex].lpwszTemplate; } else PropPage.pszTemplate=(LPTSTR)pServerPage[nIndex].lpwszTemplate; if(clsidPropSheet!=CLSID_LegacyServer)//If third party software do not enforce theme. ((LPHPROPSHEETPAGE)pPages)[nIndex++]=SHNoFusionCreatePropertySheetPageW(&PropPage); else ((LPHPROPSHEETPAGE)pPages)[nIndex++]=CreatePropertySheetPage(&PropPage); } while(nIndexnNumPages); //Launch modal property sheet dialog. PropertySheet(&SH); pCore->Update(); return(S_OK); } #undef cA