windows-nt/Source/XPSP1/NT/multimedia/directx/gamectrl/client/cpanel.cpp

2888 lines
89 KiB
C++
Raw Normal View History

2020-09-26 03:20:57 -05:00
/*
* 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
*/