Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2377 lines
78 KiB

  1. /*
  2. File: Advanced.cpp
  3. Project: Joystick Control Panel OLE Client
  4. Author: Brycej
  5. Date: 02/07/97
  6. Comments:
  7. Window proc for Avanced page in cpanel
  8. Copyright (c) 1997, Microsoft Corporation
  9. */
  10. // This is necessary LVS_EX_INFOTIP
  11. /*
  12. #if (_WIN32_IE < 0x0500)
  13. #undef _WIN32_IE
  14. #define _WIN32_IE 0x0500
  15. #endif
  16. */
  17. #include <afxcmn.h>
  18. #include <windowsx.h>
  19. #include <cpl.h>
  20. #include <winuser.h> // For RegisterDeviceNotification stuff!
  21. #include <dbt.h> // for DBT_ defines!!!
  22. #include "cpanel.h"
  23. #include "hsvrguid.h"
  24. #include "resource.h"
  25. #include "joyarray.h"
  26. // MyListCtrl prototypes
  27. #include "inplace.h"
  28. #define USE_DEFAULT 0x1000 // If this bit is set, the device is going to use GCDEF!
  29. #define SHOW_DEFAULT 0x2000 // Show default check box if clsidConfig is != CLSID_LegacyServer
  30. // constants
  31. const short NO_ITEM = -1;
  32. #define DEVICE_ID 0
  33. #define DEVICE_FRIENDLY 1
  34. #define DEVICE_TYPE 2
  35. #define DEVICE_PORT 3
  36. LPCWSTR lpMSANALOG_VXD = L"MSANALOG.VXD";
  37. LPTSTR lpstrNone;
  38. #define ADVANCED_ID_COLUMN 0
  39. #define ADVANCED_DEVICE_COLUMN 1
  40. extern const DWORD gaHelpIDs[];
  41. // externs for arguements!
  42. extern BYTE nID, nStartPageDef, nStartPageCPL;
  43. // Update flag!
  44. extern short nFlags;
  45. // local (module-scope) variables
  46. HWND hAdvListCtrl;
  47. #ifdef _UNICODE
  48. static PVOID hAdvNotifyDevNode;
  49. #endif
  50. extern short iItem;
  51. static HWND ghDlg;
  52. //static UINT JoyCfgChangedMsg;
  53. static BOOL bProcess;
  54. // Message Procedures for handling VK_DELETE in Advanced window
  55. static WNDPROC fpMainWndProc;
  56. static BOOL WINAPI SubClassProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
  57. // Message Procedures for handling the VK_ENTER/VK_DELETE in Adv Window
  58. static WNDPROC fpPageWndProc;
  59. static BOOL WINAPI KeySubClassProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
  60. short iAdvItem = NO_ITEM; // index of selected item
  61. char iGameportDriverItem = NO_ITEM;
  62. short nOldID;
  63. // externs
  64. extern IDirectInputJoyConfig *pDIJoyConfig;
  65. extern LPDIRECTINPUT lpDIInterface;
  66. extern BYTE nGameportBus;
  67. extern PJOY pAssigned[MAX_ASSIGNED]; // List of assigned devices
  68. extern BYTE nAssigned; // Number of elements in pAssigned array
  69. extern HINSTANCE ghInstance;
  70. #ifdef WINNT
  71. // external function defined in CPANEL.CPP
  72. extern void RunWDMJOY ( void );
  73. #endif
  74. // local message handlers
  75. static BOOL OnInitDialog (HWND, HWND, LPARAM);
  76. static void OnCommand (HWND, int, HWND, UINT);
  77. static BOOL OnNotify (HWND, WPARAM, LPNMHDR);
  78. static void OnDestroy (HWND);
  79. static void OnAdvHelp (LPARAM);
  80. static void OnContextMenu (WPARAM wParam, LPARAM lParam);
  81. static void OnListviewContextMenu ( LPARAM lParam );
  82. // local utility fns
  83. static BOOL SetActiveGlobalDriver ( void );
  84. static BOOL AdvUpdateListCtrl ( void );
  85. static BOOL UpdateChangeListCtrl ( HWND hCtrl );
  86. #ifndef _UNICODE
  87. static void PopulateGlobalPortDriverComboBox( void );
  88. extern WCHAR *pwszGameportDriverArray[MAX_GLOBAL_PORT_DRIVERS];
  89. extern BYTE nGameportDriver; // Global Port Driver Enumeration Counter
  90. #define POLL_FLAGS_REG_STR TEXT("PollFlags")
  91. #endif
  92. static void LaunchChange ( HWND hTmp );
  93. int CALLBACK CompareIDItems (LPARAM item1, LPARAM item2, LPARAM uDirection);
  94. void EditSubLabel( BYTE nItem, BYTE nCol );
  95. ///////////////////////////////////////////////////////////////////////////////
  96. // FUNCTION: AdvancedProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
  97. //
  98. // PARAMETERS: hDlg -
  99. // uMsg -
  100. // wParam -
  101. // lParam -
  102. //
  103. // PURPOSE: Main callback function for "Advanced" sheet
  104. ///////////////////////////////////////////////////////////////////////////////
  105. INT_PTR CALLBACK AdvancedProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
  106. {
  107. switch( uMsg )
  108. {
  109. case WM_ACTIVATEAPP:
  110. if( wParam )
  111. SetListCtrlItemFocus(hAdvListCtrl, (BYTE)iAdvItem);
  112. break;
  113. case WM_DEVICECHANGE:
  114. switch( (UINT)wParam )
  115. {
  116. case DBT_DEVICEARRIVAL:
  117. // case DBT_DEVICEREMOVECOMPLETE:
  118. // Clear the old "known devices" list
  119. nFlags |= UPDATE_ALL;
  120. // Clear pAssigned
  121. while( nAssigned )
  122. {
  123. if( pAssigned[--nAssigned] )
  124. {
  125. delete[] (pAssigned[nAssigned]);
  126. pAssigned[nAssigned] = 0;
  127. }
  128. }
  129. // Rebuild the "known devices" list - pAssigned
  130. lpDIInterface->EnumDevices(DIDEVTYPE_JOYSTICK, (LPDIENUMDEVICESCALLBACK)DIEnumDevicesProc, (LPVOID)hDlg, DIEDFL_ALLDEVICES);
  131. AdvUpdateListCtrl();
  132. break;
  133. }
  134. break;
  135. case WM_LBUTTONDOWN:
  136. // Click Drag service for PropSheets!
  137. PostMessage(GetParent(hDlg), WM_NCLBUTTONDOWN, (WPARAM)HTCAPTION, lParam);
  138. break;
  139. case WM_INITDIALOG:
  140. if( !HANDLE_WM_INITDIALOG(hDlg, wParam, lParam, OnInitDialog) )
  141. {
  142. // Fix #108983 NT, Remove Flash on Error condition.
  143. SetWindowPos(::GetParent(hDlg), HWND_BOTTOM, 0, 0, 0, 0, SWP_HIDEWINDOW);
  144. DestroyWindow(hDlg);
  145. }
  146. return(TRUE);
  147. case WM_COMMAND:
  148. HANDLE_WM_COMMAND(hDlg, wParam, lParam, OnCommand);
  149. return(TRUE);
  150. case WM_DESTROY:
  151. return(HANDLE_WM_DESTROY(hDlg, wParam, lParam, OnDestroy));
  152. case WM_NOTIFY:
  153. return(HANDLE_WM_NOTIFY(hDlg, wParam, lParam, OnNotify));
  154. case WM_HELP:
  155. OnAdvHelp(lParam);
  156. return(TRUE);
  157. case WM_CONTEXTMENU:
  158. OnContextMenu(wParam, lParam);
  159. return(TRUE);
  160. default:
  161. break;
  162. }
  163. return(0);
  164. }
  165. ///////////////////////////////////////////////////////////////////////////////
  166. // FUNCTION: OnInitDialog(HWND hDlg, HWND hWnd, LPARAM lParam)
  167. //
  168. // PARAMETERS: hDlg -
  169. // hWnd -
  170. // lParam -
  171. //
  172. // PURPOSE: WM_INITDIALOG message handler
  173. ///////////////////////////////////////////////////////////////////////////////
  174. BOOL OnInitDialog(HWND hDlg, HWND hWnd, LPARAM lParam)
  175. {
  176. bProcess = TRUE;
  177. // Just in case Advanced is launched as the startup page!
  178. if( !lpDIInterface )
  179. {
  180. if( FAILED(DirectInputCreate(ghInstance, DIRECTINPUT_VERSION, &lpDIInterface, NULL)) )
  181. {
  182. #ifdef _DEBUG
  183. OutputDebugString(TEXT("GCDEF.DLL: DirectInputCreate() failed\n"));
  184. #endif
  185. Error((short)IDS_INTERNAL_ERROR, (short)IDS_NO_DIJOYCONFIG);
  186. return(FALSE);
  187. }
  188. if( !pDIJoyConfig )
  189. {
  190. if( FAILED(lpDIInterface->QueryInterface(IID_IDirectInputJoyConfig, (LPVOID*)&pDIJoyConfig)) )
  191. {
  192. #ifdef _DEBUG
  193. OutputDebugString (TEXT("JOY.CPL: CoCreateInstance Failed... Closing CPL!\n"));
  194. #endif
  195. Error((short)IDS_INTERNAL_ERROR, (short)IDS_NO_DIJOYCONFIG);
  196. return(FALSE);
  197. }
  198. VERIFY(SUCCEEDED(pDIJoyConfig->SetCooperativeLevel(hDlg, DISCL_EXCLUSIVE | DISCL_BACKGROUND)));
  199. // Enumerate all the Types!
  200. VERIFY(SUCCEEDED(pDIJoyConfig->EnumTypes((LPDIJOYTYPECALLBACK)DIEnumJoyTypeProc, NULL)));
  201. // If you're here, you came in via the CMD line arg and you need to enumerate for devices so...
  202. lpDIInterface->EnumDevices(DIDEVTYPE_JOYSTICK, (LPDIENUMDEVICESCALLBACK)DIEnumDevicesProc, (LPVOID)hDlg, DIEDFL_ALLDEVICES);
  203. }
  204. }
  205. // if we find an object, then enable the Change... button
  206. //HWND hChangeCtrl = GetDlgItem(hDlg, IDC_ADV_CHANGE);
  207. // Determine Privilege and disable Change accordingly!
  208. if( pDIJoyConfig->Acquire() == DIERR_INSUFFICIENTPRIVS )
  209. {
  210. // Assign here because the Advanced sheet could be launched first
  211. // via command line args!
  212. nFlags |= USER_MODE;
  213. //PostEnableWindow(hChangeCtrl, FALSE);
  214. }
  215. #ifdef WINNT
  216. else
  217. {
  218. // Run the WDMJOY.INF file!!!
  219. RunWDMJOY();
  220. }
  221. #endif
  222. // set the global dialog handle
  223. ghDlg = hDlg;
  224. // blj: TODO: Make advanced page update on JOYCONFIGCHANGED message!
  225. // JOY_CONFIGCHANGED_MSGSTRING defined in MMDDK.H
  226. //JoyCfgChangedMsg = RegisterWindowMessage(JOY_CONFIGCHANGED_MSGSTRING);
  227. // initialize our list control
  228. hAdvListCtrl = GetDlgItem(hDlg, IDC_ADV_LIST_DEVICE);
  229. #ifdef _UNICODE
  230. // Set the Attributes! Removed LVS_EX_ONECLICKACTIVATE per GSeirra | LVS_EX_INFOTIP
  231. ::SendMessage(hAdvListCtrl, LVM_SETEXTENDEDLISTVIEWSTYLE, 0, LVS_EX_FULLROWSELECT | LVS_EX_GRIDLINES | LVS_EX_HEADERDRAGDROP);
  232. #else
  233. ::SendMessage(hAdvListCtrl, LVM_SETEXTENDEDLISTVIEWSTYLE, 0, LVS_EX_FULLROWSELECT | LVS_EX_HEADERDRAGDROP);
  234. #endif
  235. RECT rc;
  236. GetClientRect(hAdvListCtrl, &rc);
  237. rc.left = (short)((rc.right-GetSystemMetrics(SM_CXVSCROLL))/5);
  238. // Set up the columns!
  239. #ifdef _UNICODE
  240. InsertColumn(hAdvListCtrl, DEVICE_ID, IDS_ADV_DEVICE_HEADING, (USHORT)(rc.left >> 1 ));
  241. InsertColumn(hAdvListCtrl, DEVICE_FRIENDLY, IDS_ADV_DEVICE_FRIENDLY, (USHORT)(rc.left + (rc.left>>1)));
  242. InsertColumn(hAdvListCtrl, DEVICE_TYPE, IDS_ADV_GAME_CONTROLLERS, (USHORT)(rc.left << 1 ));
  243. InsertColumn(hAdvListCtrl, DEVICE_PORT, IDS_ADV_DEVICE_PORT, (USHORT)(rc.left ));
  244. // Remove the Global Port Driver stuff!!!
  245. const USHORT nCtrlArray[] = {IDC_TEXT_PORTDRIVER, IDC_COMBO1, IDC_ADV_GRP2, IDC_TEXT_DRIVER};
  246. BYTE nIndex = sizeof(nCtrlArray)/sizeof(short);
  247. while( DestroyWindow(GetDlgItem(hDlg, nCtrlArray[--nIndex])) );
  248. #else
  249. rc.right = (rc.left << 1) + (rc.left >> 2);
  250. InsertColumn(hAdvListCtrl, DEVICE_ID, IDS_ADV_DEVICE_HEADING, (USHORT)(rc.left >> 1));
  251. InsertColumn(hAdvListCtrl, DEVICE_FRIENDLY, IDS_ADV_DEVICE_FRIENDLY, (USHORT)rc.right);
  252. InsertColumn(hAdvListCtrl, DEVICE_TYPE, IDS_ADV_GAME_CONTROLLERS, (USHORT)rc.right);
  253. #endif
  254. lpstrNone = new TCHAR[STR_LEN_32];
  255. ASSERT (lpstrNone);
  256. // everyone needs the "None" string so I've loaded it here!
  257. VERIFY(LoadString(ghInstance, IDS_NONE, lpstrNone, STR_LEN_32));
  258. fpMainWndProc = (WNDPROC)SetWindowLongPtr(hAdvListCtrl, GWLP_WNDPROC, (LONG_PTR)SubClassProc);
  259. // Only center the dialog if this was the page that we started on!
  260. if( nStartPageCPL == 1 )
  261. {
  262. HWND hParentWnd = GetParent(hDlg);
  263. GetWindowRect(hParentWnd, &rc);
  264. // Centre the Dialog!
  265. SetWindowPos(hParentWnd, NULL,
  266. (GetSystemMetrics(SM_CXSCREEN) - (rc.right-rc.left))>>1,
  267. (GetSystemMetrics(SM_CYSCREEN) - (rc.bottom-rc.top))>>1,
  268. NULL, NULL, SWP_NOSIZE | SWP_NOZORDER | SWP_SHOWWINDOW);
  269. // Do that move button thing!
  270. MoveOK(hParentWnd);
  271. // Set the Update flag...
  272. nFlags |= UPDATE_FOR_ADV;
  273. }
  274. // the user is requesting that the CPL be shown
  275. // and an extention associated with nID be Launched.
  276. if( nID < NUMJOYDEVS )
  277. {
  278. LaunchExtention(hDlg);
  279. // Zero out so you don't do it twice!
  280. nID = 0;
  281. }
  282. // SetActive will use this flag to make sure that the ListCtrl is populated!
  283. nFlags |= UPDATE_FOR_ADV;
  284. return(TRUE);
  285. }
  286. ///////////////////////////////////////////////////////////////////////////////
  287. // FUNCTION: OnCommand(HWND hDlg, int id, HWND hWndCtl, UINT code)
  288. //
  289. // PARAMETERS: hDlg -
  290. // id -
  291. // hWndCtl -
  292. // code -
  293. //
  294. // PURPOSE: WM_COMMAND message handler
  295. ///////////////////////////////////////////////////////////////////////////////
  296. void OnCommand(HWND hDlg, int id, HWND hWndCtl, UINT code)
  297. {
  298. // Hit the "What's This..."
  299. switch( id )
  300. {
  301. case IDC_RENAME:
  302. // Only SubClass when we need to!
  303. if( !(nFlags & USER_MODE) )
  304. {
  305. HWND hParentWnd = GetParent(GetDlgItem(hDlg, IDC_ADV_LIST_DEVICE));
  306. // this is required because the CPL can be launched via RUNDLL32
  307. if( ::IsWindow(hParentWnd) )
  308. hParentWnd = GetParent(hParentWnd);
  309. if( !fpPageWndProc )
  310. fpPageWndProc = (WNDPROC)SetWindowLongPtr(hParentWnd, GWLP_WNDPROC, (LONG_PTR)KeySubClassProc);
  311. nFlags |= UPDATE_INPROCESS;
  312. // Find the column as it Could have been moved!
  313. LPTSTR szName = new (TCHAR[STR_LEN_32]);
  314. ASSERT (szName);
  315. // First, Load the string of the column we are looking to find!
  316. if( LoadString(ghInstance, IDS_ADV_DEVICE_FRIENDLY, szName, STR_LEN_32) )
  317. {
  318. // Now, traverse the columns to find the one with the title that matches szName!
  319. HWND hHeader = GetDlgItem(hAdvListCtrl, 0);
  320. BYTE nColumns = (BYTE)::SendMessage(hHeader, HDM_GETITEMCOUNT, 0, 0L);
  321. HDITEM *phdItem = new (HDITEM);
  322. ASSERT (phdItem);
  323. ZeroMemory(phdItem, sizeof(HD_ITEM));
  324. phdItem->pszText = new TCHAR[STR_LEN_32];
  325. ASSERT (phdItem->pszText);
  326. phdItem->cchTextMax = STR_LEN_32;
  327. phdItem->mask = HDI_TEXT | HDI_ORDER;
  328. do
  329. {
  330. ::SendMessage(hHeader, HDM_GETITEM, (WPARAM)(int)--nColumns, (LPARAM)(LPHDITEM)phdItem);
  331. if( _tcscmp(phdItem->pszText, szName) == 0 )
  332. {
  333. nColumns = (BYTE)phdItem->iOrder;
  334. break;
  335. }
  336. } while( nColumns );
  337. if( phdItem->pszText )
  338. delete[] (phdItem->pszText);
  339. if( phdItem )
  340. delete (phdItem);
  341. EditSubLabel( (BYTE)iAdvItem, nColumns );
  342. }
  343. if( szName )
  344. delete[] (szName);
  345. }
  346. break;
  347. case IDS_WHATSTHIS:
  348. {
  349. // point to help file
  350. LPTSTR pszHelpFileName = new TCHAR[STR_LEN_32];
  351. ASSERT (pszHelpFileName);
  352. if( LoadString(ghInstance, IDS_HELPFILENAME, pszHelpFileName, STR_LEN_32) )
  353. WinHelp((HWND)hAdvListCtrl, pszHelpFileName, HELP_WM_HELP, (ULONG_PTR)gaHelpIDs);
  354. #ifdef _DEBUG
  355. else OutputDebugString(TEXT("JOY.CPL: Advanced.cpp: OnCommand: LoadString Failed to find IDS_HELPFILENAME!\n"));
  356. #endif // _DEBUG
  357. if( pszHelpFileName )
  358. delete[] (pszHelpFileName);
  359. }
  360. break;
  361. #ifndef _UNICODE
  362. // this is the handler for the Global Port Driver Combo box
  363. case IDC_COMBO1:
  364. if( code == CBN_SELCHANGE )
  365. SetActiveGlobalDriver();
  366. break;
  367. // handler for PollFlags entry in the registry for the Global Port Driver
  368. case IDC_POLLFLAGS:
  369. if( iGameportDriverItem == NO_ITEM )
  370. break;
  371. if( SUCCEEDED(pDIJoyConfig->Acquire()) )
  372. {
  373. HKEY hKey;
  374. VERIFY(SUCCEEDED(pDIJoyConfig->OpenTypeKey(pwszGameportDriverArray[iGameportDriverItem], KEY_ALL_ACCESS, &hKey)));
  375. // this entry is only valid if the user is running MSANALOG.VXD!
  376. DWORD nFlags = (IsDlgButtonChecked(hDlg, id)) ? 1 : 0;
  377. RegSetValueEx(hKey, POLL_FLAGS_REG_STR, 0, REG_BINARY, (PBYTE)&nFlags, sizeof(nFlags));
  378. RegCloseKey(hKey);
  379. pDIJoyConfig->SendNotify();
  380. pDIJoyConfig->Unacquire();
  381. }
  382. break;
  383. #endif // _UNICODE
  384. // this is the handler for the Device list box
  385. case IDC_ADV_LIST_DEVICE:
  386. // Fall into Change on DBLCLK
  387. if( code != LBN_DBLCLK )
  388. break;
  389. case IDC_ADV_CHANGE:
  390. if( nFlags & USER_MODE )
  391. Error((short)IDS_USER_MODE_TITLE, (short)IDS_USER_MODE);
  392. else
  393. {
  394. LaunchChange(hDlg);
  395. }
  396. break;
  397. case IDC_ADV_USEOEMPAGE:
  398. if( !nAssigned ) {
  399. break;
  400. }
  401. if( IsWindowVisible(GetDlgItem(hDlg,IDC_ADV_USEOEMPAGE)) )
  402. {
  403. // Boy are you going to pay the price for making that selection...
  404. LPDIJOYCONFIG_DX5 lpDIJoyConfig = new (DIJOYCONFIG_DX5);
  405. ASSERT (lpDIJoyConfig);
  406. ZeroMemory(lpDIJoyConfig, sizeof(DIJOYCONFIG_DX5));
  407. lpDIJoyConfig->dwSize = sizeof (DIJOYCONFIG_DX5);
  408. // Get the index from the selected item (iAdvItem)
  409. BYTE n1 = (BYTE)GetItemData(hAdvListCtrl, (BYTE)iAdvItem);
  410. BYTE n = 0;
  411. do
  412. {
  413. if( pAssigned[n] && (n1 == pAssigned[n]->ID) )
  414. break;
  415. n++;
  416. } while( n < NUMJOYDEVS );
  417. // Find out the type name...
  418. if( SUCCEEDED(pDIJoyConfig->GetConfig(pAssigned[n]->ID, (LPDIJOYCONFIG)lpDIJoyConfig, DIJC_REGHWCONFIGTYPE)) )
  419. {
  420. LPDIJOYTYPEINFO lpDIJoyTypeInfo = new (DIJOYTYPEINFO);
  421. ASSERT (lpDIJoyTypeInfo);
  422. ZeroMemory(lpDIJoyTypeInfo, sizeof(DIJOYTYPEINFO));
  423. lpDIJoyTypeInfo->dwSize = sizeof(DIJOYTYPEINFO);
  424. // Get the TypeInfo you start with!
  425. if( SUCCEEDED(pDIJoyConfig->GetTypeInfo(lpDIJoyConfig->wszType, lpDIJoyTypeInfo, DITC_FLAGS1 | DITC_CLSIDCONFIG)) )
  426. {
  427. DWORD dwFlags = GetItemData(hAdvListCtrl, (BYTE)iAdvItem);
  428. // If it's checked... you want the OEM supplied property sheet page!
  429. if( IsDlgButtonChecked(hDlg, IDC_ADV_USEOEMPAGE) )
  430. {
  431. // Turn off the USE_DEFAULT flag
  432. dwFlags &= ~USE_DEFAULT;
  433. // Update the global pointer!!!
  434. pAssigned[n]->clsidPropSheet = lpDIJoyTypeInfo->clsidConfig;
  435. // Update the pointer being sent to the registry
  436. lpDIJoyTypeInfo->dwFlags1 &= ~JOYTYPE_DEFAULTPROPSHEET;
  437. } else
  438. {
  439. // Turn on the USE_DEFAULT flag
  440. dwFlags |= USE_DEFAULT;
  441. // Update the global list!
  442. pAssigned[n]->clsidPropSheet = CLSID_LegacyServer;
  443. // Update the pointer being sent to the registry
  444. lpDIJoyTypeInfo->dwFlags1 |= JOYTYPE_DEFAULTPROPSHEET;
  445. }
  446. if( SUCCEEDED(pDIJoyConfig->Acquire()) ) {
  447. // Update the registry
  448. VERIFY(SUCCEEDED(pDIJoyConfig->SetTypeInfo(lpDIJoyConfig->wszType, lpDIJoyTypeInfo, DITC_FLAGS1)));
  449. // Set the data in the list control!
  450. SetItemData(hAdvListCtrl, (BYTE)iAdvItem, dwFlags);
  451. }
  452. pDIJoyConfig->Unacquire();
  453. }
  454. if( lpDIJoyTypeInfo )
  455. delete (lpDIJoyTypeInfo);
  456. }
  457. if( lpDIJoyConfig )
  458. delete (lpDIJoyConfig);
  459. }
  460. break;
  461. default:
  462. break;
  463. }
  464. }
  465. ////////////////////////////////////////////////////////////////////////////////
  466. //
  467. // FUNCTION: OnNotify(HWND hDlg, WPARAM idFrom, NMHDR* pnmhdr)
  468. //
  469. // PARAMETERS: hDlg -
  470. // idFrom - ID of control sending WM_NOTIFY message
  471. // pnmhdr -
  472. //
  473. // PURPOSE: WM_NOTIFY message handler
  474. ////////////////////////////////////////////////////////////////////////////////
  475. BOOL OnNotify(HWND hDlg, WPARAM idFrom, LPNMHDR pnmhdr)
  476. {
  477. switch( pnmhdr->code )
  478. {
  479. case PSN_QUERYCANCEL:
  480. if( nFlags & UPDATE_INPROCESS )
  481. {
  482. nFlags &= ~UPDATE_INPROCESS;
  483. SetFocus(hAdvListCtrl);
  484. }
  485. break;
  486. /*
  487. case LVN_GETINFOTIP:
  488. {
  489. LPLVHITTESTINFO lpHit = new (LVHITTESTINFO);
  490. ASSERT (lpHit);
  491. BOOL bRet = FALSE;
  492. POINT pt;
  493. GetCursorPos(&pt);
  494. ScreenToClient(hAdvListCtrl, &pt);
  495. lpHit->pt = pt;
  496. lpHit->flags = lpHit->iItem = lpHit->iSubItem = 0;
  497. ::SendMessage(hAdvListCtrl, LVM_SUBITEMHITTEST, 0, (LPARAM)(LPLVHITTESTINFO)lpHit);
  498. if (lpHit->flags & LVHT_ONITEMLABEL)
  499. {
  500. // Determine the text length of the column text
  501. LPTSTR lpStr = new (TCHAR[MAX_STR_LEN+1]);
  502. ASSERT (lpStr);
  503. GetItemText(hAdvListCtrl, lpHit->iItem, lpHit->iSubItem, lpStr, MAX_STR_LEN);
  504. // Determine if the latter will fit inside the former...
  505. SIZE size;
  506. HDC hDC = GetDC(hAdvListCtrl);
  507. GetTextExtentPoint(hDC, lpStr, lstrlen(lpStr), &size);
  508. ReleaseDC(hAdvListCtrl, hDC);
  509. // Determine how wide the column is!
  510. short nWidth = (short)::SendMessage(hAdvListCtrl, LVM_GETCOLUMNWIDTH, lpHit->iSubItem, 0);
  511. bRet = (BOOL)(size.cx > nWidth);
  512. if (bRet)
  513. // if not, copy the text into lpHit->pszText
  514. _tcscpy(((LPNMLVGETINFOTIP)pnmhdr)->pszText, lpStr);
  515. if (lpStr)
  516. delete[] (lpStr);
  517. }
  518. if (lpHit)
  519. delete (lpHit);
  520. return bRet;
  521. }
  522. */
  523. case LVN_BEGINLABELEDIT:
  524. if( !(GetItemData(hAdvListCtrl, (BYTE)iAdvItem) & ID_NONE) )
  525. OnCommand(hDlg, IDC_RENAME, 0, 0);
  526. SetWindowLongPtr(hDlg, DWLP_MSGRESULT, 1);
  527. break;
  528. case LVN_ENDLABELEDIT:
  529. if( !(nFlags & UPDATE_INPROCESS) )
  530. return(FALSE);
  531. if( !bProcess )
  532. return(FALSE);
  533. nFlags &= ~UPDATE_INPROCESS;
  534. if( fpPageWndProc )
  535. {
  536. HWND hParentWnd = GetParent(hDlg);
  537. // this is required because the CPL can be launched via RUNDLL32
  538. if( ::IsWindow(hParentWnd) )
  539. hParentWnd = GetParent(hParentWnd);
  540. // Reset the subclass proc
  541. // SetWindowLongPtr(hParentWnd, GWLP_WNDPROC, (LONG_PTR)fpPageWndProc);
  542. }
  543. // Make sure the name is usable!
  544. if( _tcschr(((NMLVDISPINFO *)pnmhdr)->item.pszText, TEXT('\\')) )
  545. {
  546. Error((short)IDS_INVALID_NAME_TITLE, (short)IDS_INVALID_NAME);
  547. } else
  548. {
  549. nFlags |= UPDATE_ALL;
  550. LPDIPROPSTRING pDIPropString = new (DIPROPSTRING);
  551. ASSERT (pDIPropString);
  552. ZeroMemory(pDIPropString, sizeof(DIPROPSTRING));
  553. pDIPropString->diph.dwSize = sizeof(DIPROPSTRING);
  554. pDIPropString->diph.dwHeaderSize = sizeof(DIPROPHEADER);
  555. pDIPropString->diph.dwHow = DIPH_DEVICE;
  556. #ifdef _UNICODE
  557. wcscpy(pDIPropString->wsz, ((NMLVDISPINFO *)pnmhdr)->item.pszText);
  558. #else
  559. USES_CONVERSION;
  560. wcscpy(pDIPropString->wsz, A2W(((NMLVDISPINFO *)pnmhdr)->item.pszText));
  561. #endif
  562. // Search nAssigned for the ID...
  563. BYTE n = nAssigned;
  564. do
  565. {
  566. if( pAssigned[--n]->ID == ((NMLVDISPINFO *)pnmhdr)->item.iItem )
  567. break;
  568. } while( n );
  569. if( SUCCEEDED(pAssigned[n]->fnDeviceInterface->SetProperty(DIPROP_INSTANCENAME, &pDIPropString->diph)) )
  570. {
  571. SetItemText(hAdvListCtrl, (BYTE)((NMLVDISPINFO *)pnmhdr)->item.iItem, 1, ((NMLVDISPINFO *)pnmhdr)->item.pszText);
  572. } else
  573. {
  574. Error((short)IDS_NO_RENAME_TITLE, (short)IDS_NO_RENAME);
  575. }
  576. if( pDIPropString )
  577. delete (pDIPropString);
  578. }
  579. break;
  580. #if 0
  581. case LVN_COLUMNCLICK:
  582. switch( ((NM_LISTVIEW*)pnmhdr)->iSubItem )
  583. {
  584. case DEVICE_ID:
  585. {
  586. static BOOL bIDDirection = TRUE;
  587. ::SendMessage(hAdvListCtrl, LVM_SORTITEMS, (WPARAM)(LPARAM)(bIDDirection =! bIDDirection), (LPARAM)(PFNLVCOMPARE)CompareIDItems);
  588. }
  589. break;
  590. default:
  591. {
  592. BOOL bDirection;
  593. CListCtrl *pCtrl = new (CListCtrl);
  594. ASSERT(pCtrl);
  595. pCtrl->Attach(hAdvListCtrl);
  596. switch( ((NM_LISTVIEW*)pnmhdr)->iSubItem )
  597. {
  598. case DEVICE_FRIENDLY:
  599. {
  600. static BOOL bFriendlyDirection = FALSE;
  601. bDirection = (bFriendlyDirection =! bFriendlyDirection);
  602. }
  603. break;
  604. case DEVICE_TYPE:
  605. {
  606. static BOOL bTypeDirection = FALSE;
  607. bDirection = (bTypeDirection =! bTypeDirection);
  608. }
  609. break;
  610. case DEVICE_PORT:
  611. {
  612. static BOOL bPortDirection = FALSE;
  613. bDirection = (bPortDirection =! bPortDirection);
  614. }
  615. break;
  616. }
  617. SortTextItems(pCtrl, (short)((NM_LISTVIEW*)pnmhdr)->iSubItem, bDirection, 0, 15);
  618. pCtrl->Detach();
  619. if( pCtrl )
  620. delete (pCtrl);
  621. }
  622. break;
  623. }
  624. if( nAssigned )
  625. {
  626. iAdvItem = (short)::SendMessage(hAdvListCtrl, LVM_GETNEXTITEM, (WPARAM)(int)-1, MAKELPARAM(LVNI_SELECTED, 0));
  627. ::PostMessage(hAdvListCtrl, LVM_ENSUREVISIBLE, iAdvItem, TRUE);
  628. if( !(nFlags & USER_MODE) )
  629. PostDlgItemEnableWindow(hDlg, IDC_ADV_CHANGE, (GetItemData(hAdvListCtrl, (BYTE)iAdvItem) & ID_NONE) ? FALSE : TRUE);
  630. SetListCtrlItemFocus(hAdvListCtrl, (BYTE)iAdvItem);
  631. }
  632. break;
  633. #endif
  634. case PSN_KILLACTIVE:
  635. if( nFlags & UPDATE_INPROCESS )
  636. SetFocus(hAdvListCtrl);
  637. #ifdef _UNICODE
  638. if( hAdvNotifyDevNode )
  639. UnregisterDeviceNotification(hAdvNotifyDevNode);
  640. #endif
  641. break;
  642. case NM_DBLCLK:
  643. switch( idFrom )
  644. {
  645. case IDC_ADV_LIST_DEVICE:
  646. if( !(GetItemData(hAdvListCtrl, (BYTE)iAdvItem) & ID_NONE) )
  647. LaunchChange(hDlg);
  648. break;
  649. }
  650. break;
  651. case PSN_SETACTIVE:
  652. #ifdef _UNICODE
  653. RegisterForDevChange(hDlg, &hAdvNotifyDevNode);
  654. #endif
  655. if( nFlags & UPDATE_FOR_ADV )
  656. {
  657. if( !AdvUpdateListCtrl() )
  658. {
  659. #ifdef _DEBUG
  660. OutputDebugString(TEXT("JOY.CPL: OnNotify: Failed UpdateListCtrl!\n"));
  661. #endif
  662. }
  663. }
  664. if( nAssigned )
  665. {
  666. iAdvItem = 0;
  667. // This will happen when the user comes in via the CMD line!
  668. if( iItem != NO_ITEM )
  669. {
  670. // Find the ID of the device... the Brute Force Method!
  671. do
  672. {
  673. if( (pAssigned[iItem] != NULL) && ((BYTE)GetItemData(hAdvListCtrl, (BYTE)iAdvItem) == pAssigned[iItem]->ID) )
  674. break;
  675. iAdvItem++;
  676. } while( iAdvItem < NUMJOYDEVS );
  677. }
  678. if( iAdvItem == NUMJOYDEVS ) {
  679. iAdvItem = 0;
  680. }
  681. SetListCtrlItemFocus(hAdvListCtrl, (BYTE)iAdvItem);
  682. ::PostMessage(hAdvListCtrl, LVM_ENSUREVISIBLE, iAdvItem, FALSE );
  683. }
  684. // No global port drivers in NT so...
  685. //if (nGameportDriver)
  686. #ifndef _UNICODE
  687. if( !(nFlags & ON_NT) )
  688. PopulateGlobalPortDriverComboBox();
  689. #endif
  690. // disable the Change button if iAdvItem points to a (none) selection
  691. if( !(nFlags & USER_MODE) )
  692. PostDlgItemEnableWindow(hDlg, IDC_ADV_CHANGE, (nAssigned) ? ((iAdvItem & ID_NONE) ? FALSE : TRUE) : FALSE);
  693. break;
  694. case LVN_ITEMCHANGED:
  695. if( iAdvItem != (short)((NM_LISTVIEW*)pnmhdr)->iItem )
  696. {
  697. iAdvItem = (short)((NM_LISTVIEW*)pnmhdr)->iItem;
  698. HWND hCtrl = GetDlgItem(hDlg, IDC_ADV_USEOEMPAGE);
  699. if( nAssigned )
  700. {
  701. SetWindowPos( hCtrl, NULL, NULL, NULL, NULL, NULL, SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER |
  702. ((((NM_LISTVIEW*)pnmhdr)->lParam & SHOW_DEFAULT) ? SWP_SHOWWINDOW : SWP_HIDEWINDOW) );
  703. // Check the box appropriatly!
  704. if( ((NM_LISTVIEW*)pnmhdr)->lParam & SHOW_DEFAULT )
  705. ::PostMessage(GetDlgItem(hDlg, IDC_ADV_USEOEMPAGE), BM_SETCHECK, (((NM_LISTVIEW*)pnmhdr)->lParam & USE_DEFAULT) ? BST_UNCHECKED : BST_CHECKED, 0);
  706. if( ((NM_LISTVIEW*)pnmhdr)->lParam )
  707. PostEnableWindow(hCtrl, (BOOL)!(((NM_LISTVIEW*)pnmhdr)->lParam & ID_NONE));
  708. if( !(nFlags & USER_MODE) )
  709. PostDlgItemEnableWindow(hDlg, IDC_ADV_CHANGE, (BOOL)!(((NM_LISTVIEW*)pnmhdr)->lParam & ID_NONE));
  710. } else SetWindowPos( hCtrl, NULL, NULL, NULL, NULL, NULL, SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_HIDEWINDOW);
  711. }
  712. break;
  713. case LVN_KEYDOWN:
  714. switch( ((LV_KEYDOWN*)pnmhdr)->wVKey )
  715. {
  716. case VK_DELETE:
  717. iAdvItem = (short)::SendMessage(hAdvListCtrl, LVM_GETNEXTITEM, (WPARAM)(int)-1, MAKELPARAM(LVNI_SELECTED, 0));
  718. {
  719. BYTE nRet = (BYTE)GetItemData(hAdvListCtrl, (BYTE)iAdvItem);
  720. DeleteSelectedItem((PBYTE)&nRet);
  721. }
  722. // Missing break intentional!
  723. case VK_F5:
  724. Enumerate( hDlg );
  725. AdvUpdateListCtrl();
  726. SetListCtrlItemFocus(hAdvListCtrl, (BYTE)iAdvItem);
  727. ::PostMessage(hAdvListCtrl, LVM_ENSUREVISIBLE, iAdvItem, FALSE );
  728. break;
  729. }
  730. break;
  731. }
  732. return(TRUE);
  733. }
  734. ////////////////////////////////////////////////////////////////////////////////////////
  735. // FUNCTION: OnDestroy ( HWND hWnd )
  736. //
  737. // PARAMETERS: hWnd - Handle to window being destroyed
  738. //
  739. // PURPOSE: WM_DESTROY message handler
  740. ////////////////////////////////////////////////////////////////////////////////////////
  741. void OnDestroy(HWND hWnd)
  742. {
  743. ASSERT (hWnd);
  744. if( lpstrNone )
  745. delete[] (lpstrNone);
  746. // Reset the subclass proc
  747. SetWindowLongPtr(hWnd, GWLP_WNDPROC, (LONG_PTR)fpMainWndProc);
  748. // release the DI JoyConfig interface pointer
  749. if( pDIJoyConfig )
  750. {
  751. pDIJoyConfig->Release();
  752. pDIJoyConfig = 0;
  753. }
  754. }
  755. ////////////////////////////////////////////////////////////////////////////////////////
  756. // FUNCTION: OnAdvHelp ( LPARAM lParam )
  757. //
  758. // PARAMETERS: lParam - Pointer to HELPINFO struct
  759. //
  760. // PURPOSE: WM_HELP message handler
  761. ////////////////////////////////////////////////////////////////////////////////////////
  762. void OnAdvHelp(LPARAM lParam)
  763. {
  764. ASSERT (lParam);
  765. // point to help file
  766. LPTSTR pszHelpFileName = new TCHAR[STR_LEN_32];
  767. ASSERT (pszHelpFileName);
  768. if( LoadString(ghInstance, IDS_HELPFILENAME, pszHelpFileName, STR_LEN_32) )
  769. {
  770. if( ((LPHELPINFO)lParam)->iContextType == HELPINFO_WINDOW )
  771. WinHelp((HWND)((LPHELPINFO)lParam)->hItemHandle, pszHelpFileName, HELP_WM_HELP, (ULONG_PTR)gaHelpIDs);
  772. }
  773. #ifdef _DEBUG
  774. else OutputDebugString(TEXT("JOY.CPL: Advanced.cpp: OnAdvHelp: LoadString Failed to find IDS_HELPFILENAME!\n"));
  775. #endif // _DEBUG
  776. if( pszHelpFileName )
  777. delete[] (pszHelpFileName);
  778. }
  779. ////////////////////////////////////////////////////////////////////////////////////////
  780. // FUNCTION: OnContextMenu ( WPARAM wParam )
  781. //
  782. // PARAMETERS: wParam - HWND of window under the pointer
  783. //
  784. // PURPOSE: Handle WM_RBUTTONDOWN over all client windows
  785. // (except the list control... that's OnListviewContextMenu() job)
  786. ////////////////////////////////////////////////////////////////////////////////////////
  787. void OnContextMenu(WPARAM wParam, LPARAM lParam)
  788. {
  789. ASSERT (wParam);
  790. // If you are on the ListCtrl...
  791. if( (HWND)wParam == hAdvListCtrl )
  792. {
  793. SetFocus(hAdvListCtrl);
  794. // Don't attempt if nothing selected
  795. if( iAdvItem != NO_ITEM )
  796. OnListviewContextMenu(lParam);
  797. } else
  798. {
  799. // point to help file
  800. LPTSTR pszHelpFileName = new TCHAR[STR_LEN_32];
  801. ASSERT (pszHelpFileName);
  802. if( LoadString(ghInstance, IDS_HELPFILENAME, pszHelpFileName, STR_LEN_32) )
  803. WinHelp((HWND)wParam, pszHelpFileName, HELP_CONTEXTMENU, (ULONG_PTR)gaHelpIDs);
  804. #ifdef _DEBUG
  805. else OutputDebugString(TEXT("JOY.CPL: Advanced.cpp: OnContextMenu: LoadString Failed to find IDS_HELPFILENAME!\n"));
  806. #endif // _DEBUG
  807. if( pszHelpFileName )
  808. delete[] (pszHelpFileName);
  809. }
  810. }
  811. ///////////////////////////////////////////////////////////////////////////////
  812. // FUNCTION: SetActiveGlobalDriver( void )
  813. //
  814. // PURPOSE: Commit user selection to persistent storage.
  815. //
  816. // RETURN: TRUE if successfull, FALSE otherwise
  817. ///////////////////////////////////////////////////////////////////////////////
  818. #ifndef _UNICODE
  819. BOOL SetActiveGlobalDriver( void )
  820. {
  821. // It's Perfectly valid to not have a Global Port Driver so... be prepared!
  822. short n = (short)SendDlgItemMessage(ghDlg, IDC_COMBO1, CB_GETCURSEL, 0, 0);
  823. if( n == CB_ERR )
  824. return(FALSE);
  825. LPDIJOYUSERVALUES pDIJoyUserValues = new (DIJOYUSERVALUES);
  826. ASSERT (pDIJoyUserValues);
  827. ZeroMemory(pDIJoyUserValues, sizeof(DIJOYUSERVALUES));
  828. pDIJoyUserValues->dwSize = sizeof(DIJOYUSERVALUES);
  829. HWND hCtrl = GetDlgItem(ghDlg, IDC_COMBO1);
  830. // Don't worry about this not being a TCHAR, this code will never be executed in NT!
  831. LPSTR pszDisplayName = new char[SendMessage(hCtrl, LB_GETTEXTLEN, (WPARAM)n, 0)+1];
  832. ASSERT (pszDisplayName);
  833. SendMessage(hCtrl, CB_GETLBTEXT, n, (LPARAM)(LPCTSTR)pszDisplayName);
  834. hCtrl = GetDlgItem(ghDlg, IDC_POLLFLAGS);
  835. SetWindowPos( hCtrl, NULL, NULL, NULL, NULL, NULL,
  836. SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_HIDEWINDOW );
  837. // Fix #9815, Set wszGlobalDriver to
  838. if( _tcsncmp(pszDisplayName, lpstrNone, sizeof(lpstrNone)/sizeof(TCHAR)) == 0 )
  839. {
  840. //wcscpy(pDIJoyUserValues->wszGlobalDriver, L"");
  841. if( SUCCEEDED(pDIJoyConfig->Acquire()) )
  842. {
  843. if( FAILED(pDIJoyConfig->SetUserValues(pDIJoyUserValues, DIJU_GLOBALDRIVER)) )
  844. {
  845. TRACE (TEXT("JOY.CPL: SetUserValues failed to set DIJU_GLOBALDRIVER!\n"));
  846. }
  847. }
  848. } else
  849. {
  850. LPDIJOYTYPEINFO lpdiJoyInfo = new DIJOYTYPEINFO;
  851. ASSERT (lpdiJoyInfo);
  852. ZeroMemory(lpdiJoyInfo, sizeof(DIJOYTYPEINFO));
  853. lpdiJoyInfo->dwSize = sizeof(DIJOYTYPEINFO);
  854. USES_CONVERSION;
  855. short nIndex = 0;
  856. // traverse the list of Global Port Drivers 'till you find the matching display name
  857. // this also disallows the user from doing something ugly when they only have "standard gameport"
  858. while( pwszGameportDriverArray[nIndex] )
  859. {
  860. // populate the Type Info
  861. if( SUCCEEDED(pDIJoyConfig->GetTypeInfo(pwszGameportDriverArray[nIndex], lpdiJoyInfo, DITC_DISPLAYNAME | DITC_CALLOUT)) )
  862. {
  863. if( _wcsicmp(lpdiJoyInfo->wszDisplayName, A2W(pszDisplayName)) == 0 )
  864. {
  865. wcscpy(pDIJoyUserValues->wszGlobalDriver, lpdiJoyInfo->wszCallout );
  866. if( SUCCEEDED(pDIJoyConfig->Acquire()) )
  867. {
  868. if( FAILED(pDIJoyConfig->SetUserValues(pDIJoyUserValues, DIJU_GLOBALDRIVER)) )
  869. {
  870. TRACE (TEXT("JOY.CPL: SetUserValues failed to set DIJU_GLOBALDRIVER!\n"));
  871. }
  872. // check to see if you need to display the poll flags check box!
  873. if( _wcsicmp(pDIJoyUserValues->wszGlobalDriver, lpMSANALOG_VXD) == 0 )
  874. {
  875. SetWindowPos( hCtrl, NULL, NULL, NULL, NULL, NULL,
  876. SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_SHOWWINDOW );
  877. // Get the state from the registry and update the check mark
  878. HKEY hKey;
  879. if( FAILED(pDIJoyConfig->OpenTypeKey(pwszGameportDriverArray[nIndex], KEY_ALL_ACCESS, &hKey)) )
  880. {
  881. TRACE (TEXT("JOY.CPL: OpenTypeKey failed to open key %s!\n"), pwszGameportDriverArray[nIndex]);
  882. }
  883. DWORD dwFlag;
  884. ULONG ulType = REG_BINARY;
  885. ULONG ulSize = sizeof(dwFlag);
  886. // this will happen if there is no entry for POLL_FLAGS_REG_STR
  887. if( ERROR_SUCCESS != RegQueryValueEx(hKey, POLL_FLAGS_REG_STR, NULL, &ulType, (PBYTE)&dwFlag, &ulSize) )
  888. dwFlag = 0;
  889. ::PostMessage(GetDlgItem(ghDlg, IDC_POLLFLAGS), BM_SETCHECK, (dwFlag) ? BST_CHECKED : BST_UNCHECKED, 0);
  890. RegCloseKey(hKey);
  891. }
  892. }
  893. break;
  894. }
  895. }
  896. nIndex++;
  897. }
  898. // delete the DIJOYTYPEINFO variable
  899. if( lpdiJoyInfo )
  900. delete (lpdiJoyInfo);
  901. }
  902. pDIJoyConfig->SendNotify();
  903. pDIJoyConfig->Unacquire();
  904. if( pszDisplayName )
  905. delete[] (pszDisplayName);
  906. if( pDIJoyUserValues )
  907. delete pDIJoyUserValues;
  908. return(TRUE);
  909. }
  910. #endif // _UNICODE
  911. ///////////////////////////////////////////////////////////////////////////////
  912. // FUNCTION: OnListviewContextMenu( void )
  913. //
  914. // PURPOSE: Handle Context menu in Listview
  915. //
  916. // RETURN: TRUE if successfull, FALSE otherwise
  917. ///////////////////////////////////////////////////////////////////////////////
  918. static void OnListviewContextMenu( LPARAM lParam )
  919. {
  920. HMENU hPopupMenu = CreatePopupMenu();
  921. ASSERT (hPopupMenu);
  922. // unlike life, bRet defaults to bliss
  923. BOOL bRet = TRUE;
  924. LPTSTR pszText = new TCHAR[STR_LEN_32];
  925. ASSERT (pszText);
  926. // Don't display Rename/Change if on (none) entry
  927. if( !(GetItemData(hAdvListCtrl, (BYTE)iAdvItem) & ID_NONE) )
  928. {
  929. if( !(nFlags & USER_MODE) )
  930. {
  931. // add the "Change..." string
  932. ::SendDlgItemMessage(GetParent(hAdvListCtrl), IDC_ADV_CHANGE, WM_GETTEXT, (WPARAM)STR_LEN_32, (LPARAM)(LPCTSTR)pszText);
  933. bRet = AppendMenu(hPopupMenu, MF_ENABLED, IDC_ADV_CHANGE, pszText);
  934. #ifdef _DEBUG
  935. if( !bRet )
  936. TRACE(TEXT("JOY.CPL: OnListviewCOntextMenu: AppendMenu Failed to insert %s\n"), pszText);
  937. #endif //_DEBUG
  938. // Add the Rename text
  939. VERIFY(LoadString(ghInstance, IDS_RENAME, pszText, STR_LEN_32));
  940. bRet = AppendMenu(hPopupMenu, MF_ENABLED, IDC_RENAME, pszText);
  941. #ifdef _DEBUG
  942. if( !bRet )
  943. TRACE(TEXT("JOY.CPL: OnListviewCOntextMenu: AppendMenu Failed to insert %s\n"), pszText);
  944. #endif //_DEBUG
  945. // Add the SEPERATOR and "What's this?"
  946. //PREFIX #WI279965. False positive.
  947. //MSDN: if uFlags==MF_SEPARATOR, LPCTSTR lpNewItem is ignored.
  948. bRet = AppendMenu(hPopupMenu, MF_SEPARATOR, 0, 0);
  949. #ifdef _DEBUG
  950. if( !bRet )
  951. TRACE(TEXT("JOY.CPL: OnListviewCOntextMenu: AppendMenu Failed to insert SEPERATOR!\n"));
  952. #endif //_DEBUG
  953. }
  954. }
  955. VERIFY(LoadString(ghInstance, IDS_WHATSTHIS, pszText, STR_LEN_32));
  956. bRet = AppendMenu(hPopupMenu, MF_ENABLED, IDS_WHATSTHIS, pszText);
  957. #ifdef _DEBUG
  958. if( !bRet )
  959. TRACE(TEXT("JOY.CPL: OnListviewCOntextMenu: AppendMenu Failed to insert %s\n"), pszText);
  960. #endif //_DEBUG
  961. if( pszText ) delete[] (pszText);
  962. POINT pt;
  963. // lParam is -1 if we got here via Shift+F10
  964. if( lParam > 0 )
  965. {
  966. pt.x = GET_X_LPARAM(lParam);
  967. pt.y = GET_Y_LPARAM(lParam);
  968. } else
  969. {
  970. // Centre the popup on the selected item!
  971. // This get's a good X pos, but the y is the start of the control!
  972. ::SendMessage(hAdvListCtrl, LVM_GETITEMPOSITION, iAdvItem, (LPARAM)&pt);
  973. RECT rc;
  974. ::GetClientRect(hAdvListCtrl, &rc);
  975. pt.x = rc.right>>1;
  976. ClientToScreen(hAdvListCtrl, &pt);
  977. }
  978. bRet = TrackPopupMenu (hPopupMenu, TPM_LEFTALIGN|TPM_LEFTBUTTON|TPM_RIGHTBUTTON, pt.x, pt.y, 0, ghDlg, NULL);
  979. #ifdef _DEBUG
  980. if( !bRet )
  981. TRACE (TEXT("JOY.CPL: OnListviewContextMenu: TrackPopupMenu Failed!\n"));
  982. #endif //_DEBUG
  983. if(hPopupMenu) DestroyMenu (hPopupMenu); // PREFIX 45089
  984. }
  985. ///////////////////////////////////////////////////////////////////////////////
  986. // FUNCTION: UpdateListCtrl( void )
  987. //
  988. // PURPOSE: Refreshes enumerated device list
  989. //
  990. // RETURN: TRUE if successfull, FALSE otherwise
  991. ///////////////////////////////////////////////////////////////////////////////
  992. static BOOL AdvUpdateListCtrl()
  993. {
  994. // Turn Redraw off here else it will flicker!
  995. ::SendMessage(hAdvListCtrl, WM_SETREDRAW, (WPARAM)FALSE, 0);
  996. // Out with the old...
  997. ::SendMessage(hAdvListCtrl, LVM_DELETEALLITEMS, 0, 0);
  998. // This buffer is so large because it is used to hold IDS_GEN_STATUS_UNKNOWN
  999. TCHAR sz1[16];
  1000. // find and assign ID's
  1001. BYTE n = NUMJOYDEVS;
  1002. BYTE nIndex;
  1003. SendMessage(hAdvListCtrl, LVM_SETITEMCOUNT, (WPARAM)(int)NUMJOYDEVS, (LPARAM)LVSICF_NOINVALIDATEALL | LVSICF_NOSCROLL);
  1004. // Set everything to NONE to start!
  1005. do
  1006. {
  1007. itoa((BYTE)n--, (LPTSTR)&sz1);
  1008. // Insert the ID
  1009. // Set the device ID and ID_NONE in Extended info...
  1010. nIndex = InsertItem( hAdvListCtrl, sz1, n);
  1011. // Populate the columns with "(none)"
  1012. SetItemText(hAdvListCtrl, nIndex, DEVICE_FRIENDLY, lpstrNone);
  1013. SetItemText(hAdvListCtrl, nIndex, DEVICE_TYPE, lpstrNone);
  1014. #ifdef _UNICODE
  1015. SetItemText(hAdvListCtrl, nIndex, DEVICE_PORT, lpstrNone);
  1016. #endif
  1017. } while( n );
  1018. if( nAssigned )
  1019. {
  1020. // insert the assigned ones!
  1021. n = nAssigned;
  1022. DIPROPSTRING *pDIPropStr = new (DIPROPSTRING);
  1023. ASSERT (pDIPropStr);
  1024. ZeroMemory(pDIPropStr, sizeof(DIPROPSTRING));
  1025. pDIPropStr->diph.dwSize = sizeof(DIPROPSTRING);
  1026. pDIPropStr->diph.dwHeaderSize = sizeof(DIPROPHEADER);
  1027. pDIPropStr->diph.dwHow = DIPH_DEVICE;
  1028. #ifndef _UNICODE
  1029. USES_CONVERSION;
  1030. #endif
  1031. // The low half will be populated by the ID, the upper by bit flags!
  1032. DWORD dwData;
  1033. do
  1034. {
  1035. // Set the Product Column!
  1036. if( SUCCEEDED(pAssigned[--n]->fnDeviceInterface->GetProperty(DIPROP_PRODUCTNAME, &pDIPropStr->diph)) )
  1037. {
  1038. #ifdef _UNICODE
  1039. SetItemText(hAdvListCtrl, pAssigned[n]->ID, DEVICE_TYPE, (LPTSTR)pDIPropStr->wsz);
  1040. #else
  1041. SetItemText(hAdvListCtrl, pAssigned[n]->ID, DEVICE_TYPE, (LPTSTR)W2A(pDIPropStr->wsz));
  1042. #endif
  1043. }
  1044. // Set the Friendly Name!
  1045. if( SUCCEEDED(pAssigned[n]->fnDeviceInterface->GetProperty(DIPROP_INSTANCENAME, &pDIPropStr->diph)) )
  1046. {
  1047. #ifdef _UNICODE
  1048. SetItemText(hAdvListCtrl, pAssigned[n]->ID, DEVICE_FRIENDLY, (LPTSTR)pDIPropStr->wsz);
  1049. #else
  1050. SetItemText(hAdvListCtrl, pAssigned[n]->ID, DEVICE_FRIENDLY, (LPTSTR)W2A(pDIPropStr->wsz));
  1051. #endif
  1052. }
  1053. #ifdef _UNICODE
  1054. // Set the Game Port Column!
  1055. if( SUCCEEDED(pAssigned[n]->fnDeviceInterface->GetProperty(DIPROP_GETPORTDISPLAYNAME, &pDIPropStr->diph)) )
  1056. {
  1057. SetItemText(hAdvListCtrl, pAssigned[n]->ID, DEVICE_PORT, (LPTSTR)pDIPropStr->wsz);
  1058. } else
  1059. {
  1060. VERIFY(LoadString(ghInstance, IDS_GEN_STATUS_UNKNOWN, sz1, sizeof(sz1)/sizeof(TCHAR)));
  1061. SetItemText(hAdvListCtrl, pAssigned[n]->ID, DEVICE_PORT, (LPTSTR)sz1);
  1062. }
  1063. #endif // _UNICODE
  1064. // Set the ID in the data...
  1065. // This is necessary for Sorting!
  1066. dwData = pAssigned[n]->ID;
  1067. //if( pAssigned[n]->clsidPropSheet != CLSID_LegacyServer )
  1068. if( pAssigned[n]->fHasOemSheet )
  1069. {
  1070. LPDIJOYCONFIG_DX5 lpDIJoyConfig = new (DIJOYCONFIG_DX5);
  1071. ASSERT (lpDIJoyConfig);
  1072. ZeroMemory(lpDIJoyConfig, sizeof(DIJOYCONFIG_DX5));
  1073. lpDIJoyConfig->dwSize = sizeof (DIJOYCONFIG_DX5);
  1074. // Set the DefaultPropertySheet flag
  1075. if( SUCCEEDED(pDIJoyConfig->GetConfig(pAssigned[n]->ID, (LPDIJOYCONFIG)lpDIJoyConfig, DIJC_REGHWCONFIGTYPE)) )
  1076. {
  1077. LPDIJOYTYPEINFO lpDIJoyTypeInfo = new (DIJOYTYPEINFO);
  1078. ASSERT (lpDIJoyTypeInfo);
  1079. ZeroMemory(lpDIJoyTypeInfo, sizeof(DIJOYTYPEINFO));
  1080. lpDIJoyTypeInfo->dwSize = sizeof (DIJOYTYPEINFO);
  1081. if( SUCCEEDED(pDIJoyConfig->GetTypeInfo(lpDIJoyConfig->wszType, lpDIJoyTypeInfo, DITC_FLAGS1 )) )
  1082. {
  1083. if( lpDIJoyTypeInfo->dwFlags1 & JOYTYPE_DEFAULTPROPSHEET )
  1084. {
  1085. // Set the USE_DEFAULT mask!
  1086. dwData |= USE_DEFAULT;
  1087. // Update the global list!
  1088. pAssigned[n]->clsidPropSheet = CLSID_LegacyServer;
  1089. }
  1090. }
  1091. if( lpDIJoyTypeInfo )
  1092. delete (lpDIJoyTypeInfo);
  1093. }
  1094. dwData |= SHOW_DEFAULT;
  1095. if( lpDIJoyConfig )
  1096. delete (lpDIJoyConfig);
  1097. }
  1098. // Set the Item Data to the ID!
  1099. SetItemData(hAdvListCtrl, pAssigned[n]->ID, dwData);
  1100. } while( n );
  1101. // clean up, clean up... everybody do your share!
  1102. if( pDIPropStr )
  1103. delete (pDIPropStr);
  1104. }
  1105. // turn the flag off!
  1106. if( nFlags & UPDATE_FOR_ADV )
  1107. nFlags &= ~UPDATE_FOR_ADV;
  1108. // Turn the redraw flag back on!
  1109. ::SendMessage (hAdvListCtrl, WM_SETREDRAW, (WPARAM)TRUE, 0);
  1110. InvalidateRect(hAdvListCtrl, NULL, TRUE);
  1111. return(TRUE);
  1112. }
  1113. ////////////////////////////////////////////////////////////////////////////////
  1114. //
  1115. // FUNCTION: ChangeDialogProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
  1116. //
  1117. // PARAMETERS: HWND hDlg -
  1118. // UINT uMsg -
  1119. // WPARAM wParam -
  1120. // LPARAM lParam -
  1121. //
  1122. // PURPOSE:
  1123. ////////////////////////////////////////////////////////////////////////////////
  1124. INT_PTR CALLBACK ChangeDialogProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
  1125. {
  1126. switch( uMsg )
  1127. {
  1128. case WM_LBUTTONDOWN:
  1129. // Click Drag service for PropSheets!
  1130. PostMessage(hDlg, WM_NCLBUTTONDOWN, (WPARAM)HTCAPTION, lParam);
  1131. break;
  1132. case WM_HELP:
  1133. OnHelp(lParam);
  1134. return(1);
  1135. case WM_CONTEXTMENU:
  1136. OnContextMenu(wParam, lParam);
  1137. return(TRUE);
  1138. case WM_INITDIALOG:
  1139. {
  1140. HICON hIcon = (HICON)LoadImage(ghInstance, MAKEINTRESOURCE(IDI_CPANEL), IMAGE_ICON, 0, 0, LR_DEFAULTSIZE);
  1141. ASSERT (hIcon);
  1142. if( hIcon )
  1143. ::PostMessage(hDlg, WM_SETICON, (WPARAM)ICON_SMALL, (LPARAM)hIcon);
  1144. HWND hCtrl = GetDlgItem(hDlg, IDC_CHANGE_LIST);
  1145. ASSERT (hCtrl);
  1146. UpdateChangeListCtrl( hCtrl );
  1147. BYTE nCounter = nAssigned;
  1148. while( nCounter-- )
  1149. {
  1150. if( (BYTE)::SendMessage(hCtrl, LB_GETITEMDATA, (WPARAM)nCounter, 0) == nOldID )
  1151. break;
  1152. }
  1153. // Set the list box selections!
  1154. ::PostMessage(hCtrl, LB_SETCURSEL, (WPARAM)nCounter, 0);
  1155. // Done with the ListCtrl, now... on to the ComboBox
  1156. if( nFlags & ON_NT )
  1157. {
  1158. if( !PopulatePortList(hDlg) )
  1159. {
  1160. #ifdef _DEBUG
  1161. OutputDebugString(TEXT("JOY.CPL: ADVANCED.CPP: PopulatePortList failed!\n"));
  1162. #endif
  1163. }
  1164. }
  1165. // Set up the Spin Control!
  1166. HWND hSpinCtrl = GetDlgItem(hDlg, IDC_SPIN);
  1167. ::PostMessage(hSpinCtrl, UDM_SETRANGE, 0, MAKELPARAM(NUMJOYDEVS, 1));
  1168. ::PostMessage(hSpinCtrl, UDM_SETBASE, 10, 0L);
  1169. ::PostMessage(hSpinCtrl, UDM_SETPOS, 0, MAKELPARAM(nOldID+1, 0));
  1170. }
  1171. return(FALSE);
  1172. case WM_COMMAND:
  1173. {
  1174. switch( LOWORD(wParam) )
  1175. {
  1176. /* I'll leave this commented out, as it's likely they'll want double clicking back once I take it out
  1177. case IDC_CHANGE_LIST:
  1178. // Fall into Change on DBLCLK
  1179. if (HIWORD(wParam) != LBN_DBLCLK)
  1180. break;
  1181. */
  1182. case IDOK:
  1183. {
  1184. HWND hCtrl = GetDlgItem(hDlg, IDC_CHANGE_LIST);
  1185. ASSERT (hCtrl);
  1186. char nSelectedItem = (char)(SendMessage(hCtrl, LB_GETITEMDATA, SendMessage(hCtrl, LB_GETCURSEL, 0, 0), 0));
  1187. TCHAR tsz[4];
  1188. hCtrl = GetDlgItem(hDlg, IDC_SPINBUDDY);
  1189. tsz[0] = 4;
  1190. SendMessage(hCtrl, EM_GETLINE, 0, (LPARAM)(LPCSTR)&tsz);
  1191. // The '-1' is to account for the 1 based list
  1192. // and the 0 based id's!
  1193. char nSelectedID = (char)atoi((LPCTSTR)&tsz)-1;
  1194. pDIJoyConfig->Acquire();
  1195. // first check to see if the user has selected NONE!
  1196. if( nSelectedItem == -2 )
  1197. {
  1198. // User has selected NONE!
  1199. VERIFY (SUCCEEDED(pDIJoyConfig->DeleteConfig(nSelectedID)));
  1200. } else
  1201. {
  1202. // see if the selected item and the ID match!
  1203. // if so... get out of here!
  1204. if( nSelectedID == nSelectedItem )
  1205. {
  1206. #ifdef _DEBUG
  1207. OutputDebugString(TEXT("JOY.CPL: ADVANCED.CPP: OnChangeCommand: IDOK: Device already at selected ID!\n"));
  1208. #endif
  1209. } else
  1210. {
  1211. SwapIDs(nSelectedID, nSelectedItem);
  1212. // SetListCtrlItemFocus(hAdvListCtrl, (BYTE)nSelectedID);
  1213. }
  1214. }
  1215. pDIJoyConfig->Unacquire();
  1216. }
  1217. // missing break intentional!
  1218. case IDCANCEL:
  1219. EndDialog(hDlg, LOWORD(wParam));
  1220. break;
  1221. }
  1222. }
  1223. return(1);
  1224. case WM_DESTROY:
  1225. DestroyIcon((HICON)SendMessage(hDlg, WM_GETICON, (WPARAM)ICON_SMALL, 0));
  1226. return(TRUE);
  1227. }
  1228. return(FALSE);
  1229. }
  1230. ///////////////////////////////////////////////////////////////////////////////
  1231. // FUNCTION: PopulateGlobalPortDriverComboBox( void )
  1232. //
  1233. // PARAMETERS:
  1234. //
  1235. // PURPOSE:
  1236. ///////////////////////////////////////////////////////////////////////////////
  1237. #ifndef UNICODE
  1238. void PopulateGlobalPortDriverComboBox( void )
  1239. {
  1240. HWND hCtrl = GetDlgItem(ghDlg, IDC_COMBO1);
  1241. // make sure the combo is clear before we start populating it!
  1242. SendMessage(hCtrl, CB_RESETCONTENT, 0, 0);
  1243. // Type info
  1244. LPDIJOYTYPEINFO_DX5 lpdiJoyInfo = new (DIJOYTYPEINFO_DX5);
  1245. ASSERT (lpdiJoyInfo);
  1246. ZeroMemory(lpdiJoyInfo, sizeof(DIJOYTYPEINFO_DX5));
  1247. lpdiJoyInfo->dwSize = sizeof(DIJOYTYPEINFO_DX5);
  1248. BYTE nIndex = nGameportDriver;
  1249. USES_CONVERSION;
  1250. // Populate the Combobox
  1251. while( nIndex-- )
  1252. {
  1253. // populate the Type Info and place the Index in the extra memory!
  1254. if( SUCCEEDED(pDIJoyConfig->GetTypeInfo(pwszGameportDriverArray[nIndex], (LPDIJOYTYPEINFO)lpdiJoyInfo, DITC_DISPLAYNAME)) )
  1255. ::SendMessage(hCtrl, CB_SETITEMDATA, ::SendMessage(hCtrl, CB_ADDSTRING, 0, (LPARAM)(LPCTSTR)W2A(lpdiJoyInfo->wszDisplayName)), nIndex);
  1256. #ifdef _DEBUG
  1257. else
  1258. OutputDebugString (TEXT("JOY.CPL: ADVANCED.CPP: PopulateGlobalPortDriverComboBox: GetTypeInfo failed!\n"));
  1259. #endif
  1260. }
  1261. // Display the Current selected GlobalPortDriver or None!
  1262. LPDIJOYUSERVALUES pDIJoyUserValues = new DIJOYUSERVALUES;
  1263. ASSERT (pDIJoyUserValues);
  1264. ZeroMemory(pDIJoyUserValues, sizeof(DIJOYUSERVALUES));
  1265. pDIJoyUserValues->dwSize = sizeof(DIJOYUSERVALUES);
  1266. VERIFY (SUCCEEDED(pDIJoyConfig->GetUserValues(pDIJoyUserValues, DIJU_GLOBALDRIVER)));
  1267. // Fix #9815, If the user has No Global port driver label as NONE!
  1268. if( !(*pDIJoyUserValues->wszGlobalDriver && pDIJoyUserValues->wszGlobalDriver) )
  1269. {
  1270. iGameportDriverItem = NO_ITEM;
  1271. PostMessage(hCtrl, CB_SETCURSEL, (WPARAM)SendMessage(hCtrl, CB_FINDSTRING, (WPARAM)-1, (LPARAM)lpstrNone), (LPARAM)0);
  1272. } else
  1273. {
  1274. ZeroMemory(lpdiJoyInfo, sizeof(DIJOYTYPEINFO_DX5));
  1275. lpdiJoyInfo->dwSize = sizeof(DIJOYTYPEINFO_DX5);
  1276. nIndex = 0;
  1277. // get type info 'till you find the one you want and place it's callout
  1278. while( pwszGameportDriverArray[nIndex] )
  1279. {
  1280. VERIFY(SUCCEEDED(pDIJoyConfig->GetTypeInfo(pwszGameportDriverArray[nIndex], (LPDIJOYTYPEINFO)lpdiJoyInfo, DITC_CALLOUT | DITC_DISPLAYNAME)));
  1281. if( _wcsicmp(lpdiJoyInfo->wszCallout, pDIJoyUserValues->wszGlobalDriver) == 0 )
  1282. {
  1283. ::PostMessage(hCtrl, CB_SETCURSEL, (WPARAM)::SendMessage(hCtrl, CB_FINDSTRING, (WPARAM)-1, (LPARAM)W2A(lpdiJoyInfo->wszDisplayName)), (LPARAM)0);
  1284. iGameportDriverItem = nIndex;
  1285. // enable the PollFlags checkbox!
  1286. if( _wcsicmp(pDIJoyUserValues->wszGlobalDriver, lpMSANALOG_VXD) == 0 )
  1287. {
  1288. SetWindowPos( GetDlgItem( ghDlg, IDC_POLLFLAGS), NULL, NULL, NULL, NULL, NULL,
  1289. SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_SHOWWINDOW );
  1290. VERIFY(SUCCEEDED(pDIJoyConfig->Acquire()));
  1291. // Get the state from the registry and update the check mark
  1292. HKEY hKey;
  1293. DWORD dwFlag;
  1294. if( SUCCEEDED(pDIJoyConfig->OpenTypeKey(pwszGameportDriverArray[nIndex], KEY_ALL_ACCESS, &hKey)) )
  1295. {
  1296. ULONG ulType = REG_BINARY;
  1297. ULONG ulSize = sizeof(dwFlag);
  1298. // this will happen if there is no entry for POLL_FLAGS_REG_STR
  1299. if( ERROR_SUCCESS != RegQueryValueEx(hKey, POLL_FLAGS_REG_STR, NULL, &ulType, (PBYTE)&dwFlag, &ulSize) )
  1300. dwFlag = 0;
  1301. RegCloseKey(hKey);
  1302. }
  1303. pDIJoyConfig->Unacquire();
  1304. ::PostMessage(GetDlgItem(ghDlg, IDC_POLLFLAGS), BM_SETCHECK, (dwFlag) ? BST_CHECKED : BST_UNCHECKED, 0);
  1305. }
  1306. break;
  1307. }
  1308. nIndex++;
  1309. }
  1310. }
  1311. // delete the DIJOYUSERVALUES variable
  1312. if( pDIJoyUserValues )
  1313. delete pDIJoyUserValues;
  1314. // clean up, clean up... everybody do your share!
  1315. if( lpdiJoyInfo )
  1316. delete (lpdiJoyInfo);
  1317. // VERIFY(SendMessage(hCtrl, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)lpstrNone) != CB_ERR);
  1318. }
  1319. #endif
  1320. ///////////////////////////////////////////////////////////////////////////////
  1321. // FUNCTION: SubClassProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  1322. //
  1323. // PARAMETERS: HWND hWnd -
  1324. // UINT uMsg -
  1325. // WPARAM wParam -
  1326. // LPARAM lParam -
  1327. //
  1328. // PURPOSE: SubClass Procedure for Setting the ID to NONE on VK_DELETE on the Advanced Page
  1329. ///////////////////////////////////////////////////////////////////////////////
  1330. BOOL WINAPI KeySubClassProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  1331. {
  1332. switch( uMsg )
  1333. {
  1334. case WM_COMMAND:
  1335. switch( LOWORD(wParam) )
  1336. {
  1337. case IDCANCEL:
  1338. case IDOK:
  1339. if( nFlags & UPDATE_INPROCESS )
  1340. {
  1341. bProcess = (LOWORD(wParam) == IDOK) ? TRUE : FALSE;
  1342. SetFocus(hAdvListCtrl);
  1343. nFlags &= ~UPDATE_INPROCESS;
  1344. return(FALSE);
  1345. }
  1346. break;
  1347. }
  1348. break;
  1349. }
  1350. return(BOOL)CallWindowProc(fpPageWndProc, hWnd, uMsg, wParam, lParam);
  1351. }
  1352. ///////////////////////////////////////////////////////////////////////////////
  1353. // FUNCTION: SubClassProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  1354. //
  1355. // PARAMETERS: HWND hWnd -
  1356. // UINT uMsg -
  1357. // WPARAM wParam -
  1358. // LPARAM lParam -
  1359. //
  1360. // PURPOSE: SubClass Procedure for Setting the ID to NONE on VK_DELETE on the Advanced Page
  1361. ///////////////////////////////////////////////////////////////////////////////
  1362. BOOL WINAPI SubClassProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  1363. {
  1364. switch( uMsg )
  1365. {
  1366. case WM_PARENTNOTIFY:
  1367. if( LOWORD(wParam) == WM_LBUTTONDOWN )
  1368. {
  1369. if( nFlags & UPDATE_INPROCESS )
  1370. SetFocus(hAdvListCtrl);
  1371. }
  1372. break;
  1373. case WM_SYSCOMMAND:
  1374. if( wParam & SC_VSCROLL )
  1375. {
  1376. if( nFlags & UPDATE_INPROCESS )
  1377. SetFocus(hAdvListCtrl);
  1378. }
  1379. break;
  1380. }
  1381. return(BOOL)CallWindowProc(fpMainWndProc, hWnd, uMsg, wParam, lParam);
  1382. }
  1383. ///////////////////////////////////////////////////////////////////////////////
  1384. // FUNCTION: UpdateChangeListCtrl ( HWND hCtrl )
  1385. //
  1386. // PARAMETERS: HWND hCtrl - Handle to Change list box
  1387. //
  1388. // PURPOSE: Update the Change List box
  1389. ///////////////////////////////////////////////////////////////////////////////
  1390. static BOOL UpdateChangeListCtrl ( HWND hCtrl )
  1391. {
  1392. #ifndef _UNICODE
  1393. USES_CONVERSION;
  1394. #endif
  1395. DIPROPSTRING *pDIPropStr = new (DIPROPSTRING);
  1396. ASSERT (pDIPropStr);
  1397. ZeroMemory(pDIPropStr, sizeof(DIPROPSTRING));
  1398. pDIPropStr->diph.dwSize = sizeof(DIPROPSTRING);
  1399. pDIPropStr->diph.dwHeaderSize = sizeof(DIPROPHEADER);
  1400. pDIPropStr->diph.dwHow = DIPH_DEVICE;
  1401. BYTE n = nAssigned;
  1402. LPTSTR lpStr = new (TCHAR[MAX_STR_LEN]);
  1403. ASSERT (lpStr);
  1404. // find and assign ID's
  1405. while( n-- )
  1406. {
  1407. if( SUCCEEDED(pAssigned[n]->fnDeviceInterface->GetProperty(DIPROP_INSTANCENAME, &pDIPropStr->diph)) )
  1408. {
  1409. // Our buffer is Only soooo big...
  1410. // besides, it just doesn't make sence to display Everything!
  1411. if( wcslen(pDIPropStr->wsz) > STR_LEN_64 )
  1412. {
  1413. pDIPropStr->wsz[60] = pDIPropStr->wsz[61] = pDIPropStr->wsz[62] = TEXT('.');
  1414. pDIPropStr->wsz[63] = TEXT('\0');
  1415. }
  1416. #ifdef _UNICODE
  1417. _tcscpy(lpStr, pDIPropStr->wsz);
  1418. #else
  1419. _tcscpy(lpStr, W2A(pDIPropStr->wsz));
  1420. #endif
  1421. // Put the first bracket on...
  1422. _tcscat(lpStr, TEXT(" ("));
  1423. // Now, get the productname of the device!
  1424. if( SUCCEEDED(pAssigned[n]->fnDeviceInterface->GetProperty(DIPROP_PRODUCTNAME, &pDIPropStr->diph)) )
  1425. {
  1426. #ifdef _UNICODE
  1427. _tcscat(lpStr, pDIPropStr->wsz);
  1428. #else
  1429. _tcscat(lpStr, W2A(pDIPropStr->wsz));
  1430. #endif
  1431. }
  1432. // put the end bracket on...
  1433. _tcscat(lpStr, TEXT(")"));
  1434. BYTE n1 = (BYTE)SendMessage(hCtrl, LB_ADDSTRING, 0, (LPARAM)(LPCTSTR)lpStr);
  1435. SendMessage(hCtrl, LB_SETITEMDATA, n1, pAssigned[n]->ID);
  1436. }
  1437. #ifdef _DEBUG
  1438. else OutputDebugString(TEXT("JOY.CPL: Advanced.cpp: UpdateChangeListCtrl: GetProperty failed!\n"));
  1439. #endif // _DEBUG
  1440. }
  1441. if( lpStr )
  1442. delete[] (lpStr);
  1443. if( pDIPropStr )
  1444. delete (pDIPropStr);
  1445. return(TRUE);
  1446. }
  1447. ///////////////////////////////////////////////////////////////////////////////
  1448. // FUNCTION: itoa(BYTE n, LPTSTR lpStr)
  1449. //
  1450. // PARAMETERS: BYTE n - Number to be translated
  1451. // LPTSTR lpStr - Buffer to recieve translated value
  1452. //
  1453. // PURPOSE: Convert BYTE values < 20 to strings.
  1454. ///////////////////////////////////////////////////////////////////////////////
  1455. void itoa(BYTE n, LPTSTR lpStr)
  1456. {
  1457. // designed for use with the CPL ONLY!
  1458. // Only supports values < NUMJOYDEVS!
  1459. if( n > NUMJOYDEVS )
  1460. {
  1461. #ifdef _DEBUG
  1462. OutputDebugString(TEXT("JOY.CPL: itoa: n > NUMJOYDEVS!\n"));
  1463. #endif
  1464. return;
  1465. }
  1466. lpStr[0] = n % 10 + '0';
  1467. if( n > 9 )
  1468. {
  1469. // Reverse the string and send it back...
  1470. lpStr[1] = lpStr[0];
  1471. lpStr[0] = '1';
  1472. lpStr[2] = '\0';
  1473. } else lpStr[1] = '\0';
  1474. }
  1475. int CALLBACK CompareIDItems(LPARAM item1, LPARAM item2, LPARAM uDirection)
  1476. {
  1477. if( LOWORD(item1) == LOWORD(item2) )
  1478. return(0);
  1479. short nRet = (LOWORD(item1) > LOWORD(item2)) ? 1 : -1;
  1480. return(uDirection) ? nRet : (nRet < 0) ? 1 : -1;
  1481. }
  1482. void LaunchChange( HWND hTmp )
  1483. {
  1484. // Don't allow if you're in USER mode!
  1485. if( (nFlags & USER_MODE) )
  1486. return;
  1487. iAdvItem = (short)::SendMessage(hAdvListCtrl, LVM_GETNEXTITEM, (WPARAM)(int)-1, MAKELPARAM(LVNI_SELECTED, 0));
  1488. nOldID = (BYTE)GetItemData(hAdvListCtrl, (BYTE)iAdvItem);
  1489. if( nOldID & ID_NONE )
  1490. return;
  1491. // valid returns are IDOK, IDCANCEL, and IDC_CHANGE_LIST
  1492. if( IDCANCEL != DialogBox(ghInstance, (PTSTR)IDD_ADV_CHANGE, ghDlg, ChangeDialogProc) )
  1493. {
  1494. // Yeah, it's not really a DEVICEARRIVAL...
  1495. ::SendMessage(hTmp, WM_DEVICECHANGE, DBT_DEVICEARRIVAL, 0);
  1496. ::PostMessage(hAdvListCtrl, LVM_ENSUREVISIBLE, (BYTE)iAdvItem, TRUE);
  1497. SetFocus(hAdvListCtrl);
  1498. SetListCtrlItemFocus(hAdvListCtrl, (BYTE)iAdvItem);
  1499. }
  1500. }
  1501. ///////////////////////////////////////////////////////////////////////////////
  1502. // FUNCTION: SortTextItems( CListCtrl *pCtrl, short nCol, BOOL bAscending, int low, int high )
  1503. //
  1504. // SortTextItems - Sort the list based on column text
  1505. //
  1506. // PARAMETERS:
  1507. // pCtrl - pointer to list to sort
  1508. // nCol - column that contains the text to be sorted
  1509. // bAscending - indicate sort order
  1510. // low - row to start scanning from - default row is 0
  1511. // high - row to end scan. -1 indicates last row
  1512. //
  1513. // PURPOSE: Sort text items in ListCtrl
  1514. // Returns - Returns true for success
  1515. ///////////////////////////////////////////////////////////////////////////////
  1516. BOOL SortTextItems( CListCtrl *pCtrl, short nCol, BOOL bAscending, short low, short high )
  1517. {
  1518. CHeaderCtrl* pHeader = (CHeaderCtrl*) pCtrl->GetDlgItem(0);
  1519. if( nCol >= pHeader->GetItemCount() )
  1520. return(FALSE);
  1521. if( high == -1 )
  1522. high = pCtrl->GetItemCount() - 1;
  1523. short lo = low;
  1524. short hi = high;
  1525. if( hi <= lo ) return(FALSE);
  1526. // The choices here are to malloc a buffer large enough for the largest
  1527. // string, or malloc an LV_ITEM struct to get the length, then malloc
  1528. // just the size we need.
  1529. CString midItem = pCtrl->GetItemText( (lo+hi)/2, nCol );
  1530. // loop through the list until indices cross
  1531. while( lo <= hi )
  1532. {
  1533. // rowText will hold all column text for one row
  1534. CStringArray rowText;
  1535. // find the first element that is greater than or equal to
  1536. // the partition element starting from the left Index.
  1537. if( bAscending )
  1538. while( ( lo < high ) && ( pCtrl->GetItemText(lo, nCol) < midItem ) )
  1539. ++lo;
  1540. else
  1541. while( ( lo < high ) && ( pCtrl->GetItemText(lo, nCol) > midItem ) )
  1542. ++lo;
  1543. // find an element that is smaller than or equal to
  1544. // the partition element starting from the right Index.
  1545. if( bAscending )
  1546. while( ( hi > low ) && ( pCtrl->GetItemText(hi, nCol) > midItem ) )
  1547. --hi;
  1548. else
  1549. while( ( hi > low ) && ( pCtrl->GetItemText(hi, nCol) < midItem ) )
  1550. --hi;
  1551. // if the indexes have not crossed, swap
  1552. // and if the items are not equal
  1553. if( lo <= hi )
  1554. {
  1555. // swap only if the items are not equal
  1556. if( pCtrl->GetItemText(lo, nCol) != pCtrl->GetItemText(hi, nCol) )
  1557. {
  1558. // swap the rows
  1559. LV_ITEM lvitemlo, lvitemhi;
  1560. BYTE nColCount = (BYTE)pHeader->GetItemCount();
  1561. rowText.SetSize( nColCount );
  1562. for( BYTE i = 0; i < nColCount; i++ )
  1563. rowText[i] = pCtrl->GetItemText(lo, i);
  1564. lvitemlo.mask = LVIF_IMAGE | LVIF_PARAM | LVIF_STATE;
  1565. lvitemlo.iItem = lo;
  1566. lvitemlo.iSubItem = 0;
  1567. lvitemlo.stateMask = LVIS_CUT | LVIS_DROPHILITED | LVIS_FOCUSED | LVIS_SELECTED | LVIS_OVERLAYMASK | LVIS_STATEIMAGEMASK;
  1568. lvitemhi = lvitemlo;
  1569. lvitemhi.iItem = hi;
  1570. ListView_GetItem(pCtrl->GetSafeHwnd(), &lvitemlo );
  1571. ListView_GetItem(pCtrl->GetSafeHwnd(), &lvitemhi );
  1572. for( i=0; i<nColCount; i++ )
  1573. pCtrl->SetItemText(lo, i, pCtrl->GetItemText(hi, i));
  1574. lvitemhi.iItem = lo;
  1575. ListView_SetItem(pCtrl->GetSafeHwnd(), &lvitemhi );
  1576. for( i=0; i<nColCount; i++ )
  1577. pCtrl->SetItemText(hi, i, rowText[i]);
  1578. lvitemlo.iItem = hi;
  1579. ListView_SetItem(pCtrl->GetSafeHwnd(), &lvitemlo );
  1580. }
  1581. ++lo;
  1582. --hi;
  1583. }
  1584. }
  1585. // If the right index has not reached the left side of array
  1586. // must now sort the left partition.
  1587. if( low < hi )
  1588. SortTextItems( pCtrl, nCol, bAscending, low, hi);
  1589. // If the left index has not reached the right side of array
  1590. // must now sort the right partition.
  1591. if( lo < high )
  1592. SortTextItems( pCtrl, nCol, bAscending, lo, high);
  1593. return(TRUE);
  1594. }
  1595. ///////////////////////////////////////////////////////////////////////////////
  1596. // FUNCTION: EditSubLabel( BYTE nItem, BYTE nCol )
  1597. //
  1598. // PARAMETERS:
  1599. // EditSubLabel - Start edit of a sub item label
  1600. // Returns - Temporary pointer to the new edit control
  1601. // nItem - The row index of the item to edit
  1602. // nCol - The column of the sub item.
  1603. // PURPOSE: Provide editing services for any column in a CListCtrl
  1604. ///////////////////////////////////////////////////////////////////////////////
  1605. void EditSubLabel( BYTE nItem, BYTE nCol )
  1606. {
  1607. #ifdef _DEBUG
  1608. // Make sure that the item is visible
  1609. if( !SendMessage(hAdvListCtrl, LVM_ENSUREVISIBLE, nItem, TRUE ) )
  1610. {
  1611. OutputDebugString(TEXT("JOY.CPL: ADVANCED.CPP: EditSubLabel: requested item not visible!\n"));
  1612. return;
  1613. }
  1614. #endif // _DEBUG
  1615. // Get the column offset
  1616. short offset = 0;
  1617. BYTE i = 0;
  1618. // OK, so here's what we have to do...
  1619. // Traverse the columns incrementing the widths of the ones lesser than the one we're looking for!
  1620. HDITEM *phdItem = new (HDITEM);
  1621. ASSERT (phdItem);
  1622. phdItem->mask = HDI_ORDER | HDI_WIDTH;
  1623. HWND hHeader = GetDlgItem(hAdvListCtrl, 0);
  1624. BYTE nColumns = (BYTE)::SendMessage(hHeader, HDM_GETITEMCOUNT, 0, 0L);
  1625. BYTE nColWidth;
  1626. do
  1627. {
  1628. ::SendMessage(hHeader, HDM_GETITEM, (WPARAM)(int)--nColumns, (LPARAM)(LPHDITEM)phdItem);
  1629. if( phdItem->iOrder < nCol )
  1630. offset += (short)phdItem->cxy;
  1631. if( phdItem->iOrder == nCol )
  1632. nColWidth = (BYTE)phdItem->cxy;
  1633. } while( nColumns );
  1634. if( phdItem )
  1635. delete (phdItem);
  1636. RECT rect;
  1637. ListView_GetItemRect(hAdvListCtrl, nItem, &rect, LVIR_BOUNDS );
  1638. // Now scroll if we need to expose the column
  1639. CRect rcClient;
  1640. ::GetClientRect(hAdvListCtrl, &rcClient);
  1641. if( offset + rect.left < 0 || offset + rect.left > rcClient.right )
  1642. {
  1643. ::SendMessage(hAdvListCtrl, LVM_SCROLL, (WPARAM)(int)offset + rect.left, (LPARAM)(int)0);
  1644. rect.left -= (offset + rect.left);
  1645. }
  1646. rect.left += offset+4;
  1647. rect.right = rect.left + nColWidth - 3; // + ::SendMessage(hAdvListCtrl, LVM_GETCOLUMNWIDTH, (WPARAM)(int)nCol, (LPARAM)0L) - 3 ;
  1648. if( rect.right > rcClient.right )
  1649. rect.right = rcClient.right;
  1650. CEdit *pEdit = new CInPlaceEdit(nItem, 1);
  1651. ASSERT (pEdit);
  1652. // malloc the list ctrl
  1653. CWnd *pListCtrl = new (CWnd);
  1654. ASSERT (pListCtrl);
  1655. pListCtrl->Attach(hAdvListCtrl);
  1656. pEdit->Create(WS_BORDER | WS_CHILD | WS_VISIBLE | ES_AUTOHSCROLL | ES_CENTER, rect, pListCtrl, IDC_IPEDIT );
  1657. pListCtrl->Detach();
  1658. if( pListCtrl )
  1659. delete (pListCtrl);
  1660. }
  1661. #ifdef _UNICODE
  1662. void SwapIDs(BYTE nSource, BYTE nTarget)
  1663. {
  1664. // malloc and retrieve the data from the selected item
  1665. LPDIJOYCONFIG lpSelectedID = new (DIJOYCONFIG);
  1666. ASSERT (lpSelectedID);
  1667. ZeroMemory(lpSelectedID, sizeof(DIJOYCONFIG));
  1668. lpSelectedID->dwSize = sizeof(DIJOYCONFIG);
  1669. // Get the Config of device on ID taken from Change List box!
  1670. HRESULT hr = pDIJoyConfig->GetConfig(nSource, lpSelectedID, DIJC_ALL);
  1671. if( hr == DIERR_NOTFOUND || hr == S_FALSE )
  1672. {
  1673. // No Object on Selected ID!
  1674. if( lpSelectedID )
  1675. delete (lpSelectedID);
  1676. lpSelectedID = NULL;
  1677. }
  1678. // malloc and retrieve the data from the item associated
  1679. // with the ID taken from the Item selected in the List box!
  1680. LPDIJOYCONFIG lpSelectedItem = new (DIJOYCONFIG);
  1681. ASSERT (lpSelectedItem);
  1682. ZeroMemory(lpSelectedItem, sizeof(DIJOYCONFIG));
  1683. lpSelectedItem->dwSize = sizeof (DIJOYCONFIG);
  1684. hr = pDIJoyConfig->GetConfig(nTarget, lpSelectedItem, DIJC_ALL);
  1685. if( hr == DIERR_NOTFOUND || hr == S_FALSE )
  1686. {
  1687. if( lpSelectedItem )
  1688. delete (lpSelectedItem);
  1689. lpSelectedItem = NULL;
  1690. }
  1691. // ***********************************************************
  1692. // Delete the configurations!
  1693. // ***********************************************************
  1694. // Set the hour glass
  1695. SetCursor(LoadCursor(NULL, IDC_WAIT));
  1696. // ********************************************************
  1697. // OK, now... at this point you have:
  1698. // lpSelectedID: containing NULL if the device wasn't present or...
  1699. // a valid pointer containing the configuration of nSelectedID
  1700. // lpSelected : containing NULL if the device wasn't present or...
  1701. // a valid pointer containing the configuration of id
  1702. // ********************************************************
  1703. // Time to Set the Configurations!
  1704. if( lpSelectedID )
  1705. {
  1706. hr = pDIJoyConfig->SetConfig(nTarget, lpSelectedID, DIJC_ALL);
  1707. if( lpSelectedID )
  1708. delete (lpSelectedID);
  1709. } else pDIJoyConfig->DeleteConfig(nSource);
  1710. // delete both configurations
  1711. // pointers will be NULL if the config was not found!
  1712. if( lpSelectedItem )
  1713. {
  1714. hr = pDIJoyConfig->SetConfig(nSource, lpSelectedItem, DIJC_ALL );
  1715. if( lpSelectedItem )
  1716. delete (lpSelectedItem);
  1717. }
  1718. pDIJoyConfig->SendNotify();
  1719. // Set the hour glass
  1720. SetCursor(LoadCursor(NULL, IDC_ARROW));
  1721. }
  1722. #else
  1723. // Memphis version of SwapIDs...
  1724. // Caution!!! Very Sensitive!!!
  1725. void SwapIDs(BYTE nSelectedID, BYTE nSelectedItem)
  1726. {
  1727. // malloc and retrieve the data from the selected item
  1728. LPDIJOYCONFIG lpSelectedID = new (DIJOYCONFIG);
  1729. DWORD dwSelectedID = 0, dwSelectedItem = 0;
  1730. ASSERT (lpSelectedID);
  1731. ZeroMemory(lpSelectedID, sizeof(DIJOYCONFIG));
  1732. lpSelectedID->dwSize = sizeof(DIJOYCONFIG);
  1733. // Get the Config of device on ID taken from Change List box!
  1734. HRESULT hr = pDIJoyConfig->GetConfig(nSelectedID, lpSelectedID, DIJC_ALL);
  1735. if( hr == DIERR_NOTFOUND || hr == S_FALSE )
  1736. {
  1737. // No Object on Selected ID!
  1738. if( lpSelectedID )
  1739. delete (lpSelectedID);
  1740. lpSelectedID = NULL;
  1741. } else {
  1742. if( lpSelectedID )
  1743. delete (lpSelectedID);
  1744. lpSelectedID = NULL;
  1745. Error((short)IDS_DEST_ID_OCCUPIED_TITLE, (short)IDS_DEST_ID_OCCUPIED);
  1746. return;
  1747. }
  1748. // malloc and retrieve the data from the item associated
  1749. // with the ID taken from the Item selected in the List box!
  1750. LPDIJOYCONFIG lpSelectedItem = new (DIJOYCONFIG);
  1751. ASSERT (lpSelectedItem);
  1752. ZeroMemory(lpSelectedItem, sizeof(DIJOYCONFIG));
  1753. lpSelectedItem->dwSize = sizeof (DIJOYCONFIG);
  1754. hr = pDIJoyConfig->GetConfig(nSelectedItem, lpSelectedItem, DIJC_ALL);
  1755. if( hr == DIERR_NOTFOUND || hr == S_FALSE )
  1756. {
  1757. if( lpSelectedItem )
  1758. delete (lpSelectedItem);
  1759. lpSelectedItem = NULL;
  1760. return;
  1761. }
  1762. // ***********************************************************
  1763. // Delete the configurations!
  1764. // ***********************************************************
  1765. // Set the hour glass
  1766. SetCursor(LoadCursor(NULL, IDC_WAIT));
  1767. // ********************************************************
  1768. // OK, now... at this point you have:
  1769. // lpSelectedID: containing NULL if the device wasn't present or...
  1770. // a valid pointer containing the configuration of nSelectedID
  1771. // lpSelected : containing NULL if the device wasn't present or...
  1772. // a valid pointer containing the configuration of id
  1773. // ********************************************************
  1774. // Time to Set the Configurations!
  1775. if( lpSelectedID )
  1776. {
  1777. DWORD dwFlags = DIJC_REGHWCONFIGTYPE | DIJC_CALLOUT | DIJC_GAIN | DIJC_GUIDINSTANCE;
  1778. USES_CONVERSION;
  1779. // if the callout is joyhid.vxd then the device is USB so...
  1780. // OR on the DIJC_WDMGAMEPORT flag!
  1781. if( !_stricmp(TEXT("joyhid.vxd"), W2A(lpSelectedID->wszCallout)) )
  1782. {
  1783. // dwFlags |= DIJC_WDMGAMEPORT;
  1784. dwSelectedID = 2;
  1785. } else
  1786. {
  1787. dwSelectedID = 1;
  1788. }
  1789. if( dwSelectedID == 1 ) {
  1790. hr = pDIJoyConfig->DeleteConfig(nSelectedID);
  1791. /*
  1792. * This notify is to fix the bug changing id on 2-axis 2-button joystick.
  1793. */
  1794. pDIJoyConfig->SendNotify();
  1795. if( SUCCEEDED(hr) )
  1796. {
  1797. hr = pDIJoyConfig->SetConfig(nSelectedItem, lpSelectedID, dwFlags );
  1798. if( SUCCEEDED(hr) ) {
  1799. pDIJoyConfig->SendNotify();
  1800. }
  1801. }
  1802. } else {
  1803. hr = pDIJoyConfig->SetConfig(nSelectedItem, lpSelectedID, dwFlags);
  1804. pDIJoyConfig->SendNotify();
  1805. if( SUCCEEDED(hr) )
  1806. {
  1807. hr = pDIJoyConfig->DeleteConfig(nSelectedID);
  1808. pDIJoyConfig->SendNotify();
  1809. if( nSelectedID < nSelectedItem ) {
  1810. pDIJoyConfig->SendNotify();
  1811. }
  1812. }
  1813. }
  1814. if( lpSelectedID )
  1815. delete (lpSelectedID);
  1816. }
  1817. // delete both configurations
  1818. // pointers will be NULL if the config was not found!
  1819. if( lpSelectedItem )
  1820. {
  1821. DWORD dwFlags = DIJC_REGHWCONFIGTYPE | DIJC_CALLOUT | DIJC_GAIN | DIJC_GUIDINSTANCE;
  1822. USES_CONVERSION;
  1823. if( _tcsicmp(TEXT("joyhid.vxd"), W2A(lpSelectedItem->wszCallout)) == 0 )
  1824. {
  1825. // dwFlags |= DIJC_WDMGAMEPORT;
  1826. dwSelectedItem = 2; //joyhid.vxd
  1827. }
  1828. #if 0
  1829. /*
  1830. * Since MSGAME.VXD will directly write to the registry with some unhealthy data.
  1831. * We have to change it before we move to other ID.
  1832. */
  1833. else if( _tcsicmp(TEXT("MSGAME.VXD"), W2A(lpSelectedItem->wszCallout)) == 0 )
  1834. {
  1835. lpSelectedItem->hwc.dwType += 1;
  1836. dwSelectedItem = 3; //msgame.vxd (Sidewinder driver)
  1837. }
  1838. #endif
  1839. else {
  1840. dwSelectedItem = 1; //vjoyd.vxd
  1841. }
  1842. if( dwSelectedItem == 1 // VJOYD.VXD,
  1843. // || dwSelectedItem == 3
  1844. ){ // MSGAME.VXD
  1845. hr = pDIJoyConfig->DeleteConfig(nSelectedItem);
  1846. /*
  1847. * This notify is to fix the bug changing id on 2-axis 2-button joystick.
  1848. */
  1849. pDIJoyConfig->SendNotify();
  1850. if( SUCCEEDED(hr) )
  1851. {
  1852. hr = pDIJoyConfig->SetConfig(nSelectedID, lpSelectedItem, dwFlags );
  1853. if( SUCCEEDED(hr) ) {
  1854. pDIJoyConfig->SendNotify();
  1855. }
  1856. }
  1857. } else {
  1858. hr = pDIJoyConfig->SetConfig(nSelectedID, lpSelectedItem, dwFlags );
  1859. /*
  1860. * This notify is to fix the bug changing id on 2-axis 2-button joystick.
  1861. */
  1862. pDIJoyConfig->SendNotify();
  1863. if( SUCCEEDED(hr) )
  1864. {
  1865. hr = pDIJoyConfig->DeleteConfig(nSelectedItem);
  1866. pDIJoyConfig->SendNotify();
  1867. if( nSelectedID < nSelectedItem ) {
  1868. pDIJoyConfig->SendNotify();
  1869. }
  1870. }
  1871. }
  1872. if( lpSelectedItem )
  1873. {
  1874. delete (lpSelectedItem);
  1875. }
  1876. }
  1877. // Set the hour glass
  1878. SetCursor(LoadCursor(NULL, IDC_ARROW));
  1879. }
  1880. #endif