windows-nt/Source/XPSP1/NT/multimedia/directx/gamectrl/default/cplsvr1.cpp
2020-09-26 16:20:57 +08:00

787 lines
23 KiB
C++

//===========================================================================
// 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()