/* * 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 #include #ifndef _UNICODE #define INC_OLE2 #include // For COM stuff! #endif #include #include #include // For RegisterDeviceNotification stuff! #include // for DBT_ defines!!! #include #include // for _alloca #include // 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 */