Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

2377 lines
76 KiB

/*
File: Advanced.cpp
Project: Joystick Control Panel OLE Client
Author: Brycej
Date: 02/07/97
Comments:
Window proc for Avanced page in cpanel
Copyright (c) 1997, 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>
#include <cpl.h>
#include <winuser.h> // For RegisterDeviceNotification stuff!
#include <dbt.h> // for DBT_ defines!!!
#include "cpanel.h"
#include "hsvrguid.h"
#include "resource.h"
#include "joyarray.h"
// MyListCtrl prototypes
#include "inplace.h"
#define USE_DEFAULT 0x1000 // If this bit is set, the device is going to use GCDEF!
#define SHOW_DEFAULT 0x2000 // Show default check box if clsidConfig is != CLSID_LegacyServer
// constants
const short NO_ITEM = -1;
#define DEVICE_ID 0
#define DEVICE_FRIENDLY 1
#define DEVICE_TYPE 2
#define DEVICE_PORT 3
LPCWSTR lpMSANALOG_VXD = L"MSANALOG.VXD";
LPTSTR lpstrNone;
#define ADVANCED_ID_COLUMN 0
#define ADVANCED_DEVICE_COLUMN 1
extern const DWORD gaHelpIDs[];
// externs for arguements!
extern BYTE nID, nStartPageDef, nStartPageCPL;
// Update flag!
extern short nFlags;
// local (module-scope) variables
HWND hAdvListCtrl;
#ifdef _UNICODE
static PVOID hAdvNotifyDevNode;
#endif
extern short iItem;
static HWND ghDlg;
//static UINT JoyCfgChangedMsg;
static BOOL bProcess;
// Message Procedures for handling VK_DELETE in Advanced window
static WNDPROC fpMainWndProc;
static BOOL WINAPI SubClassProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
// Message Procedures for handling the VK_ENTER/VK_DELETE in Adv Window
static WNDPROC fpPageWndProc;
static BOOL WINAPI KeySubClassProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
short iAdvItem = NO_ITEM; // index of selected item
char iGameportDriverItem = NO_ITEM;
short nOldID;
// externs
extern IDirectInputJoyConfig *pDIJoyConfig;
extern LPDIRECTINPUT lpDIInterface;
extern BYTE nGameportBus;
extern PJOY pAssigned[MAX_ASSIGNED]; // List of assigned devices
extern BYTE nAssigned; // Number of elements in pAssigned array
extern HINSTANCE ghInstance;
#ifdef WINNT
// external function defined in CPANEL.CPP
extern void RunWDMJOY ( void );
#endif
// local message handlers
static BOOL OnInitDialog (HWND, HWND, LPARAM);
static void OnCommand (HWND, int, HWND, UINT);
static BOOL OnNotify (HWND, WPARAM, LPNMHDR);
static void OnDestroy (HWND);
static void OnAdvHelp (LPARAM);
static void OnContextMenu (WPARAM wParam, LPARAM lParam);
static void OnListviewContextMenu ( LPARAM lParam );
// local utility fns
static BOOL SetActiveGlobalDriver ( void );
static BOOL AdvUpdateListCtrl ( void );
static BOOL UpdateChangeListCtrl ( HWND hCtrl );
#ifndef _UNICODE
static void PopulateGlobalPortDriverComboBox( void );
extern WCHAR *pwszGameportDriverArray[MAX_GLOBAL_PORT_DRIVERS];
extern BYTE nGameportDriver; // Global Port Driver Enumeration Counter
#define POLL_FLAGS_REG_STR TEXT("PollFlags")
#endif
static void LaunchChange ( HWND hTmp );
int CALLBACK CompareIDItems (LPARAM item1, LPARAM item2, LPARAM uDirection);
void EditSubLabel( BYTE nItem, BYTE nCol );
///////////////////////////////////////////////////////////////////////////////
// FUNCTION: AdvancedProc(HWND hDlg, ULONG uMsg, WPARAM wParam, LPARAM lParam)
//
// PARAMETERS: hDlg -
// uMsg -
// wParam -
// lParam -
//
// PURPOSE: Main callback function for "Advanced" sheet
///////////////////////////////////////////////////////////////////////////////
BOOL WINAPI AdvancedProc(HWND hDlg, ULONG uMsg, WPARAM wParam, LPARAM lParam)
{
switch( uMsg )
{
case WM_ACTIVATEAPP:
if( wParam )
SetListCtrlItemFocus(hAdvListCtrl, (BYTE)iAdvItem);
break;
case WM_DEVICECHANGE:
switch( (UINT)wParam )
{
case DBT_DEVICEARRIVAL:
// case DBT_DEVICEREMOVECOMPLETE:
// Clear the old "known devices" list
nFlags |= UPDATE_ALL;
// Clear pAssigned
while( nAssigned )
{
if( pAssigned[--nAssigned] )
{
delete[] (pAssigned[nAssigned]);
pAssigned[nAssigned] = 0;
}
}
// Rebuild the "known devices" list - pAssigned
lpDIInterface->EnumDevices(DIDEVTYPE_JOYSTICK, (LPDIENUMDEVICESCALLBACK)DIEnumDevicesProc, (LPVOID)hDlg, DIEDFL_ALLDEVICES);
AdvUpdateListCtrl();
break;
}
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);
}
return(TRUE);
case WM_COMMAND:
HANDLE_WM_COMMAND(hDlg, wParam, lParam, OnCommand);
return(TRUE);
case WM_DESTROY:
return(HANDLE_WM_DESTROY(hDlg, wParam, lParam, OnDestroy));
case WM_NOTIFY:
return(HANDLE_WM_NOTIFY(hDlg, wParam, lParam, OnNotify));
case WM_HELP:
OnAdvHelp(lParam);
return(TRUE);
case WM_CONTEXTMENU:
OnContextMenu(wParam, lParam);
return(TRUE);
default:
break;
}
return(0);
}
///////////////////////////////////////////////////////////////////////////////
// FUNCTION: OnInitDialog(HWND hDlg, HWND hWnd, LPARAM lParam)
//
// PARAMETERS: hDlg -
// hWnd -
// lParam -
//
// PURPOSE: WM_INITDIALOG message handler
///////////////////////////////////////////////////////////////////////////////
BOOL OnInitDialog(HWND hDlg, HWND hWnd, LPARAM lParam)
{
bProcess = TRUE;
// Just in case Advanced is launched as the startup page!
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);
}
if( !pDIJoyConfig )
{
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)));
// Enumerate all the Types!
VERIFY(SUCCEEDED(pDIJoyConfig->EnumTypes((LPDIJOYTYPECALLBACK)DIEnumJoyTypeProc, NULL)));
// If you're here, you came in via the CMD line arg and you need to enumerate for devices so...
lpDIInterface->EnumDevices(DIDEVTYPE_JOYSTICK, (LPDIENUMDEVICESCALLBACK)DIEnumDevicesProc, (LPVOID)hDlg, DIEDFL_ALLDEVICES);
}
}
// if we find an object, then enable the Change... button
//HWND hChangeCtrl = GetDlgItem(hDlg, IDC_ADV_CHANGE);
// Determine Privilege and disable Change accordingly!
if( pDIJoyConfig->Acquire() == DIERR_INSUFFICIENTPRIVS )
{
// Assign here because the Advanced sheet could be launched first
// via command line args!
nFlags |= USER_MODE;
//PostEnableWindow(hChangeCtrl, FALSE);
}
#ifdef WINNT
else
{
// Run the WDMJOY.INF file!!!
RunWDMJOY();
}
#endif
// set the global dialog handle
ghDlg = hDlg;
// blj: TODO: Make advanced page update on JOYCONFIGCHANGED message!
// JOY_CONFIGCHANGED_MSGSTRING defined in MMDDK.H
//JoyCfgChangedMsg = RegisterWindowMessage(JOY_CONFIGCHANGED_MSGSTRING);
// initialize our list control
hAdvListCtrl = GetDlgItem(hDlg, IDC_ADV_LIST_DEVICE);
#ifdef _UNICODE
// Set the Attributes! Removed LVS_EX_ONECLICKACTIVATE per GSeirra | LVS_EX_INFOTIP
::SendMessage(hAdvListCtrl, LVM_SETEXTENDEDLISTVIEWSTYLE, 0, LVS_EX_FULLROWSELECT | LVS_EX_GRIDLINES | LVS_EX_HEADERDRAGDROP);
#else
::SendMessage(hAdvListCtrl, LVM_SETEXTENDEDLISTVIEWSTYLE, 0, LVS_EX_FULLROWSELECT | LVS_EX_HEADERDRAGDROP);
#endif
RECT rc;
GetClientRect(hAdvListCtrl, &rc);
rc.left = (short)((rc.right-GetSystemMetrics(SM_CXVSCROLL))/5);
// Set up the columns!
#ifdef _UNICODE
InsertColumn(hAdvListCtrl, DEVICE_ID, IDS_ADV_DEVICE_HEADING, (USHORT)(rc.left >> 1 ));
InsertColumn(hAdvListCtrl, DEVICE_FRIENDLY, IDS_ADV_DEVICE_FRIENDLY, (USHORT)(rc.left + (rc.left>>1)));
InsertColumn(hAdvListCtrl, DEVICE_TYPE, IDS_ADV_GAME_CONTROLLERS, (USHORT)(rc.left << 1 ));
InsertColumn(hAdvListCtrl, DEVICE_PORT, IDS_ADV_DEVICE_PORT, (USHORT)(rc.left ));
// Remove the Global Port Driver stuff!!!
const USHORT nCtrlArray[] = {IDC_TEXT_PORTDRIVER, IDC_COMBO1, IDC_ADV_GRP2, IDC_TEXT_DRIVER};
BYTE nIndex = sizeof(nCtrlArray)/sizeof(short);
while( DestroyWindow(GetDlgItem(hDlg, nCtrlArray[--nIndex])) );
#else
rc.right = (rc.left << 1) + (rc.left >> 2);
InsertColumn(hAdvListCtrl, DEVICE_ID, IDS_ADV_DEVICE_HEADING, (USHORT)(rc.left >> 1));
InsertColumn(hAdvListCtrl, DEVICE_FRIENDLY, IDS_ADV_DEVICE_FRIENDLY, (USHORT)rc.right);
InsertColumn(hAdvListCtrl, DEVICE_TYPE, IDS_ADV_GAME_CONTROLLERS, (USHORT)rc.right);
#endif
lpstrNone = new TCHAR[STR_LEN_32];
ASSERT (lpstrNone);
// everyone needs the "None" string so I've loaded it here!
VERIFY(LoadString(ghInstance, IDS_NONE, lpstrNone, STR_LEN_32));
fpMainWndProc = (WNDPROC)SetWindowLongPtr(hAdvListCtrl, GWLP_WNDPROC, (LONG_PTR)SubClassProc);
// Only center the dialog if this was the page that we started on!
if( nStartPageCPL == 1 )
{
HWND hParentWnd = GetParent(hDlg);
GetWindowRect(hParentWnd, &rc);
// 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);
// Do that move button thing!
MoveOK(hParentWnd);
// Set the Update flag...
nFlags |= UPDATE_FOR_ADV;
}
// the user is requesting that the CPL be shown
// and an extention associated with nID be Launched.
if( nID < NUMJOYDEVS )
{
LaunchExtention(hDlg);
// Zero out so you don't do it twice!
nID = 0;
}
// SetActive will use this flag to make sure that the ListCtrl is populated!
nFlags |= UPDATE_FOR_ADV;
return(TRUE);
}
///////////////////////////////////////////////////////////////////////////////
// FUNCTION: OnCommand(HWND hDlg, int id, HWND hWndCtl, UINT code)
//
// PARAMETERS: hDlg -
// id -
// hWndCtl -
// code -
//
// PURPOSE: WM_COMMAND message handler
///////////////////////////////////////////////////////////////////////////////
void OnCommand(HWND hDlg, int id, HWND hWndCtl, UINT code)
{
// Hit the "What's This..."
switch( id )
{
case IDC_RENAME:
// Only SubClass when we need to!
if( !(nFlags & USER_MODE) )
{
HWND hParentWnd = GetParent(GetDlgItem(hDlg, IDC_ADV_LIST_DEVICE));
// this is required because the CPL can be launched via RUNDLL32
if( ::IsWindow(hParentWnd) )
hParentWnd = GetParent(hParentWnd);
if( !fpPageWndProc )
fpPageWndProc = (WNDPROC)SetWindowLongPtr(hParentWnd, GWLP_WNDPROC, (LONG_PTR)KeySubClassProc);
nFlags |= UPDATE_INPROCESS;
// Find the column as it Could have been moved!
LPTSTR szName = new (TCHAR[STR_LEN_32]);
ASSERT (szName);
// First, Load the string of the column we are looking to find!
if( LoadString(ghInstance, IDS_ADV_DEVICE_FRIENDLY, szName, STR_LEN_32) )
{
// Now, traverse the columns to find the one with the title that matches szName!
HWND hHeader = GetDlgItem(hAdvListCtrl, 0);
BYTE nColumns = (BYTE)::SendMessage(hHeader, HDM_GETITEMCOUNT, 0, 0L);
HDITEM *phdItem = new (HDITEM);
ASSERT (phdItem);
ZeroMemory(phdItem, sizeof(HD_ITEM));
phdItem->pszText = new TCHAR[STR_LEN_32];
ASSERT (phdItem->pszText);
phdItem->cchTextMax = STR_LEN_32;
phdItem->mask = HDI_TEXT | HDI_ORDER;
do
{
::SendMessage(hHeader, HDM_GETITEM, (WPARAM)(int)--nColumns, (LPARAM)(LPHDITEM)phdItem);
if( _tcscmp(phdItem->pszText, szName) == 0 )
{
nColumns = (BYTE)phdItem->iOrder;
break;
}
} while( nColumns );
if( phdItem->pszText )
delete[] (phdItem->pszText);
if( phdItem )
delete (phdItem);
EditSubLabel( (BYTE)iAdvItem, nColumns );
}
if( szName )
delete[] (szName);
}
break;
case IDS_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)hAdvListCtrl, pszHelpFileName, HELP_WM_HELP, (ULONG_PTR)gaHelpIDs);
#ifdef _DEBUG
else OutputDebugString(TEXT("JOY.CPL: Advanced.cpp: OnCommand: LoadString Failed to find IDS_HELPFILENAME!\n"));
#endif // _DEBUG
if( pszHelpFileName )
delete[] (pszHelpFileName);
}
break;
#ifndef _UNICODE
// this is the handler for the Global Port Driver Combo box
case IDC_COMBO1:
if( code == CBN_SELCHANGE )
SetActiveGlobalDriver();
break;
// handler for PollFlags entry in the registry for the Global Port Driver
case IDC_POLLFLAGS:
if( iGameportDriverItem == NO_ITEM )
break;
if( SUCCEEDED(pDIJoyConfig->Acquire()) )
{
HKEY hKey;
VERIFY(SUCCEEDED(pDIJoyConfig->OpenTypeKey(pwszGameportDriverArray[iGameportDriverItem], KEY_ALL_ACCESS, &hKey)));
// this entry is only valid if the user is running MSANALOG.VXD!
DWORD nFlags = (IsDlgButtonChecked(hDlg, id)) ? 1 : 0;
RegSetValueEx(hKey, POLL_FLAGS_REG_STR, 0, REG_BINARY, (PBYTE)&nFlags, sizeof(nFlags));
RegCloseKey(hKey);
pDIJoyConfig->SendNotify();
pDIJoyConfig->Unacquire();
}
break;
#endif // _UNICODE
// this is the handler for the Device list box
case IDC_ADV_LIST_DEVICE:
// Fall into Change on DBLCLK
if( code != LBN_DBLCLK )
break;
case IDC_ADV_CHANGE:
if( nFlags & USER_MODE )
Error((short)IDS_USER_MODE_TITLE, (short)IDS_USER_MODE);
else
{
LaunchChange(hDlg);
}
break;
case IDC_ADV_USEOEMPAGE:
if( !nAssigned ) {
break;
}
if( IsWindowVisible(GetDlgItem(hDlg,IDC_ADV_USEOEMPAGE)) )
{
// Boy are you going to pay the price for making that selection...
LPDIJOYCONFIG_DX5 lpDIJoyConfig = new (DIJOYCONFIG_DX5);
ASSERT (lpDIJoyConfig);
ZeroMemory(lpDIJoyConfig, sizeof(DIJOYCONFIG_DX5));
lpDIJoyConfig->dwSize = sizeof (DIJOYCONFIG_DX5);
// Get the index from the selected item (iAdvItem)
BYTE n1 = (BYTE)GetItemData(hAdvListCtrl, (BYTE)iAdvItem);
BYTE n = 0;
do
{
if( pAssigned[n] && (n1 == pAssigned[n]->ID) )
break;
n++;
} while( n < NUMJOYDEVS );
// Find out the type name...
if( SUCCEEDED(pDIJoyConfig->GetConfig(pAssigned[n]->ID, (LPDIJOYCONFIG)lpDIJoyConfig, DIJC_REGHWCONFIGTYPE)) )
{
LPDIJOYTYPEINFO lpDIJoyTypeInfo = new (DIJOYTYPEINFO);
ASSERT (lpDIJoyTypeInfo);
ZeroMemory(lpDIJoyTypeInfo, sizeof(DIJOYTYPEINFO));
lpDIJoyTypeInfo->dwSize = sizeof(DIJOYTYPEINFO);
// Get the TypeInfo you start with!
if( SUCCEEDED(pDIJoyConfig->GetTypeInfo(lpDIJoyConfig->wszType, lpDIJoyTypeInfo, DITC_FLAGS1 | DITC_CLSIDCONFIG)) )
{
DWORD dwFlags = GetItemData(hAdvListCtrl, (BYTE)iAdvItem);
// If it's checked... you want the OEM supplied property sheet page!
if( IsDlgButtonChecked(hDlg, IDC_ADV_USEOEMPAGE) )
{
// Turn off the USE_DEFAULT flag
dwFlags &= ~USE_DEFAULT;
// Update the global pointer!!!
pAssigned[n]->clsidPropSheet = lpDIJoyTypeInfo->clsidConfig;
// Update the pointer being sent to the registry
lpDIJoyTypeInfo->dwFlags1 &= ~JOYTYPE_DEFAULTPROPSHEET;
} else
{
// Turn on the USE_DEFAULT flag
dwFlags |= USE_DEFAULT;
// Update the global list!
pAssigned[n]->clsidPropSheet = CLSID_LegacyServer;
// Update the pointer being sent to the registry
lpDIJoyTypeInfo->dwFlags1 |= JOYTYPE_DEFAULTPROPSHEET;
}
if( SUCCEEDED(pDIJoyConfig->Acquire()) ) {
// Update the registry
VERIFY(SUCCEEDED(pDIJoyConfig->SetTypeInfo(lpDIJoyConfig->wszType, lpDIJoyTypeInfo, DITC_FLAGS1)));
// Set the data in the list control!
SetItemData(hAdvListCtrl, (BYTE)iAdvItem, dwFlags);
}
pDIJoyConfig->Unacquire();
}
if( lpDIJoyTypeInfo )
delete (lpDIJoyTypeInfo);
}
if( lpDIJoyConfig )
delete (lpDIJoyConfig);
}
break;
default:
break;
}
}
////////////////////////////////////////////////////////////////////////////////
//
// FUNCTION: OnNotify(HWND hDlg, WPARAM idFrom, NMHDR* pnmhdr)
//
// PARAMETERS: hDlg -
// idFrom - ID of control sending WM_NOTIFY message
// pnmhdr -
//
// PURPOSE: WM_NOTIFY message handler
////////////////////////////////////////////////////////////////////////////////
BOOL OnNotify(HWND hDlg, WPARAM idFrom, LPNMHDR pnmhdr)
{
switch( pnmhdr->code )
{
case PSN_QUERYCANCEL:
if( nFlags & UPDATE_INPROCESS )
{
nFlags &= ~UPDATE_INPROCESS;
SetFocus(hAdvListCtrl);
}
break;
/*
case LVN_GETINFOTIP:
{
LPLVHITTESTINFO lpHit = new (LVHITTESTINFO);
ASSERT (lpHit);
BOOL bRet = FALSE;
POINT pt;
GetCursorPos(&pt);
ScreenToClient(hAdvListCtrl, &pt);
lpHit->pt = pt;
lpHit->flags = lpHit->iItem = lpHit->iSubItem = 0;
::SendMessage(hAdvListCtrl, LVM_SUBITEMHITTEST, 0, (LPARAM)(LPLVHITTESTINFO)lpHit);
if (lpHit->flags & LVHT_ONITEMLABEL)
{
// Determine the text length of the column text
LPTSTR lpStr = new (TCHAR[MAX_STR_LEN+1]);
ASSERT (lpStr);
GetItemText(hAdvListCtrl, lpHit->iItem, lpHit->iSubItem, lpStr, MAX_STR_LEN);
// Determine if the latter will fit inside the former...
SIZE size;
HDC hDC = GetDC(hAdvListCtrl);
GetTextExtentPoint(hDC, lpStr, lstrlen(lpStr), &size);
ReleaseDC(hAdvListCtrl, hDC);
// Determine how wide the column is!
short nWidth = (short)::SendMessage(hAdvListCtrl, 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_BEGINLABELEDIT:
if( !(GetItemData(hAdvListCtrl, (BYTE)iAdvItem) & ID_NONE) )
OnCommand(hDlg, IDC_RENAME, 0, 0);
SetWindowLongPtr(hDlg, DWLP_MSGRESULT, 1);
break;
case LVN_ENDLABELEDIT:
if( !(nFlags & UPDATE_INPROCESS) )
return(FALSE);
if( !bProcess )
return(FALSE);
nFlags &= ~UPDATE_INPROCESS;
if( fpPageWndProc )
{
HWND hParentWnd = GetParent(hDlg);
// this is required because the CPL can be launched via RUNDLL32
if( ::IsWindow(hParentWnd) )
hParentWnd = GetParent(hParentWnd);
// Reset the subclass proc
// SetWindowLongPtr(hParentWnd, GWLP_WNDPROC, (LONG_PTR)fpPageWndProc);
}
// Make sure the name is usable!
if( _tcschr(((NMLVDISPINFO *)pnmhdr)->item.pszText, TEXT('\\')) )
{
Error((short)IDS_INVALID_NAME_TITLE, (short)IDS_INVALID_NAME);
} else
{
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
// Search nAssigned for the ID...
BYTE n = nAssigned;
do
{
if( pAssigned[--n]->ID == ((NMLVDISPINFO *)pnmhdr)->item.iItem )
break;
} while( n );
if( SUCCEEDED(pAssigned[n]->fnDeviceInterface->SetProperty(DIPROP_INSTANCENAME, &pDIPropString->diph)) )
{
SetItemText(hAdvListCtrl, (BYTE)((NMLVDISPINFO *)pnmhdr)->item.iItem, 1, ((NMLVDISPINFO *)pnmhdr)->item.pszText);
} else
{
Error((short)IDS_NO_RENAME_TITLE, (short)IDS_NO_RENAME);
}
if( pDIPropString )
delete (pDIPropString);
}
break;
#if 0
case LVN_COLUMNCLICK:
switch( ((NM_LISTVIEW*)pnmhdr)->iSubItem )
{
case DEVICE_ID:
{
static BOOL bIDDirection = TRUE;
::SendMessage(hAdvListCtrl, LVM_SORTITEMS, (WPARAM)(LPARAM)(bIDDirection =! bIDDirection), (LPARAM)(PFNLVCOMPARE)CompareIDItems);
}
break;
default:
{
BOOL bDirection;
CListCtrl *pCtrl = new (CListCtrl);
ASSERT(pCtrl);
pCtrl->Attach(hAdvListCtrl);
switch( ((NM_LISTVIEW*)pnmhdr)->iSubItem )
{
case DEVICE_FRIENDLY:
{
static BOOL bFriendlyDirection = FALSE;
bDirection = (bFriendlyDirection =! bFriendlyDirection);
}
break;
case DEVICE_TYPE:
{
static BOOL bTypeDirection = FALSE;
bDirection = (bTypeDirection =! bTypeDirection);
}
break;
case DEVICE_PORT:
{
static BOOL bPortDirection = FALSE;
bDirection = (bPortDirection =! bPortDirection);
}
break;
}
SortTextItems(pCtrl, (short)((NM_LISTVIEW*)pnmhdr)->iSubItem, bDirection, 0, 15);
pCtrl->Detach();
if( pCtrl )
delete (pCtrl);
}
break;
}
if( nAssigned )
{
iAdvItem = (short)::SendMessage(hAdvListCtrl, LVM_GETNEXTITEM, (WPARAM)(int)-1, MAKELPARAM(LVNI_SELECTED, 0));
::PostMessage(hAdvListCtrl, LVM_ENSUREVISIBLE, iAdvItem, TRUE);
if( !(nFlags & USER_MODE) )
PostDlgItemEnableWindow(hDlg, IDC_ADV_CHANGE, (GetItemData(hAdvListCtrl, (BYTE)iAdvItem) & ID_NONE) ? FALSE : TRUE);
SetListCtrlItemFocus(hAdvListCtrl, (BYTE)iAdvItem);
}
break;
#endif
case PSN_KILLACTIVE:
if( nFlags & UPDATE_INPROCESS )
SetFocus(hAdvListCtrl);
#ifdef _UNICODE
if( hAdvNotifyDevNode )
UnregisterDeviceNotification(hAdvNotifyDevNode);
#endif
break;
case NM_DBLCLK:
switch( idFrom )
{
case IDC_ADV_LIST_DEVICE:
if( !(GetItemData(hAdvListCtrl, (BYTE)iAdvItem) & ID_NONE) )
LaunchChange(hDlg);
break;
}
break;
case PSN_SETACTIVE:
#ifdef _UNICODE
RegisterForDevChange(hDlg, &hAdvNotifyDevNode);
#endif
if( nFlags & UPDATE_FOR_ADV )
{
if( !AdvUpdateListCtrl() )
{
#ifdef _DEBUG
OutputDebugString(TEXT("JOY.CPL: OnNotify: Failed UpdateListCtrl!\n"));
#endif
}
}
if( nAssigned )
{
iAdvItem = 0;
// This will happen when the user comes in via the CMD line!
if( iItem != NO_ITEM )
{
// Find the ID of the device... the Brute Force Method!
do
{
if( (pAssigned[iItem] != NULL) && ((BYTE)GetItemData(hAdvListCtrl, (BYTE)iAdvItem) == pAssigned[iItem]->ID) )
break;
iAdvItem++;
} while( iAdvItem < NUMJOYDEVS );
}
if( iAdvItem == NUMJOYDEVS ) {
iAdvItem = 0;
}
SetListCtrlItemFocus(hAdvListCtrl, (BYTE)iAdvItem);
::PostMessage(hAdvListCtrl, LVM_ENSUREVISIBLE, iAdvItem, FALSE );
}
// No global port drivers in NT so...
//if (nGameportDriver)
#ifndef _UNICODE
if( !(nFlags & ON_NT) )
PopulateGlobalPortDriverComboBox();
#endif
// disable the Change button if iAdvItem points to a (none) selection
if( !(nFlags & USER_MODE) )
PostDlgItemEnableWindow(hDlg, IDC_ADV_CHANGE, (nAssigned) ? ((iAdvItem & ID_NONE) ? FALSE : TRUE) : FALSE);
break;
case LVN_ITEMCHANGED:
if( iAdvItem != (short)((NM_LISTVIEW*)pnmhdr)->iItem )
{
iAdvItem = (short)((NM_LISTVIEW*)pnmhdr)->iItem;
HWND hCtrl = GetDlgItem(hDlg, IDC_ADV_USEOEMPAGE);
if( nAssigned )
{
SetWindowPos( hCtrl, NULL, NULL, NULL, NULL, NULL, SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER |
((((NM_LISTVIEW*)pnmhdr)->lParam & SHOW_DEFAULT) ? SWP_SHOWWINDOW : SWP_HIDEWINDOW) );
// Check the box appropriatly!
if( ((NM_LISTVIEW*)pnmhdr)->lParam & SHOW_DEFAULT )
::PostMessage(GetDlgItem(hDlg, IDC_ADV_USEOEMPAGE), BM_SETCHECK, (((NM_LISTVIEW*)pnmhdr)->lParam & USE_DEFAULT) ? BST_UNCHECKED : BST_CHECKED, 0);
if( ((NM_LISTVIEW*)pnmhdr)->lParam )
PostEnableWindow(hCtrl, (BOOL)!(((NM_LISTVIEW*)pnmhdr)->lParam & ID_NONE));
if( !(nFlags & USER_MODE) )
PostDlgItemEnableWindow(hDlg, IDC_ADV_CHANGE, (BOOL)!(((NM_LISTVIEW*)pnmhdr)->lParam & ID_NONE));
} else SetWindowPos( hCtrl, NULL, NULL, NULL, NULL, NULL, SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_HIDEWINDOW);
}
break;
case LVN_KEYDOWN:
switch( ((LV_KEYDOWN*)pnmhdr)->wVKey )
{
case VK_DELETE:
iAdvItem = (short)::SendMessage(hAdvListCtrl, LVM_GETNEXTITEM, (WPARAM)(int)-1, MAKELPARAM(LVNI_SELECTED, 0));
{
BYTE nRet = (BYTE)GetItemData(hAdvListCtrl, (BYTE)iAdvItem);
DeleteSelectedItem((PBYTE)&nRet);
}
// Missing break intentional!
case VK_F5:
Enumerate( hDlg );
AdvUpdateListCtrl();
SetListCtrlItemFocus(hAdvListCtrl, (BYTE)iAdvItem);
::PostMessage(hAdvListCtrl, LVM_ENSUREVISIBLE, iAdvItem, FALSE );
break;
}
break;
}
return(TRUE);
}
////////////////////////////////////////////////////////////////////////////////////////
// FUNCTION: OnDestroy ( HWND hWnd )
//
// PARAMETERS: hWnd - Handle to window being destroyed
//
// PURPOSE: WM_DESTROY message handler
////////////////////////////////////////////////////////////////////////////////////////
void OnDestroy(HWND hWnd)
{
ASSERT (hWnd);
if( lpstrNone )
delete[] (lpstrNone);
// Reset the subclass proc
SetWindowLongPtr(hWnd, GWLP_WNDPROC, (LONG_PTR)fpMainWndProc);
// release the DI JoyConfig interface pointer
if( pDIJoyConfig )
{
pDIJoyConfig->Release();
pDIJoyConfig = 0;
}
}
////////////////////////////////////////////////////////////////////////////////////////
// FUNCTION: OnAdvHelp ( LPARAM lParam )
//
// PARAMETERS: lParam - Pointer to HELPINFO struct
//
// PURPOSE: WM_HELP message handler
////////////////////////////////////////////////////////////////////////////////////////
void OnAdvHelp(LPARAM lParam)
{
ASSERT (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: Advanced.cpp: OnAdvHelp: LoadString Failed to find IDS_HELPFILENAME!\n"));
#endif // _DEBUG
if( pszHelpFileName )
delete[] (pszHelpFileName);
}
////////////////////////////////////////////////////////////////////////////////////////
// FUNCTION: OnContextMenu ( WPARAM wParam )
//
// PARAMETERS: wParam - HWND of window under the pointer
//
// PURPOSE: Handle WM_RBUTTONDOWN over all client windows
// (except the list control... that's OnListviewContextMenu() job)
////////////////////////////////////////////////////////////////////////////////////////
void OnContextMenu(WPARAM wParam, LPARAM lParam)
{
ASSERT (wParam);
// If you are on the ListCtrl...
if( (HWND)wParam == hAdvListCtrl )
{
SetFocus(hAdvListCtrl);
// Don't attempt if nothing selected
if( iAdvItem != NO_ITEM )
OnListviewContextMenu(lParam);
} else
{
// 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: Advanced.cpp: OnContextMenu: LoadString Failed to find IDS_HELPFILENAME!\n"));
#endif // _DEBUG
if( pszHelpFileName )
delete[] (pszHelpFileName);
}
}
///////////////////////////////////////////////////////////////////////////////
// FUNCTION: SetActiveGlobalDriver( void )
//
// PURPOSE: Commit user selection to persistent storage.
//
// RETURN: TRUE if successfull, FALSE otherwise
///////////////////////////////////////////////////////////////////////////////
#ifndef _UNICODE
BOOL SetActiveGlobalDriver( void )
{
// It's Perfectly valid to not have a Global Port Driver so... be prepared!
short n = (short)SendDlgItemMessage(ghDlg, IDC_COMBO1, CB_GETCURSEL, 0, 0);
if( n == CB_ERR )
return(FALSE);
LPDIJOYUSERVALUES pDIJoyUserValues = new (DIJOYUSERVALUES);
ASSERT (pDIJoyUserValues);
ZeroMemory(pDIJoyUserValues, sizeof(DIJOYUSERVALUES));
pDIJoyUserValues->dwSize = sizeof(DIJOYUSERVALUES);
HWND hCtrl = GetDlgItem(ghDlg, IDC_COMBO1);
// Don't worry about this not being a TCHAR, this code will never be executed in NT!
LPSTR pszDisplayName = new char[SendMessage(hCtrl, LB_GETTEXTLEN, (WPARAM)n, 0)+1];
ASSERT (pszDisplayName);
SendMessage(hCtrl, CB_GETLBTEXT, n, (LPARAM)(LPCTSTR)pszDisplayName);
hCtrl = GetDlgItem(ghDlg, IDC_POLLFLAGS);
SetWindowPos( hCtrl, NULL, NULL, NULL, NULL, NULL,
SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_HIDEWINDOW );
// Fix #9815, Set wszGlobalDriver to
if( _tcsncmp(pszDisplayName, lpstrNone, sizeof(lpstrNone)/sizeof(TCHAR)) == 0 )
{
//wcscpy(pDIJoyUserValues->wszGlobalDriver, L"");
if( SUCCEEDED(pDIJoyConfig->Acquire()) )
{
if( FAILED(pDIJoyConfig->SetUserValues(pDIJoyUserValues, DIJU_GLOBALDRIVER)) )
{
TRACE (TEXT("JOY.CPL: SetUserValues failed to set DIJU_GLOBALDRIVER!\n"));
}
}
} else
{
LPDIJOYTYPEINFO lpdiJoyInfo = new DIJOYTYPEINFO;
ASSERT (lpdiJoyInfo);
ZeroMemory(lpdiJoyInfo, sizeof(DIJOYTYPEINFO));
lpdiJoyInfo->dwSize = sizeof(DIJOYTYPEINFO);
USES_CONVERSION;
short nIndex = 0;
// traverse the list of Global Port Drivers 'till you find the matching display name
// this also disallows the user from doing something ugly when they only have "standard gameport"
while( pwszGameportDriverArray[nIndex] )
{
// populate the Type Info
if( SUCCEEDED(pDIJoyConfig->GetTypeInfo(pwszGameportDriverArray[nIndex], lpdiJoyInfo, DITC_DISPLAYNAME | DITC_CALLOUT)) )
{
if( _wcsicmp(lpdiJoyInfo->wszDisplayName, A2W(pszDisplayName)) == 0 )
{
wcscpy(pDIJoyUserValues->wszGlobalDriver, lpdiJoyInfo->wszCallout );
if( SUCCEEDED(pDIJoyConfig->Acquire()) )
{
if( FAILED(pDIJoyConfig->SetUserValues(pDIJoyUserValues, DIJU_GLOBALDRIVER)) )
{
TRACE (TEXT("JOY.CPL: SetUserValues failed to set DIJU_GLOBALDRIVER!\n"));
}
// check to see if you need to display the poll flags check box!
if( _wcsicmp(pDIJoyUserValues->wszGlobalDriver, lpMSANALOG_VXD) == 0 )
{
SetWindowPos( hCtrl, NULL, NULL, NULL, NULL, NULL,
SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_SHOWWINDOW );
// Get the state from the registry and update the check mark
HKEY hKey;
if( FAILED(pDIJoyConfig->OpenTypeKey(pwszGameportDriverArray[nIndex], KEY_ALL_ACCESS, &hKey)) )
{
TRACE (TEXT("JOY.CPL: OpenTypeKey failed to open key %s!\n"), pwszGameportDriverArray[nIndex]);
}
DWORD dwFlag;
ULONG ulType = REG_BINARY;
ULONG ulSize = sizeof(dwFlag);
// this will happen if there is no entry for POLL_FLAGS_REG_STR
if( ERROR_SUCCESS != RegQueryValueEx(hKey, POLL_FLAGS_REG_STR, NULL, &ulType, (PBYTE)&dwFlag, &ulSize) )
dwFlag = 0;
::PostMessage(GetDlgItem(ghDlg, IDC_POLLFLAGS), BM_SETCHECK, (dwFlag) ? BST_CHECKED : BST_UNCHECKED, 0);
RegCloseKey(hKey);
}
}
break;
}
}
nIndex++;
}
// delete the DIJOYTYPEINFO variable
if( lpdiJoyInfo )
delete (lpdiJoyInfo);
}
pDIJoyConfig->SendNotify();
pDIJoyConfig->Unacquire();
if( pszDisplayName )
delete[] (pszDisplayName);
if( pDIJoyUserValues )
delete pDIJoyUserValues;
return(TRUE);
}
#endif // _UNICODE
///////////////////////////////////////////////////////////////////////////////
// FUNCTION: OnListviewContextMenu( void )
//
// PURPOSE: Handle Context menu in Listview
//
// RETURN: TRUE if successfull, FALSE otherwise
///////////////////////////////////////////////////////////////////////////////
static void OnListviewContextMenu( LPARAM lParam )
{
HMENU hPopupMenu = CreatePopupMenu();
ASSERT (hPopupMenu);
// unlike life, bRet defaults to bliss
BOOL bRet = TRUE;
LPTSTR pszText = new TCHAR[STR_LEN_32];
ASSERT (pszText);
// Don't display Rename/Change if on (none) entry
if( !(GetItemData(hAdvListCtrl, (BYTE)iAdvItem) & ID_NONE) )
{
if( !(nFlags & USER_MODE) )
{
// add the "Change..." string
::SendDlgItemMessage(GetParent(hAdvListCtrl), IDC_ADV_CHANGE, WM_GETTEXT, (WPARAM)STR_LEN_32, (LPARAM)(LPCTSTR)pszText);
bRet = AppendMenu(hPopupMenu, MF_ENABLED, IDC_ADV_CHANGE, pszText);
#ifdef _DEBUG
if( !bRet )
TRACE(TEXT("JOY.CPL: OnListviewCOntextMenu: AppendMenu Failed to insert %s\n"), pszText);
#endif //_DEBUG
// Add the Rename text
VERIFY(LoadString(ghInstance, IDS_RENAME, pszText, STR_LEN_32));
bRet = AppendMenu(hPopupMenu, MF_ENABLED, IDC_RENAME, pszText);
#ifdef _DEBUG
if( !bRet )
TRACE(TEXT("JOY.CPL: OnListviewCOntextMenu: AppendMenu Failed to insert %s\n"), pszText);
#endif //_DEBUG
// Add the SEPERATOR and "What's this?"
//PREFIX #WI279965. False positive.
//MSDN: if uFlags==MF_SEPARATOR, LPCTSTR lpNewItem is ignored.
bRet = AppendMenu(hPopupMenu, MF_SEPARATOR, 0, 0);
#ifdef _DEBUG
if( !bRet )
TRACE(TEXT("JOY.CPL: OnListviewCOntextMenu: AppendMenu Failed to insert SEPERATOR!\n"));
#endif //_DEBUG
}
}
VERIFY(LoadString(ghInstance, IDS_WHATSTHIS, pszText, STR_LEN_32));
bRet = AppendMenu(hPopupMenu, MF_ENABLED, IDS_WHATSTHIS, pszText);
#ifdef _DEBUG
if( !bRet )
TRACE(TEXT("JOY.CPL: OnListviewCOntextMenu: AppendMenu Failed to insert %s\n"), pszText);
#endif //_DEBUG
if( pszText ) delete[] (pszText);
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(hAdvListCtrl, LVM_GETITEMPOSITION, iAdvItem, (LPARAM)&pt);
RECT rc;
::GetClientRect(hAdvListCtrl, &rc);
pt.x = rc.right>>1;
ClientToScreen(hAdvListCtrl, &pt);
}
bRet = TrackPopupMenu (hPopupMenu, TPM_LEFTALIGN|TPM_LEFTBUTTON|TPM_RIGHTBUTTON, pt.x, pt.y, 0, ghDlg, NULL);
#ifdef _DEBUG
if( !bRet )
TRACE (TEXT("JOY.CPL: OnListviewContextMenu: TrackPopupMenu Failed!\n"));
#endif //_DEBUG
if(hPopupMenu) DestroyMenu (hPopupMenu); // PREFIX 45089
}
///////////////////////////////////////////////////////////////////////////////
// FUNCTION: UpdateListCtrl( void )
//
// PURPOSE: Refreshes enumerated device list
//
// RETURN: TRUE if successfull, FALSE otherwise
///////////////////////////////////////////////////////////////////////////////
static BOOL AdvUpdateListCtrl()
{
// Turn Redraw off here else it will flicker!
::SendMessage(hAdvListCtrl, WM_SETREDRAW, (WPARAM)FALSE, 0);
// Out with the old...
::SendMessage(hAdvListCtrl, LVM_DELETEALLITEMS, 0, 0);
// This buffer is so large because it is used to hold IDS_GEN_STATUS_UNKNOWN
TCHAR sz1[16];
// find and assign ID's
BYTE n = NUMJOYDEVS;
BYTE nIndex;
SendMessage(hAdvListCtrl, LVM_SETITEMCOUNT, (WPARAM)(int)NUMJOYDEVS, (LPARAM)LVSICF_NOINVALIDATEALL | LVSICF_NOSCROLL);
// Set everything to NONE to start!
do
{
itoa((BYTE)n--, (LPTSTR)&sz1);
// Insert the ID
// Set the device ID and ID_NONE in Extended info...
nIndex = InsertItem( hAdvListCtrl, sz1, n);
// Populate the columns with "(none)"
SetItemText(hAdvListCtrl, nIndex, DEVICE_FRIENDLY, lpstrNone);
SetItemText(hAdvListCtrl, nIndex, DEVICE_TYPE, lpstrNone);
#ifdef _UNICODE
SetItemText(hAdvListCtrl, nIndex, DEVICE_PORT, lpstrNone);
#endif
} while( n );
if( nAssigned )
{
// insert the assigned ones!
n = nAssigned;
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;
#ifndef _UNICODE
USES_CONVERSION;
#endif
// The low half will be populated by the ID, the upper by bit flags!
DWORD dwData;
do
{
// Set the Product Column!
if( SUCCEEDED(pAssigned[--n]->fnDeviceInterface->GetProperty(DIPROP_PRODUCTNAME, &pDIPropStr->diph)) )
{
#ifdef _UNICODE
SetItemText(hAdvListCtrl, pAssigned[n]->ID, DEVICE_TYPE, (LPTSTR)pDIPropStr->wsz);
#else
SetItemText(hAdvListCtrl, pAssigned[n]->ID, DEVICE_TYPE, (LPTSTR)W2A(pDIPropStr->wsz));
#endif
}
// Set the Friendly Name!
if( SUCCEEDED(pAssigned[n]->fnDeviceInterface->GetProperty(DIPROP_INSTANCENAME, &pDIPropStr->diph)) )
{
#ifdef _UNICODE
SetItemText(hAdvListCtrl, pAssigned[n]->ID, DEVICE_FRIENDLY, (LPTSTR)pDIPropStr->wsz);
#else
SetItemText(hAdvListCtrl, pAssigned[n]->ID, DEVICE_FRIENDLY, (LPTSTR)W2A(pDIPropStr->wsz));
#endif
}
#ifdef _UNICODE
// Set the Game Port Column!
if( SUCCEEDED(pAssigned[n]->fnDeviceInterface->GetProperty(DIPROP_GETPORTDISPLAYNAME, &pDIPropStr->diph)) )
{
SetItemText(hAdvListCtrl, pAssigned[n]->ID, DEVICE_PORT, (LPTSTR)pDIPropStr->wsz);
} else
{
VERIFY(LoadString(ghInstance, IDS_GEN_STATUS_UNKNOWN, sz1, sizeof(sz1)/sizeof(TCHAR)));
SetItemText(hAdvListCtrl, pAssigned[n]->ID, DEVICE_PORT, (LPTSTR)sz1);
}
#endif // _UNICODE
// Set the ID in the data...
// This is necessary for Sorting!
dwData = pAssigned[n]->ID;
//if( pAssigned[n]->clsidPropSheet != CLSID_LegacyServer )
if( pAssigned[n]->fHasOemSheet )
{
LPDIJOYCONFIG_DX5 lpDIJoyConfig = new (DIJOYCONFIG_DX5);
ASSERT (lpDIJoyConfig);
ZeroMemory(lpDIJoyConfig, sizeof(DIJOYCONFIG_DX5));
lpDIJoyConfig->dwSize = sizeof (DIJOYCONFIG_DX5);
// Set the DefaultPropertySheet flag
if( SUCCEEDED(pDIJoyConfig->GetConfig(pAssigned[n]->ID, (LPDIJOYCONFIG)lpDIJoyConfig, DIJC_REGHWCONFIGTYPE)) )
{
LPDIJOYTYPEINFO lpDIJoyTypeInfo = new (DIJOYTYPEINFO);
ASSERT (lpDIJoyTypeInfo);
ZeroMemory(lpDIJoyTypeInfo, sizeof(DIJOYTYPEINFO));
lpDIJoyTypeInfo->dwSize = sizeof (DIJOYTYPEINFO);
if( SUCCEEDED(pDIJoyConfig->GetTypeInfo(lpDIJoyConfig->wszType, lpDIJoyTypeInfo, DITC_FLAGS1 )) )
{
if( lpDIJoyTypeInfo->dwFlags1 & JOYTYPE_DEFAULTPROPSHEET )
{
// Set the USE_DEFAULT mask!
dwData |= USE_DEFAULT;
// Update the global list!
pAssigned[n]->clsidPropSheet = CLSID_LegacyServer;
}
}
if( lpDIJoyTypeInfo )
delete (lpDIJoyTypeInfo);
}
dwData |= SHOW_DEFAULT;
if( lpDIJoyConfig )
delete (lpDIJoyConfig);
}
// Set the Item Data to the ID!
SetItemData(hAdvListCtrl, pAssigned[n]->ID, dwData);
} while( n );
// clean up, clean up... everybody do your share!
if( pDIPropStr )
delete (pDIPropStr);
}
// turn the flag off!
if( nFlags & UPDATE_FOR_ADV )
nFlags &= ~UPDATE_FOR_ADV;
// Turn the redraw flag back on!
::SendMessage (hAdvListCtrl, WM_SETREDRAW, (WPARAM)TRUE, 0);
InvalidateRect(hAdvListCtrl, NULL, TRUE);
return(TRUE);
}
////////////////////////////////////////////////////////////////////////////////
//
// FUNCTION: ChangeDialogProc(HWND hDlg, ULONG uMsg, WPARAM wParam, LPARAM lParam)
//
// PARAMETERS: HWND hDlg -
// ULONG uMsg -
// WPARAM wParam -
// LPARAM lParam -
//
// PURPOSE:
////////////////////////////////////////////////////////////////////////////////
BOOL WINAPI ChangeDialogProc(HWND hDlg, ULONG uMsg, WPARAM wParam, LPARAM lParam)
{
switch( uMsg )
{
case WM_LBUTTONDOWN:
// Click Drag service for PropSheets!
PostMessage(hDlg, WM_NCLBUTTONDOWN, (WPARAM)HTCAPTION, lParam);
break;
case WM_HELP:
OnHelp(lParam);
return(1);
case WM_CONTEXTMENU:
OnContextMenu(wParam, lParam);
return(TRUE);
case WM_INITDIALOG:
{
HICON hIcon = (HICON)LoadImage(ghInstance, MAKEINTRESOURCE(IDI_CPANEL), IMAGE_ICON, 0, 0, LR_DEFAULTSIZE);
ASSERT (hIcon);
if( hIcon )
::PostMessage(hDlg, WM_SETICON, (WPARAM)ICON_SMALL, (LPARAM)hIcon);
HWND hCtrl = GetDlgItem(hDlg, IDC_CHANGE_LIST);
ASSERT (hCtrl);
UpdateChangeListCtrl( hCtrl );
BYTE nCounter = nAssigned;
while( nCounter-- )
{
if( (BYTE)::SendMessage(hCtrl, LB_GETITEMDATA, (WPARAM)nCounter, 0) == nOldID )
break;
}
// Set the list box selections!
::PostMessage(hCtrl, LB_SETCURSEL, (WPARAM)nCounter, 0);
// Done with the ListCtrl, now... on to the ComboBox
if( nFlags & ON_NT )
{
if( !PopulatePortList(hDlg) )
{
#ifdef _DEBUG
OutputDebugString(TEXT("JOY.CPL: ADVANCED.CPP: PopulatePortList failed!\n"));
#endif
}
}
// Set up the Spin Control!
HWND hSpinCtrl = GetDlgItem(hDlg, IDC_SPIN);
::PostMessage(hSpinCtrl, UDM_SETRANGE, 0, MAKELPARAM(NUMJOYDEVS, 1));
::PostMessage(hSpinCtrl, UDM_SETBASE, 10, 0L);
::PostMessage(hSpinCtrl, UDM_SETPOS, 0, MAKELPARAM(nOldID+1, 0));
}
return(FALSE);
case WM_COMMAND:
{
switch( LOWORD(wParam) )
{
/* I'll leave this commented out, as it's likely they'll want double clicking back once I take it out
case IDC_CHANGE_LIST:
// Fall into Change on DBLCLK
if (HIWORD(wParam) != LBN_DBLCLK)
break;
*/
case IDOK:
{
HWND hCtrl = GetDlgItem(hDlg, IDC_CHANGE_LIST);
ASSERT (hCtrl);
char nSelectedItem = (char)(SendMessage(hCtrl, LB_GETITEMDATA, SendMessage(hCtrl, LB_GETCURSEL, 0, 0), 0));
TCHAR tsz[4];
hCtrl = GetDlgItem(hDlg, IDC_SPINBUDDY);
tsz[0] = 4;
SendMessage(hCtrl, EM_GETLINE, 0, (LPARAM)(LPCSTR)&tsz);
// The '-1' is to account for the 1 based list
// and the 0 based id's!
char nSelectedID = (char)atoi((LPCTSTR)&tsz)-1;
pDIJoyConfig->Acquire();
// first check to see if the user has selected NONE!
if( nSelectedItem == -2 )
{
// User has selected NONE!
VERIFY (SUCCEEDED(pDIJoyConfig->DeleteConfig(nSelectedID)));
} else
{
// see if the selected item and the ID match!
// if so... get out of here!
if( nSelectedID == nSelectedItem )
{
#ifdef _DEBUG
OutputDebugString(TEXT("JOY.CPL: ADVANCED.CPP: OnChangeCommand: IDOK: Device already at selected ID!\n"));
#endif
} else
{
SwapIDs(nSelectedID, nSelectedItem);
// SetListCtrlItemFocus(hAdvListCtrl, (BYTE)nSelectedID);
}
}
pDIJoyConfig->Unacquire();
}
// missing break intentional!
case IDCANCEL:
EndDialog(hDlg, LOWORD(wParam));
break;
}
}
return(1);
case WM_DESTROY:
DestroyIcon((HICON)SendMessage(hDlg, WM_GETICON, (WPARAM)ICON_SMALL, 0));
return(TRUE);
}
return(FALSE);
}
///////////////////////////////////////////////////////////////////////////////
// FUNCTION: PopulateGlobalPortDriverComboBox( void )
//
// PARAMETERS:
//
// PURPOSE:
///////////////////////////////////////////////////////////////////////////////
#ifndef UNICODE
void PopulateGlobalPortDriverComboBox( void )
{
HWND hCtrl = GetDlgItem(ghDlg, IDC_COMBO1);
// make sure the combo is clear before we start populating it!
SendMessage(hCtrl, CB_RESETCONTENT, 0, 0);
// Type info
LPDIJOYTYPEINFO_DX5 lpdiJoyInfo = new (DIJOYTYPEINFO_DX5);
ASSERT (lpdiJoyInfo);
ZeroMemory(lpdiJoyInfo, sizeof(DIJOYTYPEINFO_DX5));
lpdiJoyInfo->dwSize = sizeof(DIJOYTYPEINFO_DX5);
BYTE nIndex = nGameportDriver;
USES_CONVERSION;
// Populate the Combobox
while( nIndex-- )
{
// populate the Type Info and place the Index in the extra memory!
if( SUCCEEDED(pDIJoyConfig->GetTypeInfo(pwszGameportDriverArray[nIndex], (LPDIJOYTYPEINFO)lpdiJoyInfo, DITC_DISPLAYNAME)) )
::SendMessage(hCtrl, CB_SETITEMDATA, ::SendMessage(hCtrl, CB_ADDSTRING, 0, (LPARAM)(LPCTSTR)W2A(lpdiJoyInfo->wszDisplayName)), nIndex);
#ifdef _DEBUG
else
OutputDebugString (TEXT("JOY.CPL: ADVANCED.CPP: PopulateGlobalPortDriverComboBox: GetTypeInfo failed!\n"));
#endif
}
// Display the Current selected GlobalPortDriver or None!
LPDIJOYUSERVALUES pDIJoyUserValues = new DIJOYUSERVALUES;
ASSERT (pDIJoyUserValues);
ZeroMemory(pDIJoyUserValues, sizeof(DIJOYUSERVALUES));
pDIJoyUserValues->dwSize = sizeof(DIJOYUSERVALUES);
VERIFY (SUCCEEDED(pDIJoyConfig->GetUserValues(pDIJoyUserValues, DIJU_GLOBALDRIVER)));
// Fix #9815, If the user has No Global port driver label as NONE!
if( !(*pDIJoyUserValues->wszGlobalDriver && pDIJoyUserValues->wszGlobalDriver) )
{
iGameportDriverItem = NO_ITEM;
PostMessage(hCtrl, CB_SETCURSEL, (WPARAM)SendMessage(hCtrl, CB_FINDSTRING, (WPARAM)-1, (LPARAM)lpstrNone), (LPARAM)0);
} else
{
ZeroMemory(lpdiJoyInfo, sizeof(DIJOYTYPEINFO_DX5));
lpdiJoyInfo->dwSize = sizeof(DIJOYTYPEINFO_DX5);
nIndex = 0;
// get type info 'till you find the one you want and place it's callout
while( pwszGameportDriverArray[nIndex] )
{
VERIFY(SUCCEEDED(pDIJoyConfig->GetTypeInfo(pwszGameportDriverArray[nIndex], (LPDIJOYTYPEINFO)lpdiJoyInfo, DITC_CALLOUT | DITC_DISPLAYNAME)));
if( _wcsicmp(lpdiJoyInfo->wszCallout, pDIJoyUserValues->wszGlobalDriver) == 0 )
{
::PostMessage(hCtrl, CB_SETCURSEL, (WPARAM)::SendMessage(hCtrl, CB_FINDSTRING, (WPARAM)-1, (LPARAM)W2A(lpdiJoyInfo->wszDisplayName)), (LPARAM)0);
iGameportDriverItem = nIndex;
// enable the PollFlags checkbox!
if( _wcsicmp(pDIJoyUserValues->wszGlobalDriver, lpMSANALOG_VXD) == 0 )
{
SetWindowPos( GetDlgItem( ghDlg, IDC_POLLFLAGS), NULL, NULL, NULL, NULL, NULL,
SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_SHOWWINDOW );
VERIFY(SUCCEEDED(pDIJoyConfig->Acquire()));
// Get the state from the registry and update the check mark
HKEY hKey;
DWORD dwFlag;
if( SUCCEEDED(pDIJoyConfig->OpenTypeKey(pwszGameportDriverArray[nIndex], KEY_ALL_ACCESS, &hKey)) )
{
ULONG ulType = REG_BINARY;
ULONG ulSize = sizeof(dwFlag);
// this will happen if there is no entry for POLL_FLAGS_REG_STR
if( ERROR_SUCCESS != RegQueryValueEx(hKey, POLL_FLAGS_REG_STR, NULL, &ulType, (PBYTE)&dwFlag, &ulSize) )
dwFlag = 0;
RegCloseKey(hKey);
}
pDIJoyConfig->Unacquire();
::PostMessage(GetDlgItem(ghDlg, IDC_POLLFLAGS), BM_SETCHECK, (dwFlag) ? BST_CHECKED : BST_UNCHECKED, 0);
}
break;
}
nIndex++;
}
}
// delete the DIJOYUSERVALUES variable
if( pDIJoyUserValues )
delete pDIJoyUserValues;
// clean up, clean up... everybody do your share!
if( lpdiJoyInfo )
delete (lpdiJoyInfo);
// VERIFY(SendMessage(hCtrl, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)lpstrNone) != CB_ERR);
}
#endif
///////////////////////////////////////////////////////////////////////////////
// FUNCTION: SubClassProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
//
// PARAMETERS: HWND hWnd -
// UINT uMsg -
// WPARAM wParam -
// LPARAM lParam -
//
// PURPOSE: SubClass Procedure for Setting the ID to NONE on VK_DELETE on the Advanced Page
///////////////////////////////////////////////////////////////////////////////
BOOL WINAPI KeySubClassProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch( uMsg )
{
case WM_COMMAND:
switch( LOWORD(wParam) )
{
case IDCANCEL:
case IDOK:
if( nFlags & UPDATE_INPROCESS )
{
bProcess = (LOWORD(wParam) == IDOK) ? TRUE : FALSE;
SetFocus(hAdvListCtrl);
nFlags &= ~UPDATE_INPROCESS;
return(FALSE);
}
break;
}
break;
}
return(BOOL)CallWindowProc(fpPageWndProc, hWnd, uMsg, wParam, lParam);
}
///////////////////////////////////////////////////////////////////////////////
// FUNCTION: SubClassProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
//
// PARAMETERS: HWND hWnd -
// UINT uMsg -
// WPARAM wParam -
// LPARAM lParam -
//
// PURPOSE: SubClass Procedure for Setting the ID to NONE on VK_DELETE on the Advanced Page
///////////////////////////////////////////////////////////////////////////////
BOOL WINAPI SubClassProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch( uMsg )
{
case WM_PARENTNOTIFY:
if( LOWORD(wParam) == WM_LBUTTONDOWN )
{
if( nFlags & UPDATE_INPROCESS )
SetFocus(hAdvListCtrl);
}
break;
case WM_SYSCOMMAND:
if( wParam & SC_VSCROLL )
{
if( nFlags & UPDATE_INPROCESS )
SetFocus(hAdvListCtrl);
}
break;
}
return(BOOL)CallWindowProc(fpMainWndProc, hWnd, uMsg, wParam, lParam);
}
///////////////////////////////////////////////////////////////////////////////
// FUNCTION: UpdateChangeListCtrl ( HWND hCtrl )
//
// PARAMETERS: HWND hCtrl - Handle to Change list box
//
// PURPOSE: Update the Change List box
///////////////////////////////////////////////////////////////////////////////
static BOOL UpdateChangeListCtrl ( HWND hCtrl )
{
#ifndef _UNICODE
USES_CONVERSION;
#endif
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;
BYTE n = nAssigned;
LPTSTR lpStr = new (TCHAR[MAX_STR_LEN]);
ASSERT (lpStr);
// find and assign ID's
while( n-- )
{
if( SUCCEEDED(pAssigned[n]->fnDeviceInterface->GetProperty(DIPROP_INSTANCENAME, &pDIPropStr->diph)) )
{
// Our buffer is Only soooo big...
// besides, it just doesn't make sence to display Everything!
if( wcslen(pDIPropStr->wsz) > STR_LEN_64 )
{
pDIPropStr->wsz[60] = pDIPropStr->wsz[61] = pDIPropStr->wsz[62] = TEXT('.');
pDIPropStr->wsz[63] = TEXT('\0');
}
#ifdef _UNICODE
_tcscpy(lpStr, pDIPropStr->wsz);
#else
_tcscpy(lpStr, W2A(pDIPropStr->wsz));
#endif
// Put the first bracket on...
_tcscat(lpStr, TEXT(" ("));
// Now, get the productname of the device!
if( SUCCEEDED(pAssigned[n]->fnDeviceInterface->GetProperty(DIPROP_PRODUCTNAME, &pDIPropStr->diph)) )
{
#ifdef _UNICODE
_tcscat(lpStr, pDIPropStr->wsz);
#else
_tcscat(lpStr, W2A(pDIPropStr->wsz));
#endif
}
// put the end bracket on...
_tcscat(lpStr, TEXT(")"));
BYTE n1 = (BYTE)SendMessage(hCtrl, LB_ADDSTRING, 0, (LPARAM)(LPCTSTR)lpStr);
SendMessage(hCtrl, LB_SETITEMDATA, n1, pAssigned[n]->ID);
}
#ifdef _DEBUG
else OutputDebugString(TEXT("JOY.CPL: Advanced.cpp: UpdateChangeListCtrl: GetProperty failed!\n"));
#endif // _DEBUG
}
if( lpStr )
delete[] (lpStr);
if( pDIPropStr )
delete (pDIPropStr);
return(TRUE);
}
///////////////////////////////////////////////////////////////////////////////
// FUNCTION: itoa(BYTE n, LPTSTR lpStr)
//
// PARAMETERS: BYTE n - Number to be translated
// LPTSTR lpStr - Buffer to recieve translated value
//
// PURPOSE: Convert BYTE values < 20 to strings.
///////////////////////////////////////////////////////////////////////////////
void itoa(BYTE n, LPTSTR lpStr)
{
// designed for use with the CPL ONLY!
// Only supports values < NUMJOYDEVS!
if( n > NUMJOYDEVS )
{
#ifdef _DEBUG
OutputDebugString(TEXT("JOY.CPL: itoa: n > NUMJOYDEVS!\n"));
#endif
return;
}
lpStr[0] = n % 10 + '0';
if( n > 9 )
{
// Reverse the string and send it back...
lpStr[1] = lpStr[0];
lpStr[0] = '1';
lpStr[2] = '\0';
} else lpStr[1] = '\0';
}
int CALLBACK CompareIDItems(LPARAM item1, LPARAM item2, LPARAM uDirection)
{
if( LOWORD(item1) == LOWORD(item2) )
return(0);
short nRet = (LOWORD(item1) > LOWORD(item2)) ? 1 : -1;
return(uDirection) ? nRet : (nRet < 0) ? 1 : -1;
}
void LaunchChange( HWND hTmp )
{
// Don't allow if you're in USER mode!
if( (nFlags & USER_MODE) )
return;
iAdvItem = (short)::SendMessage(hAdvListCtrl, LVM_GETNEXTITEM, (WPARAM)(int)-1, MAKELPARAM(LVNI_SELECTED, 0));
nOldID = (BYTE)GetItemData(hAdvListCtrl, (BYTE)iAdvItem);
if( nOldID & ID_NONE )
return;
// valid returns are IDOK, IDCANCEL, and IDC_CHANGE_LIST
if( IDCANCEL != DialogBox(ghInstance, (PTSTR)IDD_ADV_CHANGE, ghDlg, (DLGPROC)ChangeDialogProc) )
{
// Yeah, it's not really a DEVICEARRIVAL...
::SendMessage(hTmp, WM_DEVICECHANGE, DBT_DEVICEARRIVAL, 0);
::PostMessage(hAdvListCtrl, LVM_ENSUREVISIBLE, (BYTE)iAdvItem, TRUE);
SetFocus(hAdvListCtrl);
SetListCtrlItemFocus(hAdvListCtrl, (BYTE)iAdvItem);
}
}
///////////////////////////////////////////////////////////////////////////////
// FUNCTION: SortTextItems( CListCtrl *pCtrl, short nCol, BOOL bAscending, int low, int high )
//
// SortTextItems - Sort the list based on column text
//
// PARAMETERS:
// pCtrl - pointer to list to sort
// nCol - column that contains the text to be sorted
// bAscending - indicate sort order
// low - row to start scanning from - default row is 0
// high - row to end scan. -1 indicates last row
//
// PURPOSE: Sort text items in ListCtrl
// Returns - Returns true for success
///////////////////////////////////////////////////////////////////////////////
BOOL SortTextItems( CListCtrl *pCtrl, short nCol, BOOL bAscending, short low, short high )
{
CHeaderCtrl* pHeader = (CHeaderCtrl*) pCtrl->GetDlgItem(0);
if( nCol >= pHeader->GetItemCount() )
return(FALSE);
if( high == -1 )
high = pCtrl->GetItemCount() - 1;
short lo = low;
short hi = high;
if( hi <= lo ) return(FALSE);
// The choices here are to malloc a buffer large enough for the largest
// string, or malloc an LV_ITEM struct to get the length, then malloc
// just the size we need.
CString midItem = pCtrl->GetItemText( (lo+hi)/2, nCol );
// loop through the list until indices cross
while( lo <= hi )
{
// rowText will hold all column text for one row
CStringArray rowText;
// find the first element that is greater than or equal to
// the partition element starting from the left Index.
if( bAscending )
while( ( lo < high ) && ( pCtrl->GetItemText(lo, nCol) < midItem ) )
++lo;
else
while( ( lo < high ) && ( pCtrl->GetItemText(lo, nCol) > midItem ) )
++lo;
// find an element that is smaller than or equal to
// the partition element starting from the right Index.
if( bAscending )
while( ( hi > low ) && ( pCtrl->GetItemText(hi, nCol) > midItem ) )
--hi;
else
while( ( hi > low ) && ( pCtrl->GetItemText(hi, nCol) < midItem ) )
--hi;
// if the indexes have not crossed, swap
// and if the items are not equal
if( lo <= hi )
{
// swap only if the items are not equal
if( pCtrl->GetItemText(lo, nCol) != pCtrl->GetItemText(hi, nCol) )
{
// swap the rows
LV_ITEM lvitemlo, lvitemhi;
BYTE nColCount = (BYTE)pHeader->GetItemCount();
rowText.SetSize( nColCount );
for( BYTE i = 0; i < nColCount; i++ )
rowText[i] = pCtrl->GetItemText(lo, i);
lvitemlo.mask = LVIF_IMAGE | LVIF_PARAM | LVIF_STATE;
lvitemlo.iItem = lo;
lvitemlo.iSubItem = 0;
lvitemlo.stateMask = LVIS_CUT | LVIS_DROPHILITED | LVIS_FOCUSED | LVIS_SELECTED | LVIS_OVERLAYMASK | LVIS_STATEIMAGEMASK;
lvitemhi = lvitemlo;
lvitemhi.iItem = hi;
ListView_GetItem(pCtrl->GetSafeHwnd(), &lvitemlo );
ListView_GetItem(pCtrl->GetSafeHwnd(), &lvitemhi );
for( i=0; i<nColCount; i++ )
pCtrl->SetItemText(lo, i, pCtrl->GetItemText(hi, i));
lvitemhi.iItem = lo;
ListView_SetItem(pCtrl->GetSafeHwnd(), &lvitemhi );
for( i=0; i<nColCount; i++ )
pCtrl->SetItemText(hi, i, rowText[i]);
lvitemlo.iItem = hi;
ListView_SetItem(pCtrl->GetSafeHwnd(), &lvitemlo );
}
++lo;
--hi;
}
}
// If the right index has not reached the left side of array
// must now sort the left partition.
if( low < hi )
SortTextItems( pCtrl, nCol, bAscending, low, hi);
// If the left index has not reached the right side of array
// must now sort the right partition.
if( lo < high )
SortTextItems( pCtrl, nCol, bAscending, lo, high);
return(TRUE);
}
///////////////////////////////////////////////////////////////////////////////
// FUNCTION: EditSubLabel( BYTE nItem, BYTE nCol )
//
// PARAMETERS:
// EditSubLabel - Start edit of a sub item label
// Returns - Temporary pointer to the new edit control
// nItem - The row index of the item to edit
// nCol - The column of the sub item.
// PURPOSE: Provide editing services for any column in a CListCtrl
///////////////////////////////////////////////////////////////////////////////
void EditSubLabel( BYTE nItem, BYTE nCol )
{
#ifdef _DEBUG
// Make sure that the item is visible
if( !SendMessage(hAdvListCtrl, LVM_ENSUREVISIBLE, nItem, TRUE ) )
{
OutputDebugString(TEXT("JOY.CPL: ADVANCED.CPP: EditSubLabel: requested item not visible!\n"));
return;
}
#endif // _DEBUG
// Get the column offset
short offset = 0;
BYTE i = 0;
// OK, so here's what we have to do...
// Traverse the columns incrementing the widths of the ones lesser than the one we're looking for!
HDITEM *phdItem = new (HDITEM);
ASSERT (phdItem);
phdItem->mask = HDI_ORDER | HDI_WIDTH;
HWND hHeader = GetDlgItem(hAdvListCtrl, 0);
BYTE nColumns = (BYTE)::SendMessage(hHeader, HDM_GETITEMCOUNT, 0, 0L);
BYTE nColWidth;
do
{
::SendMessage(hHeader, HDM_GETITEM, (WPARAM)(int)--nColumns, (LPARAM)(LPHDITEM)phdItem);
if( phdItem->iOrder < nCol )
offset += (short)phdItem->cxy;
if( phdItem->iOrder == nCol )
nColWidth = (BYTE)phdItem->cxy;
} while( nColumns );
if( phdItem )
delete (phdItem);
RECT rect;
ListView_GetItemRect(hAdvListCtrl, nItem, &rect, LVIR_BOUNDS );
// Now scroll if we need to expose the column
CRect rcClient;
::GetClientRect(hAdvListCtrl, &rcClient);
if( offset + rect.left < 0 || offset + rect.left > rcClient.right )
{
::SendMessage(hAdvListCtrl, LVM_SCROLL, (WPARAM)(int)offset + rect.left, (LPARAM)(int)0);
rect.left -= (offset + rect.left);
}
rect.left += offset+4;
rect.right = rect.left + nColWidth - 3; // + ::SendMessage(hAdvListCtrl, LVM_GETCOLUMNWIDTH, (WPARAM)(int)nCol, (LPARAM)0L) - 3 ;
if( rect.right > rcClient.right )
rect.right = rcClient.right;
CEdit *pEdit = new CInPlaceEdit(nItem, 1);
ASSERT (pEdit);
// malloc the list ctrl
CWnd *pListCtrl = new (CWnd);
ASSERT (pListCtrl);
pListCtrl->Attach(hAdvListCtrl);
pEdit->Create(WS_BORDER | WS_CHILD | WS_VISIBLE | ES_AUTOHSCROLL | ES_CENTER, rect, pListCtrl, IDC_IPEDIT );
pListCtrl->Detach();
if( pListCtrl )
delete (pListCtrl);
}
#ifdef _UNICODE
void SwapIDs(BYTE nSource, BYTE nTarget)
{
// malloc and retrieve the data from the selected item
LPDIJOYCONFIG lpSelectedID = new (DIJOYCONFIG);
ASSERT (lpSelectedID);
ZeroMemory(lpSelectedID, sizeof(DIJOYCONFIG));
lpSelectedID->dwSize = sizeof(DIJOYCONFIG);
// Get the Config of device on ID taken from Change List box!
HRESULT hr = pDIJoyConfig->GetConfig(nSource, lpSelectedID, DIJC_ALL);
if( hr == DIERR_NOTFOUND || hr == S_FALSE )
{
// No Object on Selected ID!
if( lpSelectedID )
delete (lpSelectedID);
lpSelectedID = NULL;
}
// malloc and retrieve the data from the item associated
// with the ID taken from the Item selected in the List box!
LPDIJOYCONFIG lpSelectedItem = new (DIJOYCONFIG);
ASSERT (lpSelectedItem);
ZeroMemory(lpSelectedItem, sizeof(DIJOYCONFIG));
lpSelectedItem->dwSize = sizeof (DIJOYCONFIG);
hr = pDIJoyConfig->GetConfig(nTarget, lpSelectedItem, DIJC_ALL);
if( hr == DIERR_NOTFOUND || hr == S_FALSE )
{
if( lpSelectedItem )
delete (lpSelectedItem);
lpSelectedItem = NULL;
}
// ***********************************************************
// Delete the configurations!
// ***********************************************************
// Set the hour glass
SetCursor(LoadCursor(NULL, IDC_WAIT));
// ********************************************************
// OK, now... at this point you have:
// lpSelectedID: containing NULL if the device wasn't present or...
// a valid pointer containing the configuration of nSelectedID
// lpSelected : containing NULL if the device wasn't present or...
// a valid pointer containing the configuration of id
// ********************************************************
// Time to Set the Configurations!
if( lpSelectedID )
{
hr = pDIJoyConfig->SetConfig(nTarget, lpSelectedID, DIJC_ALL);
if( lpSelectedID )
delete (lpSelectedID);
} else pDIJoyConfig->DeleteConfig(nSource);
// delete both configurations
// pointers will be NULL if the config was not found!
if( lpSelectedItem )
{
hr = pDIJoyConfig->SetConfig(nSource, lpSelectedItem, DIJC_ALL );
if( lpSelectedItem )
delete (lpSelectedItem);
}
pDIJoyConfig->SendNotify();
// Set the hour glass
SetCursor(LoadCursor(NULL, IDC_ARROW));
}
#else
// Memphis version of SwapIDs...
// Caution!!! Very Sensitive!!!
void SwapIDs(BYTE nSelectedID, BYTE nSelectedItem)
{
// malloc and retrieve the data from the selected item
LPDIJOYCONFIG lpSelectedID = new (DIJOYCONFIG);
DWORD dwSelectedID = 0, dwSelectedItem = 0;
ASSERT (lpSelectedID);
ZeroMemory(lpSelectedID, sizeof(DIJOYCONFIG));
lpSelectedID->dwSize = sizeof(DIJOYCONFIG);
// Get the Config of device on ID taken from Change List box!
HRESULT hr = pDIJoyConfig->GetConfig(nSelectedID, lpSelectedID, DIJC_ALL);
if( hr == DIERR_NOTFOUND || hr == S_FALSE )
{
// No Object on Selected ID!
if( lpSelectedID )
delete (lpSelectedID);
lpSelectedID = NULL;
} else {
if( lpSelectedID )
delete (lpSelectedID);
lpSelectedID = NULL;
Error((short)IDS_DEST_ID_OCCUPIED_TITLE, (short)IDS_DEST_ID_OCCUPIED);
return;
}
// malloc and retrieve the data from the item associated
// with the ID taken from the Item selected in the List box!
LPDIJOYCONFIG lpSelectedItem = new (DIJOYCONFIG);
ASSERT (lpSelectedItem);
ZeroMemory(lpSelectedItem, sizeof(DIJOYCONFIG));
lpSelectedItem->dwSize = sizeof (DIJOYCONFIG);
hr = pDIJoyConfig->GetConfig(nSelectedItem, lpSelectedItem, DIJC_ALL);
if( hr == DIERR_NOTFOUND || hr == S_FALSE )
{
if( lpSelectedItem )
delete (lpSelectedItem);
lpSelectedItem = NULL;
return;
}
// ***********************************************************
// Delete the configurations!
// ***********************************************************
// Set the hour glass
SetCursor(LoadCursor(NULL, IDC_WAIT));
// ********************************************************
// OK, now... at this point you have:
// lpSelectedID: containing NULL if the device wasn't present or...
// a valid pointer containing the configuration of nSelectedID
// lpSelected : containing NULL if the device wasn't present or...
// a valid pointer containing the configuration of id
// ********************************************************
// Time to Set the Configurations!
if( lpSelectedID )
{
DWORD dwFlags = DIJC_REGHWCONFIGTYPE | DIJC_CALLOUT | DIJC_GAIN | DIJC_GUIDINSTANCE;
USES_CONVERSION;
// if the callout is joyhid.vxd then the device is USB so...
// OR on the DIJC_WDMGAMEPORT flag!
if( !_stricmp(TEXT("joyhid.vxd"), W2A(lpSelectedID->wszCallout)) )
{
// dwFlags |= DIJC_WDMGAMEPORT;
dwSelectedID = 2;
} else
{
dwSelectedID = 1;
}
if( dwSelectedID == 1 ) {
hr = pDIJoyConfig->DeleteConfig(nSelectedID);
/*
* This notify is to fix the bug changing id on 2-axis 2-button joystick.
*/
pDIJoyConfig->SendNotify();
if( SUCCEEDED(hr) )
{
hr = pDIJoyConfig->SetConfig(nSelectedItem, lpSelectedID, dwFlags );
if( SUCCEEDED(hr) ) {
pDIJoyConfig->SendNotify();
}
}
} else {
hr = pDIJoyConfig->SetConfig(nSelectedItem, lpSelectedID, dwFlags);
pDIJoyConfig->SendNotify();
if( SUCCEEDED(hr) )
{
hr = pDIJoyConfig->DeleteConfig(nSelectedID);
pDIJoyConfig->SendNotify();
if( nSelectedID < nSelectedItem ) {
pDIJoyConfig->SendNotify();
}
}
}
if( lpSelectedID )
delete (lpSelectedID);
}
// delete both configurations
// pointers will be NULL if the config was not found!
if( lpSelectedItem )
{
DWORD dwFlags = DIJC_REGHWCONFIGTYPE | DIJC_CALLOUT | DIJC_GAIN | DIJC_GUIDINSTANCE;
USES_CONVERSION;
if( _tcsicmp(TEXT("joyhid.vxd"), W2A(lpSelectedItem->wszCallout)) == 0 )
{
// dwFlags |= DIJC_WDMGAMEPORT;
dwSelectedItem = 2; //joyhid.vxd
}
#if 0
/*
* Since MSGAME.VXD will directly write to the registry with some unhealthy data.
* We have to change it before we move to other ID.
*/
else if( _tcsicmp(TEXT("MSGAME.VXD"), W2A(lpSelectedItem->wszCallout)) == 0 )
{
lpSelectedItem->hwc.dwType += 1;
dwSelectedItem = 3; //msgame.vxd (Sidewinder driver)
}
#endif
else {
dwSelectedItem = 1; //vjoyd.vxd
}
if( dwSelectedItem == 1 // VJOYD.VXD,
// || dwSelectedItem == 3
){ // MSGAME.VXD
hr = pDIJoyConfig->DeleteConfig(nSelectedItem);
/*
* This notify is to fix the bug changing id on 2-axis 2-button joystick.
*/
pDIJoyConfig->SendNotify();
if( SUCCEEDED(hr) )
{
hr = pDIJoyConfig->SetConfig(nSelectedID, lpSelectedItem, dwFlags );
if( SUCCEEDED(hr) ) {
pDIJoyConfig->SendNotify();
}
}
} else {
hr = pDIJoyConfig->SetConfig(nSelectedID, lpSelectedItem, dwFlags );
/*
* This notify is to fix the bug changing id on 2-axis 2-button joystick.
*/
pDIJoyConfig->SendNotify();
if( SUCCEEDED(hr) )
{
hr = pDIJoyConfig->DeleteConfig(nSelectedItem);
pDIJoyConfig->SendNotify();
if( nSelectedID < nSelectedItem ) {
pDIJoyConfig->SendNotify();
}
}
}
if( lpSelectedItem )
{
delete (lpSelectedItem);
}
}
// Set the hour glass
SetCursor(LoadCursor(NULL, IDC_ARROW));
}
#endif