//----------------------------------------------------------------------------- // 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 }