//=========================================================================== // CPLSVR1.CPP // // Simple sample "Game Controllers" control panel extension server. // // Functions: // DLLMain() // DllGetClassObject() // DllCanUnloadNow() // CServerClassFactory::CServerClassFactory() // CServerClassFactory::~CServerClassFactory() // CServerClassFactory::QueryInterface() // CServerClassFactory::AddRef() // CServerClassFactory::Release() // CServerClassFactory::CreateInstance() // CServerClassFactory::LockServer() // CDIGameCntrlPropSheet_X::CDIGameCntrlPropSheet_X() // CDIGameCntrlPropSheet_X::~CDIGameCntrlPropSheet_X() // CDIGameCntrlPropSheet_X::QueryInterface() // CDIGameCntrlPropSheet_X::AddRef() // CDIGameCntrlPropSheet_X::Release() // CDIGameCntrlPropSheet_X::GetSheetInfo() // CDIGameCntrlPropSheet_X::GetPageInfo() // CDIGameCntrlPropSheet_X::SetID() // CDIGameCntrlPropSheet_X::Initialize() // CDIGameCntrlPropSheet_X::SetDevice() // CDIGameCntrlPropSheet_X::GetDevice() // CDIGameCntrlPropSheet_X::SetJoyConfig() // CDIGameCntrlPropSheet_X::GetJoyConfig() // //=========================================================================== //=========================================================================== // (C) Copyright 1997 Microsoft Corp. All rights reserved. // // You have a royalty-free right to use, modify, reproduce and // distribute the Sample Files (and/or any modified version) in // any way you find useful, provided that you agree that // Microsoft has no warranty obligations or liability for any // Sample Application Files which are modified. //=========================================================================== #define INITGUID #define STRICT #include "cplsvr1.h" #include "pov.h" #include "assert.h" //--------------------------------------------------------------------------- // file global variables static BYTE glDLLRefCount = 0; // DLL reference count static LONG glServerLocks = 0; // Count of locks CDIGameCntrlPropSheet_X *pdiCpl; HINSTANCE ghInst; CRITICAL_SECTION gcritsect; DWORD myPOV[2][JOY_POV_NUMDIRS+1]; BOOL bPolledPOV; //--------------------------------------------------------------------------- // LegacyServer GUID!!! // {92187326-72B4-11d0-A1AC-0000F8026977} DEFINE_GUID(CLSID_LegacyServer, 0x92187326, 0x72b4, 0x11d0, 0xa1, 0xac, 0x0, 0x0, 0xf8, 0x2, 0x69, 0x77); //--------------------------------------------------------------------------- //=========================================================================== // DLLMain // // DLL entry point. // // Parameters: // HINSTANCE hInst - the DLL's instance handle // DWORD dwReason - reason why DLLMain was called // LPVOID lpvReserved - // // Returns: // BOOL - TRUE if succeeded // //=========================================================================== int APIENTRY DllMain(HINSTANCE hInst, DWORD dwReason, LPVOID lpvReserved) { switch (dwReason) { case DLL_PROCESS_ATTACH: ghInst = hInst; InitializeCriticalSection(&gcritsect); break; case DLL_PROCESS_DETACH: DeleteCriticalSection(&gcritsect); break; case DLL_THREAD_ATTACH: DisableThreadLibraryCalls((HMODULE)hInst); case DLL_THREAD_DETACH: break; } //** end switch(dwReason) return TRUE; } //*** end DLLMain() //=========================================================================== // DllGetClassObject // // Gets an IClassFactory object. // // Parameters: // REFCLSID rclsid - CLSID value (by reference) // REFIID riid - IID value (by reference) // PPVOID ppv - ptr to store interface ptr // // Returns: // HRESULT - OLE type success/failure code (S_OK if succeeded) // //=========================================================================== STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, PPVOID ppv) { // did the caller pass in our CLSID? if(!IsEqualCLSID(rclsid, CLSID_LegacyServer)) { // no, return class not available error return CLASS_E_CLASSNOTAVAILABLE; } // did the caller request our class factory? if(!IsEqualIID(riid, IID_IClassFactory)) { // no, return no interface error return E_NOINTERFACE; } // instantiate class factory object CServerClassFactory *pClsFactory = new CServerClassFactory(); if (NULL == pClsFactory) { // could not create the object // // chances are we were out of memory return E_OUTOFMEMORY; } // query for interface riid, and return it via ppv HRESULT hRes = pClsFactory->QueryInterface(riid, ppv); // we're finished with our local object pClsFactory->Release(); // return the result code from QueryInterface return hRes; } //*** end DllGetClassObject() //=========================================================================== // DllCanUnloadNow // // Reports whether or not the DLL can be unloaded. // // Parameters: none // // Returns // HRESULT - OLE type success/failure code (S_OK if succeeded) // //=========================================================================== STDAPI DllCanUnloadNow(void) { // unloading should be safe if the global dll refcount is zero and server lock ref is 0 return (glDLLRefCount == 0 && glServerLocks == 0) ? S_OK : S_FALSE; } //*** end DllCanUnloadNow() //=========================================================================== // CServerClassFactory::CServerClassFactory // // Class constructor. // // Parameters: none // // Returns: // CServerClassFactory* (implicit) // //=========================================================================== CServerClassFactory::CServerClassFactory(void) { // initialize and increment the object refcount m_ServerCFactory_refcount = 0; AddRef(); // increment the dll refcount InterlockedIncrement((LPLONG)&glDLLRefCount); } //*** end CServerClassFactory::CServerClassFactory() //=========================================================================== // CServerClassFactory::CServerClassFactory // // Class constructor. // // Parameters: none // // Returns: // CServerClassFactory* (implicit) // //=========================================================================== CServerClassFactory::~CServerClassFactory(void) { // decrement the dll refcount InterlockedDecrement((LPLONG)&glDLLRefCount); } //*** end CServerClassFactory::~CServerClassFactory() //=========================================================================== // CServerClassFactory::QueryInterface // // Implementation of the QueryInterface() method. // // Parameters: // REFIID riid - the interface that is being looked for // PPVOID ppv - pointer to target interface pointer // // Returns: // HRESULT - OLE type success/failure code (S_OK if succeeded) // //=========================================================================== STDMETHODIMP CServerClassFactory::QueryInterface(REFIID riid, PPVOID ppv) { // make sure that if anything fails, we return something reasonable *ppv = NULL; // we support IUnknown... if (IsEqualIID(riid, IID_IUnknown)) { // return our object as an IUnknown *ppv = (LPUNKNOWN)(LPCLASSFACTORY)this; } else { // ... and our interface if (IsEqualIID(riid, IID_IClassFactory)) // return our object as a class factory *ppv = (LPCLASSFACTORY)this; else // we do not support any other interfaces return E_NOINTERFACE; } // we got this far, so we've succeeded // increment our refcount and return AddRef(); return S_OK; } //*** end CServerClassFactory::QueryInterface() //=========================================================================== // CServerClassFactory::AddRef // // Implementation of the AddRef() method. // // Parameters: none // // Returns: // ULONG - updated reference count. // NOTE: apps should NOT rely on this value! // //=========================================================================== STDMETHODIMP_(ULONG) CServerClassFactory::AddRef(void) { // update and return our object's reference count InterlockedIncrement((LPLONG)&m_ServerCFactory_refcount); return m_ServerCFactory_refcount; } //*** end CServerClassFactory::AddRef() //=========================================================================== // CServerClassFactory::Release // // Implementation of the Release() method. // // Parameters: none // // Returns: // ULONG - updated reference count. // NOTE: apps should NOT rely on this value! // //=========================================================================== STDMETHODIMP_(ULONG) CServerClassFactory::Release(void) { // update and return our object's reference count InterlockedDecrement((LPLONG)&m_ServerCFactory_refcount); if (0 == m_ServerCFactory_refcount) { // it's now safe to call the destructor delete this; return 0; } else return m_ServerCFactory_refcount; } //*** end CServerClassFactory::Release() //=========================================================================== // CServerClassFactory::CreateInstance // // Implementation of the CreateInstance() method. // // Parameters: none // // Returns: // HRESULT - OLE type success/failure code (S_OK if succeeded) // //=========================================================================== STDMETHODIMP CServerClassFactory::CreateInstance(LPUNKNOWN pUnkOuter, REFIID riid, PPVOID ppvObj) { CDIGameCntrlPropSheet_X *pdiGCPropSheet = NULL; HRESULT hRes = E_NOTIMPL; // make sure that if anything fails, we return something reasonable *ppvObj = NULL; // we want pUnkOuter to be NULL // // we do not support aggregation if (pUnkOuter != NULL) { // tell the caller that we do not support this feature return CLASS_E_NOAGGREGATION; } // Create a new instance of the game controller property sheet object pdiGCPropSheet = new CDIGameCntrlPropSheet_X(); if (NULL == pdiGCPropSheet) { // we could not create our object // chances are, we have run out of memory return E_OUTOFMEMORY; } // initialize the object (memory allocations, etc) if (SUCCEEDED(pdiGCPropSheet->Initialize())) // query for interface riid, and return it via ppvObj hRes = pdiGCPropSheet->QueryInterface(riid, ppvObj); // release the local object pdiGCPropSheet->Release(); // all done, return result from QueryInterface return hRes; } //*** end CServerClassFactory::CreateInstance() //=========================================================================== // CServerClassFactory::LockServer // // Implementation of the LockServer() method. // // Parameters: none // // Returns: // HRESULT - OLE type success/failure code (S_OK if succeeded) // //=========================================================================== STDMETHODIMP CServerClassFactory::LockServer(BOOL fLock) { //HRESULT hRes = E_NOTIMPL; // increment/decrement based on fLock if (fLock) InterlockedIncrement((LPLONG)&glDLLRefCount); else InterlockedDecrement((LPLONG)&glDLLRefCount); // all done return S_OK; } //*** end CServerClassFactory::LockServer() //=========================================================================== // CDIGameCntrlPropSheet_X::CDIGameCntrlPropSheet_X // // Class constructor. // // Parameters: none // // Returns: nothing // //=========================================================================== CDIGameCntrlPropSheet_X::CDIGameCntrlPropSheet_X(void) { // initialize and increment the object refcount m_cProperty_refcount = 0; AddRef(); // initialize our device id to -1 just to be safe m_nID = (BYTE)-1; // init m_bUser = FALSE; // initialize all of our pointers m_pdigcPageInfo = NULL; m_pdiDevice2 = NULL; m_pdiJoyCfg = NULL; pdiCpl = NULL; // increment the dll refcount InterlockedIncrement((LPLONG)&glDLLRefCount); // Register the POV hat class m_aPovClass = RegisterPOVClass(); // Register the custom Button class m_aButtonClass = RegisterCustomButtonClass(); } //*** end CDIGameCntrlPropSheet_X::CDIGameCntrlPropSheet_X() //=========================================================================== // CDIGameCntrlPropSheet_X::~CDIGameCntrlPropSheet_X // // Class destructor. // // Parameters: none // // Returns: nothing // //=========================================================================== CDIGameCntrlPropSheet_X::~CDIGameCntrlPropSheet_X(void) { // free the DIGCPAGEINFO memory if (m_pdigcPageInfo) LocalFree(m_pdigcPageInfo); // free the DIGCSHEETINFO memory if (m_pdigcSheetInfo) LocalFree(m_pdigcSheetInfo); // free up the StateFlags memory! if (m_pStateFlags) delete (m_pStateFlags); // cleanup directinput objects // m_pdiDevice2 if (m_pdiDevice2) { m_pdiDevice2->Unacquire(); m_pdiDevice2->Release(); m_pdiDevice2 = NULL; } // m_pdiJoyCfg if (m_pdiJoyCfg) { m_pdiJoyCfg->Unacquire(); m_pdiJoyCfg->Release(); m_pdiJoyCfg = NULL; } // Unregister the classes!!! if (m_aPovClass) UnregisterClass((LPCTSTR)m_aPovClass, ghInst); if (m_aButtonClass) UnregisterClass((LPCTSTR)m_aButtonClass, ghInst); // decrement the dll refcount InterlockedDecrement((LPLONG)&glDLLRefCount); } //*** end CDIGameCntrlPropSheet_X::~CDIGameCntrlPropSheet_X() //=========================================================================== // CDIGameCntrlPropSheet_X::QueryInterface // // Implementation of the QueryInterface() method. // // Parameters: // REFIID riid - the interface that is being looked for // PPVOID ppv - pointer to target interface pointer // // Returns: // HRESULT - OLE type success/failure code (S_OK if succeeded) // //=========================================================================== STDMETHODIMP CDIGameCntrlPropSheet_X::QueryInterface(REFIID riid, PPVOID ppv) { // make sure that if anything fails, we return something reasonable *ppv = NULL; // we support IUnknown... if(IsEqualIID(riid, IID_IUnknown)) { *ppv = (LPUNKNOWN)(LPCDIGAMECNTRLPROPSHEET)this; } else { // ... and IID_IDIGameCntrlPropSheet if(IsEqualIID(riid, IID_IDIGameCntrlPropSheet)) *ppv = (LPCDIGAMECNTRLPROPSHEET)this; else // we do not support any other interfaces return E_NOINTERFACE; } // we got this far, so we've succeeded // increment our refcount and return AddRef(); return S_OK; } //*** end CDIGameCntrlPropSheet_X::QueryInterface() //=========================================================================== // CDIGameCntrlPropSheet_X::AddRef // // Implementation of the AddRef() method. // // Parameters: none // // Returns: // ULONG - updated reference count. // NOTE: apps should NOT rely on this value! //=========================================================================== STDMETHODIMP_(ULONG) CDIGameCntrlPropSheet_X::AddRef(void) { // update and return our object's reference count InterlockedIncrement((LPLONG)&m_cProperty_refcount); return m_cProperty_refcount; } //*** end CDIGameCntrlPropSheet_X::AddRef() //=========================================================================== // CDIGameCntrlPropSheet_X::Release // // Implementation of the Release() method. // // Parameters: none // // Returns: // ULONG - updated reference count. // NOTE: apps should NOT rely on this value! //=========================================================================== STDMETHODIMP_(ULONG) CDIGameCntrlPropSheet_X::Release(void) { // update and return our object's reference count InterlockedDecrement((LPLONG)&m_cProperty_refcount); if (m_cProperty_refcount) return m_cProperty_refcount; // it's now safe to call the destructor delete this; return S_OK; } //*** end CDIGameCntrlPropSheet_X::Release() //=========================================================================== // CDIGameCntrlPropSheet_X::GetSheetInfo // // Implementation of the GetSheetInfo() method. // // Parameters: // LPDIGCSHEETINFO *ppSheetInfo - ptr to DIGCSHEETINFO struct ptr // // Returns: // HRESULT - OLE type success/failure code (S_OK if succeeded) //=========================================================================== STDMETHODIMP CDIGameCntrlPropSheet_X::GetSheetInfo(LPDIGCSHEETINFO *ppSheetInfo) { // pass back the our sheet information *ppSheetInfo = m_pdigcSheetInfo; // all done here return S_OK; } //*** end CDIGameCntrlPropSheet_X::GetSheetInfo() //=========================================================================== // CDIGameCntrlPropSheet_X::GetPageInfo // // Implementation of the GetPageInfo() method. // // NOTE: This returns the information for ALL pages. There is no mechanism // in place to request only page n's DIGCPAGEINFO. // // Parameters: // LPDIGCPAGEINFO *ppPageInfo - ptr to DIGCPAGEINFO struct ptr // // Returns: // HRESULT - OLE type success/failure code (S_OK if succeeded) //=========================================================================== STDMETHODIMP CDIGameCntrlPropSheet_X::GetPageInfo(LPDIGCPAGEINFO *ppPageInfo) { // pass back the our page information *ppPageInfo = m_pdigcPageInfo; // all done here return S_OK; } //*** end CDIGameCntrlPropSheet_X::GetPageInfo() //=========================================================================== // CDIGameCntrlPropSheet_X::SetID // // Implementation of the SetID() method. // // Parameters: // USHORT nID - identifier to set // // Returns: // HRESULT - OLE type success/failure code (S_OK if succeeded) //=========================================================================== STDMETHODIMP CDIGameCntrlPropSheet_X::SetID(USHORT nID) { // store the device id m_nID = (BYTE)nID; return S_OK; } //*** end CDIGameCntrlPropSheet_X::SetID() //=========================================================================== // CDIGameCntrlPropSheet::Initialize // // Implementation of the Initialize() method. // // Parameters: none // // Returns: // HRESULT - OLE type success/failure code (S_OK if succeeded) //=========================================================================== HRESULT CDIGameCntrlPropSheet_X::Initialize(void) { // provide the following information for each device page // { dialog template, callback function pointer } CPLPAGEINFO grgcpInfo[NUMPAGES] = { IDD_SETTINGS, (DLGPROC)Settings_DlgProc, IDD_TEST, (DLGPROC)Test_DlgProc #ifdef FORCE_FEEDBACK , // Template DlgProc IDD_FORCEFEEDBACK, (DLGPROC)ForceFeedback_DlgProc #endif // FORCE_FEEDBACK }; // allocate memory for the DIGCPAGEINFO structures m_pdigcPageInfo = (DIGCPAGEINFO *)LocalAlloc(LPTR, NUMPAGES * sizeof(DIGCPAGEINFO)); if (!m_pdigcPageInfo){ return E_OUTOFMEMORY; } m_pdigcSheetInfo = (DIGCSHEETINFO *)LocalAlloc(LPTR, sizeof(DIGCSHEETINFO)); if (!m_pdigcSheetInfo) { LocalFree(m_pdigcPageInfo); return E_OUTOFMEMORY; } // populate the DIGCPAGEINFO structure for each sheet BYTE i = 0; do { m_pdigcPageInfo[i].dwSize = sizeof(DIGCPAGEINFO); m_pdigcPageInfo[i].fIconFlag = FALSE; // This is done to test JOY.CPL... // It's also better for Win9x, as it will not be required to convert it! // m_pdigcPageInfo[i].lpwszPageIcon = (LPWSTR)IDI_GCICON; //MAKEINTRESOURCE(IDI_GCICON); m_pdigcPageInfo[i].hInstance = ghInst; m_pdigcPageInfo[i].lParam = (LPARAM)this; // the following data is unique to each page m_pdigcPageInfo[i].fpPageProc = grgcpInfo[i].fpPageProc; m_pdigcPageInfo[i].lpwszTemplate = (LPWSTR)grgcpInfo[i++].lpwszDlgTemplate; } while (i < NUMPAGES); // populate the DIGCSHEETINFO structure m_pdigcSheetInfo->dwSize = sizeof(DIGCSHEETINFO); m_pdigcSheetInfo->nNumPages = NUMPAGES; m_pdigcSheetInfo->fSheetIconFlag = TRUE; m_pdigcSheetInfo->lpwszSheetIcon = (LPWSTR)IDI_GCICON; //MAKEINTRESOURCEW(IDI_GCICON); // Do that device object enumeration thing! m_pStateFlags = new (STATEFLAGS); if (!m_pStateFlags) { LocalFree(m_pdigcPageInfo); LocalFree(m_pdigcSheetInfo); return E_OUTOFMEMORY; } ZeroMemory(m_pStateFlags, sizeof(STATEFLAGS)); // all done return S_OK; } //*** end CDIGameCntrlPropSheet::Initialize() //=========================================================================== // CDIGameCntrlPropSheet_X::SetDevice // // Implementation of the SetDevice() method. // // Parameters: // LPDIRECTINPUTDEVICE2 pdiDevice2 - device object ptr // // Returns: // HRESULT - OLE type success/failure code (S_OK if succeeded) //=========================================================================== STDMETHODIMP CDIGameCntrlPropSheet_X::SetDevice(LPDIRECTINPUTDEVICE2 pdiDevice2) { // store the device object ptr m_pdiDevice2 = pdiDevice2; return S_OK; } //*** end CDIGameCntrlPropSheet_X::SetDevice() //=========================================================================== // CDIGameCntrlPropSheet_X::GetDevice // // Implementation of the GetDevice() method. // // Parameters: // LPDIRECTINPUTDEVICE2 *ppdiDevice2 - ptr to device object ptr // // Returns: // HRESULT - OLE type success/failure code (S_OK if succeeded) //=========================================================================== STDMETHODIMP CDIGameCntrlPropSheet_X::GetDevice(LPDIRECTINPUTDEVICE2 *ppdiDevice2) { // retrieve the device object ptr *ppdiDevice2 = m_pdiDevice2; return S_OK; } //*** end CDIGameCntrlPropSheet_X::GetDevice() //=========================================================================== // CDIGameCntrlPropSheet_X::SetJoyConfig // // Implementation of the SetJoyConfig() method. // // Parameters: // LPDIRECTINPUTJOYCONFIG pdiJoyCfg - joyconfig object ptr // // Returns: // HRESULT - OLE type success/failure code (S_OK if succeeded) //=========================================================================== STDMETHODIMP CDIGameCntrlPropSheet_X::SetJoyConfig(LPDIRECTINPUTJOYCONFIG pdiJoyCfg) { // store the joyconfig object ptr m_pdiJoyCfg = pdiJoyCfg; return S_OK; } //*** end CDIGameCntrlPropSheet_X::SetJoyConfig() //=========================================================================== // CDIGameCntrlPropSheet_X::SetJoyConfig // // Implementation of the SetJoyConfig() method. // // Parameters: // LPDIRECTINPUTJOYCONFIG *ppdiJoyCfg - ptr to joyconfig object ptr // // Returns: // HRESULT - OLE type success/failure code (S_OK if succeeded) //=========================================================================== STDMETHODIMP CDIGameCntrlPropSheet_X::GetJoyConfig(LPDIRECTINPUTJOYCONFIG *ppdiJoyCfg) { // retrieve the joyconfig object ptr *ppdiJoyCfg = m_pdiJoyCfg; return S_OK; } //*** end CDIGameCntrlPropSheet_X::GetJoyConfig()