|
|
/*
* File: Cpanel.cpp * Project: Universal Joystick Control Panel OLE Client * Author: Brycej * Date: 02/08/95 - Started this maddness... * 04/15/97 - Updated to use DI interface * Comments: * window proc for General page in cpanel * * Copyright (c) 1995, Microsoft Corporation */
/*
// This is necessary LVS_EX_INFOTIP
#if (_WIN32_IE < 0x0500)
#undef _WIN32_IE
#define _WIN32_IE 0x0500
#endif
*/
#include <afxcmn.h>
#include <windowsx.h>
#ifndef _UNICODE
#define INC_OLE2
#include <objbase.h> // For COM stuff!
#endif
#include <initguid.h>
#include <cpl.h>
#include <winuser.h> // For RegisterDeviceNotification stuff!
#include <dbt.h> // for DBT_ defines!!!
#include <hidclass.h>
#include <malloc.h> // for _alloca
#include <regstr.h> // for REGSTR_PATH_JOYOEM reference!
#include "hsvrguid.h"
#include "cpanel.h"
#include "resource.h"
#include "joyarray.h"
// constants
const short ID_MYTIMER = 1000; const short POLLRATE = 850; const short NO_ITEM = -1;
#define IDC_WHATSTHIS 400
// externs
extern const DWORD gaHelpIDs[]; extern HINSTANCE ghInstance;
// externs for arguements!
extern BYTE nID, nStartPageDef, nStartPageCPL;
// DI globals
IDirectInputJoyConfig* pDIJoyConfig = 0; LPDIRECTINPUT lpDIInterface = 0;
// Array of all available devices
#ifndef _UNICODE
WCHAR *pwszGameportDriverArray[MAX_GLOBAL_PORT_DRIVERS]; // List of enumerated Gameport Drivers
BYTE nGameportDriver; // Global Port Driver Enumeration Counter
#endif
WCHAR *pwszTypeArray[MAX_DEVICES]; // List of enumerated devices
WCHAR *pwszGameportBus[MAX_BUSSES]; // List of enumerated gameport buses
PJOY pAssigned[MAX_ASSIGNED]; // List of assigned devices
BYTE nGamingDevices; // Gaming Devices Enumeration Counter
BYTE nGameportBus; // Gameport Bus Enumeration Counter
BYTE nAssigned; // Number of elements in pAssigned array
BYTE nTargetAssigned; // Number of elements expected in pAssigned array when pending adds complete
BYTE nReEnum; // Counter used to decide when to reenumerate
GUID guidOccupied[MAX_BUSSES]; //Whether the gameport bus has been occupied.
short nFlags; // Flags for Update, User Mode, and if the user is on this page!
// local (module-scope) variables
static HWND hListCtrl; short iItem = NO_ITEM; // index of selected item
extern short iAdvItem;
// Global to avoid creating in timer!
static LPDIJOYSTATE lpDIJoyState;
static UINT JoyCfgChangedMsg; // vjoyd JoyConfigChanged message
static BOOL WINAPI MsgSubClassProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam); static WNDPROC fpMainWindowProc;
#ifdef _UNICODE
static PVOID hNotifyDevNode; #endif
// local message handlers
static BOOL OnInitDialog (HWND, HWND, LPARAM); static void OnCommand (HWND, int, HWND, UINT); static BOOL OnNotify (HWND, WPARAM, NMHDR*); static void OnDestroy (HWND); static void OnListViewContextMenu (HWND hDlg, LPARAM lParam);
#ifndef _UNICODE
BOOL AddListCtrlItem(BYTE nItemID, LPDIJOYCONFIG pJoyConfig); #endif
// Share these with Add.cpp
void OnContextMenu (WPARAM wParam, LPARAM lParam); void OnHelp (LPARAM);
#ifdef WINNT
// Share this one with Advanced.cpp
void RunWDMJOY ( void ); #endif
// local utility fns
static BOOL DetectHotplug ( HWND hDlg, BYTE nItemSelected ); static BOOL SetActive ( HWND hDlg ); static void UpdateListCtrl ( HWND hDlg ); static void UpdateButtonState ( HWND hDlg ); static void StatusChanged ( HWND hDlg, BYTE i );
JOY::JOY() { ID = nStatus = nButtons = -1; clsidPropSheet = CLSID_LegacyServer; fnDeviceInterface = 0; }
JOY::~JOY() { if( fnDeviceInterface ) { fnDeviceInterface->Unacquire(); fnDeviceInterface->Release(); fnDeviceInterface = 0; } }
///////////////////////////////////////////////////////////////////////////////
//CPanelProc(HWND hDlg, ULONG uMsg, WPARAM wParam, LPARAM lParam)
///////////////////////////////////////////////////////////////////////////////
BOOL WINAPI CPanelProc(HWND hDlg, ULONG uMsg, WPARAM wParam, LPARAM lParam) { switch( uMsg ) { case WM_ACTIVATEAPP: if( nFlags & ON_PAGE ) { if( wParam ) { if( nFlags & UPDATE_FOR_GEN ) { nFlags &= ~UPDATE_FOR_GEN; UpdateListCtrl(hDlg); }
// Set the focus!
if( nAssigned ) { if( iItem == NO_ITEM ) iItem = 0;
if( pDIJoyConfig ) SetActive(hDlg);
// restore selection focus
SetListCtrlItemFocus(hListCtrl, (BYTE)iItem); } else { UpdateButtonState(hDlg); }
// the user is requesting that the CPL be shown
// and an extention associated with nID be Launched.
if( nID < NUMJOYDEVS ) {
BYTE nCount = (BYTE)::SendMessage(hListCtrl, LVM_GETITEMCOUNT, 0, 0);
while( nCount-- ) { if( pAssigned[GetItemData(hListCtrl, (BYTE)iItem)]->ID == nID ) { KillTimer(hDlg, ID_MYTIMER);
OnCommand(hDlg, IDC_BTN_PROPERTIES, 0, 0);
SetTimer(hDlg, ID_MYTIMER, POLLRATE, 0); break; } }
// just to get nID > NUMJOYDEVS!
nID = (NUMJOYDEVS<<1); } } else { KillTimer(hDlg, ID_MYTIMER); } } break;
case WM_LBUTTONDOWN: // Click Drag service for PropSheets!
PostMessage(GetParent(hDlg), WM_NCLBUTTONDOWN, (WPARAM)HTCAPTION, lParam); break;
case WM_INITDIALOG: if( !HANDLE_WM_INITDIALOG(hDlg, wParam, lParam, OnInitDialog) ) { // Fix #108983 NT, Remove Flash on Error condition.
SetWindowPos(::GetParent(hDlg), HWND_BOTTOM, 0, 0, 0, 0, SWP_HIDEWINDOW); DestroyWindow(hDlg); }
// if we want to set focus, get the control hWnd
// and set it as the wParam.
return(TRUE);
case WM_DESTROY: HANDLE_WM_DESTROY(hDlg, wParam, lParam, OnDestroy); return(1);
// OnTimer
case WM_TIMER: { BYTE i = nAssigned; BYTE nButtons; BYTE nLoop;
if( nReEnum ) { if( !( --nReEnum & 3 ) ) { // ISSUE-2001/03/29-timgill Much used code
// (MarcAnd) I hope this code is generally appropriate
// it appears in much the same form all over the place.
KillTimer(hDlg, ID_MYTIMER); // Set the Update Flag!
nFlags |= UPDATE_ALL; UpdateListCtrl(hDlg); SetActive(hDlg); SetTimer(hDlg, ID_MYTIMER, POLLRATE, 0); } }
while( i-- ) { if( pAssigned[i]->fnDeviceInterface ) { int nPollFail;
pAssigned[i]->fnDeviceInterface->Acquire();
// LOOKOUT RE-USE of nButtons!
nButtons = pAssigned[i]->nStatus;
nLoop = 5; nPollFail = 0;
// Special work for the sidewinder folks...
// ACT LAB: You can't poll actrs.vxd (ACT LAB) too often, otherwise it fails.
// See Manbug 41049. - qzheng 8/1/2000
do { if( FAILED(pAssigned[i]->fnDeviceInterface->Poll()) ) { nPollFail ++; } else { break; }
Sleep(30); } while( nLoop-- );
// Check to see if things have changed!
pAssigned[i]->nStatus = (nPollFail > 2) ? (BYTE)0 : (BYTE)JOY_US_PRESENT;
if( pAssigned[i]->nStatus != nButtons ) { StatusChanged(hDlg, i); }
// Check for button press and set focus to it!!!
if( pAssigned[i]->nStatus == JOY_US_PRESENT ) { // Do the button press launch thing!
if( SUCCEEDED(pAssigned[i]->fnDeviceInterface->GetDeviceState(sizeof(DIJOYSTATE), lpDIJoyState)) ) { nButtons = pAssigned[i]->nButtons;
// run up the list of buttons and check if there's one that's down!
while( nButtons-- ) { if( lpDIJoyState->rgbButtons[nButtons] & 0x80 ) { // SetFocus on Selected Item
SetListCtrlItemFocus(hListCtrl, i); break; } } } } } }
if( nAssigned ) { /*
* If the selected device is "Not Connected", grey out the property button. */ int id = GetItemData(hListCtrl, (BYTE)iItem); PostDlgItemEnableWindow(hDlg, IDC_BTN_PROPERTIES, (BOOL)(pAssigned[id]->nStatus & JOY_US_PRESENT)); }
} break;
case WM_COMMAND: HANDLE_WM_COMMAND(hDlg, wParam, lParam, OnCommand); return(1);
case WM_NOTIFY: return(HANDLE_WM_NOTIFY(hDlg, wParam, lParam, OnNotify));
case WM_POWERBROADCAST: switch( wParam ) { case PBT_APMSUSPEND: // Suspend operation!
KillTimer(hDlg, ID_MYTIMER); break;
case PBT_APMRESUMESUSPEND: case PBT_APMRESUMECRITICAL: // Resume operation!
SetActive(hDlg); break; } break;
case WM_DEVICECHANGE: switch( (UINT)wParam ) { case DBT_DEVICEQUERYREMOVE: { KillTimer(hDlg, ID_MYTIMER);
BYTE i = (BYTE)::SendMessage(hListCtrl, LVM_GETITEMCOUNT, 0, 0);
// Acquire All Devices that are Attached!!!
char nIndex;
while( i-- ) { // get joystick config of item
nIndex = (char)GetItemData(hListCtrl, i);
if( pAssigned[nIndex]->nStatus & JOY_US_PRESENT ) pAssigned[nIndex]->fnDeviceInterface->Unacquire(); } } break;
case DBT_DEVICEARRIVAL: case DBT_DEVICEREMOVECOMPLETE: if( nFlags & ON_PAGE ) { PostMessage(hDlg, WM_COMMAND, IDC_BTN_REFRESH, 0);
#if 0
if( !(nFlags & BLOCK_UPDATE) ) { KillTimer(hDlg, ID_MYTIMER);
// Set the Update Flag!
nFlags |= UPDATE_ALL;
UpdateListCtrl(hDlg);
SetActive(hDlg);
SetTimer(hDlg, ID_MYTIMER, POLLRATE, 0); } #endif
} break; } break;
case WM_HELP: KillTimer(hDlg, ID_MYTIMER); OnHelp(lParam); SetTimer(hDlg, ID_MYTIMER, POLLRATE, 0); break;
case WM_CONTEXTMENU: nFlags &= ~ON_PAGE; KillTimer(hDlg, ID_MYTIMER); OnContextMenu(wParam, lParam); nFlags |= ON_PAGE; SetTimer(hDlg, ID_MYTIMER, POLLRATE, 0); return(1); }
return(0); }
///////////////////////////////////////////////////////////////////////////////
// StatusChanged( HWND hDlg, BYTE i )
///////////////////////////////////////////////////////////////////////////////
void StatusChanged( HWND hDlg, BYTE i ) { // Update the buttons and set focus to changed item!
PostDlgItemEnableWindow(hDlg, IDC_BTN_PROPERTIES, (BOOL)(pAssigned[i]->nStatus & JOY_US_PRESENT));
if( pAssigned[0] ) { PostDlgItemEnableWindow(hDlg, IDC_BTN_REMOVE, TRUE ); }
// Don't try to make this buffer any smaller...
// Remember... we also have "Not Connected"!
TCHAR sz[20];
// display result
VERIFY(LoadString(ghInstance, (pAssigned[i]->nStatus & JOY_US_PRESENT) ? IDS_GEN_STATUS_OK : IDS_GEN_STATUS_NOTCONNECTED, (LPTSTR)&sz, 20));
LVFINDINFO *lpFindInfo = new (LVFINDINFO); ASSERT (lpFindInfo);
ZeroMemory(lpFindInfo, sizeof(LVFINDINFO));
lpFindInfo->flags = LVFI_PARAM; lpFindInfo->lParam = i;
// Make sure you place i where it's suppose to be!
i = (BYTE)::SendMessage(hListCtrl, LVM_FINDITEM, (WPARAM)(int)-1, (LPARAM)(const LVFINDINFO*)lpFindInfo);
if( lpFindInfo ) delete (lpFindInfo);
SetItemText(hListCtrl, i, STATUS_COLUMN, sz); ::PostMessage(hListCtrl, LVM_UPDATE, (WPARAM)i, 0L); SetListCtrlItemFocus(hListCtrl, i); }
///////////////////////////////////////////////////////////////////////////////
//OnInitDialog(HWND hDlg, HWND hWnd, LPARAM lParam)
///////////////////////////////////////////////////////////////////////////////
BOOL OnInitDialog(HWND hDlg, HWND hWnd, LPARAM lParam) { // initialize our list control
hListCtrl = GetDlgItem(hDlg, IDC_LIST_DEVICE); ASSERT(hListCtrl);
// LVS_EX_ONECLICKACTIVATE removed per PSierra | LVS_EX_INFOTIP
::SendMessage(hListCtrl, LVM_SETEXTENDEDLISTVIEWSTYLE, 0, LVS_EX_FULLROWSELECT);
if( !lpDIInterface ) { if( FAILED(DirectInputCreate(ghInstance, DIRECTINPUT_VERSION, &lpDIInterface, NULL)) ) { #ifdef _DEBUG
OutputDebugString(TEXT("GCDEF.DLL: DirectInputCreate() failed\n")); #endif
Error((short)IDS_INTERNAL_ERROR, (short)IDS_NO_DIJOYCONFIG); return(FALSE); } }
// Dynamically size the columns!
RECT rc; ::GetClientRect(hListCtrl, &rc);
// cut the list control into 1/4ths
rc.right >>= 2;
// This one get's 3/4ths
InsertColumn(hListCtrl, DEVICE_COLUMN, IDS_GEN_DEVICE_HEADING, (USHORT)(rc.right*3));
// Column heading for Status
InsertColumn(hListCtrl, STATUS_COLUMN, IDS_GEN_STATUS_HEADING, (USHORT)(rc.right+3));
if( !pDIJoyConfig ) {
// just in case CoCreateInstanceFailed...
if( FAILED(lpDIInterface->QueryInterface(IID_IDirectInputJoyConfig, (LPVOID*)&pDIJoyConfig)) ) { #ifdef _DEBUG
OutputDebugString (TEXT("JOY.CPL: CoCreateInstance Failed... Closing CPL!\n")); #endif
Error((short)IDS_INTERNAL_ERROR, (short)IDS_NO_DIJOYCONFIG);
return(FALSE); }
VERIFY (SUCCEEDED(pDIJoyConfig->SetCooperativeLevel(hDlg, DISCL_EXCLUSIVE | DISCL_BACKGROUND))); }
// Zero out the global counters!
#ifndef _UNICODE
nGameportDriver = 0; #endif
nGamingDevices = nGameportBus = 0;
// Try to Acquire, if you fail... Disable the Add and Remove buttons!
if( pDIJoyConfig->Acquire() == DIERR_INSUFFICIENTPRIVS ) { nFlags |= USER_MODE;
LONG style = ::GetWindowLong(hListCtrl, GWL_STYLE); style &= ~LVS_EDITLABELS;
::SetWindowLong(hListCtrl, GWL_STYLE, style); } #ifdef WINNT
else { //Run the WDMJOY.INF file!!!
RunWDMJOY(); pDIJoyConfig->SendNotify(); } #endif
if( FAILED(pDIJoyConfig->EnumTypes((LPDIJOYTYPECALLBACK)DIEnumJoyTypeProc, NULL)) ) { #ifdef _DEBUG
OutputDebugString( TEXT("JOY.CPL: Failed BuildEnumList!\n") ); #endif
return(FALSE); }
// Don't allow Add if there is nothing to add!
// OR no port to add them to!
if( ((!nGameportBus) && (!nGamingDevices)) #ifdef _UNICODE
|| GetSystemMetrics(SM_REMOTESESSION) #endif
) { PostDlgItemEnableWindow(hDlg, IDC_BTN_ADD, FALSE); }
// register the JOY_CONFIGCHANGED_MSGSTRING defined in MMDDK.H if you're on Memphis
JoyCfgChangedMsg = (nFlags & ON_NT) ? NULL : RegisterWindowMessage(TEXT("MSJSTICK_VJOYD_MSGSTR"));
// blj: Warning Message that you can't add any more devices!
if( nGamingDevices == MAX_DEVICES-1 ) Error((short)IDS_MAX_DEVICES_TITLE, (short)IDS_MAX_DEVICES_MSG);
// blj: beginning of fix for 5.0 to turn on all devices!
LPDIJOYCONFIG_DX5 pJoyConfig = new (DIJOYCONFIG_DX5); ASSERT (pJoyConfig);
ZeroMemory(pJoyConfig, sizeof(DIJOYCONFIG_DX5));
pJoyConfig->dwSize = sizeof(DIJOYCONFIG_DX5);
// Set the hour glass
SetCursor(LoadCursor(NULL, IDC_WAIT));
BYTE nIndex = nAssigned; HRESULT hr;
while( nIndex ) { hr = pDIJoyConfig->GetConfig(pAssigned[--nIndex]->ID, (LPDIJOYCONFIG)pJoyConfig, DIJC_REGHWCONFIGTYPE);
if( (hr == S_FALSE) || FAILED(hr) ) continue;
if( pJoyConfig->hwc.dwUsageSettings & JOY_US_PRESENT ) continue;
pJoyConfig->hwc.dwUsageSettings |= JOY_US_PRESENT;
VERIFY(SUCCEEDED(pDIJoyConfig->SetConfig(pAssigned[nIndex]->ID, (LPDIJOYCONFIG)pJoyConfig, DIJC_REGHWCONFIGTYPE)));
// Fix #55524
VERIFY(SUCCEEDED(pDIJoyConfig->GetConfig(pAssigned[nIndex]->ID, (LPDIJOYCONFIG)pJoyConfig, DIJC_REGHWCONFIGTYPE)));
if( !(pJoyConfig->hwc.dwUsageSettings & JOY_US_PRESENT) ) { if( SUCCEEDED(pDIJoyConfig->Acquire()) ) { pJoyConfig->hwc.dwUsageSettings |= JOY_US_PRESENT; pJoyConfig->hwc.hwv.dwCalFlags |= 0x80000000; VERIFY(SUCCEEDED(pDIJoyConfig->SetConfig(pAssigned[nIndex]->ID, (LPDIJOYCONFIG)pJoyConfig, DIJC_REGHWCONFIGTYPE))); } } // end of Fix #55524
}
if( pJoyConfig ) delete (pJoyConfig); // blj: end of fix for 5.0 to turn on all devices!
// Set the hour glass
SetCursor(LoadCursor(NULL, IDC_ARROW));
HWND hParentWnd = GetParent(hDlg);
GetWindowRect(hParentWnd, &rc);
// Only center the dialog if this was the page that we started on!
if( (nStartPageCPL == 0) || (nStartPageCPL == NUMJOYDEVS) ) { // Centre the Dialog!
SetWindowPos(hParentWnd, NULL, (GetSystemMetrics(SM_CXSCREEN) - (rc.right-rc.left))>>1, (GetSystemMetrics(SM_CYSCREEN) - (rc.bottom-rc.top))>>1, NULL, NULL, SWP_NOSIZE | SWP_NOZORDER | SWP_SHOWWINDOW);
if( nStartPageCPL == NUMJOYDEVS ) PostMessage(hDlg, WM_COMMAND, IDC_BTN_ADD, 0); }
// Do that move button thing!
MoveOK(hParentWnd);
// this is required because the CPL can be launched via RUNDLL32
if( ::IsWindow(hParentWnd) ) hParentWnd = GetParent(hParentWnd);
// Since the JOY_CONFIGCHANGED_MSGSTRING msg only gets sent to top-level
// windows, this calls for a subclass!
if( JoyCfgChangedMsg ) fpMainWindowProc = (WNDPROC)SetWindowLongPtr(hParentWnd, GWLP_WNDPROC, (LONG_PTR)MsgSubClassProc);
// Set bOnPage so WM_ACTIVATEAPP will work!
nFlags |= ON_PAGE;
// Update the list ctrl!
nFlags |= UPDATE_FOR_GEN;
// to put the selection on the first item on startup...
if( nAssigned ) iItem = 0;
lpDIJoyState = new (DIJOYSTATE); ASSERT (lpDIJoyState);
ZeroMemory(lpDIJoyState, sizeof(DIJOYSTATE));
return(TRUE); }
///////////////////////////////////////////////////////////////////////////////
//OnCommand(HWND hDlg, int id, HWND hWndCtl, UINT code)
///////////////////////////////////////////////////////////////////////////////
void OnCommand(HWND hDlg, int id, HWND hWndCtl, UINT code) { switch( id ) { case IDC_WHATSTHIS: { // point to help file
LPTSTR pszHelpFileName = new TCHAR[STR_LEN_32]; ASSERT (pszHelpFileName);
if( LoadString(ghInstance, IDS_HELPFILENAME, pszHelpFileName, STR_LEN_32) ) WinHelp((HWND)hListCtrl, pszHelpFileName, HELP_WM_HELP, (ULONG_PTR)gaHelpIDs); #ifdef _DEBUG
else OutputDebugString(TEXT("JOY.CPL: OnCommand: LoadString Failed to find IDS_HELPFILENAME!\n")); #endif // _DEBUG
if( pszHelpFileName ) { delete[] (pszHelpFileName); } } return;
case IDC_BTN_REMOVE: KillTimer(hDlg, ID_MYTIMER); nFlags &= ~ON_PAGE;
// Block Update, otherwise we'll be forced to update and we don't need to!
nFlags |= BLOCK_UPDATE;
if( nFlags & USER_MODE ) Error((short)IDS_USER_MODE_TITLE, (short)IDS_USER_MODE); else if( DeleteSelectedItem((PBYTE)&iItem) ) { UpdateButtonState(hDlg);
// Set the UpdateFlag!
nFlags |= UPDATE_FOR_ADV;
// Set the default push button to the Add button!
::PostMessage(hDlg, WM_NEXTDLGCTL, (WPARAM)1, (LPARAM)LOWORD(FALSE)); }
// Unblock the WM_DEVICECHANGE message handler!
nFlags &= ~BLOCK_UPDATE;
nFlags |= ON_PAGE; SetTimer(hDlg, ID_MYTIMER, POLLRATE, 0); break;
case IDC_BTN_ADD: // Don't set ON_PAGE flag!
// We need the WM_DEVICECHANGE message in the case a user plugs in a device!
KillTimer(hDlg, ID_MYTIMER);
ClearArrays();
// Clear everything up before you call this...
if( FAILED(pDIJoyConfig->EnumTypes((LPDIJOYTYPECALLBACK)DIEnumJoyTypeProc, NULL)) ) break;
nFlags &= ~ON_PAGE;
if( nFlags & USER_MODE ) { Error((short)IDS_USER_MODE_TITLE, (short)IDS_USER_MODE); } // call AddDevice dialog
else if( DialogBox( ghInstance, (PTSTR)IDD_ADD, hDlg, (DLGPROC)AddDialogProc ) == IDOK ) { SendMessage(hDlg, WM_COMMAND, IDC_BTN_REFRESH, 0); }
SetListCtrlItemFocus(hListCtrl, (BYTE)iItem);
nFlags &= ~BLOCK_UPDATE; nFlags |= ON_PAGE;
// Now, we set it back active!
SetTimer(hDlg, ID_MYTIMER, POLLRATE, 0); break;
case IDC_BTN_REFRESH: KillTimer(hDlg, ID_MYTIMER);
nFlags |= UPDATE_ALL;
pDIJoyConfig->Acquire(); pDIJoyConfig->SendNotify();
UpdateListCtrl(hDlg); UpdateButtonState(hDlg);
pDIJoyConfig->SendNotify(); pDIJoyConfig->Unacquire();
SetTimer(hDlg, ID_MYTIMER, POLLRATE, 0); break;
case IDC_RENAME: // Don't allow editing of Mouse or Keyboard names!
// Don't allow renaming if in USER mode!
if( !(nFlags & USER_MODE) ) { KillTimer(hDlg, ID_MYTIMER);
::PostMessage(hListCtrl, LVM_EDITLABEL, (WPARAM)(int)iItem, 0); } return;
/* If we want this back...
case IDC_SW_HACK: { // SideWinder Hack button!
BYTE nID = pAssigned[GetItemData(hListCtrl, (BYTE)iItem)]->ID; if (nID == 0) { ::PostMessage(GetDlgItem(hDlg, IDC_SW_HACK), BM_SETCHECK, BST_CHECKED, 0); //CheckDlgButton(hDlg, IDC_SW_HACK, BST_CHECKED);
break; } // Get the Selected Item and force its ID to Zero!
SwapIDs((BYTE)nID, (BYTE)0); } */ // Missing break intentional!
// Used to fall into IDC_BTN_REFRESH!
case IDC_BTN_TSHOOT: { LPTSTR lpszCmd = new (TCHAR[STR_LEN_64]); ASSERT (lpszCmd);
if( LoadString(ghInstance, IDS_TSHOOT_CMD, lpszCmd, STR_LEN_64) ) { LPSTARTUPINFO pSi = (LPSTARTUPINFO)_alloca(sizeof(STARTUPINFO)); LPPROCESS_INFORMATION pPi = (LPPROCESS_INFORMATION)_alloca(sizeof(PROCESS_INFORMATION));
ZeroMemory(pSi, sizeof(STARTUPINFO)); ZeroMemory(pPi, sizeof(PROCESS_INFORMATION));
pSi->cb = sizeof(STARTUPINFO); pSi->dwFlags = STARTF_USESHOWWINDOW | STARTF_FORCEONFEEDBACK; pSi->wShowWindow = SW_NORMAL;
if( CreateProcess(0, lpszCmd, 0, 0, 0, 0, 0, 0, pSi, pPi) ) { CloseHandle(pPi->hThread); CloseHandle(pPi->hProcess); } }
if( lpszCmd ) delete[] (lpszCmd); } break; #if 0 //disable UPDATE button, see manbug 33666.
case IDC_BTN_UPDATE: if (DialogBox(ghInstance, MAKEINTRESOURCE(IDD_UPDATE), hDlg, CplUpdateProc) == IDOK) { Update( hDlg, 1, NULL ); //NO Proxy
} break; #endif
case IDC_BTN_PROPERTIES:
// Because PSN_KILLACTIVE is not sent... we do it ourselves
// kill status timer
KillTimer(hDlg, ID_MYTIMER); nFlags &= ~ON_PAGE;
{ char nIndex = (char)GetItemData(hListCtrl, (BYTE)iItem);
// default to the first page!
#ifdef _DEBUG
HRESULT hr = #endif _DEBUG
Launch(hDlg, pAssigned[nIndex], IsEqualIID(pAssigned[nIndex]->clsidPropSheet, CLSID_LegacyServer) ? 1 : 0);
#ifdef _DEBUG
switch( hr ) { case DIGCERR_NUMPAGESZERO: TRACE (TEXT("JOY.CPL: Launch failed device ID #%d, Page #%d, with the error DIGCERR_NUMPAGESZERO!\n"), pAssigned[nIndex]->ID, id); break;
case DIGCERR_NODLGPROC: TRACE (TEXT("JOY.CPL: Launch failed device ID #%d, Page #%d, with the error DIGCERR_NODLGPROC!\n"), pAssigned[nIndex]->ID, id); break;
case DIGCERR_NOPREPOSTPROC: TRACE (TEXT("JOY.CPL: Launch failed device ID #%d, Page #%d, with the error DIGCERR_NOPREPOSTPROC!\n"), pAssigned[nIndex]->ID, id); break;
case DIGCERR_NOTITLE: TRACE (TEXT("JOY.CPL: Launch failed device ID #%d, Page #%d, with the error DIGCERR_NOTITLE!\n"), pAssigned[nIndex]->ID, id); break;
case DIGCERR_NOCAPTION: TRACE (TEXT("JOY.CPL: Launch failed device ID #%d, Page #%d, with the error DIGCERR_NOCAPTION!\n"), pAssigned[nIndex]->ID, id); break;
case DIGCERR_NOICON: TRACE (TEXT("JOY.CPL: Launch failed device ID #%d, Page #%d, with the error DIGCERR_NOICON!\n"), pAssigned[nIndex]->ID, id); break;
case DIGCERR_STARTPAGETOOLARGE: TRACE (TEXT("JOY.CPL: Launch failed device ID #%d, Page #%d, with the error DIGCERR_STARTPAGETOOLARGE!\n"), pAssigned[nIndex]->ID, id); break;
case DIGCERR_NUMPAGESTOOLARGE: TRACE (TEXT("JOY.CPL: Launch failed device ID #%d, Page #%d, with the error DIGCERR_NUMPAGESTOOLARGE!\n"), pAssigned[nIndex]->ID, id); break;
case DIGCERR_INVALIDDWSIZE: TRACE (TEXT("JOY.CPL: Launch failed device ID #%d, Page #%d, with the error DIGCERR_INVALIDDWSIZE!\n"), pAssigned[nIndex]->ID, id); break;
case E_NOINTERFACE: TRACE (TEXT("JOY.CPL: Launch failed device ID #%d, Page #%d, with the error E_NOINTERFACE!\n"), pAssigned[nIndex]->ID, id); break;
case E_OUTOFMEMORY: TRACE (TEXT("JOY.CPL: Launch failed device ID #%d, Page #%d, with the error E_OUTOFMEMORY!\n"), pAssigned[nIndex]->ID, id); break;
//case DIGCERR_NUMPAGESTOOLARGE:
//case DIGCERR_STARTPAGETOOLARGE:
default: // Only display this return code if things are going Really weird.
TRACE (TEXT("JOY.CPL: Launch return code is %x %s!\n"), hr, strerror(hr)); break; } #endif // _DEBUG
nFlags |= ON_PAGE;
//OutputDebugString(TEXT("JOY.CPL: Cpanel.cpp: returned from Property sheet!\n"));
InvalidateRect(hDlg, NULL, TRUE); UpdateWindow(hDlg);
// Now, we set it back active!
// create timer
SetTimer(hDlg, ID_MYTIMER, POLLRATE, 0); } break; }
// Set the focus where we left off!
if( iItem == NO_ITEM ) iItem = 0;
SetListCtrlItemFocus(hListCtrl, (BYTE)iItem); }
////////////////////////////////////////////////////////////////////////////////
// OnNotify(HWND hDlg, WPARAM idFrom, NMHDR* pnmhdr)
// Purpose: WM_NOTIFY Handler
////////////////////////////////////////////////////////////////////////////////
BOOL OnNotify(HWND hDlg, WPARAM idFrom, NMHDR* pnmhdr) { switch( pnmhdr->code ) { case PSN_QUERYCANCEL: if( nFlags & UPDATE_INPROCESS ) nFlags &= ~UPDATE_INPROCESS; break;
case LVN_BEGINLABELEDIT: if( nFlags & USER_MODE ) return(TRUE);
KillTimer(hDlg, ID_MYTIMER); ::PostMessage((HWND)::SendMessage(hListCtrl, LVM_GETEDITCONTROL, 0, 0), EM_SETLIMITTEXT, MAX_STR_LEN, 0);
// This lets us know if the edit field is up!
nFlags |= UPDATE_INPROCESS; return(FALSE);
/*
case LVN_GETINFOTIP: { LPLVHITTESTINFO lpHit = new (LVHITTESTINFO); ASSERT (lpHit);
BOOL bRet = FALSE;
POINT pt; GetCursorPos(&pt); ScreenToClient(hListCtrl, &pt);
lpHit->pt = pt; lpHit->flags = lpHit->iItem = lpHit->iSubItem = 0;
::SendMessage(hListCtrl, LVM_SUBITEMHITTEST, 0, (LPARAM)(LPLVHITTESTINFO)lpHit);
// We only want to support the device column!
if (lpHit->iSubItem == 0) { if (lpHit->flags & LVHT_ONITEMLABEL) { // Determine the text length of the column text
LPTSTR lpStr = new (TCHAR[MAX_STR_LEN+1]); ASSERT (lpStr);
GetItemText(hListCtrl, lpHit->iItem, lpHit->iSubItem, lpStr, MAX_STR_LEN);
// Determine if the latter will fit inside the former...
SIZE size; HDC hDC = GetDC(hListCtrl); GetTextExtentPoint(hDC, lpStr, lstrlen(lpStr), &size); ReleaseDC(hListCtrl, hDC);
// Determine how wide the column is!
short nWidth = (short)::SendMessage(hListCtrl, LVM_GETCOLUMNWIDTH, lpHit->iSubItem, 0);
bRet = (BOOL)(size.cx > nWidth);
if (bRet) // if not, copy the text into lpHit->pszText
_tcscpy(((LPNMLVGETINFOTIP)pnmhdr)->pszText, lpStr);
if (lpStr) delete[] (lpStr); } }
if (lpHit) delete (lpHit);
return bRet; } */
case LVN_ENDLABELEDIT: if( nFlags & UPDATE_INPROCESS ) { HWND hCtrl = (HWND)::SendMessage(hListCtrl, LVM_GETEDITCONTROL, 0, 0); ASSERT(::IsWindow(hCtrl));
if( ::SendMessage(hCtrl, EM_GETMODIFY, 0, 0) ) { BYTE nLen = (BYTE)lstrlen(((NMLVDISPINFO *)pnmhdr)->item.pszText);
if( (nLen > MAX_STR_LEN) || (nLen == 0) ) MessageBeep(MB_ICONHAND);
// Make sure the name is usable!
else if( _tcschr(((NMLVDISPINFO *)pnmhdr)->item.pszText, TEXT('\\')) ) { Error((short)IDS_INVALID_NAME_TITLE, (short)IDS_INVALID_NAME); } else { // Set the Update flag!
nFlags |= UPDATE_ALL;
LPDIPROPSTRING pDIPropString = new (DIPROPSTRING); ASSERT (pDIPropString);
ZeroMemory(pDIPropString, sizeof(DIPROPSTRING));
pDIPropString->diph.dwSize = sizeof(DIPROPSTRING); pDIPropString->diph.dwHeaderSize = sizeof(DIPROPHEADER); pDIPropString->diph.dwHow = DIPH_DEVICE;
#ifdef _UNICODE
wcscpy(pDIPropString->wsz, ((NMLVDISPINFO *)pnmhdr)->item.pszText); #else
USES_CONVERSION; wcscpy(pDIPropString->wsz, A2W(((NMLVDISPINFO *)pnmhdr)->item.pszText)); #endif
if( SUCCEEDED(pAssigned[iItem]->fnDeviceInterface->SetProperty(DIPROP_INSTANCENAME, &pDIPropString->diph)) ) { SetItemText(hListCtrl, (BYTE)iItem, 0, ((NMLVDISPINFO *)pnmhdr)->item.pszText); } else { Error((short)IDS_NO_RENAME_TITLE, (short)IDS_NO_RENAME); }
if( pDIPropString ) delete (pDIPropString);
// Trip the flag so the Advanced page knows it needs to update!
nFlags |= UPDATE_FOR_ADV; } } // Clear the InProcess flag!
nFlags &= ~UPDATE_INPROCESS;
} SetTimer(hDlg, ID_MYTIMER, POLLRATE, 0); break;
case LVN_KEYDOWN: switch( ((LV_KEYDOWN*)pnmhdr)->wVKey ) { case VK_DELETE: if( iItem != NO_ITEM ) SendMessage(hDlg, WM_COMMAND, IDC_BTN_REMOVE, 0); break;
case VK_F5: nFlags |= UPDATE_ALL;
UpdateListCtrl(hDlg);
if( GetKeyState(VK_SHIFT) & 0x80 ) { #ifdef WINNT
RunWDMJOY(); #endif
ClearArrays();
pDIJoyConfig->EnumTypes((LPDIJOYTYPECALLBACK)DIEnumJoyTypeProc, NULL); } break; } break;
#if 0
case LVN_COLUMNCLICK: { CListCtrl *pCtrl = new (CListCtrl); ASSERT(pCtrl);
pCtrl->Attach(hListCtrl);
if( ((NM_LISTVIEW*)pnmhdr)->iSubItem ) { static bItemDirection = TRUE;
SortTextItems(pCtrl, 0, bItemDirection =! bItemDirection, 0, -1); } else { static bLabelDirection = TRUE;
SortTextItems(pCtrl, 0, bLabelDirection =! bLabelDirection, 0, -1); }
pCtrl->Detach();
if( pCtrl ) delete (pCtrl); } break; #endif
case LVN_ITEMCHANGED: if( iItem != NO_ITEM ) { // get index of selected item
// no point if it's not changed!
if( iItem != (short)((NM_LISTVIEW*)pnmhdr)->iItem ) { int i = GetItemData(hListCtrl, (char)iItem);
iItem = (short)((NM_LISTVIEW*)pnmhdr)->iItem;
iAdvItem = pAssigned[i]->ID;
UpdateButtonState(hDlg); } } break;
case NM_DBLCLK: switch( idFrom ) { case IDC_LIST_DEVICE: if( iItem == NO_ITEM ) { if( !(nFlags & USER_MODE) && nGameportBus ) OnCommand(hDlg, IDC_BTN_ADD, 0, 0); } else if( IsWindowEnabled(GetDlgItem(hDlg, IDC_BTN_PROPERTIES)) ) { // make sure the connected one has got an interface pointer...
OnCommand(hDlg, IDC_BTN_PROPERTIES, 0, 0); } break; } break;
case PSN_KILLACTIVE: KillTimer(hDlg, ID_MYTIMER);
nFlags &= ~ON_PAGE;
if( nFlags & UPDATE_INPROCESS ) SetFocus(hListCtrl);
#ifdef _UNICODE
if( hNotifyDevNode ) UnregisterDeviceNotification(hNotifyDevNode); #endif
PostMessage(hDlg, WM_ACTIVATEAPP, FALSE, 0); break;
case PSN_SETACTIVE: nFlags |= ON_PAGE; nFlags |= UPDATE_FOR_GEN; #ifdef _UNICODE
// Set up the Device Notification
RegisterForDevChange(hDlg, &hNotifyDevNode); #endif
SendMessage(hDlg, WM_ACTIVATEAPP, TRUE, 0); break; } return(TRUE); }
////////////////////////////////////////////////////////////////////////////////////////
// OnDestroy(HWND hWnd)
////////////////////////////////////////////////////////////////////////////////////////
void OnDestroy(HWND hWnd) { SetWindowPos( GetParent(hWnd), NULL, NULL, NULL, NULL, NULL, SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_HIDEWINDOW);
if( lpDIJoyState ) delete (lpDIJoyState);
// if you are looking for where the following variables are deleted, look
// in DLL_PROCESS_DETACH in MAIN.CPP:
// pwszTypeArray, pwszGameportDriverArray, pwszGameportBus
// This is done because of the way several Microsoft games load the CPL and
// Don't Unload it between loads.
// Clear pAssigned
while( nAssigned ) { if( pAssigned[--nAssigned] ) { delete (pAssigned[nAssigned]);
pAssigned[nAssigned] = 0; } } // delete all existing entries
//::PostMessage(hListCtrl, LVM_DELETEALLITEMS, 0, 0);
// release the DI JoyConfig interface pointer
if( pDIJoyConfig ) { pDIJoyConfig->Release(); pDIJoyConfig = 0; }
// release the DI Device interface pointer
if( lpDIInterface ) { lpDIInterface->Release(); lpDIInterface = 0; }
// Drop the subclass, else you'll crash!
if( !(nFlags & ON_NT) ) SetWindowLongPtr(GetParent(GetParent(hWnd)), GWLP_WNDPROC, (LONG_PTR)fpMainWindowProc); }
////////////////////////////////////////////////////////////////////////////////////////
// OnHelp(LPARAM lParam)
////////////////////////////////////////////////////////////////////////////////////////
void OnHelp(LPARAM lParam) { // point to help file
LPTSTR pszHelpFileName = new TCHAR[STR_LEN_32]; ASSERT (pszHelpFileName);
if( LoadString(ghInstance, IDS_HELPFILENAME, pszHelpFileName, STR_LEN_32) ) { if( ((LPHELPINFO)lParam)->iContextType == HELPINFO_WINDOW ) WinHelp((HWND)((LPHELPINFO)lParam)->hItemHandle, pszHelpFileName, HELP_WM_HELP, (ULONG_PTR)gaHelpIDs);
} #ifdef _DEBUG
else OutputDebugString(TEXT("JOY.CPL: OnHelp: LoadString Failed to find IDS_HELPFILENAME!\n")); #endif
if( pszHelpFileName ) delete[] (pszHelpFileName); }
////////////////////////////////////////////////////////////////////////////////////////
// OnContextMenu(WPARAM wParam)
////////////////////////////////////////////////////////////////////////////////////////
void OnContextMenu(WPARAM wParam, LPARAM lParam) { // this prevents double handling of this message
if( (HWND)wParam == hListCtrl ) { OnListViewContextMenu(GetParent((HWND)wParam), lParam); return; }
// point to help file
LPTSTR pszHelpFileName = new TCHAR[STR_LEN_32]; ASSERT (pszHelpFileName);
if( LoadString(ghInstance, IDS_HELPFILENAME, pszHelpFileName, STR_LEN_32) ) WinHelp((HWND)wParam, pszHelpFileName, HELP_CONTEXTMENU, (ULONG_PTR)gaHelpIDs); #ifdef _DEBUG
else OutputDebugString(TEXT("JOY.CPL: OnContextMenu: LoadString Failed to find IDS_HELPFILENAME!\n")); #endif
if( pszHelpFileName ) delete[] (pszHelpFileName); }
/////////////////////////////////////////////////////////////////////////////////////////
// OnListViewContextMenu(HWND hDlg)
// Purpose: Query the plug-in for the selected device for it's characteristics
// Then construct a menu to reflect your findings
/////////////////////////////////////////////////////////////////////////////////////////
void OnListViewContextMenu(HWND hDlg, LPARAM lParam) { BOOL bRet = TRUE;
HMENU hPopupMenu = CreatePopupMenu(); ASSERT (hPopupMenu);
LPTSTR psz = new TCHAR[STR_LEN_32]; ASSERT (psz);
// Add the Refresh text
VERIFY(LoadString(ghInstance, IDS_REFRESH, psz, STR_LEN_32)); bRet = AppendMenu(hPopupMenu, MF_ENABLED, IDC_BTN_REFRESH, psz);
// Add the Add text
HWND hCtrl;
// Only Display Add menu option if we've found a GameportBus!!!
if( nGameportBus #ifdef _UNICODE
&& !GetSystemMetrics(SM_REMOTESESSION) #endif
) { hCtrl = GetDlgItem(hDlg, IDC_BTN_ADD); ASSERT(hCtrl);
if( IsWindowEnabled(hCtrl) ) { ::SendMessage(hCtrl, WM_GETTEXT, (WPARAM)STR_LEN_32, (LPARAM)(LPCTSTR)psz);
bRet = AppendMenu(hPopupMenu, MF_ENABLED, IDC_BTN_ADD, psz); if( !bRet ) TRACE(TEXT("JOY.CPL: AppendMenu Failed to insert %s\n"), psz); } }
// Add the Remove text
hCtrl = GetDlgItem(hDlg, IDC_BTN_REMOVE); ASSERT(hCtrl);
// Only Show it if it's available
if( IsWindowEnabled(hCtrl) && (iItem != NO_ITEM) ) { ::SendMessage(hCtrl, WM_GETTEXT, (WPARAM)STR_LEN_32, (LPARAM)(LPCTSTR)psz);
bRet = AppendMenu(hPopupMenu, MF_ENABLED, IDC_BTN_REMOVE, psz); if( !bRet ) TRACE(TEXT("JOY.CPL: AppendMenu Failed to insert %s\n"), psz); }
// Add the Properties text
hCtrl = GetDlgItem(hDlg, IDC_BTN_PROPERTIES); ASSERT (hCtrl);
if( IsWindowEnabled(hCtrl) ) { ::SendMessage(hCtrl, WM_GETTEXT, (WPARAM)STR_LEN_32, (LPARAM)(LPCTSTR)psz);
bRet = AppendMenu(hPopupMenu, MF_ENABLED, IDC_BTN_PROPERTIES, psz); if( !bRet ) TRACE(TEXT("JOY.CPL: AppendMenu Failed to insert %s\n"), psz); }
// Add the Rename text if not a USER!
if( !(nFlags & USER_MODE) ) { if( nAssigned && (iItem != NO_ITEM) ) { VERIFY(LoadString(ghInstance, IDS_RENAME, psz, STR_LEN_32)); bRet = AppendMenu(hPopupMenu, MF_ENABLED, IDC_RENAME, psz); } }
bRet = AppendMenu(hPopupMenu, MF_SEPARATOR, 0, 0); if( !bRet ) TRACE(TEXT("JOY.CPL: AppendMenu Failed to insert the separator!\n"), psz);
VERIFY(LoadString(ghInstance, IDS_WHATSTHIS, psz, STR_LEN_32)); bRet = AppendMenu(hPopupMenu, MF_ENABLED, IDC_WHATSTHIS, psz); if( !bRet ) TRACE(TEXT("JOY.CPL: AppendMenu Failed to insert %s\n"), psz);
if( psz ) delete[] (psz);
POINT pt;
// lParam is -1 if we got here via Shift+F10
if( lParam > 0 ) { pt.x = GET_X_LPARAM(lParam); pt.y = GET_Y_LPARAM(lParam); } else { // Centre the popup on the selected item!
// This get's a good X pos, but the y is the start of the control!
::SendMessage(hListCtrl, LVM_GETITEMPOSITION, iItem, (LPARAM)&pt);
RECT rc; ::GetClientRect(hListCtrl, &rc);
pt.x = rc.right>>1;
ClientToScreen(hListCtrl, &pt); }
// restore selection focus
SetListCtrlItemFocus(hListCtrl, (BYTE)iItem);
bRet = TrackPopupMenu (hPopupMenu, TPM_LEFTALIGN|TPM_LEFTBUTTON|TPM_RIGHTBUTTON, pt.x, pt.y, 0, hDlg, NULL); if( !bRet ) TRACE (TEXT("JOY.CPL: TrackPopupMenu Failed!\n"));
if(hPopupMenu) DestroyMenu (hPopupMenu); // PREFIX 45088
// Set the focus back to the item it came from!
SetListCtrlItemFocus(hListCtrl, (BYTE)iItem); }
int CALLBACK CompareStatusItems(LPARAM item1, LPARAM item2, LPARAM uDirection) { if( (((PJOY)item1)->nStatus & JOY_US_PRESENT) == (((PJOY)item2)->nStatus & JOY_US_PRESENT) ) return(0);
return(uDirection) ? -1 : 1; }
///////////////////////////////////////////////////////////////////////////////
// FUNCTION: DeleteSelectedItem ( BYTE nItem )
//
// PARAMETERS: nItem - ID of item to remove
//
// PURPOSE: Prompt the user, delete the selected device from the listview, and update the registry
//
// RETURN: TRUE if successfull, FALSE otherwise
///////////////////////////////////////////////////////////////////////////////
BOOL DeleteSelectedItem( PBYTE pnItem ) { BYTE nItem = *pnItem; // don't process if nothing is selected.
if( *pnItem == NO_ITEM ) return(FALSE);
LV_ITEM lvItem; lvItem.mask = LVIF_PARAM; lvItem.iSubItem = 0; lvItem.iItem = *pnItem;
if( !ListView_GetItem(hListCtrl, &lvItem) ) return(FALSE);
::PostMessage(hListCtrl, LVM_ENSUREVISIBLE, *pnItem, FALSE );
LPTSTR pszTitle = new TCHAR[STR_LEN_64]; ASSERT (pszTitle);
// Query user if they are sure!
VERIFY(LoadString(ghInstance, IDS_GEN_AREYOUSURE, pszTitle, STR_LEN_64));
// Get the name of the device for the message box!
//PREFIX #WI226554. Won't fix. Obsolete code, from Whistler on replaced with new version.
LPTSTR lptszTmp = new TCHAR[STR_LEN_64];
// Make sure the name isn't so long as to over-write the buffer!
if( GetItemText(hListCtrl, (BYTE)*pnItem, DEVICE_COLUMN, lptszTmp, STR_LEN_64) > 60 ) { lptszTmp[60] = lptszTmp[61] = lptszTmp[62] = TEXT('.'); lptszTmp[63] = TEXT('\0'); }
LPTSTR pszMsg = new TCHAR[MAX_STR_LEN]; ASSERT (pszMsg);
wsprintf( pszMsg, pszTitle, lptszTmp);
if( lptszTmp ) delete[] (lptszTmp);
VERIFY(LoadString(ghInstance, IDS_GEN_AREYOUSURE_TITLE, pszTitle, STR_LEN_64));
BOOL bRet = (BOOL)(IDYES == MessageBox(GetFocus(), pszMsg, pszTitle, MB_ICONQUESTION | MB_YESNO | MB_APPLMODAL));
if( pszMsg ) delete[] (pszMsg); if( pszTitle ) delete[] (pszTitle);
if( bRet ) { HRESULT hr;
// Check for privileges!
if( SUCCEEDED(hr = pDIJoyConfig->Acquire()) ) { char nIndex = (char)GetItemData(hListCtrl, (BYTE)*pnItem);
// Set the hour glass
SetCursor(LoadCursor(NULL, IDC_WAIT));
// Verify that you can delete the Config before you release the interface pointers!
if( SUCCEEDED(hr = pDIJoyConfig->DeleteConfig(pAssigned[nIndex]->ID)) ) { // make sure VJOYD is initialized
if( !(nFlags & ON_NT) ) VERIFY (SUCCEEDED(pDIJoyConfig->SendNotify()));
::SendMessage(hListCtrl, LVM_DELETEITEM, (WPARAM)(int)*pnItem, 0);
// Move the last assigned to the hole... if there is one!
if( nIndex != (nAssigned-1) ) { // Before you move the tail to the hole,
// Release() the interfaces at the hole!
pAssigned[nIndex]->fnDeviceInterface->Unacquire(); pAssigned[nIndex]->fnDeviceInterface->Release();
// Move the tail to the hole.
CopyMemory(pAssigned[nIndex], pAssigned[nAssigned-1], sizeof (JOY));
pAssigned[nAssigned-1]->fnDeviceInterface = 0;
// Don't forget to set the index in the item data!
SetItemData(hListCtrl, nItem, nIndex);
// Assign the tail to the hole so it gets deleted!
nIndex = nAssigned-1;
// Don't forget to set the index in the item data!
// QZheng: This line is very wrong!!!
//SetItemData(hListCtrl, (BYTE)*pnItem, nIndex);
}
// delete the memory...
if( pAssigned[nIndex] ) { delete (pAssigned[nIndex]); pAssigned[nIndex] = 0; }
// Set the focus before you corrupt iItem
SetListCtrlItemFocus(hListCtrl, nIndex);
pDIJoyConfig->SendNotify(); //do more to make sure
pDIJoyConfig->Unacquire();
// dec nAssigned
nAssigned--;
// if there's no items, tell iItem about it!
if( nAssigned == 0 ) *pnItem = NO_ITEM; } else if( hr == DIERR_UNSUPPORTED ) { Error((short)IDS_GEN_AREYOUSURE_TITLE, (short)IDS_GEN_NO_REMOVE_USB); }
// Set the hour glass
SetCursor(LoadCursor(NULL, IDC_ARROW)); } } return(bRet); }
///////////////////////////////////////////////////////////////////////////////
// FUNCTION: DIEnumJoyTypeProc( LPCWSTR pwszTypeName, LPVOID pvRef )
//
// PARAMETERS: LPCWSTR pwszTypeName - Type name of the device enumerated
// LPVOID pvRef -
//
// PURPOSE: To Enumerate the types of devices associated with this system
//
// RETURN: TRUE if successfull, FALSE otherwise
///////////////////////////////////////////////////////////////////////////////
BOOL CALLBACK DIEnumJoyTypeProc( LPCWSTR pwszTypeName, LPVOID pvRef ) { // Type info
LPDIJOYTYPEINFO_DX5 lpdiJoyInfo = (LPDIJOYTYPEINFO_DX5)_alloca(sizeof(DIJOYTYPEINFO_DX5)); ASSERT (lpdiJoyInfo);
ZeroMemory(lpdiJoyInfo, sizeof(DIJOYTYPEINFO_DX5));
lpdiJoyInfo->dwSize = sizeof(DIJOYTYPEINFO_DX5);
// populate the Type Info
switch( pDIJoyConfig->GetTypeInfo(pwszTypeName, (LPDIJOYTYPEINFO)lpdiJoyInfo, DITC_REGHWSETTINGS) ) { // errors to continue with...
case DIERR_NOTFOUND: TRACE(TEXT("JOY.CPL: GetTypeInfo returned DIERR_NOTFOUND for type %s!\n"), pwszTypeName); return(DIENUM_CONTINUE);
// errors to stop with...
case DIERR_INVALIDPARAM: TRACE(TEXT("JOY.CPL: GetTypeInfo returned DIERR_INVALIDPARAM!\n")); case DIERR_NOMOREITEMS: return(DIENUM_STOP); }
// a quick check to make sure we don't have the infamous array out of bounds problem!
#ifndef _UNICODE
if( nGameportDriver > MAX_GLOBAL_PORT_DRIVERS-1 ) { #ifdef DEBUG
OutputDebugString(TEXT("JOY.CPL: Cpanel.cpp: DIEnumJoyTypeProc: Global Gameport Drivers have exceeded MAX_GLOBAL_PORT_DRIVERS!\n")); #endif
return(DIENUM_STOP); } #endif
if( nGameportBus > MAX_BUSSES-1 ) { #ifdef DEBUG
OutputDebugString(TEXT("JOY.CPL: Cpanel.cpp: DIEnumJoyTypeProc: Enumerated Gameport busses have exceeded MAX_BUSSES!\n")); #endif // _DEBUG
return(DIENUM_STOP); }
if( nGamingDevices > MAX_DEVICES-1 ) { #ifdef DEBUG
OutputDebugString(TEXT("JOY.CPL: Cpanel.cpp: DIEnumJoyTypeProc: Enumerated Gameport busses have exceeded MAX_DEVICES!\n")); #endif // _DEBUG
return(DIENUM_STOP); }
// check to see if it's a global port driver
#ifndef _UNICODE
if( lpdiJoyInfo->hws.dwFlags & JOY_HWS_ISGAMEPORTDRIVER ) { if( pwszGameportDriverArray[nGameportDriver] ) wcsncpy(pwszGameportDriverArray[nGameportDriver], pwszTypeName, wcslen(pwszTypeName)+1); else pwszGameportDriverArray[nGameportDriver] = _wcsdup(pwszTypeName); nGameportDriver++; } else #endif // _UNICODE
if( lpdiJoyInfo->hws.dwFlags & JOY_HWS_ISGAMEPORTBUS ) { if( pwszGameportBus[nGameportBus] ) wcscpy(pwszGameportBus[nGameportBus], pwszTypeName); else pwszGameportBus[nGameportBus] = _wcsdup(pwszTypeName); nGameportBus++; } else { if( !(lpdiJoyInfo->hws.dwFlags & JOY_HWS_AUTOLOAD) ) { // it's a standard gaming device
if( pwszTypeArray[nGamingDevices] ) wcsncpy(pwszTypeArray[nGamingDevices], pwszTypeName, wcslen(pwszTypeName)+1); else pwszTypeArray[nGamingDevices] = _wcsdup(pwszTypeName); nGamingDevices++; } } return(DIENUM_CONTINUE); }
///////////////////////////////////////////////////////////////////////////////
// FUNCTION: DIEnumDevicesProc(LPDIDEVICEINSTANCE lpDeviceInst, LPVOID lpVoid)
//
// PARAMETERS: LPDIDEVICEINSTANCE lpDeviceInst - Device Instance
// LPVOID lpVoid -
//
// PURPOSE: To Enumerate the devices associated with this system
//
// RETURN: TRUE if successfull, FALSE otherwise
///////////////////////////////////////////////////////////////////////////////
BOOL CALLBACK DIEnumDevicesProc(LPDIDEVICEINSTANCE lpDeviceInst, LPVOID lpVoid) { LPDIRECTINPUTDEVICE pdiDevTemp;
pDIJoyConfig->Acquire();
// First Create the device
if( SUCCEEDED(lpDIInterface->CreateDevice(lpDeviceInst->guidInstance, &pdiDevTemp, 0)) ) { PJOY pNewJoy = new JOY; ASSERT (pNewJoy);
// Query for a device2 object
if( FAILED(pdiDevTemp->QueryInterface(IID_IDirectInputDevice2, (LPVOID*)&pNewJoy->fnDeviceInterface)) ) { #ifdef _DEBUG
OutputDebugString(TEXT("JOY.CPL: Cpanel.cpp: DIEnumDevicesProc: QueryInterface failed!\n")); #endif
// release the temporary object
pdiDevTemp->Release(); return(FALSE); }
DIPROPDWORD *pDIPropDW = new (DIPROPDWORD); ASSERT (pDIPropDW);
ZeroMemory(pDIPropDW, sizeof(DIPROPDWORD));
pDIPropDW->diph.dwSize = sizeof(DIPROPDWORD); pDIPropDW->diph.dwHeaderSize = sizeof(DIPROPHEADER); pDIPropDW->diph.dwHow = DIPH_DEVICE;
// Get the device ID
VERIFY (SUCCEEDED(pdiDevTemp->GetProperty(DIPROP_JOYSTICKID, &pDIPropDW->diph)));
// release the temporary object
pdiDevTemp->Release();
pNewJoy->ID = (char)pDIPropDW->dwData;
if( pDIPropDW ) delete (pDIPropDW);
// Get the Type name
LPDIJOYCONFIG_DX5 lpDIJoyCfg = new (DIJOYCONFIG_DX5); ASSERT (lpDIJoyCfg);
ZeroMemory(lpDIJoyCfg, sizeof(DIJOYCONFIG_DX5));
lpDIJoyCfg->dwSize = sizeof(DIJOYCONFIG_DX5);
VERIFY (SUCCEEDED(pDIJoyConfig->GetConfig(pNewJoy->ID, (LPDIJOYCONFIG)lpDIJoyCfg, DIJC_REGHWCONFIGTYPE | DIJC_CALLOUT)));
// Get the clsidConfig
LPDIJOYTYPEINFO lpDIJoyType = new (DIJOYTYPEINFO); ASSERT(lpDIJoyType);
ZeroMemory(lpDIJoyType, sizeof(DIJOYTYPEINFO));
lpDIJoyType->dwSize = sizeof(DIJOYTYPEINFO);
VERIFY (SUCCEEDED(pDIJoyConfig->GetTypeInfo(lpDIJoyCfg->wszType, (LPDIJOYTYPEINFO)lpDIJoyType, DITC_CLSIDCONFIG | DITC_REGHWSETTINGS | DITC_FLAGS1 )));
if( lpDIJoyCfg ) delete (lpDIJoyCfg);
// if NULL, Leave as default.
if( !IsEqualIID(lpDIJoyType->clsidConfig, GUID_NULL) ) { pNewJoy->fHasOemSheet = TRUE; if( !(lpDIJoyType->dwFlags1 & JOYTYPE_DEFAULTPROPSHEET) ) { pNewJoy->clsidPropSheet = lpDIJoyType->clsidConfig; } } else { pNewJoy->fHasOemSheet = FALSE; }
// Assign the number of buttons!
pNewJoy->nButtons = (BYTE)(lpDIJoyType->hws.dwNumButtons);
if( lpDIJoyType ) delete (lpDIJoyType);
// Set it's format!!!
if( SUCCEEDED(pNewJoy->fnDeviceInterface->SetDataFormat(&c_dfDIJoystick)) ) { // Set it's Cooperative Level!
if( FAILED(pNewJoy->fnDeviceInterface->SetCooperativeLevel(GetParent((HWND)GetParent(hListCtrl)), DISCL_NONEXCLUSIVE | DISCL_BACKGROUND)) ) { #ifdef _DEBUG
OutputDebugString(TEXT("JOY.CPL: Cpanel.cpp: DIEnumDevicesProc: SetCooperativeLevel Failed!\n")); #endif
} }
// Add the item to the tree!
pAssigned[nAssigned] = pNewJoy;
// If you're on the General page!
if( nFlags & ON_PAGE ) { // add to tree
LVITEM lvItem = {LVIF_TEXT | LVIF_PARAM, nAssigned, 0, 0, 0, lpDeviceInst->tszInstanceName, lstrlen(lpDeviceInst->tszInstanceName), 0, (LPARAM)nAssigned, 0}; ::SendMessage(hListCtrl, LVM_INSERTITEM, 0, (LPARAM) (const LPLVITEM)&lvItem); //InsertItem(hListCtrl, lpDeviceInst->tszInstanceName, nAssigned);
TCHAR sz[STR_LEN_32]; VERIFY(LoadString(ghInstance, IDS_GEN_STATUS_UNKNOWN, (LPTSTR)&sz, STR_LEN_32));
SetItemText(hListCtrl, nAssigned, STATUS_COLUMN, sz); }
// Increment the array counter!
nAssigned++; if( nAssigned == nTargetAssigned ) { /*
* A new device arrived so assume there's no * longer any point in checking on the timer. */ nTargetAssigned = (BYTE)-1; nReEnum = 0; }
} return(DIENUM_CONTINUE); }
///////////////////////////////////////////////////////////////////////////////
// FUNCTION: ClearArrays ( void )
//
// PARAMETERS:
//
//
// PURPOSE:
//
// RETURN:
///////////////////////////////////////////////////////////////////////////////
void ClearArrays( void ) { #ifndef _UNICODE
while( nGameportDriver ) { free(pwszGameportDriverArray[--nGameportDriver]); pwszGameportDriverArray[nGameportDriver] = L'\0'; }
#endif // _UNICODE
while( nGamingDevices ) { free(pwszTypeArray[--nGamingDevices]); pwszTypeArray[nGamingDevices] = L'\0'; }
while( nGameportBus ) { free(pwszGameportBus[--nGameportBus]); pwszGameportBus[nGameportBus] = L'\0'; memset( &guidOccupied[nGameportBus], 0, sizeof(GUID) ); } }
///////////////////////////////////////////////////////////////////////////////
// FUNCTION: UpdateListCtrl( HWND hDlg )
//
// PARAMETERS: HWND hDlg - Handle to window to update
//
// PURPOSE: Refreshes enumerated device list
//
// RETURN: TRUE if successfull, FALSE otherwise
///////////////////////////////////////////////////////////////////////////////
static void UpdateListCtrl( HWND hDlg ) { if( !(nFlags & ON_PAGE) ) return;
// Turn Redraw off here else it will flicker!
::SendMessage(hListCtrl, WM_SETREDRAW, (WPARAM)FALSE, 0);
// delete all existing entries
::SendMessage(hListCtrl, LVM_DELETEALLITEMS, 0, 0);
Enumerate( hDlg );
// turn the flag off!
if( nFlags & UPDATE_FOR_GEN ) nFlags &= ~UPDATE_FOR_GEN;
// Turn the redraw flag back on!
::SendMessage (hListCtrl, WM_SETREDRAW, (WPARAM)TRUE, 0); InvalidateRect(hListCtrl, NULL, TRUE); }
//#ifdef _UNICODE
HRESULT Enumerate( HWND hDlg ) { nFlags |= UPDATE_ALL;
// Clear pAssigned
while( nAssigned ) { if( pAssigned[--nAssigned] ) { delete (pAssigned[nAssigned]);
pAssigned[nAssigned] = 0; } }
// Enumerate the Joysticks and put them in the list... | DIEDFL_INCLUDEPHANTOMS
#ifdef _UNICODE
return(lpDIInterface->EnumDevices(DIDEVTYPE_JOYSTICK, (LPDIENUMDEVICESCALLBACK)DIEnumDevicesProc, (LPVOID)hDlg, DIEDFL_ALLDEVICES )); #else
return(lpDIInterface->EnumDevices(DIDEVTYPE_JOYSTICK, (LPDIENUMDEVICESCALLBACK)DIEnumDevicesProc, (LPVOID)hDlg, DIEDFL_ALLDEVICES | DIEDFL_INCLUDEPHANTOMS)); #endif
} /*
#else
HRESULT Enumerate( HWND hDlg ) { // Clear pAssigned
while (nAssigned) { if (pAssigned[--nAssigned]) { delete (pAssigned[nAssigned]);
pAssigned[nAssigned] = 0; } }
DIJOYCONFIG *pJoyConfig = new DIJOYCONFIG; ASSERT (pJoyConfig);
pJoyConfig->dwSize = sizeof (DIJOYCONFIG);
LPDIJOYTYPEINFO pdiJoyTypeInfo = new DIJOYTYPEINFO; ASSERT (pdiJoyTypeInfo);
pdiJoyTypeInfo->dwSize = sizeof (DIJOYTYPEINFO);
HRESULT hr;
// find and assign ID's
for (BYTE n = 0; n < NUMJOYDEVS; n++) { hr = pDIJoyConfig->GetConfig(n, pJoyConfig, DIJC_REGHWCONFIGTYPE | DIJC_GUIDINSTANCE);
if (hr == S_OK) AddListCtrlItem(n, pJoyConfig); }
// clean up, clean up... everybody do your share!
if (pJoyConfig) delete (pJoyConfig); if (pdiJoyTypeInfo) delete (pdiJoyTypeInfo);
return hr; }
BOOL AddListCtrlItem(BYTE nItemID, LPDIJOYCONFIG pJoyConfig) { LPDIRECTINPUTDEVICE pdiDevTemp;
pDIJoyConfig->Acquire();
// First Create the device
if (SUCCEEDED(lpDIInterface->CreateDevice(pJoyConfig->guidInstance, &pdiDevTemp, 0))) { PJOY pNewJoy = new JOY; ASSERT (pNewJoy);
// Query for a device2 object
if (FAILED(pdiDevTemp->QueryInterface(IID_IDirectInputDevice2, (LPVOID*)&pNewJoy->fnDeviceInterface))) { #ifdef _DEBUG
OutputDebugString(TEXT("JOY.CPL: Cpanel.cpp: DIEnumDevicesProc: QueryInterface failed!\n")); #endif
// release the temporary object
pdiDevTemp->Release(); return FALSE; }
DIPROPDWORD *pDIPropDW = new (DIPROPDWORD); ASSERT (pDIPropDW);
ZeroMemory(pDIPropDW, sizeof(DIPROPDWORD));
pDIPropDW->diph.dwSize = sizeof(DIPROPDWORD); pDIPropDW->diph.dwHeaderSize = sizeof(DIPROPHEADER); pDIPropDW->diph.dwHow = DIPH_DEVICE;
// Get the device ID
VERIFY (SUCCEEDED(pdiDevTemp->GetProperty(DIPROP_JOYSTICKID, &pDIPropDW->diph)));
// release the temporary object
pdiDevTemp->Release();
pNewJoy->ID = (char)pDIPropDW->dwData;
if (pDIPropDW) delete (pDIPropDW);
// Get the Type name
LPDIJOYCONFIG_DX5 lpDIJoyCfg = new (DIJOYCONFIG_DX5); ASSERT (lpDIJoyCfg);
ZeroMemory(lpDIJoyCfg, sizeof(DIJOYCONFIG_DX5));
lpDIJoyCfg->dwSize = sizeof(DIJOYCONFIG_DX5);
VERIFY (SUCCEEDED(pDIJoyConfig->GetConfig(pNewJoy->ID, (LPDIJOYCONFIG)lpDIJoyCfg, DIJC_REGHWCONFIGTYPE))); // Get the clsidConfig
LPDIJOYTYPEINFO_DX5 lpDIJoyType = new (DIJOYTYPEINFO_DX5); ASSERT(lpDIJoyType);
ZeroMemory(lpDIJoyType, sizeof(DIJOYTYPEINFO_DX5));
lpDIJoyType->dwSize = sizeof(DIJOYTYPEINFO_DX5);
VERIFY (SUCCEEDED(pDIJoyConfig->GetTypeInfo(lpDIJoyCfg->wszType, (LPDIJOYTYPEINFO)lpDIJoyType, DITC_CLSIDCONFIG))); // if NULL, Leave as default.
if (!IsEqualIID(lpDIJoyType->clsidConfig, GUID_NULL)) pNewJoy->clsidPropSheet = lpDIJoyType->clsidConfig;
if (lpDIJoyType) delete (lpDIJoyType);
// Set it's format!!!
if (FAILED(pNewJoy->fnDeviceInterface->SetDataFormat(&c_dfDIJoystick))) { #ifdef _DEBUG
OutputDebugString(TEXT("JOY.CPL: Cpanel.cpp: DIEnumDevicesProc: SetDataFormat() Failed!\n")); #endif
}
// Set it's Cooperative Level!
if (FAILED(pNewJoy->fnDeviceInterface->SetCooperativeLevel(GetParent((HWND)GetParent(hListCtrl)), DISCL_NONEXCLUSIVE | DISCL_BACKGROUND))) { #ifdef _DEBUG
OutputDebugString(TEXT("JOY.CPL: Cpanel.cpp: DIEnumDevicesProc: SetCooperativeLevel Failed!\n")); #endif
}
// Add the item to the tree!
pAssigned[nAssigned] = pNewJoy;
// Get the number of buttons!
LPDIDEVCAPS_DX3 lpDIDevCaps = new (DIDEVCAPS_DX3); ASSERT (lpDIDevCaps);
ZeroMemory(lpDIDevCaps, sizeof(DIDEVCAPS_DX3)); lpDIDevCaps->dwSize = sizeof(DIDEVCAPS_DX3);
pAssigned[nAssigned]->fnDeviceInterface->Acquire();
if (SUCCEEDED(pAssigned[nAssigned]->fnDeviceInterface->GetCapabilities((LPDIDEVCAPS)lpDIDevCaps))) pAssigned[nAssigned]->nButtons = (BYTE)lpDIDevCaps->dwButtons;
if (lpDIDevCaps) delete (lpDIDevCaps);
// If you're on the General page!
if (nFlags & ON_PAGE) { DIPROPSTRING *pDIPropStr = new (DIPROPSTRING); ASSERT (pDIPropStr); ZeroMemory(pDIPropStr, sizeof(DIPROPSTRING));
pDIPropStr->diph.dwSize = sizeof(DIPROPSTRING); pDIPropStr->diph.dwHeaderSize = sizeof(DIPROPHEADER); pDIPropStr->diph.dwHow = DIPH_DEVICE; pAssigned[nAssigned]->fnDeviceInterface->GetProperty(DIPROP_INSTANCENAME, &pDIPropStr->diph);
USES_CONVERSION;
// add to tree
LVITEM lvItem = {LVIF_TEXT | LVIF_PARAM, nAssigned, 0, 0, 0, W2A(pDIPropStr->wsz), lstrlen(W2A(pDIPropStr->wsz)), 0, (LPARAM)nAssigned, 0}; ::SendMessage(hListCtrl, LVM_INSERTITEM, 0, (LPARAM) (const LPLVITEM)&lvItem);
TCHAR sz[STR_LEN_32]; VERIFY(LoadString(ghInstance, IDS_GEN_STATUS_UNKNOWN, (LPTSTR)&sz, STR_LEN_32));
SetItemText(hListCtrl, nAssigned, STATUS_COLUMN, sz);
if (pDIPropStr) delete (pDIPropStr); }
// Increment the array counter!
nAssigned++; }
return TRUE; }
#endif
*/
///////////////////////////////////////////////////////////////////////////////
// FUNCTION: SetActive ( HWND hDlg )
//
// PARAMETERS:
//
//
// PURPOSE:
//
// RETURN:
///////////////////////////////////////////////////////////////////////////////
BOOL SetActive(HWND hDlg) { // restore selection focus to nItemSelected
SetListCtrlItemFocus(hListCtrl, (BYTE)iItem);
BYTE i = (BYTE)::SendMessage(hListCtrl, LVM_GETITEMCOUNT, 0, 0);
// Acquire All Devices that are Attached!!!
char nIndex;
while( i-- ) { // get joystick config of item
nIndex = (char)GetItemData(hListCtrl, i);
if( pAssigned[nIndex]->nStatus & JOY_US_PRESENT ) pAssigned[nIndex]->fnDeviceInterface->Acquire(); }
// create timer
SetTimer(hDlg, ID_MYTIMER, POLLRATE, 0);
UpdateButtonState( hDlg );
return(TRUE); }
///////////////////////////////////////////////////////////////////////////////
// FUNCTION: MsgSubClassProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
//
// PARAMETERS: HWND hWnd
// UINT uMsg
// WPARAM wParam
// LPARAM lParam
//
// PURPOSE:
//
// RETURN:
///////////////////////////////////////////////////////////////////////////////
BOOL WINAPI MsgSubClassProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { // Only do this if you are ON THIS PAGE!
if( nFlags & ON_PAGE ) { if( uMsg == JoyCfgChangedMsg ) { if( !(nFlags & BLOCK_UPDATE) ) { // kill status timer
KillTimer(hWnd, ID_MYTIMER); nFlags |= UPDATE_ALL; ClearArrays(); pDIJoyConfig->EnumTypes((LPDIJOYTYPECALLBACK)DIEnumJoyTypeProc, NULL); UpdateListCtrl(hWnd); SetActive(hWnd); } } }
return(BOOL)CallWindowProc(fpMainWindowProc, hWnd, uMsg, wParam, lParam); }
///////////////////////////////////////////////////////////////////////////////
// FUNCTION: Error ( short nTitleID, short nMsgID )
//
// PARAMETERS: nTitleID - Resource ID for Message Title
// nMsgID - Resource ID for Message
//
// PURPOSE: Prompt user when error occurs
//
// RETURN: TRUE
///////////////////////////////////////////////////////////////////////////////
void Error(short nTitleID, short nMsgID) { LPTSTR lptTitle = new TCHAR[STR_LEN_64]; ASSERT (lptTitle);
if( LoadString(ghInstance, nTitleID, lptTitle, STR_LEN_64) ) { LPTSTR lptMsg = new TCHAR[MAX_STR_LEN]; ASSERT (lptMsg);
if( LoadString(ghInstance, nMsgID, lptMsg, MAX_STR_LEN) ) MessageBox(NULL, lptMsg, lptTitle, MB_ICONHAND | MB_OK | MB_APPLMODAL);
if( lptMsg ) delete[] (lptMsg); }
if( lptTitle ) delete[] (lptTitle); }
///////////////////////////////////////////////////////////////////////////////
// FUNCTION: MoveOK ( HWND hParentWnd )
//
// PARAMETERS:
//
//
// PURPOSE:
//
// RETURN:
///////////////////////////////////////////////////////////////////////////////
void MoveOK(HWND hParentWnd) { // Hide the Cancel and move the OK...
HWND hCtrl = GetDlgItem(hParentWnd, IDCANCEL);
// if there is no IDCANCEL, we've been here before!
if( hCtrl ) { RECT rc; GetWindowRect(hCtrl, &rc);
DestroyWindow(hCtrl);
//POINT pt = {rc.left, rc.top};
//ScreenToClient(hParentWnd, &pt);
// This should take care of Mirroring and work for normal windows
MapWindowPoints(NULL, hParentWnd, (LPPOINT)&rc, 2);
hCtrl = GetDlgItem(hParentWnd, IDOK); ASSERT(hCtrl);
//SetWindowPos(hCtrl, NULL, pt.x, pt.y, NULL, NULL, SWP_NOSIZE | SWP_NOZORDER);
SetWindowPos(hCtrl, NULL, rc.left, rc.top, NULL, NULL, SWP_NOSIZE | SWP_NOZORDER);
LPTSTR lpszDone = new TCHAR[12]; ASSERT (lpszDone);
// Used to be IDS_DONE, but we changed it from DONE to OK
VERIFY(LoadString(ghInstance, IDS_GEN_STATUS_OK, lpszDone, 12)); ::SendMessage(hCtrl, WM_SETTEXT, 0, (LPARAM)(LPCTSTR)lpszDone);
if( lpszDone ) delete[] (lpszDone); } }
///////////////////////////////////////////////////////////////////////////////
// FUNCTION: UpdateButtonState ( HWND hDlg )
//
// PARAMETERS:
//
//
// PURPOSE:
//
// RETURN:
///////////////////////////////////////////////////////////////////////////////
void UpdateButtonState( HWND hDlg ) { PostDlgItemEnableWindow(hDlg, IDC_BTN_REMOVE, (BOOL)nAssigned); PostDlgItemEnableWindow(hDlg, IDC_BTN_PROPERTIES, (BOOL)nAssigned); }
#ifdef WINNT
///////////////////////////////////////////////////////////////////////////////
// FUNCTION: RunWDMJoy ( void )
//
// PURPOSE: Run wdmjoy.inf to install
//
///////////////////////////////////////////////////////////////////////////////
void RunWDMJOY( void ) { //Check if we have already placed the first value
//HKLM,SYSTEM\CurrentControlSet\Control\MediaProperties\PrivateProperties\Joystick\OEM\VID_045E&PID_01F0
HKEY hKey;
long lTest = RegOpenKeyEx(HKEY_LOCAL_MACHINE, REGSTR_PATH_JOYOEM TEXT("\\VID_045E&PID_01F0"), 0, KEY_READ, &hKey); if (lTest == ERROR_SUCCESS) { RegCloseKey(hKey); return; }
LPTSTR lpszWDMJoy = new (TCHAR[STR_LEN_64]); ASSERT (lpszWDMJoy);
// Check to see if the file is present
WIN32_FIND_DATA findData; BYTE nLen = (BYTE)GetWindowsDirectory(lpszWDMJoy, STR_LEN_64); VERIFY(LoadString(ghInstance, IDS_WDMJOY_INF, &lpszWDMJoy[nLen], STR_LEN_64-nLen));
HANDLE hFind = FindFirstFile(lpszWDMJoy, &findData);
// If you've found one... run it!
if( hFind != INVALID_HANDLE_VALUE ) { LPTSTR lpStr = new (TCHAR[MAX_STR_LEN]); ASSERT (lpStr);
// Copy the Windows directory to the buffer!
_tcsncpy(lpStr, lpszWDMJoy, nLen+1);
if( LoadString(ghInstance, IDS_WDMJOY, &lpStr[nLen], MAX_STR_LEN-nLen) ) { // Put IDS_WDMJOY_INF on the end of the string!
_tcscpy(&lpStr[lstrlen(lpStr)], lpszWDMJoy);
LPSTARTUPINFO psi = new (STARTUPINFO); ASSERT (psi);
ZeroMemory(psi, sizeof(STARTUPINFO));
psi->cb = sizeof(STARTUPINFO);
LPPROCESS_INFORMATION ppi = new (PROCESS_INFORMATION); ASSERT (ppi);
ZeroMemory(ppi, sizeof(PROCESS_INFORMATION));
if( CreateProcess(0, lpStr, 0, 0, 0, 0, 0, 0, psi, ppi) ) { CloseHandle(ppi->hThread); CloseHandle(ppi->hProcess); } #ifdef _DEBUG
else OutputDebugString(TEXT("JOY.CPL: CPANEL.CPP: RunWDMJoy: CreateProcess Failed!\n")); #endif
if( ppi ) delete (ppi);
if( psi ) delete (psi); }
if( lpStr ) delete[] (lpStr); }
FindClose(hFind);
if( lpszWDMJoy ) delete[] (lpszWDMJoy); } #endif
#ifdef _UNICODE
///////////////////////////////////////////////////////////////////////////////
// FUNCTION: RegisterForDevChange ( HWND hDlg, PVOID *hNoditfyDevNode )
//
// PARAMETERS:
//
//
// PURPOSE:
//
// RETURN:
///////////////////////////////////////////////////////////////////////////////
void RegisterForDevChange(HWND hDlg, PVOID *hNotifyDevNode) { DEV_BROADCAST_DEVICEINTERFACE *pFilterData = new (DEV_BROADCAST_DEVICEINTERFACE); ASSERT (pFilterData);
ZeroMemory(pFilterData, sizeof(DEV_BROADCAST_DEVICEINTERFACE));
pFilterData->dbcc_size = sizeof(DEV_BROADCAST_DEVICEINTERFACE); pFilterData->dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE; pFilterData->dbcc_classguid = GUID_CLASS_INPUT;
*hNotifyDevNode = RegisterDeviceNotification(hDlg, pFilterData, DEVICE_NOTIFY_WINDOW_HANDLE);
if( pFilterData ) delete (pFilterData); } #endif
// BEGINNING OF LIST CONTROL FUNCTIONS!
///////////////////////////////////////////////////////////////////////////////
// FUNCTION: SetListCtrlItemFocus ( HWND hCtrl, BYTE nItem )
//
// PARAMETERS: HWND hCtrl - Handle of ListControl to recieve the message
// BYTE nItem - Item to set focus to
//
// PURPOSE: Set focus to item in list control
//
// RETURN: NONE
///////////////////////////////////////////////////////////////////////////////
void SetListCtrlItemFocus ( HWND hCtrl, BYTE nItem ) { LPLVITEM plvItem = (LPLVITEM)_alloca(sizeof(LVITEM)); ASSERT (plvItem);
plvItem->lParam = plvItem->iSubItem = plvItem->iImage = plvItem->cchTextMax = plvItem->iIndent = 0;
plvItem->mask = LVIF_STATE; plvItem->iItem = nItem; plvItem->state = plvItem->stateMask = LVIS_FOCUSED | LVIS_SELECTED; plvItem->pszText = NULL;
::SendMessage(hCtrl, LVM_SETITEM, 0, (LPARAM)(const LPLVITEM)plvItem); }
///////////////////////////////////////////////////////////////////////////////
// FUNCTION: GetItemData(HWND hCtrl, BYTE nItem )
//
// PARAMETERS: HWND hCtrl - Handle of ListControl to recieve the message
//
// BYTE nItem - Item to retrieve data from
// PURPOSE: Retrieve the lower char of the item's data
//
// RETURN: Item's data cast to a char
///////////////////////////////////////////////////////////////////////////////
DWORD GetItemData(HWND hCtrl, BYTE nItem ) { LPLVITEM plvItem = (LPLVITEM)_alloca(sizeof(LVITEM)); ASSERT (plvItem);
ZeroMemory(plvItem, sizeof(LVITEM));
plvItem->mask = LVIF_PARAM; plvItem->iItem = nItem;
VERIFY(::SendMessage(hCtrl, LVM_GETITEM, 0, (LPARAM)(LPLVITEM)plvItem));
return(DWORD)plvItem->lParam; }
///////////////////////////////////////////////////////////////////////////////
// FUNCTION: SetItemData(HWND hCtrl, BYTE nItem, DWORD dwFlag )
//
// PARAMETERS: HWND hCtrl - Handle of ListControl to recieve the message
// BYTE nItem - Item to send data to
// DWORD dwFlag - DWORD to send to nItem
// PURPOSE: Set the extra memory associated with nItem to dwFlag
//
// RETURN: TRUE if Successful, FALSE otherwise
///////////////////////////////////////////////////////////////////////////////
BOOL SetItemData(HWND hCtrl, BYTE nItem, DWORD dwFlag ) { LPLVITEM plvItem = (LPLVITEM)_alloca(sizeof(LVITEM)); ASSERT (plvItem);
ZeroMemory(plvItem, sizeof(LVITEM));
plvItem->mask = LVIF_PARAM; plvItem->iItem = nItem; plvItem->lParam = dwFlag;
return(BOOL)::SendMessage(hCtrl, LVM_SETITEM, 0, (LPARAM)(const LPLVITEM)plvItem); }
///////////////////////////////////////////////////////////////////////////////
// FUNCTION: InsertColumn (HWND hCtrl, BYTE nColumn, short nStrID, short nWidth)
//
// PARAMETERS: HWND hCtrl - Handle of ListControl to recieve the message
// BYTE nColumn - Column to place string
// short nStrID - Resource ID for string
// short nWidth - Width of column
//
// PURPOSE: Insert a column in a list control
//
// RETURN: NONE
///////////////////////////////////////////////////////////////////////////////
void InsertColumn (HWND hCtrl, BYTE nColumn, USHORT nStrID, USHORT nWidth) { // Allocate the structure
LPLVCOLUMN plvColumn = (LPLVCOLUMN)_alloca(sizeof(LVCOLUMN)); ASSERT (plvColumn);
ZeroMemory(plvColumn, sizeof(LVCOLUMN));
plvColumn->mask = LVCF_FMT | LVCF_TEXT | LVCF_WIDTH; plvColumn->fmt = LVCFMT_CENTER; plvColumn->cx = nWidth;
plvColumn->pszText = (LPTSTR)_alloca(sizeof(TCHAR[STR_LEN_32])); ASSERT (plvColumn->pszText);
plvColumn->cchTextMax = LoadString(ghInstance, nStrID, plvColumn->pszText, STR_LEN_32);
::SendMessage(hCtrl, LVM_INSERTCOLUMN, (WPARAM)(int)nColumn, (LPARAM)(const LPLVCOLUMN)plvColumn); }
///////////////////////////////////////////////////////////////////////////////
// FUNCTION: SetItemText( HWND hCtrl, BYTE nItem, BYTE nSubItem, LPTSTR lpStr)
//
// PARAMETERS: HWND hCtrl - Handle of ListControl to recieve the message
// BYTE nItem - Item to set
// BYTE nSubItem - SubItem to set
// LPTSTR lpStr - String to set
//
// PURPOSE: Set list control item text
//
// RETURN: NONE
///////////////////////////////////////////////////////////////////////////////
void SetItemText( HWND hCtrl, BYTE nItem, BYTE nSubItem, LPTSTR lpStr) { LPLVITEM plvItem = (LPLVITEM)_alloca(sizeof(LVITEM)); ASSERT (plvItem);
plvItem->lParam = plvItem->stateMask = plvItem->iImage = plvItem->state = plvItem->iIndent = 0;
plvItem->mask = LVIF_TEXT; plvItem->iItem = nItem; plvItem->iSubItem = nSubItem; plvItem->cchTextMax = lstrlen(lpStr); plvItem->pszText = lpStr;
::SendMessage(hCtrl, LVM_SETITEM, 0, (LPARAM)(const LPLVITEM)plvItem); }
///////////////////////////////////////////////////////////////////////////////
// FUNCTION: GetItemText( HWND hCtrl, BYTE nItem, BYTE nSubItem, LPTSTR lpszBuff, BYTE nLen )
//
// PARAMETERS: HWND hCtrl - Handle of ListControl to recieve the message
// BYTE nItem - Item to retrive text
// BYTE nSubItem - SubItem to retrieve text
// LPTSTR lpszBuff - Buffer for retrieved text
// BYTE nLen - Size of buffer
//
// PURPOSE: Retrieve text from a list control
//
// RETURN: length of retrieved string!
///////////////////////////////////////////////////////////////////////////////
BYTE GetItemText( HWND hCtrl, BYTE nItem, BYTE nSubItem, LPTSTR lpszBuff, BYTE nLen ) { LPLVITEM plvItem = (LPLVITEM)_alloca(sizeof(LVITEM)); ASSERT (plvItem);
plvItem->lParam = plvItem->stateMask = plvItem->iImage = plvItem->state = plvItem->iIndent = 0;
plvItem->mask = LVIF_TEXT; plvItem->iItem = nItem; plvItem->iSubItem = nSubItem; plvItem->pszText = lpszBuff; plvItem->cchTextMax = nLen;
return(BYTE)::SendMessage(hCtrl, LVM_GETITEMTEXT, (WPARAM)nItem, (LPARAM)(const LPLVITEM)plvItem); }
///////////////////////////////////////////////////////////////////////////////
// FUNCTION: InsertItem(HWND hCtrl, LPTSTR lpszBuff )
//
// PARAMETERS: HWND hCtrl - Handle of ListControl to recieve the message
// BYTE nItem - Item to retrive text
// LPTSTR lpszBuff - Text to be inserted
//
// PURPOSE: Retrieve text from a list control
//
// RETURN: NONE BYTE nItem,
///////////////////////////////////////////////////////////////////////////////
BYTE InsertItem( HWND hCtrl, LPTSTR lpszBuff, BYTE nItem ) { LPLVITEM plvItem = (LPLVITEM)_alloca(sizeof(LVITEM)); ASSERT (plvItem);
plvItem->state = plvItem->stateMask = plvItem->iImage = plvItem->iItem = plvItem->iIndent = plvItem->iSubItem = 0;
plvItem->mask = LVIF_TEXT | LVIF_PARAM; plvItem->pszText = lpszBuff; plvItem->cchTextMax = lstrlen(lpszBuff); plvItem->lParam = ID_NONE | nItem;
return(BYTE)::SendMessage(hCtrl, LVM_INSERTITEM, (WPARAM)0, (LPARAM)(const LPLVITEM)plvItem); }
///////////////////////////////////////////////////////////////////////////////
// FUNCTION: Launch(HWND hWnd, BYTE nJoy, BYTE startpage)
//
// PARAMETERS: HWND hWnd - Handle to Dialog
// BYTE nJoy - Index into pAssigned global array of assigned devices
// BYTE nStartPage - Page to show first
//
// PURPOSE:
//
//
// RETURN:
///////////////////////////////////////////////////////////////////////////////
HRESULT Launch(HWND hWnd, PJOY pJoy, BYTE nStartPage) { HRESULT hresRet; ASSERT (::IsWindow(hWnd));
if( nStartPage > MAX_PAGES ) return(DIGCERR_STARTPAGETOOLARGE);
LPCDIGAMECNTRLPROPSHEET fnInterface;
/*
#ifdef _UNICODE
LPTSTR lpszWin32 = new (TCHAR[STR_LEN_64]); ASSERT (lpszWin32);
_tcscpy(&lpszWin32[GetSystemDirectory(lpszWin32, STR_LEN_64)], TEXT("\\OLE32.DLL")); //TEXT("OLE32.DLL")
HINSTANCE hOleInst = LoadLibrary(lpszWin32);
if (lpszWin32) delete[] (lpszWin32);
if (!hOleInst) { return E_NOINTERFACE; } #endif
*/
// Get the interface pointer if there is one!
// This reduces the memory footprint of the CPL but takes a bit more time to
// launch the property sheet pages!
/*
#ifdef _UNICODE
fnInterface = HasInterface(pJoy->clsidPropSheet, hOleInst);
if (!fnInterface) { // If the propsheet is not mine, try mine!
if (!IsEqualIID(pJoy->clsidPropSheet, CLSID_LegacyServer)) fnInterface = HasInterface(CLSID_LegacyServer, hOleInst); } FreeLibrary(hOleInst); #else
*/ HRESULT hr;
//if( SUCCEEDED(hr = CoInitializeEx(NULL, COINIT_DISABLE_OLE1DDE | COINIT_APARTMENTTHREADED| COINIT_SPEED_OVER_MEMORY)) )
// OLE32 on Win95 does not have CoInitializeEx.
if( SUCCEEDED(hr = CoInitialize(NULL)) ) { IClassFactory* ppv_classfactory;
if( SUCCEEDED(hr = CoGetClassObject(pJoy->clsidPropSheet, CLSCTX_INPROC_SERVER, NULL, IID_IClassFactory, (void **)&ppv_classfactory)) ) { VERIFY(SUCCEEDED(ppv_classfactory->CreateInstance(NULL, IID_IDIGameCntrlPropSheet, (LPVOID *)&fnInterface)));
ppv_classfactory->Release(); } else { fnInterface = 0; } } else { fnInterface = 0; }
//#endif
// By this point, you've tried twice (possibly)...
// if you don't have an interface by this point...
// QUIT!
if( !fnInterface ) { Error((short)IDS_INTERNAL_ERROR, (short)IDS_NO_DIJOYCONFIG); return(E_NOINTERFACE); }
// here's where we are sending the property sheet an ID describing the location of the installed device!
fnInterface->SetID(pJoy->ID);
LPDIGCSHEETINFO pServerSheet;
// Get the property sheet info from the server
if( FAILED(fnInterface->GetSheetInfo(&pServerSheet)) ) { TRACE(TEXT("JOY.CPL: CPANEL.CPP: Launch: GetSheetInfo Failed!\n")); return(E_FAIL); }
// test to make sure the number of pages is reasonable
if( pServerSheet->nNumPages == 0 ) return(DIGCERR_NUMPAGESZERO); else if( (pServerSheet->nNumPages > MAX_PAGES) || (pServerSheet->nNumPages < nStartPage) ) return(DIGCERR_NUMPAGESTOOLARGE);
LPDIGCPAGEINFO pServerPage;
// step 2 : get the information for all the pages from the server
if( FAILED(fnInterface->GetPageInfo(&pServerPage)) ) { TRACE(TEXT("JOY.CPL: CPANEL.CPP: Launch: GetPageInfo Failed!\n")); return(E_FAIL); }
// Allocate Memory for the pages!
HPROPSHEETPAGE *pPages = new (HPROPSHEETPAGE[pServerSheet->nNumPages]); ASSERT (pPages);
ZeroMemory(pPages, sizeof(HPROPSHEETPAGE)*pServerSheet->nNumPages);
if( !pPages ) return(E_OUTOFMEMORY);
// Allocate Memory for the header!
LPPROPSHEETHEADER ppsh = new (PROPSHEETHEADER); ASSERT (ppsh);
ZeroMemory(ppsh, sizeof(PROPSHEETHEADER));
ppsh->dwSize = sizeof(PROPSHEETHEADER); ppsh->hwndParent = hWnd; ppsh->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!
#ifdef _UNICODE
ppsh->pszIcon = pServerSheet->lpwszSheetIcon; #else
USES_CONVERSION; ppsh->pszIcon = W2A(pServerSheet->lpwszSheetIcon); #endif
} else ppsh->pszIcon = (LPCTSTR)(pServerSheet->lpwszSheetIcon);
ppsh->dwFlags = PSH_USEICONID; } else return(DIGCERR_NOICON); }
// do we have a sheet caption ?
if( pServerSheet->lpwszSheetCaption ) { #ifdef _UNICODE
ppsh->pszCaption = pServerSheet->lpwszSheetCaption; #else
USES_CONVERSION; ppsh->pszCaption = W2A(pServerSheet->lpwszSheetCaption); #endif
ppsh->dwFlags |= PSH_PROPTITLE; }
ppsh->nPages = pServerSheet->nNumPages; ppsh->nStartPage = nStartPage;
// set the property pages inofrmation into the header
ppsh->phpage = pPages;
// OK, sheet stuff is done... now, time to do the pages!
#ifndef _UNICODE
USES_CONVERSION; #endif
LPPROPSHEETPAGE lpPropPage = new (PROPSHEETPAGE); ASSERT(lpPropPage);
ZeroMemory(lpPropPage, sizeof(PROPSHEETPAGE));
lpPropPage->dwSize = sizeof(PROPSHEETPAGE);
// 3.2 Now proceed to fill up each page
BYTE nIndex = 0; do { // Assign the things that there are not questionable
lpPropPage->lParam = pServerPage[nIndex].lParam; lpPropPage->hInstance = pServerPage[nIndex].hInstance;
// Add the title...
if( pServerPage[nIndex].lpwszPageTitle ) { lpPropPage->dwFlags = PSP_USETITLE;
// Check to see if you are a String!!!
if( HIWORD((INT_PTR)pServerPage[nIndex].lpwszPageTitle) ) { #ifdef _UNICODE
lpPropPage->pszTitle = pServerPage[nIndex].lpwszPageTitle; #else
lpPropPage->pszTitle = W2A(pServerPage[nIndex].lpwszPageTitle); #endif
} else lpPropPage->pszTitle = (LPTSTR)pServerPage[nIndex].lpwszPageTitle; } else lpPropPage->pszTitle = NULL;
// if icon is required go ahead and add it.
if( pServerPage[nIndex].fIconFlag ) { lpPropPage->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!!!
#ifdef _UNICODE
lpPropPage->pszIcon = pServerPage[nIndex].lpwszPageIcon; #else
lpPropPage->pszIcon = W2A(pServerPage[nIndex].lpwszPageIcon); #endif
} else lpPropPage->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 ) { lpPropPage->dwFlags |= PSP_USECALLBACK; lpPropPage->pfnCallback = (LPFNPSPCALLBACK) pServerPage[nIndex].fpPrePostProc; } else return(DIGCERR_NOPREPOSTPROC); }
// and the essential "dialog" proc
if( pServerPage[nIndex].fpPageProc ) lpPropPage->pfnDlgProc = pServerPage[nIndex].fpPageProc; else return(DIGCERR_NODLGPROC);
// Assign the Dialog Template!
if( HIWORD((INT_PTR)pServerPage[nIndex].lpwszTemplate) ) { #ifdef _UNICODE
lpPropPage->pszTemplate = pServerPage[nIndex].lpwszTemplate; #else
lpPropPage->pszTemplate = W2A(pServerPage[nIndex].lpwszTemplate); #endif
} else lpPropPage->pszTemplate = (LPTSTR)pServerPage[nIndex].lpwszTemplate;
pPages[nIndex++] = CreatePropertySheetPage(lpPropPage); } while( nIndex < pServerSheet->nNumPages );
if( lpPropPage ) delete (lpPropPage);
// step 5 : launch modal property sheet dialog
hresRet = (HRESULT)PropertySheet(ppsh);
if( pPages ) delete[] (pPages);
if( ppsh ) delete (ppsh);
if( fnInterface ) fnInterface->Release();
CoFreeUnusedLibraries(); //to free gcdef.dll now
//#ifndef _UNICODE
// Let COM go... on Memphis!
CoUninitialize();
if( hresRet ) { switch( hresRet ) { // In the event that the user wants to reboot...
case ID_PSREBOOTSYSTEM: case ID_PSRESTARTWINDOWS: #ifdef _DEBUG
TRACE(TEXT("JOY.CPL: PropertySheet returned a REBOOT request!\n")); #endif
ExitWindowsEx(EWX_REBOOT, NULL); break; } } else { ::PostMessage(hWnd, WM_COMMAND, (WPARAM)IDC_BTN_REFRESH, 0); }
//#endif
// step 7 : return success / failure code back to the caller
return(hresRet); }
/*
#ifdef _UNICODE
//////////////////////////////////////////////////////////////////////
// LPCDIGAMECNTRLPROPSHEET HasInterface(REFCLSID refCLSID, HINSTANCE hOleInst)
// Purpose: Tests for existance of rrid in refCLSID
LPCDIGAMECNTRLPROPSHEET HasInterface(REFCLSID refCLSID, HINSTANCE hOleInst) { typedef HRESULT (STDAPICALLTYPE * LPFNCOGETCLASSOBJECT)(REFCLSID, DWORD, COSERVERINFO *, REFIID, LPVOID *);
LPFNCOGETCLASSOBJECT fpCoGetClassObject = (LPFNCOGETCLASSOBJECT)GetProcAddress(hOleInst, "CoGetClassObject");
IClassFactory* ppv_classfactory; LPCDIGAMECNTRLPROPSHEET fnInterface = 0;
if(SUCCEEDED(fpCoGetClassObject( refCLSID, CLSCTX_INPROC_SERVER, NULL, IID_IClassFactory, (void **)&ppv_classfactory))) { if(SUCCEEDED(ppv_classfactory->CreateInstance(NULL, IID_IDIGameCntrlPropSheet, (LPVOID *)&fnInterface))) { ppv_classfactory->Release(); } else { #ifdef _DEBUG
OutputDebugString(TEXT("CPANEL.cpp: CreateInstance Failed!\n")); #endif
// make sure the pointer is nulled
fnInterface = 0;
ppv_classfactory->Release(); } } else #ifdef _DEBUG
else OutputDebugString(TEXT("CPANEL.cpp: LoadServerInterface Failed!\n")); #endif
return fnInterface; } #endif // _UNICODE
*/
|