/* File: add.cpp Project: Universal Joystick Control Panel OLE Client Author: Brycej Date: 14/Feb/97 Comments: window proc for add dialog Copyright (c) 1995, Microsoft Corporation */ #include #include #include // for REGSTR_VAL_JOYOEMNAME reference! #include "cpanel.h" #include "joyarray.h" #include #pragma warning(disable:4200) #include #pragma warning(default:4200) // table of default joystick configs extern WCHAR *pwszTypeArray[MAX_DEVICES]; // List of enumerated gameport devices extern WCHAR *pwszGameportBus[MAX_BUSSES]; // List of enumerated gameport buses extern PJOY pAssigned[MAX_ASSIGNED]; // List of assigned devices extern BYTE nAssigned; // Number of elements in pAssigned array extern BYTE nTargetAssigned; // Number of elements expected when pending adds complete extern BYTE nReEnum; // Counter used to decide when to reenumerate extern GUID guidOccupied[MAX_BUSSES]; //Whether the gameport bus has been occupied. extern BYTE nGameportBus, nGamingDevices; extern IDirectInputJoyConfig *pDIJoyConfig; extern short iItem; extern short nFlags; // Flags set in CPANEL.CPP! // extern functions defined in CPANEL.CPP extern void OnContextMenu(WPARAM wParam, LPARAM lParam); extern void OnHelp (LPARAM); // local message handlers static BOOL OnInitDialog(HWND, HWND, LPARAM); static void OnClose(HWND); static void OnCommand(HWND, int, HWND, UINT); static char AddSelectedItem( HWND hDlg ); static BOOL UpdateListCtrl ( HWND hCtrl ); static char GetNextAvailableID( void ); static BOOL IsTypeActive( short *nArrayIndex ); static BOOL GetNextAvailableVIDPID(LPWSTR lpwszType ); //static BOOL IsCustomType(BYTE nIndex); static void PostHScrollBar(HWND hCtrl, LPCTSTR lpStr, BYTE nStrLen); extern const DWORD g_aHelpIDs[]; extern HINSTANCE ghInstance; LPTSTR lpszAutoDetect; const int NO_ITEM = -1; #define MAX_ANALOG_BUTTONS 4 #define MAX_ANALOG_AXIS 4 // This will become a problem when we support > 500 ports! #define AUTODETECT_PORT 100 // Consider achieving this from calculation of width of listview static short iAddItem = NO_ITEM; BOOL WINAPI AddDialogProc(HWND hDlg, ULONG uMsg, WPARAM wParam, LPARAM lParam) { switch( uMsg ) { case WM_DESTROY: DestroyIcon((HICON)SendMessage(hDlg, WM_GETICON, (WPARAM)ICON_SMALL, 0)); if( nGameportBus > 1 ) if( lpszAutoDetect ) delete[] (lpszAutoDetect); break; case WM_LBUTTONDOWN: // Click Drag service for PropSheets! PostMessage(hDlg, WM_NCLBUTTONDOWN, (WPARAM)HTCAPTION, lParam); break; case WM_INITDIALOG: return(BOOL)HANDLE_WM_INITDIALOG(hDlg, wParam, lParam, OnInitDialog); case WM_COMMAND: HANDLE_WM_COMMAND(hDlg, wParam, lParam, OnCommand); return(1); case WM_VKEYTOITEM: if( LOWORD(wParam) == VK_DELETE ) { HWND hWnd = GetDlgItem(hDlg, IDC_DEVICE_LIST); // determine if it's a custom type... if so... delete it // Get the next object with the SELECTED attribute iAddItem = (short)::SendMessage(hWnd, LB_GETCURSEL, 0, 0); short nArrayIndex = (short)::SendMessage(hWnd, LB_GETITEMDATA, (WPARAM)iAddItem, 0); // test to make sure they aren't trying to delete a standard type if( *pwszTypeArray[nArrayIndex] == L'#' ) break; // test that the device is a custom type (user or IHV defined) // ISSUE-2001/03/29-timgill the number of times we retrieve the same data is ridiculous LPDIJOYTYPEINFO lpdiJoyInfo = new (DIJOYTYPEINFO); ASSERT (lpdiJoyInfo); if( lpdiJoyInfo ) { /* * warning, abuse of S_OK == 0 == strcmp( identical strings ) ahead */ HRESULT CmpRes; ZeroMemory(lpdiJoyInfo, sizeof(*lpdiJoyInfo)); lpdiJoyInfo->dwSize = sizeof(*lpdiJoyInfo); /* * Test the hardware ID */ CmpRes = pDIJoyConfig->GetTypeInfo(pwszTypeArray[nArrayIndex], (LPDIJOYTYPEINFO)lpdiJoyInfo, DITC_HARDWAREID); if( SUCCEEDED( CmpRes ) ) { #ifndef WINNT if( lpdiJoyInfo->wszHardwareId[0] == L'\0' ) { /* * No hardware ID, so look for a callout VxD * If there is none, we have a custom type. */ CmpRes = pDIJoyConfig->GetTypeInfo(pwszTypeArray[nArrayIndex], (LPDIJOYTYPEINFO)lpdiJoyInfo, DITC_CALLOUT); CmpRes = ( SUCCEEDED( CmpRes ) && ( lpdiJoyInfo->wszCallout[0] == L'\0' ) ) ? S_OK : S_FALSE; } else #endif { const WCHAR wszAnalogRoot[] = L"gameport\\vid_045e&pid_01"; CmpRes = (HRESULT)_wcsnicmp( lpdiJoyInfo->wszHardwareId, wszAnalogRoot, (sizeof(wszAnalogRoot)/sizeof(wszAnalogRoot[0]) ) - 1 ); } } else { CmpRes = S_FALSE; } // clean-up! delete (lpdiJoyInfo); if( CmpRes != S_OK ) { // This is not an analog type so leave alone break; } } else { // If we can't test the type, do nothing break; } // test to make sure you are not deleting objects if( IsTypeActive(&nArrayIndex) ) { Error((short)IDS_GEN_AREYOUSURE_TITLE, (short)IDS_NO_REMOVE); break; } // This buffer has to be big enough for the name and the "are you sure..." message! LPTSTR pszMsg = new TCHAR[MAX_STR_LEN+STR_LEN_64]; ASSERT (pszMsg); LPTSTR pszTitle = new TCHAR[STR_LEN_128]; ASSERT (pszTitle); // Query user if they are sure! VERIFY(LoadString(ghInstance, IDS_GEN_AREYOUSURE, pszTitle, MAX_STR_LEN)); LPTSTR pszTmp = new TCHAR[(short)SendMessage(hWnd, LB_GETTEXTLEN, (WPARAM)iAddItem, 0)+1]; ASSERT (pszTmp); SendMessage(hWnd, LB_GETTEXT, (WPARAM)iAddItem, (LPARAM)(LPCTSTR)pszTmp); wsprintf( pszMsg, pszTitle, pszTmp); if( pszTmp ) delete[] (pszTmp); VERIFY(LoadString(ghInstance, IDS_GEN_AREYOUSURE_TITLE, pszTitle, STR_LEN_128)); HRESULT hr = MessageBox(hWnd, pszMsg, pszTitle, MB_ICONQUESTION | MB_YESNO | MB_APPLMODAL); if( pszMsg ) delete[] (pszMsg); if( pszTitle ) delete[] (pszTitle); if( IDYES == hr ) { if( SUCCEEDED(hr = pDIJoyConfig->Acquire()) ) { // traverse the list and delete any configuration that may have this type assigned to it! //DeleteAssignedType( pwszTypeArray[nArrayIndex] ); // returns E_ACCESSDENIED if it's a default item. hr = pDIJoyConfig->DeleteType(pwszTypeArray[nArrayIndex]); ASSERT(SUCCEEDED(hr)); pDIJoyConfig->Unacquire(); // the dec is for the zero based device list! // decrement the indexes nGamingDevices--; // don't move if you're on the last entry! if( nArrayIndex != nGamingDevices ) { // To avoid deleting and recreating... // Let's see if we have room to put this string! BYTE nLen = (BYTE)wcslen(pwszTypeArray[nArrayIndex])+1; // Make sure pwszTypeArray[nArrayIndex] is larger than pwszTypeArray[nCount] if( nLen < (BYTE)wcslen(pwszTypeArray[nGamingDevices])+1 ) { if( pwszTypeArray[nArrayIndex] ) free(pwszTypeArray[nArrayIndex]); pwszTypeArray[nArrayIndex] = _wcsdup(pwszTypeArray[nGamingDevices]); ASSERT (pwszTypeArray[nArrayIndex]); } // move the end element to the place of the deleted one else wcsncpy(pwszTypeArray[nArrayIndex], pwszTypeArray[nGamingDevices], wcslen(pwszTypeArray[nGamingDevices])+1); // update the extra memory to reflect the new index! // First, find the item in the listbox and get the index... LPDIJOYTYPEINFO_DX5 lpdiJoyInfo = new (DIJOYTYPEINFO_DX5); ASSERT (lpdiJoyInfo); ZeroMemory(lpdiJoyInfo, sizeof(DIJOYTYPEINFO_DX5)); lpdiJoyInfo->dwSize = sizeof(DIJOYTYPEINFO_DX5); if( SUCCEEDED(pDIJoyConfig->GetTypeInfo(pwszTypeArray[nArrayIndex], (LPDIJOYTYPEINFO)lpdiJoyInfo, DITC_DISPLAYNAME)) ) { char n = (char)SendMessage(hWnd, LB_FINDSTRINGEXACT, (WPARAM)-1, (LPARAM)lpdiJoyInfo->wszDisplayName); SendMessage(hWnd, LB_SETITEMDATA, (WPARAM)n, (LPARAM)nArrayIndex); } // clean-up! if( lpdiJoyInfo ) delete (lpdiJoyInfo); } // delete the end element from the array if( pwszTypeArray[nGamingDevices] ) { free(pwszTypeArray[nGamingDevices]); pwszTypeArray[nGamingDevices] = 0; } // Remove the entry from the list control SendMessage(hWnd, LB_DELETESTRING, (WPARAM)iAddItem, 0); // Enable the buttons! if( nGamingDevices < MAX_DEVICES-1 ) { HWND hParent = GetParent(hWnd); ASSERT (hParent); PostDlgItemEnableWindow(hParent, IDC_CUSTOM, TRUE); PostDlgItemEnableWindow(hParent, IDC_ADD_NEW, TRUE); } if( iAddItem != nGamingDevices-1 ) iAddItem--; // Set the focus to the next available item PostMessage(hWnd, LB_SETCURSEL, (WPARAM)(iAddItem == NO_ITEM) ? 0 : iAddItem, 0); } } break; } else return(-1); // case WM_NOTIFY: /// return HANDLE_WM_NOTIFY(hDlg, wParam, lParam, OnNotify); case WM_HELP: OnHelp(lParam); return(1); case WM_CONTEXTMENU: OnContextMenu(wParam, lParam); return(1); } return(0); } BOOL OnInitDialog(HWND hDlg, HWND hWnd, LPARAM lParam) { 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); if( nFlags & ON_NT ) DestroyWindow(GetDlgItem(hDlg, IDC_WDM)); else { HKEY hKey; // remove the WDM flag unless otherwise specified! if( RegOpenKey(HKEY_LOCAL_MACHINE, TEXT("SYSTEM\\CurrentControlSet\\Control\\MediaResources\\joystick\\"), &hKey) == ERROR_SUCCESS ) { DWORD n; DWORD dwSize = sizeof (DWORD); if( RegQueryValueEx(hKey, TEXT("UseWDM"), 0, 0, (LPBYTE)&n, &dwSize) == ERROR_SUCCESS ) { if( n ) DestroyWindow(GetDlgItem(hDlg, IDC_WDM)); } } RegCloseKey(hKey); } // a simple debug test to verify that the template hasn't gotten DIALOGEX style again! HWND hCtrl = GetDlgItem(hDlg, IDC_DEVICE_LIST); ASSERT (hCtrl); // Fill up the Device List if( !UpdateListCtrl(hCtrl) ) { TRACE(TEXT("JOY.CPL: ADD.CPP: Failed UpdateListCtrl!\n")); return(FALSE); } // If there is only one, don't confuse the user with the combo box if( nGameportBus > 1 ) { // Allocate for AutoDetect Gameport! lpszAutoDetect = new (TCHAR[STR_LEN_32]); ASSERT (lpszAutoDetect); VERIFY(LoadString(ghInstance, IDS_AUTO_DETECT, lpszAutoDetect, STR_LEN_32)); hCtrl = GetDlgItem(hDlg, IDC_GAMEPORTLIST); ASSERT (hCtrl); if( !PopulatePortList(hCtrl) ) { TRACE(TEXT("JOY.CPL: ADD.CPP: Failed PopulatePortList!\n")); return(FALSE); } LPDIJOYTYPEINFO lpdiJoyInfo = new DIJOYTYPEINFO; ASSERT (lpdiJoyInfo); ZeroMemory(lpdiJoyInfo, sizeof(DIJOYTYPEINFO)); lpdiJoyInfo->dwSize = sizeof(DIJOYTYPEINFO); VERIFY(SUCCEEDED(pDIJoyConfig->GetTypeInfo(pwszTypeArray[0], (LPDIJOYTYPEINFO)lpdiJoyInfo, DITC_FLAGS1))); // Search for AutoDetect in the list! char nIndex = (char)::SendMessage(hCtrl, CB_FINDSTRINGEXACT, (WPARAM)-1, (LPARAM)(LPCTSTR)lpszAutoDetect); // If it's got the JOYTYPE_NOAUTODETECTGAMEPORT flag, remove AutoDetect from the ListCtrl if( lpdiJoyInfo->dwFlags1 & JOYTYPE_NOAUTODETECTGAMEPORT ) { // it could fail because the entry is not available... if( nIndex != CB_ERR ) ::SendMessage(hCtrl, CB_DELETESTRING, (WPARAM)nIndex, 0); } // Otherwise, verify that AutoDetect is present... if not, add it! else { // it could fail because the entry is not available... if( nIndex == CB_ERR ) ::SendMessage(hCtrl, CB_SETITEMDATA, ::SendMessage(hCtrl, CB_ADDSTRING, 0, (LPARAM)(LPCTSTR)lpszAutoDetect), AUTODETECT_PORT); } if( lpdiJoyInfo ) delete (lpdiJoyInfo); SetWindowPos( hCtrl, NULL, NULL, NULL, NULL, NULL, SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_SHOWWINDOW); SetWindowPos( GetDlgItem(hDlg, IDC_GAMEPORT), NULL, NULL, NULL, NULL, NULL, SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_SHOWWINDOW); } // blj: Warning Message that you can't add any more devices! if( nGamingDevices == MAX_DEVICES-1 ) { // Disable the Custom Button! PostDlgItemEnableWindow(hDlg, IDC_CUSTOM, FALSE); PostDlgItemEnableWindow(hDlg, IDC_ADD_NEW, FALSE); // Give the user a error message! Error((short)IDS_MAX_DEVICES_TITLE, (short)IDS_MAX_DEVICES_MSG); } return(0); } /////////////////////////////////////////////////////////////////////////////// // 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) { switch( id ) { case IDC_ADD_NEW: if( SUCCEEDED(pDIJoyConfig->AddNewHardware(hDlg, GUID_MediaClass)) ) { ClearArrays(); if( FAILED(pDIJoyConfig->EnumTypes((LPDIJOYTYPECALLBACK)DIEnumJoyTypeProc, NULL)) ) { TRACE(TEXT("JOY.CPL: ADD.CPP: Failed BuildEnumList!\n")); return; } // Warning Message that you can't add any more devices! if( nGamingDevices == MAX_DEVICES-1 ) { // Disable the Custom Button! PostDlgItemEnableWindow(hDlg, IDC_CUSTOM, FALSE); PostDlgItemEnableWindow(hDlg, IDC_ADD_NEW, FALSE); // Give the user a error message! Error((short)IDS_MAX_DEVICES_TITLE, (short)IDS_MAX_DEVICES_MSG); } if( !UpdateListCtrl(GetDlgItem(hDlg, IDC_DEVICE_LIST)) ) { TRACE(TEXT("JOY.CPL: ADD.CPP: Failed to update the list control on the add page!\n")); return; } } break; case IDC_CUSTOM: // DialogBox returns either IDCANCEL or the index into the list of // defined types! if( IDOK == DialogBox(ghInstance, (PTSTR)IDD_CUSTOM, hDlg, (DLGPROC)CustomDialogProc) ) { HWND hCtrl = GetDlgItem(hDlg, IDC_DEVICE_LIST); // blj: Warning Message that you can't add any more devices! if( nGamingDevices == MAX_DEVICES-1 ) { // Disable the Custom Button! PostDlgItemEnableWindow(hDlg, IDC_CUSTOM, FALSE); // Give the user a error message! Error((short)IDS_MAX_DEVICES_TITLE, (short)IDS_MAX_DEVICES_MSG); } // Now, put the focus on the newly created item! LPDIJOYTYPEINFO_DX5 lpdiJoyInfo = new (DIJOYTYPEINFO_DX5); ASSERT (lpdiJoyInfo); ZeroMemory(lpdiJoyInfo, sizeof(DIJOYTYPEINFO_DX5)); lpdiJoyInfo->dwSize = sizeof(DIJOYTYPEINFO_DX5); // Get nGamingDevices from pwszTypeArray // Subtract 1 from nGamingDevices because the list is 0 based! if( SUCCEEDED(pDIJoyConfig->GetTypeInfo(pwszTypeArray[nGamingDevices-1], (LPDIJOYTYPEINFO)lpdiJoyInfo, DITC_DISPLAYNAME | DITC_REGHWSETTINGS)) ) { #ifdef _UNICODE iAddItem = (short)SendMessage(hCtrl, LB_ADDSTRING, 0, (LPARAM)(LPCTSTR)lpdiJoyInfo->wszDisplayName); SendMessage(hCtrl, LB_SETITEMDATA, (WPARAM)iAddItem, (LPARAM)nGamingDevices-1); PostHScrollBar(hCtrl, lpdiJoyInfo->wszDisplayName, (BYTE)wcslen(lpdiJoyInfo->wszDisplayName)); #else USES_CONVERSION; iAddItem = (short)SendMessage(hCtrl, LB_ADDSTRING, 0, (LPARAM)(LPCTSTR)W2A(lpdiJoyInfo->wszDisplayName)); SendMessage(hCtrl, LB_SETITEMDATA, (WPARAM)iAddItem, (LPARAM)nGamingDevices-1); PostHScrollBar(hCtrl, W2A(lpdiJoyInfo->wszDisplayName), (BYTE)wcslen(lpdiJoyInfo->wszDisplayName)); #endif // SetFocus to that item! SendMessage(hCtrl, LB_SETCURSEL, (WPARAM)iAddItem, 0); OnCommand(hDlg, IDC_DEVICE_LIST, 0, LBN_SELCHANGE); } // clean-up! if( lpdiJoyInfo ) delete (lpdiJoyInfo); } break; case IDC_DEVICE_LIST: if( code == LBN_SELCHANGE ) { iAddItem = (short)SendMessage(hWndCtl, LB_GETCURSEL, 0, 0); BYTE nArrayID = (BYTE)SendMessage(hWndCtl, LB_GETITEMDATA, (WPARAM)iAddItem, 0); LPDIJOYTYPEINFO lpdiJoyInfo = new DIJOYTYPEINFO; ASSERT (lpdiJoyInfo); ZeroMemory(lpdiJoyInfo, sizeof(DIJOYTYPEINFO)); lpdiJoyInfo->dwSize = sizeof(DIJOYTYPEINFO); DWORD dwFlags = DITC_REGHWSETTINGS; if( nGameportBus > 1 ) dwFlags |= DITC_FLAGS1; VERIFY(SUCCEEDED(pDIJoyConfig->GetTypeInfo(pwszTypeArray[nArrayID], (LPDIJOYTYPEINFO)lpdiJoyInfo, dwFlags))); /* if (nGameportBus > 1) { HWND hCtrl = GetDlgItem(hDlg, IDC_GAMEPORTLIST); // Search for AutoDetect in the list! char nIndex = (char)::SendMessage(hCtrl, CB_FINDSTRINGEXACT, (WPARAM)-1, (LPARAM)(LPCTSTR)lpszAutoDetect); // If it's got the JOYTYPE_NOAUTODETECTGAMEPORT flag, remove AutoDetect from the ListCtrl if (lpdiJoyInfo->dwFlags1 & JOYTYPE_NOAUTODETECTGAMEPORT) { // it could fail because the entry is not available... if (nIndex != CB_ERR) ::SendMessage(hCtrl, CB_DELETESTRING, (WPARAM)nIndex, 0); } // Otherwise, verify that AutoDetect is present... if not, add it! else { // it could fail because the entry is not available... if (nIndex == CB_ERR) ::SendMessage(hCtrl, CB_SETITEMDATA, ::SendMessage(hCtrl, CB_ADDSTRING, 0, (LPARAM)(LPCTSTR)lpszAutoDetect), AUTODETECT_PORT); } ::PostMessage(hCtrl, CB_SETCURSEL, (WPARAM)0, (LPARAM)0); } */ PostDlgItemEnableWindow(hDlg, IDC_JOY1HASRUDDER, (lpdiJoyInfo->hws.dwFlags & JOY_HWS_HASR) ? FALSE : TRUE); if( lpdiJoyInfo ) delete (lpdiJoyInfo); break; } if( code != LBN_DBLCLK ) break; case IDOK: iAddItem = (short)SendDlgItemMessage(hDlg, IDC_DEVICE_LIST, LB_GETCURSEL, 0, 0); if( iAddItem == NO_ITEM ) break; // Check to see if they have a GamePortList { HWND hCtrl = GetDlgItem(hDlg, IDC_GAMEPORTLIST); ASSERT (hCtrl); if( IsWindowVisible(hCtrl) ) { // Check to see if the user has a port selected! if( SendMessage(hCtrl, CB_GETCURSEL, 0, 0) == CB_ERR ) { // blj: TODO: Clear this message with UE Error((short)IDS_NO_GAMEPORT_TITLE, (short)IDS_NO_GAMEPORT); break; } } } iItem = 0; AddSelectedItem(hDlg); case IDCANCEL: EndDialog(hDlg, id); break; } } /// Custom Dialog procedure BOOL WINAPI CustomDialogProc(HWND hDlg, ULONG uMsg, WPARAM wParam, LPARAM lParam) { static LPWSTR lpwszVIDPID; switch( uMsg ) { case WM_DESTROY: { HICON hIcon = (HICON)SendMessage(hDlg, WM_GETICON, (WPARAM)ICON_SMALL, 0); DestroyIcon(hIcon); } break; 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: // Set up the Buttons and Axis combo boxs! { 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); // Return if no available VID/PIDs found! lpwszVIDPID = new (WCHAR[STR_LEN_32]); ASSERT (lpwszVIDPID); pDIJoyConfig->Acquire(); if( !GetNextAvailableVIDPID(lpwszVIDPID) ) { if( lpwszVIDPID ) delete[] (lpwszVIDPID); EndDialog(hDlg, IDCANCEL); // Let the user know that they need to remove some "Custom" devices! Error((short)IDS_NO_NAME_TITLE, (short)IDS_NOAVAILABLEVIDPID ); return(FALSE); } // init id list BYTE nButtons = MAX_ANALOG_BUTTONS; TCHAR szTmp[3]; HWND hCtrl = GetDlgItem(hDlg, IDC_COMBO_BUTTONS); // Fill the Buttons combo... do { itoa(nButtons, (LPTSTR)&szTmp); SendMessage(hCtrl, CB_ADDSTRING, (WPARAM)0, (LPARAM)(LPCTSTR)szTmp); } while( nButtons-- ); // Set Default to four buttons SendMessage(hCtrl, CB_SETCURSEL, MAX_ANALOG_BUTTONS, 0); // Use nButtons for Axis... nButtons = MAX_ANALOG_AXIS; hCtrl = GetDlgItem(hDlg, IDC_COMBO_AXIS); // Fill the Axis combo... do { itoa(nButtons--, (LPTSTR)&szTmp); SendMessage(hCtrl, CB_ADDSTRING, (WPARAM)0, (LPARAM)(LPCTSTR)szTmp); } while( nButtons > 1 ); // Set Default to two Axis SendMessage(hCtrl, CB_SETCURSEL, 0, 0); } ::PostMessage(GetDlgItem(hDlg, IDC_SPECIAL_JOYSTICK), BM_SETCHECK, BST_CHECKED, 0); SendDlgItemMessage(hDlg, IDC_EDIT_NAME, EM_LIMITTEXT, (WPARAM)MAX_STR_LEN, 0); return(1); case WM_COMMAND: switch( LOWORD(wParam) ) { case IDOK: { // defines for error states! #define DUPLICATE_NAME 0x01 #define NO_NAME 0x02 #define INVALID_NAME 0x04 BYTE nLen = (BYTE)SendDlgItemMessage(hDlg, IDC_EDIT_NAME, EM_LINELENGTH, 0, 0); LPTSTR pszTypeName = NULL; if( nLen ) { pszTypeName = new (TCHAR[nLen+1]); ASSERT (pszTypeName); // Get the Type/Display Name GetDlgItemText(hDlg, IDC_EDIT_NAME, (LPTSTR)pszTypeName, nLen+1); if( _tcschr(pszTypeName, TEXT('\\')) ) nLen = INVALID_NAME; else { // Make sure it's not a duplicate! // start of fix #9269 LPDIJOYTYPEINFO_DX5 lpdiGetJoyInfo = new DIJOYTYPEINFO_DX5; ASSERT (lpdiGetJoyInfo); ZeroMemory(lpdiGetJoyInfo, sizeof(DIJOYTYPEINFO_DX5)); lpdiGetJoyInfo->dwSize = sizeof(DIJOYTYPEINFO_DX5); // Clean-up nLen! BYTE n = nLen = 0; // Search for a Duplicate Display Name!!! while( pwszTypeArray[n] ) { if( FAILED(pDIJoyConfig->GetTypeInfo(pwszTypeArray[n++], (LPDIJOYTYPEINFO)lpdiGetJoyInfo, DITC_DISPLAYNAME)) ) { TRACE(TEXT("JOY.CPL: ADD.CPP: GetTypeInfo Failed!\n")); continue; } #ifndef _UNICODE USES_CONVERSION; #endif if( _tcsncmp(pszTypeName, #ifdef _UNICODE lpdiGetJoyInfo->wszDisplayName, #else W2A(lpdiGetJoyInfo->wszDisplayName), #endif wcslen(lpdiGetJoyInfo->wszDisplayName)+1) == 0 ) { nLen = DUPLICATE_NAME; break; } } if( lpdiGetJoyInfo ) { delete (lpdiGetJoyInfo); } // end of fix #9269 } } else nLen = NO_NAME; // Check for an error! if( nLen ) { if( pszTypeName ) delete[] (pszTypeName); // Give the user the appropriate error! switch( nLen ) { case DUPLICATE_NAME: Error((SHORT)IDS_NO_NAME_TITLE, (SHORT)IDS_DUPLICATE_TYPE); break; case NO_NAME: Error((short)IDS_NO_NAME_TITLE, (short)IDS_NO_NAME); break; case INVALID_NAME: Error((short)IDS_NO_NAME_TITLE, (short)IDS_INVALID_NAME); break; } // Set Focus to the Dialog SetFocus(hDlg); HWND hCtrl = GetDlgItem(hDlg, IDC_EDIT_NAME); ASSERT (hCtrl); // Set Focus to the Control SetFocus(hCtrl); // hilite the error PostMessage(hCtrl, EM_SETSEL, (WPARAM)0, (LPARAM)-1); return(FALSE); } // set the type information LPDIJOYTYPEINFO lpdiJoyInfo = new (DIJOYTYPEINFO); ASSERT (lpdiJoyInfo); ZeroMemory(lpdiJoyInfo, sizeof(DIJOYTYPEINFO)); lpdiJoyInfo->dwSize = sizeof(DIJOYTYPEINFO); #ifndef _UNICODE USES_CONVERSION; #endif // Set the Display Name wcsncpy(lpdiJoyInfo->wszDisplayName, #ifdef _UNICODE pszTypeName, #else A2W(pszTypeName), #endif // _UNICODE lstrlen(pszTypeName)+1); if( pszTypeName ) delete[] (pszTypeName); // Set the GUID - default to LegacyServer // Per Marcus, we don't want to do this anymore! //lpdiJoyInfo->clsidConfig = CLSID_LegacyServer; // Set the Hardware Settings lpdiJoyInfo->hws.dwNumButtons = (DWORD)SendDlgItemMessage(hDlg, IDC_COMBO_BUTTONS, CB_GETCURSEL, 0, 0); switch( SendDlgItemMessage(hDlg, IDC_COMBO_AXIS, CB_GETCURSEL, 0, 0) ) { // R Axis case 1: // Check to see which button got checked... lpdiJoyInfo->hws.dwFlags |= ::SendMessage(GetDlgItem(hDlg, IDC_HASRUDDER), BM_GETCHECK, 0, 0) ? JOY_HWS_HASR : JOY_HWS_HASZ; break; // Z Axis case 2: lpdiJoyInfo->hws.dwFlags |= JOY_HWS_HASR; lpdiJoyInfo->hws.dwFlags |= JOY_HWS_HASZ; break; // X/Y are default! default: lpdiJoyInfo->hws.dwFlags = 0; break; } lpdiJoyInfo->hws.dwFlags |= ::SendMessage(GetDlgItem(hDlg, IDS_CUSTOM_HASPOV), BM_GETCHECK, 0, 0) ? JOY_HWS_HASPOV : 0; // Get Special char's status lpdiJoyInfo->hws.dwFlags |= ::SendMessage(GetDlgItem(hDlg, IDC_SPECIAL_JOYSTICK), BM_GETCHECK, 0, 0) ? 0 : ::SendMessage(GetDlgItem(hDlg, IDC_SPECIAL_PAD), BM_GETCHECK, 0, 0) ? JOY_HWS_ISGAMEPAD : ::SendMessage(GetDlgItem(hDlg, IDC_SPECIAL_AUTO), BM_GETCHECK, 0, 0) ? JOY_HWS_ISCARCTRL : JOY_HWS_ISYOKE; // default to Yoke! // Set up wszHardwareId wcscpy(lpdiJoyInfo->wszHardwareId, L"GamePort\\"); // This blocks the Huge DisplayName bug! // DINPUT change requires VID/PID at the end of the hardware ID... it was //StrNCatW(lpdiJoyInfo->wszHardwareId, lpwszVIDPID, 245); // Win95 does not like StrNCatW, we will use wcsncat wcsncat(lpdiJoyInfo->wszHardwareId, lpwszVIDPID, 245); if( SUCCEEDED(pDIJoyConfig->Acquire()) ) { #ifdef _UNICODE if( FAILED(pDIJoyConfig->SetTypeInfo(lpwszVIDPID, lpdiJoyInfo, DITC_DISPLAYNAME | DITC_CLSIDCONFIG | DITC_REGHWSETTINGS | DITC_HARDWAREID)) ) #else if( FAILED(pDIJoyConfig->SetTypeInfo(lpwszVIDPID, lpdiJoyInfo, DITC_DISPLAYNAME | DITC_CLSIDCONFIG | DITC_REGHWSETTINGS ) ) ) #endif { #ifdef _DEBUG OutputDebugString(TEXT("JOY.CPL: ADD.CPP: CustomDlgProc: SetTypeInfo Failed!\n")); #endif } // Create the memory for the Custom device and stick it into the array! pwszTypeArray[nGamingDevices++] = _wcsdup(lpwszVIDPID); pDIJoyConfig->Unacquire(); } if( lpdiJoyInfo ) delete (lpdiJoyInfo); } case IDCANCEL: if( lpwszVIDPID ) delete[] (lpwszVIDPID); EndDialog(hDlg, LOWORD(wParam)); break; case IDC_SPECIAL_JOYSTICK: case IDC_SPECIAL_YOKE: case IDC_SPECIAL_PAD: case IDC_SPECIAL_AUTO: CheckRadioButton(hDlg, IDC_SPECIAL_JOYSTICK, IDC_SPECIAL_AUTO, IDC_SPECIAL_JOYSTICK); break; case IDC_COMBO_AXIS: // Show/Hide IDC_HASRUDDER based on Selection of 3 Axis if( HIWORD(wParam) == CBN_SELCHANGE ) { const USHORT nCtrlArray[] = {IDC_HASRUDDER, IDC_HASZAXIS}; BYTE nCtrls = sizeof(nCtrlArray)/sizeof(short); // the '1' in the comparison is because the CB is Zero based! BOOL bShow = (BOOL)(SendDlgItemMessage(hDlg, IDC_COMBO_AXIS, CB_GETCURSEL, 0, 0) == 1); do { SetWindowPos( GetDlgItem(hDlg, nCtrlArray[--nCtrls]), NULL, NULL, NULL, NULL, NULL, SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | ((bShow) ? SWP_SHOWWINDOW : SWP_HIDEWINDOW)); } while( nCtrls ); if( bShow ) ::PostMessage(GetDlgItem(hDlg, IDC_HASZAXIS), BM_SETCHECK, BST_CHECKED, 0); } break; } return(1); case WM_CLOSE: EndDialog(hDlg, 0); return(1); } return(0); } char GetNextAvailableID( void ) { LPDIJOYCONFIG_DX5 pJoyConfig = new (DIJOYCONFIG_DX5); ASSERT (pJoyConfig); ZeroMemory(pJoyConfig, sizeof(DIJOYCONFIG_DX5)); pJoyConfig->dwSize = sizeof (DIJOYCONFIG_DX5); char i = 0; do { switch( pDIJoyConfig->GetConfig(i, (LPDIJOYCONFIG)pJoyConfig, DIJC_REGHWCONFIGTYPE) ) { case S_FALSE: case DIERR_NOMOREITEMS: case DIERR_NOTFOUND: case E_FAIL: goto EXIT; default: i++; break; } } while( i < NUMJOYDEVS ); i = -1; // And it's Error time! Error((short)IDS_NO_IDS_TITLE, (short)IDS_NO_IDS); EXIT: if( pJoyConfig ) delete (pJoyConfig); return(i); } /////////////////////////////////////////////////////////////////////////////// // FUNCTION: AddSelectedItem(HWND hDlg) // // PARAMETERS: hDlg - Handle to page // // PURPOSE: Adds selected item from List box. /////////////////////////////////////////////////////////////////////////////// char AddSelectedItem( HWND hDlg ) { static BYTE n; DWORD dwFlags; HRESULT hr; int nID; #ifdef SUPPORT_TWO_2A2B BOOL f2_2A2B = FALSE; #endif nID = GetNextAvailableID(); // GetNextAvailableID returns -1 if it fails! if( nID < 0 ) return((char)nID); // Type info LPDIJOYTYPEINFO_DX5 lpdiJoyInfo = new (DIJOYTYPEINFO_DX5); ASSERT (lpdiJoyInfo); ZeroMemory(lpdiJoyInfo, sizeof(DIJOYTYPEINFO_DX5)); lpdiJoyInfo->dwSize = sizeof(DIJOYTYPEINFO_DX5); BYTE nArrayID = (BYTE)SendDlgItemMessage(hDlg, IDC_DEVICE_LIST, LB_GETITEMDATA, (WPARAM)iAddItem, 0); VERIFY(SUCCEEDED(pDIJoyConfig->GetTypeInfo(pwszTypeArray[nArrayID], (LPDIJOYTYPEINFO)lpdiJoyInfo, DITC_REGHWSETTINGS | DITC_CALLOUT | DITC_DISPLAYNAME))); #ifdef SUPPORT_TWO_2A2B #ifndef _UNICODE if( wcscmp( pwszTypeArray[nArrayID], L"#<" ) == 0 ) { f2_2A2B = TRUE; lpdiJoyInfo->hws.dwFlags = 0; pwszTypeArray[nArrayID][1] = L'2'; } else { f2_2A2B = FALSE; } #endif #endif LPDIJOYCONFIG pTempJoyConfig = new DIJOYCONFIG; ASSERT (pTempJoyConfig); ZeroMemory(pTempJoyConfig, sizeof(DIJOYCONFIG)); pTempJoyConfig->dwSize = sizeof (DIJOYCONFIG); pTempJoyConfig->hwc.hws = lpdiJoyInfo->hws; pTempJoyConfig->hwc.hws.dwFlags |= JOY_HWS_ISANALOGPORTDRIVER; // Do the Rudder Flags! if( ::SendMessage(GetDlgItem(hDlg, IDC_JOY1HASRUDDER), BM_GETCHECK, 0, 0) ) { pTempJoyConfig->hwc.hws.dwFlags |= JOY_HWS_HASR; pTempJoyConfig->hwc.dwUsageSettings |= JOY_US_HASRUDDER; } // set default to present pTempJoyConfig->hwc.dwUsageSettings |= JOY_US_PRESENT; pTempJoyConfig->hwc.dwType = nArrayID; wcsncpy(pTempJoyConfig->wszCallout, lpdiJoyInfo->wszCallout, wcslen(lpdiJoyInfo->wszCallout)+1); wcsncpy(pTempJoyConfig->wszType, pwszTypeArray[nArrayID], wcslen(pwszTypeArray[nArrayID])+1); LPWSTR lpszPortName = NULL; if( SUCCEEDED(pDIJoyConfig->Acquire()) ) { // This stops Memphis and gameport-less systems!!! if( nGameportBus ) { // no point asking the Combo box if there's really no choice! if( nGameportBus > 1 ) { n = (BYTE)SendDlgItemMessage(hDlg, IDC_GAMEPORTLIST, CB_GETITEMDATA, (WPARAM)SendDlgItemMessage(hDlg, IDC_GAMEPORTLIST, CB_GETCURSEL, 0, 0), 0); } else { n = 0; } if( n == AUTODETECT_PORT ) { #ifdef _DEBUG OutputDebugString(TEXT("JOY.CPL: ADD.CPP: Selected Port is AutoDetect!\n")); #endif pTempJoyConfig->guidGameport = GUID_GAMEENUM_BUS_ENUMERATOR; } else { // Zero the memory because the buffer still contains the old data!!! ZeroMemory(lpdiJoyInfo, sizeof(DIJOYTYPEINFO_DX5)); lpdiJoyInfo->dwSize = sizeof(DIJOYTYPEINFO_DX5); #ifdef _DEBUG TRACE(TEXT("JOY.CPL: ADD.CPP: Port List index is %d or %s!\n"), n, pwszGameportBus[n]); #endif if( SUCCEEDED(pDIJoyConfig->GetTypeInfo(pwszGameportBus[n], (LPDIJOYTYPEINFO)lpdiJoyInfo, DITC_CLSIDCONFIG | DITC_DISPLAYNAME)) ) { pTempJoyConfig->guidGameport = lpdiJoyInfo->clsidConfig; lpszPortName = _wcsdup(lpdiJoyInfo->wszDisplayName); } } } // This is for Memphis and odd case NT systems! if( pTempJoyConfig->guidGameport == GUID_NULL ) { pTempJoyConfig->guidGameport = GUID_GAMEENUM_BUS_ENUMERATOR; #ifdef _DEBUG OutputDebugString(TEXT("JOY.CPL: ADD.CPP: Selected Port did not return a clsidConfig so AutoDetect is being used!\n")); #endif } // Set the hour glass SetCursor(LoadCursor(NULL, IDC_WAIT)); // ISSUE-2001/03/29-timgill (MarcAnd) Why would we want to block updates when we're adding a device? #if 1 // Unblock the WM_DEVICECHANGE message handler! nFlags &= ~BLOCK_UPDATE; nFlags |= ON_PAGE; /* * Set the nReEnum counter going so that for the next n WM_TIMER * messages (or until the device arrives) we can consider * doing a refresh. * The value is somewhat arbitrary. */ nReEnum = 43; /* * Set a target for the number of devices so that the extra * reenumerations can be avoided if this target is reached. */ nTargetAssigned = nAssigned+1; #else nFlags |= BLOCK_UPDATE; #endif dwFlags = DIJC_REGHWCONFIGTYPE | DIJC_CALLOUT; dwFlags |= ::SendDlgItemMessage(hDlg, IDC_WDM, BM_GETCHECK, 0, 0) ? DIJC_WDMGAMEPORT : 0; if( FAILED(hr = pDIJoyConfig->SetConfig(nID, pTempJoyConfig, dwFlags)) ) { // Let the user know what happend! if( hr == E_ACCESSDENIED ) { // Let the use know that the port is already occupied and that they need to remove that device or // re-assign the device to an unoccupied port. LPDIJOYCONFIG lpJoyCfg = new (DIJOYCONFIG); ASSERT (lpJoyCfg); ZeroMemory(lpJoyCfg, sizeof(DIJOYCONFIG)); lpJoyCfg->dwSize = sizeof(DIJOYCONFIG); // Cycle threw pAssigned and find the device with the same port name! BYTE nIndex = nAssigned; do { if( SUCCEEDED(pDIJoyConfig->GetConfig(pAssigned[--nIndex]->ID, lpJoyCfg, DIJC_WDMGAMEPORT)) ) { if( lpJoyCfg->guidGameport == pTempJoyConfig->guidGameport ) break; } } while( nIndex ); if( lpJoyCfg ) delete (lpJoyCfg); 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; // Ok now.. you found it... use the Device pointer to get it's Friendly name! if( SUCCEEDED(pAssigned[nIndex]->fnDeviceInterface->GetProperty(DIPROP_INSTANCENAME, &pDIPropStr->diph)) ) { // Put ellipse in text to avoid buffer over-flow. // Limit displayed name to 50 chars... not completely arbitrary, // we need to leave room in the Message string... // who knows how long the string will get when translated! if( wcslen(pDIPropStr->wsz) > 50 ) { pDIPropStr->wsz[47] = pDIPropStr->wsz[48] = pDIPropStr->wsz[49] = L'.'; pDIPropStr->wsz[50] = L'\0'; } LPTSTR lptszMsgFormat = new (TCHAR[MAX_STR_LEN]); ASSERT (lptszMsgFormat); VERIFY(LoadString(ghInstance, IDS_ADD_PORT_MSGFORMAT, lptszMsgFormat, MAX_STR_LEN)); LPTSTR lptszMsg = new (TCHAR[MAX_STR_LEN]); ASSERT (lptszMsg); // Format the message wsprintf(lptszMsg, lptszMsgFormat, pDIPropStr->wsz, lpszPortName, pAssigned[nIndex]->ID+1); VERIFY(LoadString(ghInstance, IDS_ADD_PORT_OCCUPIED, lptszMsgFormat, MAX_STR_LEN)); MessageBox(hDlg, lptszMsg, lptszMsgFormat, MB_ICONHAND | MB_OK | MB_APPLMODAL); if( lptszMsgFormat ) delete[] (lptszMsgFormat); if( lptszMsg ) delete[] (lptszMsg); } if( pDIPropStr ) delete (pDIPropStr); } else if( hr == DIERR_DEVICEFULL ) { Error((short)IDS_GAMEPORT_OCCUPIED_TITLE, (short)IDS_GAMEPORT_OCCUPIED); } else { // Something Ugly happened! Error((short)IDS_NO_GAMENUM_TITLE, (short)IDS_NO_GAMENUM); } } else { #ifdef _UNICODE // Fix #55524 if( SUCCEEDED(pDIJoyConfig->GetConfig(nID, pTempJoyConfig, DIJC_REGHWCONFIGTYPE)) ) { if( !(pTempJoyConfig->hwc.dwUsageSettings & JOY_US_PRESENT) ) { pTempJoyConfig->hwc.dwUsageSettings |= JOY_US_PRESENT; pTempJoyConfig->hwc.hwv.dwCalFlags |= 0x80000000; pTempJoyConfig->hwc.hws.dwFlags |= JOY_HWS_ISANALOGPORTDRIVER; VERIFY(SUCCEEDED(pDIJoyConfig->SetConfig(nID, pTempJoyConfig, DIJC_REGHWCONFIGTYPE))); } } // end of Fix #55524 #endif // make sure VJOYD is notified if( !(nFlags & ON_NT) ) { pDIJoyConfig->SendNotify(); Sleep(10); pDIJoyConfig->SendNotify(); } #ifndef _UNICODE #ifdef SUPPORT_TWO_2A2B /* * Add the other part of Two_2Axis_2Button joystick. */ if( f2_2A2B ) { nID = GetNextAvailableID(); if( nID >= 0 ){ hr = pDIJoyConfig->SetConfig(nID, pTempJoyConfig, dwFlags); if( SUCCEEDED(hr) ) { if( !(nFlags & ON_NT) ) pDIJoyConfig->SendNotify(); } } } #endif #endif } if( lpszPortName ) free(lpszPortName); // Set the standard pointer SetCursor(LoadCursor(NULL, IDC_ARROW)); pDIJoyConfig->Unacquire(); } if( lpdiJoyInfo ) delete (lpdiJoyInfo); if( pTempJoyConfig ) delete (pTempJoyConfig); return((char)nID); } BOOL UpdateListCtrl( HWND hCtrl ) { // Turn Redraw off here else it will flicker! ::SendMessage(hCtrl, WM_SETREDRAW, (WPARAM)FALSE, 0); // delete all existing entries ::SendMessage(hCtrl, LB_RESETCONTENT, 0, 0); // Type info LPDIJOYTYPEINFO_DX5 lpdiJoyInfo = new (DIJOYTYPEINFO_DX5); ASSERT (lpdiJoyInfo); ZeroMemory(lpdiJoyInfo, sizeof(DIJOYTYPEINFO_DX5)); lpdiJoyInfo->dwSize = sizeof(DIJOYTYPEINFO_DX5); #ifndef _UNICODE USES_CONVERSION; #endif BYTE nIndex = nGamingDevices-1; ::SendMessage(hCtrl, LB_SETCOUNT, (WPARAM)(int)nIndex, 0); LPWSTR lpStr = new WCHAR[MAX_STR_LEN]; ASSERT (lpStr); BYTE nLargestStringLen = 0; do { if( SUCCEEDED(pDIJoyConfig->GetTypeInfo(pwszTypeArray[nIndex], (LPDIJOYTYPEINFO)lpdiJoyInfo, DITC_DISPLAYNAME)) ) { #ifdef _UNICODE ::SendMessage(hCtrl, LB_SETITEMDATA, (WPARAM)::SendMessage(hCtrl, LB_ADDSTRING, 0, (LPARAM)(LPCTSTR)lpdiJoyInfo->wszDisplayName), (LPARAM)nIndex); #else ::SendMessage(hCtrl, LB_SETITEMDATA, (WPARAM)::SendMessage(hCtrl, LB_ADDSTRING, 0, (LPARAM)(LPCTSTR)W2A(lpdiJoyInfo->wszDisplayName)), (LPARAM)nIndex); #endif if( wcslen(lpdiJoyInfo->wszDisplayName) > nLargestStringLen ) { nLargestStringLen = (BYTE)wcslen(lpdiJoyInfo->wszDisplayName); wcscpy(lpStr, lpdiJoyInfo->wszDisplayName); } } } while( nIndex-- ); if( lpdiJoyInfo ) delete (lpdiJoyInfo); #ifdef _UNICODE PostHScrollBar(hCtrl, lpStr, nLargestStringLen); #else PostHScrollBar(hCtrl, W2A(lpStr), nLargestStringLen); #endif if( lpStr ) delete[] (lpStr); // Select the default selection to the 0th device type iAddItem = 0; ::PostMessage(hCtrl, LB_SETCURSEL, (WPARAM)iAddItem, 0); // Turn the redraw flag back on! ::SendMessage (hCtrl, WM_SETREDRAW, (WPARAM)TRUE, 0); InvalidateRect(hCtrl, NULL, TRUE); return(TRUE); } // Please check to see if nGameportBus is > 0 before a call to this function! // It will work, but What a waste! BOOL PopulatePortList( HWND hCtrl ) { if( !::IsWindow(hCtrl) ) { TRACE(TEXT("JOY.CPL: PopulatePortList: HWND passed to PopulatePortList is NOT a valid Window!\n")); return(FALSE); } SendMessage(hCtrl, CB_SETEXTENDEDUI, TRUE, 0); // temp so we don't damage the global! BYTE n = nGameportBus; LPDIJOYTYPEINFO lpDIJoyTypeInfo = new (DIJOYTYPEINFO); ASSERT(lpDIJoyTypeInfo); #ifndef _UNICODE USES_CONVERSION; #endif lpDIJoyTypeInfo->dwSize = sizeof(DIJOYTYPEINFO); // Populate the list as they were enumerated. do { if( FAILED(pDIJoyConfig->GetTypeInfo(pwszGameportBus[--n], lpDIJoyTypeInfo, DITC_DISPLAYNAME)) ) { TRACE(TEXT("JOY.CPL: ADD.CPP: GetTypeInfo failed!\n")); continue; } // put the name in the list and place the index of the port array // in it's item data... SendMessage(hCtrl, CB_SETITEMDATA, #ifdef _UNICODE SendMessage(hCtrl, CB_ADDSTRING, 0, (LPARAM)(LPCTSTR)lpDIJoyTypeInfo->wszDisplayName), n); #else SendMessage(hCtrl, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)W2A(lpDIJoyTypeInfo->wszDisplayName)), n); #endif // Just in case you're curious, we're going backwards so the default // port is the lowest available one. } while( n ); // Don't forget Auto-Detect! // But only if there's more than one port! ::SendMessage(hCtrl, CB_SETITEMDATA, ::SendMessage(hCtrl, CB_ADDSTRING, 0, (LPARAM)(LPCTSTR)lpszAutoDetect), AUTODETECT_PORT); // While you're at it, check to see if one is available... // if so, put it as the default! ::PostMessage(hCtrl, CB_SETCURSEL, (WPARAM)0, (LPARAM)0); if( lpDIJoyTypeInfo ) delete (lpDIJoyTypeInfo); return(TRUE); } static BOOL IsTypeActive( short *nArrayIndex ) { if( *nArrayIndex > nGamingDevices ) { #ifdef _DEBUG OutputDebugString(TEXT("JOY.CPL: IsTypeActive: nArrayIndex > nGamingDevices!\n")); #endif return(FALSE); } BOOL bRet = FALSE; BYTE nIndex = nAssigned; BYTE nStrLen = (BYTE)wcslen(pwszTypeArray[*nArrayIndex])+1; LPDIJOYCONFIG_DX5 lpDIJoyConfig = new (DIJOYCONFIG_DX5); ASSERT (lpDIJoyConfig); ZeroMemory(lpDIJoyConfig, sizeof(DIJOYCONFIG_DX5)); lpDIJoyConfig->dwSize = sizeof (DIJOYCONFIG_DX5); // find the assigned ID's while( nIndex-- ) { if( SUCCEEDED(pDIJoyConfig->GetConfig(pAssigned[nIndex]->ID, (LPDIJOYCONFIG)lpDIJoyConfig, DIJC_REGHWCONFIGTYPE)) ) { // if you find it... break out! if( wcsncmp(lpDIJoyConfig->wszType, pwszTypeArray[*nArrayIndex], nStrLen) == 0 ) { bRet = TRUE; *nArrayIndex = nIndex; break; } } } if( lpDIJoyConfig ) delete (lpDIJoyConfig); return(bRet); } BOOL GetNextAvailableVIDPID(LPWSTR lpwszType ) { // Make the VID/PID to compare from the following formula // VID_045e&PID_100+JOY_HW_LASTENTRY to 100+JOY_HW_LASTENTRY+0xf HKEY hKey; BYTE n = JOY_HW_LASTENTRY; wcsncpy(lpwszType, L"VID_045E&PID_0100", 18); const WCHAR wszLookup[] = L"0123456789ABCDEF"; do { if( n < 0x10 ) { lpwszType[16] = wszLookup[n]; } else { lpwszType[15] = wszLookup[1]; lpwszType[16] = wszLookup[n%0x10]; } n++; if( FAILED(pDIJoyConfig->OpenTypeKey(lpwszType, KEY_READ, &hKey)) ) break; RegCloseKey(hKey); } while( n < (JOY_HW_LASTENTRY+0x11) ); return(BOOL)(n < 0x1d); } // // PostDlgItemEnableWindow(HWND hDlg, USHORT nItem, BOOL bEnabled) // void PostDlgItemEnableWindow(HWND hDlg, USHORT nItem, BOOL bEnabled) { HWND hCtrl = GetDlgItem(hDlg, nItem); if( hCtrl ) PostEnableWindow(hCtrl, bEnabled); } // // PostEnableWindow(HWND hCtrl, BOOL bEnabled) // void PostEnableWindow(HWND hCtrl, BOOL bEnabled) { DWORD dwStyle = GetWindowLong(hCtrl, GWL_STYLE); // No point Redrawing the Window if there's no change! if( bEnabled ) { if( dwStyle & WS_DISABLED ) dwStyle &= ~WS_DISABLED; else return; } else { if( !(dwStyle & WS_DISABLED) ) dwStyle |= WS_DISABLED; else return; } SetWindowLong(hCtrl, GWL_STYLE, dwStyle); RedrawWindow(hCtrl, NULL, NULL, RDW_INTERNALPAINT | RDW_INVALIDATE); } /* BOOL IsCustomType(BYTE nIndex) { BOOL bRet = FALSE; // First verify VID is 045E WCHAR *pwStr = StrStrW(pwszTypeArray[nIndex],L"VID_"); if (pwStr) { // Increment the pointer over the VID_ and test for 045E pwStr = &pwStr[4]; if (_wcsnicmp(pwStr, L"045e", 4) == 0) { OutputDebugString(TEXT("Hit \n")); // Now, increment the pointer over 045e and &PID_ and test for the range! pwStr = &pwStr[9]; // Second, verify PID is between 0x100 + JOY_HW_LASTENTRY and // 0x100 + JOY_HW_LASTENTRY + 0xf bRet = TRUE; } } return bRet; } */ void PostHScrollBar(HWND hCtrl, LPCTSTR lpStr, BYTE nStrLen) { SIZE sz; HDC hDC = GetWindowDC(hCtrl); if( hDC != NULL ) /* PREFIX MANBUGS: 29336*/ { GetTextExtentPoint32(hDC, lpStr, nStrLen, &sz); ReleaseDC(hCtrl, hDC); ::PostMessage(hCtrl, LB_SETHORIZONTALEXTENT, (WPARAM)sz.cx, 0); } }