311 lines
7.5 KiB
C++
311 lines
7.5 KiB
C++
//-----------------------------------------------------------------------------
|
|
// File: cfrmwrk.cpp
|
|
//
|
|
// Desc: CDirectInputActionFramework is the outer-most layer of the UI. It
|
|
// contains everything else. Its functionality is provided by one
|
|
// method: ConfigureDevices.
|
|
//
|
|
// InternalConfigureDevices is called by the CDirectInputActionFramework
|
|
// class. This function actually contains the initialization code and
|
|
// the message pump for the UI.
|
|
//
|
|
// Copyright (C) 1999-2000 Microsoft Corporation. All Rights Reserved.
|
|
//-----------------------------------------------------------------------------
|
|
|
|
#include "common.hpp"
|
|
|
|
|
|
//QueryInterface
|
|
STDMETHODIMP CDirectInputActionFramework::QueryInterface(REFIID iid, LPVOID* ppv)
|
|
{
|
|
//null the out param
|
|
*ppv = NULL;
|
|
|
|
if ((iid == IID_IUnknown) || (iid == IID_IDIActionFramework))
|
|
{
|
|
*ppv = this;
|
|
AddRef();
|
|
return S_OK;
|
|
}
|
|
|
|
return E_NOINTERFACE;
|
|
}
|
|
|
|
|
|
//AddRef
|
|
STDMETHODIMP_(ULONG) CDirectInputActionFramework::AddRef()
|
|
{
|
|
return InterlockedIncrement(&m_cRef);
|
|
}
|
|
|
|
|
|
//Release
|
|
STDMETHODIMP_(ULONG) CDirectInputActionFramework::Release()
|
|
{
|
|
|
|
if (InterlockedDecrement(&m_cRef) == 0)
|
|
{
|
|
delete this;
|
|
return 0;
|
|
}
|
|
|
|
return m_cRef;
|
|
}
|
|
|
|
// Manages auto loading/unloading WINMM.DLL
|
|
// There will only be one instance of this class: inside InternalConfigureDevicees.
|
|
class CWinMmLoader
|
|
{
|
|
public:
|
|
CWinMmLoader()
|
|
{
|
|
if (!g_hWinMmDLL)
|
|
{
|
|
g_hWinMmDLL = LoadLibrary(_T("WINMM.DLL"));
|
|
if (g_hWinMmDLL)
|
|
{
|
|
*(FARPROC*)(&g_fptimeSetEvent) = GetProcAddress(g_hWinMmDLL, "timeSetEvent");
|
|
}
|
|
}
|
|
}
|
|
~CWinMmLoader()
|
|
{
|
|
if (g_hWinMmDLL)
|
|
{
|
|
/*
|
|
* Make sure no new callbacks can get scheduled then sleep to
|
|
* allow any pending ones to complete.
|
|
//@@BEGIN_MSINTERNAL
|
|
* Use 40ms as 20ms is the UI refresh interval
|
|
*
|
|
* ISSUE-2000/11/21-MarcAnd
|
|
* Should either have a more robust way to make sure no
|
|
* timers are left running or at least use constants to
|
|
* to make sure that if any timer interval is increased,
|
|
* that this value is still long enough.
|
|
//@@END_MSINTERNAL
|
|
*/
|
|
g_fptimeSetEvent = NULL;
|
|
Sleep( 40 );
|
|
FreeLibrary(g_hWinMmDLL);
|
|
g_hWinMmDLL = NULL;
|
|
}
|
|
}
|
|
};
|
|
|
|
|
|
//@@BEGIN_MSINTERNAL
|
|
// Manages auto loading/unloading MSIMG32.DLL
|
|
// There will only be one instance of this class: inside InternalConfigureDevicees.
|
|
/*
|
|
class CMSImgLoader
|
|
{
|
|
public:
|
|
CMSImgLoader()
|
|
{
|
|
if (!g_MSImg32)
|
|
{
|
|
g_MSImg32 = LoadLibrary(_T("MSIMG32.DLL"));
|
|
if (g_MSImg32)
|
|
{
|
|
g_AlphaBlend = (ALPHABLEND)GetProcAddress(g_MSImg32, "AlphaBlend");
|
|
if (!g_AlphaBlend)
|
|
{
|
|
FreeLibrary(g_MSImg32);
|
|
g_MSImg32 = NULL;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
~CMSImgLoader()
|
|
{
|
|
if (g_MSImg32)
|
|
{
|
|
FreeLibrary(g_MSImg32);
|
|
g_MSImg32 = NULL;
|
|
g_AlphaBlend = NULL;
|
|
}
|
|
}
|
|
};
|
|
*/
|
|
//@@END_MSINTERNAL
|
|
|
|
|
|
// internal, which api wraps around
|
|
static HRESULT InternalConfigureDevices(LPDICONFIGUREDEVICESCALLBACK lpdiCallback,
|
|
LPDICONFIGUREDEVICESPARAMSW lpdiCDParams,
|
|
DWORD dwFlags,
|
|
LPVOID pvRefData)
|
|
{
|
|
tracescope(__ts, _T("InternalConfigureDevices()\n"));
|
|
|
|
//@@BEGIN_MSINTERNAL
|
|
// CMSImgLoader g_MSImgLoadingHelper; // Automatically call LoadLibrary and FreeLibrary on MSIMG32.DLL
|
|
//@@END_MSINTERNAL
|
|
CWinMmLoader g_WinMmLoadingHelper; // Automatically call LoadLibrary and FreeLibrary on WINMM.DLL
|
|
|
|
// check that we're at least 256 colors
|
|
HDC hMemDC = CreateCompatibleDC(NULL);
|
|
if (hMemDC == NULL)
|
|
{
|
|
etrace(_T("Can't get a DC! Exiting.\n"));
|
|
return E_FAIL;
|
|
}
|
|
|
|
int bpp = GetDeviceCaps(hMemDC, BITSPIXEL);
|
|
DeleteDC(hMemDC);
|
|
if (bpp < 8)
|
|
{
|
|
etrace1(_T("Screen is not at least 8bpp (bpp = %d)\n"), bpp);
|
|
return E_FAIL;
|
|
}
|
|
|
|
// do it...
|
|
{
|
|
// create the globals
|
|
CUIGlobals uig(
|
|
dwFlags,
|
|
lpdiCDParams->lptszUserNames,
|
|
lpdiCDParams->dwcFormats,
|
|
lpdiCDParams->lprgFormats,
|
|
&(lpdiCDParams->dics),
|
|
lpdiCDParams->lpUnkDDSTarget,
|
|
lpdiCallback,
|
|
pvRefData
|
|
);
|
|
HRESULT hr = uig.GetInitResult();
|
|
if (FAILED(hr))
|
|
{
|
|
etrace(_T("CUIGlobals.Init() failed\n"));
|
|
return hr;
|
|
}
|
|
|
|
// make sure the flexwnd window class is registered only during possible use
|
|
//@@BEGIN_MSINTERNAL
|
|
// TODO: consider doing this wnd class stuff at dll scope, or doing it refcount-ish within flexwnd.cpp
|
|
//@@END_MSINTERNAL
|
|
{
|
|
struct flexwndscope {
|
|
flexwndscope(CUIGlobals &uig) : m_uig(uig) {CFlexWnd::RegisterWndClass(m_uig.GetInstance());}
|
|
~flexwndscope() {CFlexWnd::UnregisterWndClass(m_uig.GetInstance());}
|
|
CUIGlobals &m_uig;
|
|
} scope(uig);
|
|
|
|
// create the main window
|
|
CConfigWnd cfgWnd(uig);
|
|
if (!cfgWnd.Create(lpdiCDParams->hwnd))
|
|
{
|
|
etrace(_T("Failed to create main window\n"));
|
|
return E_FAIL;
|
|
}
|
|
|
|
// Initialize the shared tooltip object.
|
|
RECT rc = {0, 0, 0, 0};
|
|
CFlexWnd::s_ToolTip.Create(cfgWnd.m_hWnd, rc, TRUE);
|
|
if (!CFlexWnd::s_ToolTip.m_hWnd)
|
|
{
|
|
etrace(_T("Failed to create tooltip window\n"));
|
|
return E_FAIL;
|
|
}
|
|
::ShowWindow(CFlexWnd::s_ToolTip.m_hWnd, SW_HIDE); // Hide window by default
|
|
|
|
// enter message loop
|
|
MSG msg;
|
|
while (GetMessage(&msg, NULL, 0, 0))
|
|
{
|
|
// If this is a message for the parent window (game window), only dispatch if it's WM_PAINT.
|
|
if (!cfgWnd.InRenderMode() && msg.hwnd == lpdiCDParams->hwnd && msg.message != WM_PAINT)
|
|
continue;
|
|
TranslateMessage(&msg);
|
|
DispatchMessage(&msg);
|
|
}
|
|
}
|
|
|
|
CFlexWnd::s_ToolTip.Destroy();
|
|
|
|
return uig.GetFinalResult();
|
|
}
|
|
}
|
|
|
|
|
|
BOOL AreAcForsGood(LPDIACTIONFORMATW lpAcFors, DWORD dwNumAcFors)
|
|
{
|
|
if (lpAcFors == NULL)
|
|
return FALSE;
|
|
|
|
if (dwNumAcFors < 1)
|
|
return FALSE;
|
|
|
|
if (lpAcFors->dwNumActions == 0)
|
|
return FALSE;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
//ConfigureDevices
|
|
STDMETHODIMP CDirectInputActionFramework::ConfigureDevices(
|
|
LPDICONFIGUREDEVICESCALLBACK lpdiCallback,
|
|
LPDICONFIGUREDEVICESPARAMSW lpdiCDParams,
|
|
DWORD dwFlags,
|
|
LPVOID pvRefData)
|
|
{
|
|
tracescope(__ts,_T("CDirectInputActionFramework::ConfigureDevices()\n"));
|
|
|
|
trace(_T("\nConfigureDevices() called...\n\n"));
|
|
|
|
// check parameters
|
|
if (lpdiCDParams == NULL)
|
|
{
|
|
etrace(_T("NULL params structure passed to ConfigureDevices()\n"));
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
// save passed params in case we change 'em
|
|
LPDIACTIONFORMATW lpAcFors = lpdiCDParams->lprgFormats;
|
|
DWORD dwNumAcFors = lpdiCDParams->dwcFormats;
|
|
|
|
#ifdef CFGUI__FORCE_GOOD_ACFORS
|
|
|
|
if (!AreAcForsGood(lpdiCDParams->lprgFormats, lpdiCDParams->dwcFormats))
|
|
{
|
|
etrace(_T("Passed ActionFormats aren't good... Using GetTestActionFormats() (just 2 of them).\n"));
|
|
lpdiCDParams->dwcFormats = 2;
|
|
lpdiCDParams->lprgFormats = GetTestActionFormats();
|
|
}
|
|
|
|
#endif
|
|
|
|
HRESULT hr = InternalConfigureDevices(lpdiCallback, lpdiCDParams, dwFlags, pvRefData);
|
|
|
|
// restore passed params in case changed
|
|
lpdiCDParams->lprgFormats = lpAcFors;
|
|
lpdiCDParams->dwcFormats = dwNumAcFors;
|
|
|
|
trace(_T("\n"));
|
|
|
|
if (FAILED(hr))
|
|
etrace1(_T("ConfigureDevices() failed, returning 0x%08x\n"), hr);
|
|
else
|
|
trace1(_T("ConfigureDevices() suceeded, returning 0x%08x\n"), hr);
|
|
|
|
trace(_T("\n"));
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
//constructor
|
|
CDirectInputActionFramework::CDirectInputActionFramework()
|
|
{
|
|
//set ref count
|
|
m_cRef = 1;
|
|
}
|
|
|
|
|
|
//destructor
|
|
CDirectInputActionFramework::~CDirectInputActionFramework()
|
|
{
|
|
// not necessary to cleanup action format here
|
|
}
|