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

2887 lines
89 KiB

  1. /*
  2. * File: Cpanel.cpp
  3. * Project: Universal Joystick Control Panel OLE Client
  4. * Author: Brycej
  5. * Date: 02/08/95 - Started this maddness...
  6. * 04/15/97 - Updated to use DI interface
  7. * Comments:
  8. * window proc for General page in cpanel
  9. *
  10. * Copyright (c) 1995, Microsoft Corporation
  11. */
  12. /*
  13. // This is necessary LVS_EX_INFOTIP
  14. #if (_WIN32_IE < 0x0500)
  15. #undef _WIN32_IE
  16. #define _WIN32_IE 0x0500
  17. #endif
  18. */
  19. #include <afxcmn.h>
  20. #include <windowsx.h>
  21. #ifndef _UNICODE
  22. #define INC_OLE2
  23. #include <objbase.h> // For COM stuff!
  24. #endif
  25. #include <initguid.h>
  26. #include <cpl.h>
  27. #include <winuser.h> // For RegisterDeviceNotification stuff!
  28. #include <dbt.h> // for DBT_ defines!!!
  29. #include <hidclass.h>
  30. #include <malloc.h> // for _alloca
  31. #include <regstr.h> // for REGSTR_PATH_JOYOEM reference!
  32. #include "hsvrguid.h"
  33. #include "cpanel.h"
  34. #include "resource.h"
  35. #include "joyarray.h"
  36. // constants
  37. const short ID_MYTIMER = 1000;
  38. const short POLLRATE = 850;
  39. const short NO_ITEM = -1;
  40. #define IDC_WHATSTHIS 400
  41. // externs
  42. extern const DWORD gaHelpIDs[];
  43. extern HINSTANCE ghInstance;
  44. // externs for arguements!
  45. extern BYTE nID, nStartPageDef, nStartPageCPL;
  46. // DI globals
  47. IDirectInputJoyConfig* pDIJoyConfig = 0;
  48. LPDIRECTINPUT lpDIInterface = 0;
  49. // Array of all available devices
  50. #ifndef _UNICODE
  51. WCHAR *pwszGameportDriverArray[MAX_GLOBAL_PORT_DRIVERS]; // List of enumerated Gameport Drivers
  52. BYTE nGameportDriver; // Global Port Driver Enumeration Counter
  53. #endif
  54. WCHAR *pwszTypeArray[MAX_DEVICES]; // List of enumerated devices
  55. WCHAR *pwszGameportBus[MAX_BUSSES]; // List of enumerated gameport buses
  56. PJOY pAssigned[MAX_ASSIGNED]; // List of assigned devices
  57. BYTE nGamingDevices; // Gaming Devices Enumeration Counter
  58. BYTE nGameportBus; // Gameport Bus Enumeration Counter
  59. BYTE nAssigned; // Number of elements in pAssigned array
  60. BYTE nTargetAssigned; // Number of elements expected in pAssigned array when pending adds complete
  61. BYTE nReEnum; // Counter used to decide when to reenumerate
  62. GUID guidOccupied[MAX_BUSSES]; //Whether the gameport bus has been occupied.
  63. short nFlags; // Flags for Update, User Mode, and if the user is on this page!
  64. // local (module-scope) variables
  65. static HWND hListCtrl;
  66. short iItem = NO_ITEM; // index of selected item
  67. extern short iAdvItem;
  68. // Global to avoid creating in timer!
  69. static LPDIJOYSTATE lpDIJoyState;
  70. static UINT JoyCfgChangedMsg; // vjoyd JoyConfigChanged message
  71. static BOOL WINAPI MsgSubClassProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
  72. static WNDPROC fpMainWindowProc;
  73. #ifdef _UNICODE
  74. static PVOID hNotifyDevNode;
  75. #endif
  76. // local message handlers
  77. static BOOL OnInitDialog (HWND, HWND, LPARAM);
  78. static void OnCommand (HWND, int, HWND, UINT);
  79. static BOOL OnNotify (HWND, WPARAM, NMHDR*);
  80. static void OnDestroy (HWND);
  81. static void OnListViewContextMenu (HWND hDlg, LPARAM lParam);
  82. #ifndef _UNICODE
  83. BOOL AddListCtrlItem(BYTE nItemID, LPDIJOYCONFIG pJoyConfig);
  84. #endif
  85. // Share these with Add.cpp
  86. void OnContextMenu (WPARAM wParam, LPARAM lParam);
  87. void OnHelp (LPARAM);
  88. #ifdef WINNT
  89. // Share this one with Advanced.cpp
  90. void RunWDMJOY ( void );
  91. #endif
  92. // local utility fns
  93. static BOOL DetectHotplug ( HWND hDlg, BYTE nItemSelected );
  94. static BOOL SetActive ( HWND hDlg );
  95. static void UpdateListCtrl ( HWND hDlg );
  96. static void UpdateButtonState ( HWND hDlg );
  97. static void StatusChanged ( HWND hDlg, BYTE i );
  98. JOY::JOY()
  99. {
  100. ID = nStatus = nButtons = -1;
  101. clsidPropSheet = CLSID_LegacyServer;
  102. fnDeviceInterface = 0;
  103. }
  104. JOY::~JOY()
  105. {
  106. if( fnDeviceInterface )
  107. {
  108. fnDeviceInterface->Unacquire();
  109. fnDeviceInterface->Release();
  110. fnDeviceInterface = 0;
  111. }
  112. }
  113. ///////////////////////////////////////////////////////////////////////////////
  114. //CPanelProc(HWND hDlg, ULONG uMsg, WPARAM wParam, LPARAM lParam)
  115. ///////////////////////////////////////////////////////////////////////////////
  116. BOOL WINAPI CPanelProc(HWND hDlg, ULONG uMsg, WPARAM wParam, LPARAM lParam)
  117. {
  118. switch( uMsg )
  119. {
  120. case WM_ACTIVATEAPP:
  121. if( nFlags & ON_PAGE )
  122. {
  123. if( wParam )
  124. {
  125. if( nFlags & UPDATE_FOR_GEN )
  126. {
  127. nFlags &= ~UPDATE_FOR_GEN;
  128. UpdateListCtrl(hDlg);
  129. }
  130. // Set the focus!
  131. if( nAssigned )
  132. {
  133. if( iItem == NO_ITEM )
  134. iItem = 0;
  135. if( pDIJoyConfig )
  136. SetActive(hDlg);
  137. // restore selection focus
  138. SetListCtrlItemFocus(hListCtrl, (BYTE)iItem);
  139. } else {
  140. UpdateButtonState(hDlg);
  141. }
  142. // the user is requesting that the CPL be shown
  143. // and an extention associated with nID be Launched.
  144. if( nID < NUMJOYDEVS )
  145. {
  146. BYTE nCount = (BYTE)::SendMessage(hListCtrl, LVM_GETITEMCOUNT, 0, 0);
  147. while( nCount-- )
  148. {
  149. if( pAssigned[GetItemData(hListCtrl, (BYTE)iItem)]->ID == nID )
  150. {
  151. KillTimer(hDlg, ID_MYTIMER);
  152. OnCommand(hDlg, IDC_BTN_PROPERTIES, 0, 0);
  153. SetTimer(hDlg, ID_MYTIMER, POLLRATE, 0);
  154. break;
  155. }
  156. }
  157. // just to get nID > NUMJOYDEVS!
  158. nID = (NUMJOYDEVS<<1);
  159. }
  160. } else
  161. {
  162. KillTimer(hDlg, ID_MYTIMER);
  163. }
  164. }
  165. break;
  166. case WM_LBUTTONDOWN:
  167. // Click Drag service for PropSheets!
  168. PostMessage(GetParent(hDlg), WM_NCLBUTTONDOWN, (WPARAM)HTCAPTION, lParam);
  169. break;
  170. case WM_INITDIALOG:
  171. if( !HANDLE_WM_INITDIALOG(hDlg, wParam, lParam, OnInitDialog) )
  172. {
  173. // Fix #108983 NT, Remove Flash on Error condition.
  174. SetWindowPos(::GetParent(hDlg), HWND_BOTTOM, 0, 0, 0, 0, SWP_HIDEWINDOW);
  175. DestroyWindow(hDlg);
  176. }
  177. // if we want to set focus, get the control hWnd
  178. // and set it as the wParam.
  179. return(TRUE);
  180. case WM_DESTROY:
  181. HANDLE_WM_DESTROY(hDlg, wParam, lParam, OnDestroy);
  182. return(1);
  183. // OnTimer
  184. case WM_TIMER:
  185. {
  186. BYTE i = nAssigned;
  187. BYTE nButtons;
  188. BYTE nLoop;
  189. if( nReEnum )
  190. {
  191. if( !( --nReEnum & 3 ) )
  192. {
  193. // ISSUE-2001/03/29-timgill Much used code
  194. // (MarcAnd) I hope this code is generally appropriate
  195. // it appears in much the same form all over the place.
  196. KillTimer(hDlg, ID_MYTIMER);
  197. // Set the Update Flag!
  198. nFlags |= UPDATE_ALL;
  199. UpdateListCtrl(hDlg);
  200. SetActive(hDlg);
  201. SetTimer(hDlg, ID_MYTIMER, POLLRATE, 0);
  202. }
  203. }
  204. while( i-- )
  205. {
  206. if( pAssigned[i]->fnDeviceInterface )
  207. {
  208. int nPollFail;
  209. pAssigned[i]->fnDeviceInterface->Acquire();
  210. // LOOKOUT RE-USE of nButtons!
  211. nButtons = pAssigned[i]->nStatus;
  212. nLoop = 5;
  213. nPollFail = 0;
  214. // Special work for the sidewinder folks...
  215. // ACT LAB: You can't poll actrs.vxd (ACT LAB) too often, otherwise it fails.
  216. // See Manbug 41049. - qzheng 8/1/2000
  217. do
  218. {
  219. if( FAILED(pAssigned[i]->fnDeviceInterface->Poll()) ) {
  220. nPollFail ++;
  221. } else {
  222. break;
  223. }
  224. Sleep(30);
  225. } while( nLoop-- );
  226. // Check to see if things have changed!
  227. pAssigned[i]->nStatus = (nPollFail > 2) ? (BYTE)0 : (BYTE)JOY_US_PRESENT;
  228. if( pAssigned[i]->nStatus != nButtons )
  229. {
  230. StatusChanged(hDlg, i);
  231. }
  232. // Check for button press and set focus to it!!!
  233. if( pAssigned[i]->nStatus == JOY_US_PRESENT )
  234. {
  235. // Do the button press launch thing!
  236. if( SUCCEEDED(pAssigned[i]->fnDeviceInterface->GetDeviceState(sizeof(DIJOYSTATE), lpDIJoyState)) )
  237. {
  238. nButtons = pAssigned[i]->nButtons;
  239. // run up the list of buttons and check if there's one that's down!
  240. while( nButtons-- )
  241. {
  242. if( lpDIJoyState->rgbButtons[nButtons] & 0x80 )
  243. {
  244. // SetFocus on Selected Item
  245. SetListCtrlItemFocus(hListCtrl, i);
  246. break;
  247. }
  248. }
  249. }
  250. }
  251. }
  252. }
  253. if( nAssigned ) {
  254. /*
  255. * If the selected device is "Not Connected", grey out the property button.
  256. */
  257. int id = GetItemData(hListCtrl, (BYTE)iItem);
  258. PostDlgItemEnableWindow(hDlg, IDC_BTN_PROPERTIES, (BOOL)(pAssigned[id]->nStatus & JOY_US_PRESENT));
  259. }
  260. }
  261. break;
  262. case WM_COMMAND:
  263. HANDLE_WM_COMMAND(hDlg, wParam, lParam, OnCommand);
  264. return(1);
  265. case WM_NOTIFY:
  266. return(HANDLE_WM_NOTIFY(hDlg, wParam, lParam, OnNotify));
  267. case WM_POWERBROADCAST:
  268. switch( wParam )
  269. {
  270. case PBT_APMSUSPEND:
  271. // Suspend operation!
  272. KillTimer(hDlg, ID_MYTIMER);
  273. break;
  274. case PBT_APMRESUMESUSPEND:
  275. case PBT_APMRESUMECRITICAL:
  276. // Resume operation!
  277. SetActive(hDlg);
  278. break;
  279. }
  280. break;
  281. case WM_DEVICECHANGE:
  282. switch( (UINT)wParam )
  283. {
  284. case DBT_DEVICEQUERYREMOVE:
  285. {
  286. KillTimer(hDlg, ID_MYTIMER);
  287. BYTE i = (BYTE)::SendMessage(hListCtrl, LVM_GETITEMCOUNT, 0, 0);
  288. // Acquire All Devices that are Attached!!!
  289. char nIndex;
  290. while( i-- )
  291. {
  292. // get joystick config of item
  293. nIndex = (char)GetItemData(hListCtrl, i);
  294. if( pAssigned[nIndex]->nStatus & JOY_US_PRESENT )
  295. pAssigned[nIndex]->fnDeviceInterface->Unacquire();
  296. }
  297. }
  298. break;
  299. case DBT_DEVICEARRIVAL:
  300. case DBT_DEVICEREMOVECOMPLETE:
  301. if( nFlags & ON_PAGE )
  302. {
  303. PostMessage(hDlg, WM_COMMAND, IDC_BTN_REFRESH, 0);
  304. #if 0
  305. if( !(nFlags & BLOCK_UPDATE) )
  306. {
  307. KillTimer(hDlg, ID_MYTIMER);
  308. // Set the Update Flag!
  309. nFlags |= UPDATE_ALL;
  310. UpdateListCtrl(hDlg);
  311. SetActive(hDlg);
  312. SetTimer(hDlg, ID_MYTIMER, POLLRATE, 0);
  313. }
  314. #endif
  315. }
  316. break;
  317. }
  318. break;
  319. case WM_HELP:
  320. KillTimer(hDlg, ID_MYTIMER);
  321. OnHelp(lParam);
  322. SetTimer(hDlg, ID_MYTIMER, POLLRATE, 0);
  323. break;
  324. case WM_CONTEXTMENU:
  325. nFlags &= ~ON_PAGE;
  326. KillTimer(hDlg, ID_MYTIMER);
  327. OnContextMenu(wParam, lParam);
  328. nFlags |= ON_PAGE;
  329. SetTimer(hDlg, ID_MYTIMER, POLLRATE, 0);
  330. return(1);
  331. }
  332. return(0);
  333. }
  334. ///////////////////////////////////////////////////////////////////////////////
  335. // StatusChanged( HWND hDlg, BYTE i )
  336. ///////////////////////////////////////////////////////////////////////////////
  337. void StatusChanged( HWND hDlg, BYTE i )
  338. {
  339. // Update the buttons and set focus to changed item!
  340. PostDlgItemEnableWindow(hDlg, IDC_BTN_PROPERTIES, (BOOL)(pAssigned[i]->nStatus & JOY_US_PRESENT));
  341. if( pAssigned[0] )
  342. {
  343. PostDlgItemEnableWindow(hDlg, IDC_BTN_REMOVE, TRUE );
  344. }
  345. // Don't try to make this buffer any smaller...
  346. // Remember... we also have "Not Connected"!
  347. TCHAR sz[20];
  348. // display result
  349. VERIFY(LoadString(ghInstance, (pAssigned[i]->nStatus & JOY_US_PRESENT) ? IDS_GEN_STATUS_OK : IDS_GEN_STATUS_NOTCONNECTED, (LPTSTR)&sz, 20));
  350. LVFINDINFO *lpFindInfo = new (LVFINDINFO);
  351. ASSERT (lpFindInfo);
  352. ZeroMemory(lpFindInfo, sizeof(LVFINDINFO));
  353. lpFindInfo->flags = LVFI_PARAM;
  354. lpFindInfo->lParam = i;
  355. // Make sure you place i where it's suppose to be!
  356. i = (BYTE)::SendMessage(hListCtrl, LVM_FINDITEM, (WPARAM)(int)-1, (LPARAM)(const LVFINDINFO*)lpFindInfo);
  357. if( lpFindInfo )
  358. delete (lpFindInfo);
  359. SetItemText(hListCtrl, i, STATUS_COLUMN, sz);
  360. ::PostMessage(hListCtrl, LVM_UPDATE, (WPARAM)i, 0L);
  361. SetListCtrlItemFocus(hListCtrl, i);
  362. }
  363. ///////////////////////////////////////////////////////////////////////////////
  364. //OnInitDialog(HWND hDlg, HWND hWnd, LPARAM lParam)
  365. ///////////////////////////////////////////////////////////////////////////////
  366. BOOL OnInitDialog(HWND hDlg, HWND hWnd, LPARAM lParam)
  367. {
  368. // initialize our list control
  369. hListCtrl = GetDlgItem(hDlg, IDC_LIST_DEVICE);
  370. ASSERT(hListCtrl);
  371. // LVS_EX_ONECLICKACTIVATE removed per PSierra | LVS_EX_INFOTIP
  372. ::SendMessage(hListCtrl, LVM_SETEXTENDEDLISTVIEWSTYLE, 0, LVS_EX_FULLROWSELECT);
  373. if( !lpDIInterface )
  374. {
  375. if( FAILED(DirectInputCreate(ghInstance, DIRECTINPUT_VERSION, &lpDIInterface, NULL)) )
  376. {
  377. #ifdef _DEBUG
  378. OutputDebugString(TEXT("GCDEF.DLL: DirectInputCreate() failed\n"));
  379. #endif
  380. Error((short)IDS_INTERNAL_ERROR, (short)IDS_NO_DIJOYCONFIG);
  381. return(FALSE);
  382. }
  383. }
  384. // Dynamically size the columns!
  385. RECT rc;
  386. ::GetClientRect(hListCtrl, &rc);
  387. // cut the list control into 1/4ths
  388. rc.right >>= 2;
  389. // This one get's 3/4ths
  390. InsertColumn(hListCtrl, DEVICE_COLUMN, IDS_GEN_DEVICE_HEADING, (USHORT)(rc.right*3));
  391. // Column heading for Status
  392. InsertColumn(hListCtrl, STATUS_COLUMN, IDS_GEN_STATUS_HEADING, (USHORT)(rc.right+3));
  393. if( !pDIJoyConfig )
  394. {
  395. // just in case CoCreateInstanceFailed...
  396. if( FAILED(lpDIInterface->QueryInterface(IID_IDirectInputJoyConfig, (LPVOID*)&pDIJoyConfig)) )
  397. {
  398. #ifdef _DEBUG
  399. OutputDebugString (TEXT("JOY.CPL: CoCreateInstance Failed... Closing CPL!\n"));
  400. #endif
  401. Error((short)IDS_INTERNAL_ERROR, (short)IDS_NO_DIJOYCONFIG);
  402. return(FALSE);
  403. }
  404. VERIFY (SUCCEEDED(pDIJoyConfig->SetCooperativeLevel(hDlg, DISCL_EXCLUSIVE | DISCL_BACKGROUND)));
  405. }
  406. // Zero out the global counters!
  407. #ifndef _UNICODE
  408. nGameportDriver = 0;
  409. #endif
  410. nGamingDevices = nGameportBus = 0;
  411. // Try to Acquire, if you fail... Disable the Add and Remove buttons!
  412. if( pDIJoyConfig->Acquire() == DIERR_INSUFFICIENTPRIVS )
  413. {
  414. nFlags |= USER_MODE;
  415. LONG style = ::GetWindowLong(hListCtrl, GWL_STYLE);
  416. style &= ~LVS_EDITLABELS;
  417. ::SetWindowLong(hListCtrl, GWL_STYLE, style);
  418. }
  419. #ifdef WINNT
  420. else
  421. {
  422. //Run the WDMJOY.INF file!!!
  423. RunWDMJOY();
  424. pDIJoyConfig->SendNotify();
  425. }
  426. #endif
  427. if( FAILED(pDIJoyConfig->EnumTypes((LPDIJOYTYPECALLBACK)DIEnumJoyTypeProc, NULL)) )
  428. {
  429. #ifdef _DEBUG
  430. OutputDebugString( TEXT("JOY.CPL: Failed BuildEnumList!\n") );
  431. #endif
  432. return(FALSE);
  433. }
  434. // Don't allow Add if there is nothing to add!
  435. // OR no port to add them to!
  436. if( ((!nGameportBus) && (!nGamingDevices))
  437. #ifdef _UNICODE
  438. || GetSystemMetrics(SM_REMOTESESSION)
  439. #endif
  440. ) {
  441. PostDlgItemEnableWindow(hDlg, IDC_BTN_ADD, FALSE);
  442. }
  443. // register the JOY_CONFIGCHANGED_MSGSTRING defined in MMDDK.H if you're on Memphis
  444. JoyCfgChangedMsg = (nFlags & ON_NT) ? NULL : RegisterWindowMessage(TEXT("MSJSTICK_VJOYD_MSGSTR"));
  445. // blj: Warning Message that you can't add any more devices!
  446. if( nGamingDevices == MAX_DEVICES-1 )
  447. Error((short)IDS_MAX_DEVICES_TITLE, (short)IDS_MAX_DEVICES_MSG);
  448. // blj: beginning of fix for 5.0 to turn on all devices!
  449. LPDIJOYCONFIG_DX5 pJoyConfig = new (DIJOYCONFIG_DX5);
  450. ASSERT (pJoyConfig);
  451. ZeroMemory(pJoyConfig, sizeof(DIJOYCONFIG_DX5));
  452. pJoyConfig->dwSize = sizeof(DIJOYCONFIG_DX5);
  453. // Set the hour glass
  454. SetCursor(LoadCursor(NULL, IDC_WAIT));
  455. BYTE nIndex = nAssigned;
  456. HRESULT hr;
  457. while( nIndex )
  458. {
  459. hr = pDIJoyConfig->GetConfig(pAssigned[--nIndex]->ID, (LPDIJOYCONFIG)pJoyConfig, DIJC_REGHWCONFIGTYPE);
  460. if( (hr == S_FALSE) || FAILED(hr) )
  461. continue;
  462. if( pJoyConfig->hwc.dwUsageSettings & JOY_US_PRESENT )
  463. continue;
  464. pJoyConfig->hwc.dwUsageSettings |= JOY_US_PRESENT;
  465. VERIFY(SUCCEEDED(pDIJoyConfig->SetConfig(pAssigned[nIndex]->ID, (LPDIJOYCONFIG)pJoyConfig, DIJC_REGHWCONFIGTYPE)));
  466. // Fix #55524
  467. VERIFY(SUCCEEDED(pDIJoyConfig->GetConfig(pAssigned[nIndex]->ID, (LPDIJOYCONFIG)pJoyConfig, DIJC_REGHWCONFIGTYPE)));
  468. if( !(pJoyConfig->hwc.dwUsageSettings & JOY_US_PRESENT) )
  469. {
  470. if( SUCCEEDED(pDIJoyConfig->Acquire()) )
  471. {
  472. pJoyConfig->hwc.dwUsageSettings |= JOY_US_PRESENT;
  473. pJoyConfig->hwc.hwv.dwCalFlags |= 0x80000000;
  474. VERIFY(SUCCEEDED(pDIJoyConfig->SetConfig(pAssigned[nIndex]->ID, (LPDIJOYCONFIG)pJoyConfig, DIJC_REGHWCONFIGTYPE)));
  475. }
  476. }
  477. // end of Fix #55524
  478. }
  479. if( pJoyConfig ) delete (pJoyConfig);
  480. // blj: end of fix for 5.0 to turn on all devices!
  481. // Set the hour glass
  482. SetCursor(LoadCursor(NULL, IDC_ARROW));
  483. HWND hParentWnd = GetParent(hDlg);
  484. GetWindowRect(hParentWnd, &rc);
  485. // Only center the dialog if this was the page that we started on!
  486. if( (nStartPageCPL == 0) || (nStartPageCPL == NUMJOYDEVS) )
  487. {
  488. // Centre the Dialog!
  489. SetWindowPos(hParentWnd, NULL,
  490. (GetSystemMetrics(SM_CXSCREEN) - (rc.right-rc.left))>>1,
  491. (GetSystemMetrics(SM_CYSCREEN) - (rc.bottom-rc.top))>>1,
  492. NULL, NULL, SWP_NOSIZE | SWP_NOZORDER | SWP_SHOWWINDOW);
  493. if( nStartPageCPL == NUMJOYDEVS )
  494. PostMessage(hDlg, WM_COMMAND, IDC_BTN_ADD, 0);
  495. }
  496. // Do that move button thing!
  497. MoveOK(hParentWnd);
  498. // this is required because the CPL can be launched via RUNDLL32
  499. if( ::IsWindow(hParentWnd) )
  500. hParentWnd = GetParent(hParentWnd);
  501. // Since the JOY_CONFIGCHANGED_MSGSTRING msg only gets sent to top-level
  502. // windows, this calls for a subclass!
  503. if( JoyCfgChangedMsg )
  504. fpMainWindowProc = (WNDPROC)SetWindowLongPtr(hParentWnd, GWLP_WNDPROC, (LONG_PTR)MsgSubClassProc);
  505. // Set bOnPage so WM_ACTIVATEAPP will work!
  506. nFlags |= ON_PAGE;
  507. // Update the list ctrl!
  508. nFlags |= UPDATE_FOR_GEN;
  509. // to put the selection on the first item on startup...
  510. if( nAssigned )
  511. iItem = 0;
  512. lpDIJoyState = new (DIJOYSTATE);
  513. ASSERT (lpDIJoyState);
  514. ZeroMemory(lpDIJoyState, sizeof(DIJOYSTATE));
  515. return(TRUE);
  516. }
  517. ///////////////////////////////////////////////////////////////////////////////
  518. //OnCommand(HWND hDlg, int id, HWND hWndCtl, UINT code)
  519. ///////////////////////////////////////////////////////////////////////////////
  520. void OnCommand(HWND hDlg, int id, HWND hWndCtl, UINT code)
  521. {
  522. switch( id )
  523. {
  524. case IDC_WHATSTHIS:
  525. {
  526. // point to help file
  527. LPTSTR pszHelpFileName = new TCHAR[STR_LEN_32];
  528. ASSERT (pszHelpFileName);
  529. if( LoadString(ghInstance, IDS_HELPFILENAME, pszHelpFileName, STR_LEN_32) )
  530. WinHelp((HWND)hListCtrl, pszHelpFileName, HELP_WM_HELP, (ULONG_PTR)gaHelpIDs);
  531. #ifdef _DEBUG
  532. else
  533. OutputDebugString(TEXT("JOY.CPL: OnCommand: LoadString Failed to find IDS_HELPFILENAME!\n"));
  534. #endif // _DEBUG
  535. if( pszHelpFileName ) {
  536. delete[] (pszHelpFileName);
  537. }
  538. }
  539. return;
  540. case IDC_BTN_REMOVE:
  541. KillTimer(hDlg, ID_MYTIMER);
  542. nFlags &= ~ON_PAGE;
  543. // Block Update, otherwise we'll be forced to update and we don't need to!
  544. nFlags |= BLOCK_UPDATE;
  545. if( nFlags & USER_MODE )
  546. Error((short)IDS_USER_MODE_TITLE, (short)IDS_USER_MODE);
  547. else if( DeleteSelectedItem((PBYTE)&iItem) )
  548. {
  549. UpdateButtonState(hDlg);
  550. // Set the UpdateFlag!
  551. nFlags |= UPDATE_FOR_ADV;
  552. // Set the default push button to the Add button!
  553. ::PostMessage(hDlg, WM_NEXTDLGCTL, (WPARAM)1, (LPARAM)LOWORD(FALSE));
  554. }
  555. // Unblock the WM_DEVICECHANGE message handler!
  556. nFlags &= ~BLOCK_UPDATE;
  557. nFlags |= ON_PAGE;
  558. SetTimer(hDlg, ID_MYTIMER, POLLRATE, 0);
  559. break;
  560. case IDC_BTN_ADD:
  561. // Don't set ON_PAGE flag!
  562. // We need the WM_DEVICECHANGE message in the case a user plugs in a device!
  563. KillTimer(hDlg, ID_MYTIMER);
  564. ClearArrays();
  565. // Clear everything up before you call this...
  566. if( FAILED(pDIJoyConfig->EnumTypes((LPDIJOYTYPECALLBACK)DIEnumJoyTypeProc, NULL)) )
  567. break;
  568. nFlags &= ~ON_PAGE;
  569. if( nFlags & USER_MODE )
  570. {
  571. Error((short)IDS_USER_MODE_TITLE, (short)IDS_USER_MODE);
  572. }
  573. // call AddDevice dialog
  574. else if( DialogBox( ghInstance, (PTSTR)IDD_ADD, hDlg, (DLGPROC)AddDialogProc ) == IDOK )
  575. {
  576. SendMessage(hDlg, WM_COMMAND, IDC_BTN_REFRESH, 0);
  577. }
  578. SetListCtrlItemFocus(hListCtrl, (BYTE)iItem);
  579. nFlags &= ~BLOCK_UPDATE;
  580. nFlags |= ON_PAGE;
  581. // Now, we set it back active!
  582. SetTimer(hDlg, ID_MYTIMER, POLLRATE, 0);
  583. break;
  584. case IDC_BTN_REFRESH:
  585. KillTimer(hDlg, ID_MYTIMER);
  586. nFlags |= UPDATE_ALL;
  587. pDIJoyConfig->Acquire();
  588. pDIJoyConfig->SendNotify();
  589. UpdateListCtrl(hDlg);
  590. UpdateButtonState(hDlg);
  591. pDIJoyConfig->SendNotify();
  592. pDIJoyConfig->Unacquire();
  593. SetTimer(hDlg, ID_MYTIMER, POLLRATE, 0);
  594. break;
  595. case IDC_RENAME:
  596. // Don't allow editing of Mouse or Keyboard names!
  597. // Don't allow renaming if in USER mode!
  598. if( !(nFlags & USER_MODE) )
  599. {
  600. KillTimer(hDlg, ID_MYTIMER);
  601. ::PostMessage(hListCtrl, LVM_EDITLABEL, (WPARAM)(int)iItem, 0);
  602. }
  603. return;
  604. /* If we want this back...
  605. case IDC_SW_HACK:
  606. {
  607. // SideWinder Hack button!
  608. BYTE nID = pAssigned[GetItemData(hListCtrl, (BYTE)iItem)]->ID;
  609. if (nID == 0)
  610. {
  611. ::PostMessage(GetDlgItem(hDlg, IDC_SW_HACK), BM_SETCHECK, BST_CHECKED, 0);
  612. //CheckDlgButton(hDlg, IDC_SW_HACK, BST_CHECKED);
  613. break;
  614. }
  615. // Get the Selected Item and force its ID to Zero!
  616. SwapIDs((BYTE)nID, (BYTE)0);
  617. }
  618. */
  619. // Missing break intentional!
  620. // Used to fall into IDC_BTN_REFRESH!
  621. case IDC_BTN_TSHOOT:
  622. {
  623. LPTSTR lpszCmd = new (TCHAR[STR_LEN_64]);
  624. ASSERT (lpszCmd);
  625. if( LoadString(ghInstance, IDS_TSHOOT_CMD, lpszCmd, STR_LEN_64) )
  626. {
  627. LPSTARTUPINFO pSi = (LPSTARTUPINFO)_alloca(sizeof(STARTUPINFO));
  628. LPPROCESS_INFORMATION pPi = (LPPROCESS_INFORMATION)_alloca(sizeof(PROCESS_INFORMATION));
  629. ZeroMemory(pSi, sizeof(STARTUPINFO));
  630. ZeroMemory(pPi, sizeof(PROCESS_INFORMATION));
  631. pSi->cb = sizeof(STARTUPINFO);
  632. pSi->dwFlags = STARTF_USESHOWWINDOW | STARTF_FORCEONFEEDBACK;
  633. pSi->wShowWindow = SW_NORMAL;
  634. if( CreateProcess(0, lpszCmd, 0, 0, 0, 0, 0, 0, pSi, pPi) )
  635. {
  636. CloseHandle(pPi->hThread);
  637. CloseHandle(pPi->hProcess);
  638. }
  639. }
  640. if( lpszCmd )
  641. delete[] (lpszCmd);
  642. }
  643. break;
  644. #if 0 //disable UPDATE button, see manbug 33666.
  645. case IDC_BTN_UPDATE:
  646. if (DialogBox(ghInstance, MAKEINTRESOURCE(IDD_UPDATE), hDlg, CplUpdateProc) == IDOK)
  647. {
  648. Update( hDlg, 1, NULL ); //NO Proxy
  649. }
  650. break;
  651. #endif
  652. case IDC_BTN_PROPERTIES:
  653. // Because PSN_KILLACTIVE is not sent... we do it ourselves
  654. // kill status timer
  655. KillTimer(hDlg, ID_MYTIMER);
  656. nFlags &= ~ON_PAGE;
  657. {
  658. char nIndex = (char)GetItemData(hListCtrl, (BYTE)iItem);
  659. // default to the first page!
  660. #ifdef _DEBUG
  661. HRESULT hr =
  662. #endif _DEBUG
  663. Launch(hDlg, pAssigned[nIndex], IsEqualIID(pAssigned[nIndex]->clsidPropSheet, CLSID_LegacyServer) ? 1 : 0);
  664. #ifdef _DEBUG
  665. switch( hr )
  666. {
  667. case DIGCERR_NUMPAGESZERO:
  668. TRACE (TEXT("JOY.CPL: Launch failed device ID #%d, Page #%d, with the error DIGCERR_NUMPAGESZERO!\n"), pAssigned[nIndex]->ID, id);
  669. break;
  670. case DIGCERR_NODLGPROC:
  671. TRACE (TEXT("JOY.CPL: Launch failed device ID #%d, Page #%d, with the error DIGCERR_NODLGPROC!\n"), pAssigned[nIndex]->ID, id);
  672. break;
  673. case DIGCERR_NOPREPOSTPROC:
  674. TRACE (TEXT("JOY.CPL: Launch failed device ID #%d, Page #%d, with the error DIGCERR_NOPREPOSTPROC!\n"), pAssigned[nIndex]->ID, id);
  675. break;
  676. case DIGCERR_NOTITLE:
  677. TRACE (TEXT("JOY.CPL: Launch failed device ID #%d, Page #%d, with the error DIGCERR_NOTITLE!\n"), pAssigned[nIndex]->ID, id);
  678. break;
  679. case DIGCERR_NOCAPTION:
  680. TRACE (TEXT("JOY.CPL: Launch failed device ID #%d, Page #%d, with the error DIGCERR_NOCAPTION!\n"), pAssigned[nIndex]->ID, id);
  681. break;
  682. case DIGCERR_NOICON:
  683. TRACE (TEXT("JOY.CPL: Launch failed device ID #%d, Page #%d, with the error DIGCERR_NOICON!\n"), pAssigned[nIndex]->ID, id);
  684. break;
  685. case DIGCERR_STARTPAGETOOLARGE:
  686. TRACE (TEXT("JOY.CPL: Launch failed device ID #%d, Page #%d, with the error DIGCERR_STARTPAGETOOLARGE!\n"), pAssigned[nIndex]->ID, id);
  687. break;
  688. case DIGCERR_NUMPAGESTOOLARGE:
  689. TRACE (TEXT("JOY.CPL: Launch failed device ID #%d, Page #%d, with the error DIGCERR_NUMPAGESTOOLARGE!\n"), pAssigned[nIndex]->ID, id);
  690. break;
  691. case DIGCERR_INVALIDDWSIZE:
  692. TRACE (TEXT("JOY.CPL: Launch failed device ID #%d, Page #%d, with the error DIGCERR_INVALIDDWSIZE!\n"), pAssigned[nIndex]->ID, id);
  693. break;
  694. case E_NOINTERFACE:
  695. TRACE (TEXT("JOY.CPL: Launch failed device ID #%d, Page #%d, with the error E_NOINTERFACE!\n"), pAssigned[nIndex]->ID, id);
  696. break;
  697. case E_OUTOFMEMORY:
  698. TRACE (TEXT("JOY.CPL: Launch failed device ID #%d, Page #%d, with the error E_OUTOFMEMORY!\n"), pAssigned[nIndex]->ID, id);
  699. break;
  700. //case DIGCERR_NUMPAGESTOOLARGE:
  701. //case DIGCERR_STARTPAGETOOLARGE:
  702. default:
  703. // Only display this return code if things are going Really weird.
  704. TRACE (TEXT("JOY.CPL: Launch return code is %x %s!\n"), hr, strerror(hr));
  705. break;
  706. }
  707. #endif // _DEBUG
  708. nFlags |= ON_PAGE;
  709. //OutputDebugString(TEXT("JOY.CPL: Cpanel.cpp: returned from Property sheet!\n"));
  710. InvalidateRect(hDlg, NULL, TRUE);
  711. UpdateWindow(hDlg);
  712. // Now, we set it back active!
  713. // create timer
  714. SetTimer(hDlg, ID_MYTIMER, POLLRATE, 0);
  715. }
  716. break;
  717. }
  718. // Set the focus where we left off!
  719. if( iItem == NO_ITEM )
  720. iItem = 0;
  721. SetListCtrlItemFocus(hListCtrl, (BYTE)iItem);
  722. }
  723. ////////////////////////////////////////////////////////////////////////////////
  724. // OnNotify(HWND hDlg, WPARAM idFrom, NMHDR* pnmhdr)
  725. // Purpose: WM_NOTIFY Handler
  726. ////////////////////////////////////////////////////////////////////////////////
  727. BOOL OnNotify(HWND hDlg, WPARAM idFrom, NMHDR* pnmhdr)
  728. {
  729. switch( pnmhdr->code )
  730. {
  731. case PSN_QUERYCANCEL:
  732. if( nFlags & UPDATE_INPROCESS )
  733. nFlags &= ~UPDATE_INPROCESS;
  734. break;
  735. case LVN_BEGINLABELEDIT:
  736. if( nFlags & USER_MODE )
  737. return(TRUE);
  738. KillTimer(hDlg, ID_MYTIMER);
  739. ::PostMessage((HWND)::SendMessage(hListCtrl, LVM_GETEDITCONTROL, 0, 0), EM_SETLIMITTEXT, MAX_STR_LEN, 0);
  740. // This lets us know if the edit field is up!
  741. nFlags |= UPDATE_INPROCESS;
  742. return(FALSE);
  743. /*
  744. case LVN_GETINFOTIP:
  745. {
  746. LPLVHITTESTINFO lpHit = new (LVHITTESTINFO);
  747. ASSERT (lpHit);
  748. BOOL bRet = FALSE;
  749. POINT pt;
  750. GetCursorPos(&pt);
  751. ScreenToClient(hListCtrl, &pt);
  752. lpHit->pt = pt;
  753. lpHit->flags = lpHit->iItem = lpHit->iSubItem = 0;
  754. ::SendMessage(hListCtrl, LVM_SUBITEMHITTEST, 0, (LPARAM)(LPLVHITTESTINFO)lpHit);
  755. // We only want to support the device column!
  756. if (lpHit->iSubItem == 0)
  757. {
  758. if (lpHit->flags & LVHT_ONITEMLABEL)
  759. {
  760. // Determine the text length of the column text
  761. LPTSTR lpStr = new (TCHAR[MAX_STR_LEN+1]);
  762. ASSERT (lpStr);
  763. GetItemText(hListCtrl, lpHit->iItem, lpHit->iSubItem, lpStr, MAX_STR_LEN);
  764. // Determine if the latter will fit inside the former...
  765. SIZE size;
  766. HDC hDC = GetDC(hListCtrl);
  767. GetTextExtentPoint(hDC, lpStr, lstrlen(lpStr), &size);
  768. ReleaseDC(hListCtrl, hDC);
  769. // Determine how wide the column is!
  770. short nWidth = (short)::SendMessage(hListCtrl, LVM_GETCOLUMNWIDTH, lpHit->iSubItem, 0);
  771. bRet = (BOOL)(size.cx > nWidth);
  772. if (bRet)
  773. // if not, copy the text into lpHit->pszText
  774. _tcscpy(((LPNMLVGETINFOTIP)pnmhdr)->pszText, lpStr);
  775. if (lpStr)
  776. delete[] (lpStr);
  777. }
  778. }
  779. if (lpHit)
  780. delete (lpHit);
  781. return bRet;
  782. }
  783. */
  784. case LVN_ENDLABELEDIT:
  785. if( nFlags & UPDATE_INPROCESS )
  786. {
  787. HWND hCtrl = (HWND)::SendMessage(hListCtrl, LVM_GETEDITCONTROL, 0, 0);
  788. ASSERT(::IsWindow(hCtrl));
  789. if( ::SendMessage(hCtrl, EM_GETMODIFY, 0, 0) )
  790. {
  791. BYTE nLen = (BYTE)lstrlen(((NMLVDISPINFO *)pnmhdr)->item.pszText);
  792. if( (nLen > MAX_STR_LEN) || (nLen == 0) )
  793. MessageBeep(MB_ICONHAND);
  794. // Make sure the name is usable!
  795. else if( _tcschr(((NMLVDISPINFO *)pnmhdr)->item.pszText, TEXT('\\')) )
  796. {
  797. Error((short)IDS_INVALID_NAME_TITLE, (short)IDS_INVALID_NAME);
  798. } else
  799. {
  800. // Set the Update flag!
  801. nFlags |= UPDATE_ALL;
  802. LPDIPROPSTRING pDIPropString = new (DIPROPSTRING);
  803. ASSERT (pDIPropString);
  804. ZeroMemory(pDIPropString, sizeof(DIPROPSTRING));
  805. pDIPropString->diph.dwSize = sizeof(DIPROPSTRING);
  806. pDIPropString->diph.dwHeaderSize = sizeof(DIPROPHEADER);
  807. pDIPropString->diph.dwHow = DIPH_DEVICE;
  808. #ifdef _UNICODE
  809. wcscpy(pDIPropString->wsz, ((NMLVDISPINFO *)pnmhdr)->item.pszText);
  810. #else
  811. USES_CONVERSION;
  812. wcscpy(pDIPropString->wsz, A2W(((NMLVDISPINFO *)pnmhdr)->item.pszText));
  813. #endif
  814. if( SUCCEEDED(pAssigned[iItem]->fnDeviceInterface->SetProperty(DIPROP_INSTANCENAME, &pDIPropString->diph)) )
  815. {
  816. SetItemText(hListCtrl, (BYTE)iItem, 0, ((NMLVDISPINFO *)pnmhdr)->item.pszText);
  817. } else
  818. {
  819. Error((short)IDS_NO_RENAME_TITLE, (short)IDS_NO_RENAME);
  820. }
  821. if( pDIPropString )
  822. delete (pDIPropString);
  823. // Trip the flag so the Advanced page knows it needs to update!
  824. nFlags |= UPDATE_FOR_ADV;
  825. }
  826. }
  827. // Clear the InProcess flag!
  828. nFlags &= ~UPDATE_INPROCESS;
  829. }
  830. SetTimer(hDlg, ID_MYTIMER, POLLRATE, 0);
  831. break;
  832. case LVN_KEYDOWN:
  833. switch( ((LV_KEYDOWN*)pnmhdr)->wVKey )
  834. {
  835. case VK_DELETE:
  836. if( iItem != NO_ITEM )
  837. SendMessage(hDlg, WM_COMMAND, IDC_BTN_REMOVE, 0);
  838. break;
  839. case VK_F5:
  840. nFlags |= UPDATE_ALL;
  841. UpdateListCtrl(hDlg);
  842. if( GetKeyState(VK_SHIFT) & 0x80 )
  843. {
  844. #ifdef WINNT
  845. RunWDMJOY();
  846. #endif
  847. ClearArrays();
  848. pDIJoyConfig->EnumTypes((LPDIJOYTYPECALLBACK)DIEnumJoyTypeProc, NULL);
  849. }
  850. break;
  851. }
  852. break;
  853. #if 0
  854. case LVN_COLUMNCLICK:
  855. {
  856. CListCtrl *pCtrl = new (CListCtrl);
  857. ASSERT(pCtrl);
  858. pCtrl->Attach(hListCtrl);
  859. if( ((NM_LISTVIEW*)pnmhdr)->iSubItem )
  860. {
  861. static bItemDirection = TRUE;
  862. SortTextItems(pCtrl, 0, bItemDirection =! bItemDirection, 0, -1);
  863. } else
  864. {
  865. static bLabelDirection = TRUE;
  866. SortTextItems(pCtrl, 0, bLabelDirection =! bLabelDirection, 0, -1);
  867. }
  868. pCtrl->Detach();
  869. if( pCtrl )
  870. delete (pCtrl);
  871. }
  872. break;
  873. #endif
  874. case LVN_ITEMCHANGED:
  875. if( iItem != NO_ITEM )
  876. {
  877. // get index of selected item
  878. // no point if it's not changed!
  879. if( iItem != (short)((NM_LISTVIEW*)pnmhdr)->iItem )
  880. {
  881. int i = GetItemData(hListCtrl, (char)iItem);
  882. iItem = (short)((NM_LISTVIEW*)pnmhdr)->iItem;
  883. iAdvItem = pAssigned[i]->ID;
  884. UpdateButtonState(hDlg);
  885. }
  886. }
  887. break;
  888. case NM_DBLCLK:
  889. switch( idFrom )
  890. {
  891. case IDC_LIST_DEVICE:
  892. if( iItem == NO_ITEM )
  893. {
  894. if( !(nFlags & USER_MODE) && nGameportBus )
  895. OnCommand(hDlg, IDC_BTN_ADD, 0, 0);
  896. } else if( IsWindowEnabled(GetDlgItem(hDlg, IDC_BTN_PROPERTIES)) )
  897. {
  898. // make sure the connected one has got an interface pointer...
  899. OnCommand(hDlg, IDC_BTN_PROPERTIES, 0, 0);
  900. }
  901. break;
  902. }
  903. break;
  904. case PSN_KILLACTIVE:
  905. KillTimer(hDlg, ID_MYTIMER);
  906. nFlags &= ~ON_PAGE;
  907. if( nFlags & UPDATE_INPROCESS )
  908. SetFocus(hListCtrl);
  909. #ifdef _UNICODE
  910. if( hNotifyDevNode )
  911. UnregisterDeviceNotification(hNotifyDevNode);
  912. #endif
  913. PostMessage(hDlg, WM_ACTIVATEAPP, FALSE, 0);
  914. break;
  915. case PSN_SETACTIVE:
  916. nFlags |= ON_PAGE;
  917. nFlags |= UPDATE_FOR_GEN;
  918. #ifdef _UNICODE
  919. // Set up the Device Notification
  920. RegisterForDevChange(hDlg, &hNotifyDevNode);
  921. #endif
  922. SendMessage(hDlg, WM_ACTIVATEAPP, TRUE, 0);
  923. break;
  924. }
  925. return(TRUE);
  926. }
  927. ////////////////////////////////////////////////////////////////////////////////////////
  928. // OnDestroy(HWND hWnd)
  929. ////////////////////////////////////////////////////////////////////////////////////////
  930. void OnDestroy(HWND hWnd)
  931. {
  932. SetWindowPos( GetParent(hWnd), NULL, NULL, NULL, NULL, NULL,
  933. SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_HIDEWINDOW);
  934. if( lpDIJoyState )
  935. delete (lpDIJoyState);
  936. // if you are looking for where the following variables are deleted, look
  937. // in DLL_PROCESS_DETACH in MAIN.CPP:
  938. // pwszTypeArray, pwszGameportDriverArray, pwszGameportBus
  939. // This is done because of the way several Microsoft games load the CPL and
  940. // Don't Unload it between loads.
  941. // Clear pAssigned
  942. while( nAssigned )
  943. {
  944. if( pAssigned[--nAssigned] )
  945. {
  946. delete (pAssigned[nAssigned]);
  947. pAssigned[nAssigned] = 0;
  948. }
  949. }
  950. // delete all existing entries
  951. //::PostMessage(hListCtrl, LVM_DELETEALLITEMS, 0, 0);
  952. // release the DI JoyConfig interface pointer
  953. if( pDIJoyConfig )
  954. {
  955. pDIJoyConfig->Release();
  956. pDIJoyConfig = 0;
  957. }
  958. // release the DI Device interface pointer
  959. if( lpDIInterface )
  960. {
  961. lpDIInterface->Release();
  962. lpDIInterface = 0;
  963. }
  964. // Drop the subclass, else you'll crash!
  965. if( !(nFlags & ON_NT) )
  966. SetWindowLongPtr(GetParent(GetParent(hWnd)), GWLP_WNDPROC, (LONG_PTR)fpMainWindowProc);
  967. }
  968. ////////////////////////////////////////////////////////////////////////////////////////
  969. // OnHelp(LPARAM lParam)
  970. ////////////////////////////////////////////////////////////////////////////////////////
  971. void OnHelp(LPARAM lParam)
  972. {
  973. // point to help file
  974. LPTSTR pszHelpFileName = new TCHAR[STR_LEN_32];
  975. ASSERT (pszHelpFileName);
  976. if( LoadString(ghInstance, IDS_HELPFILENAME, pszHelpFileName, STR_LEN_32) )
  977. {
  978. if( ((LPHELPINFO)lParam)->iContextType == HELPINFO_WINDOW )
  979. WinHelp((HWND)((LPHELPINFO)lParam)->hItemHandle, pszHelpFileName, HELP_WM_HELP, (ULONG_PTR)gaHelpIDs);
  980. }
  981. #ifdef _DEBUG
  982. else OutputDebugString(TEXT("JOY.CPL: OnHelp: LoadString Failed to find IDS_HELPFILENAME!\n"));
  983. #endif
  984. if( pszHelpFileName )
  985. delete[] (pszHelpFileName);
  986. }
  987. ////////////////////////////////////////////////////////////////////////////////////////
  988. // OnContextMenu(WPARAM wParam)
  989. ////////////////////////////////////////////////////////////////////////////////////////
  990. void OnContextMenu(WPARAM wParam, LPARAM lParam)
  991. {
  992. // this prevents double handling of this message
  993. if( (HWND)wParam == hListCtrl )
  994. {
  995. OnListViewContextMenu(GetParent((HWND)wParam), lParam);
  996. return;
  997. }
  998. // point to help file
  999. LPTSTR pszHelpFileName = new TCHAR[STR_LEN_32];
  1000. ASSERT (pszHelpFileName);
  1001. if( LoadString(ghInstance, IDS_HELPFILENAME, pszHelpFileName, STR_LEN_32) )
  1002. WinHelp((HWND)wParam, pszHelpFileName, HELP_CONTEXTMENU, (ULONG_PTR)gaHelpIDs);
  1003. #ifdef _DEBUG
  1004. else OutputDebugString(TEXT("JOY.CPL: OnContextMenu: LoadString Failed to find IDS_HELPFILENAME!\n"));
  1005. #endif
  1006. if( pszHelpFileName )
  1007. delete[] (pszHelpFileName);
  1008. }
  1009. /////////////////////////////////////////////////////////////////////////////////////////
  1010. // OnListViewContextMenu(HWND hDlg)
  1011. // Purpose: Query the plug-in for the selected device for it's characteristics
  1012. // Then construct a menu to reflect your findings
  1013. /////////////////////////////////////////////////////////////////////////////////////////
  1014. void OnListViewContextMenu(HWND hDlg, LPARAM lParam)
  1015. {
  1016. BOOL bRet = TRUE;
  1017. HMENU hPopupMenu = CreatePopupMenu();
  1018. ASSERT (hPopupMenu);
  1019. LPTSTR psz = new TCHAR[STR_LEN_32];
  1020. ASSERT (psz);
  1021. // Add the Refresh text
  1022. VERIFY(LoadString(ghInstance, IDS_REFRESH, psz, STR_LEN_32));
  1023. bRet = AppendMenu(hPopupMenu, MF_ENABLED, IDC_BTN_REFRESH, psz);
  1024. // Add the Add text
  1025. HWND hCtrl;
  1026. // Only Display Add menu option if we've found a GameportBus!!!
  1027. if( nGameportBus
  1028. #ifdef _UNICODE
  1029. && !GetSystemMetrics(SM_REMOTESESSION)
  1030. #endif
  1031. )
  1032. {
  1033. hCtrl = GetDlgItem(hDlg, IDC_BTN_ADD);
  1034. ASSERT(hCtrl);
  1035. if( IsWindowEnabled(hCtrl) )
  1036. {
  1037. ::SendMessage(hCtrl, WM_GETTEXT, (WPARAM)STR_LEN_32, (LPARAM)(LPCTSTR)psz);
  1038. bRet = AppendMenu(hPopupMenu, MF_ENABLED, IDC_BTN_ADD, psz);
  1039. if( !bRet )
  1040. TRACE(TEXT("JOY.CPL: AppendMenu Failed to insert %s\n"), psz);
  1041. }
  1042. }
  1043. // Add the Remove text
  1044. hCtrl = GetDlgItem(hDlg, IDC_BTN_REMOVE);
  1045. ASSERT(hCtrl);
  1046. // Only Show it if it's available
  1047. if( IsWindowEnabled(hCtrl) && (iItem != NO_ITEM) )
  1048. {
  1049. ::SendMessage(hCtrl, WM_GETTEXT, (WPARAM)STR_LEN_32, (LPARAM)(LPCTSTR)psz);
  1050. bRet = AppendMenu(hPopupMenu, MF_ENABLED, IDC_BTN_REMOVE, psz);
  1051. if( !bRet )
  1052. TRACE(TEXT("JOY.CPL: AppendMenu Failed to insert %s\n"), psz);
  1053. }
  1054. // Add the Properties text
  1055. hCtrl = GetDlgItem(hDlg, IDC_BTN_PROPERTIES);
  1056. ASSERT (hCtrl);
  1057. if( IsWindowEnabled(hCtrl) )
  1058. {
  1059. ::SendMessage(hCtrl, WM_GETTEXT, (WPARAM)STR_LEN_32, (LPARAM)(LPCTSTR)psz);
  1060. bRet = AppendMenu(hPopupMenu, MF_ENABLED, IDC_BTN_PROPERTIES, psz);
  1061. if( !bRet )
  1062. TRACE(TEXT("JOY.CPL: AppendMenu Failed to insert %s\n"), psz);
  1063. }
  1064. // Add the Rename text if not a USER!
  1065. if( !(nFlags & USER_MODE) )
  1066. {
  1067. if( nAssigned && (iItem != NO_ITEM) )
  1068. {
  1069. VERIFY(LoadString(ghInstance, IDS_RENAME, psz, STR_LEN_32));
  1070. bRet = AppendMenu(hPopupMenu, MF_ENABLED, IDC_RENAME, psz);
  1071. }
  1072. }
  1073. bRet = AppendMenu(hPopupMenu, MF_SEPARATOR, 0, 0);
  1074. if( !bRet )
  1075. TRACE(TEXT("JOY.CPL: AppendMenu Failed to insert the separator!\n"), psz);
  1076. VERIFY(LoadString(ghInstance, IDS_WHATSTHIS, psz, STR_LEN_32));
  1077. bRet = AppendMenu(hPopupMenu, MF_ENABLED, IDC_WHATSTHIS, psz);
  1078. if( !bRet )
  1079. TRACE(TEXT("JOY.CPL: AppendMenu Failed to insert %s\n"), psz);
  1080. if( psz ) delete[] (psz);
  1081. POINT pt;
  1082. // lParam is -1 if we got here via Shift+F10
  1083. if( lParam > 0 )
  1084. {
  1085. pt.x = GET_X_LPARAM(lParam);
  1086. pt.y = GET_Y_LPARAM(lParam);
  1087. } else
  1088. {
  1089. // Centre the popup on the selected item!
  1090. // This get's a good X pos, but the y is the start of the control!
  1091. ::SendMessage(hListCtrl, LVM_GETITEMPOSITION, iItem, (LPARAM)&pt);
  1092. RECT rc;
  1093. ::GetClientRect(hListCtrl, &rc);
  1094. pt.x = rc.right>>1;
  1095. ClientToScreen(hListCtrl, &pt);
  1096. }
  1097. // restore selection focus
  1098. SetListCtrlItemFocus(hListCtrl, (BYTE)iItem);
  1099. bRet = TrackPopupMenu (hPopupMenu, TPM_LEFTALIGN|TPM_LEFTBUTTON|TPM_RIGHTBUTTON, pt.x, pt.y, 0, hDlg, NULL);
  1100. if( !bRet )
  1101. TRACE (TEXT("JOY.CPL: TrackPopupMenu Failed!\n"));
  1102. if(hPopupMenu) DestroyMenu (hPopupMenu); // PREFIX 45088
  1103. // Set the focus back to the item it came from!
  1104. SetListCtrlItemFocus(hListCtrl, (BYTE)iItem);
  1105. }
  1106. int CALLBACK CompareStatusItems(LPARAM item1, LPARAM item2, LPARAM uDirection)
  1107. {
  1108. if( (((PJOY)item1)->nStatus & JOY_US_PRESENT) == (((PJOY)item2)->nStatus & JOY_US_PRESENT) )
  1109. return(0);
  1110. return(uDirection) ? -1 : 1;
  1111. }
  1112. ///////////////////////////////////////////////////////////////////////////////
  1113. // FUNCTION: DeleteSelectedItem ( BYTE nItem )
  1114. //
  1115. // PARAMETERS: nItem - ID of item to remove
  1116. //
  1117. // PURPOSE: Prompt the user, delete the selected device from the listview, and update the registry
  1118. //
  1119. // RETURN: TRUE if successfull, FALSE otherwise
  1120. ///////////////////////////////////////////////////////////////////////////////
  1121. BOOL DeleteSelectedItem( PBYTE pnItem )
  1122. {
  1123. BYTE nItem = *pnItem;
  1124. // don't process if nothing is selected.
  1125. if( *pnItem == NO_ITEM )
  1126. return(FALSE);
  1127. LV_ITEM lvItem;
  1128. lvItem.mask = LVIF_PARAM;
  1129. lvItem.iSubItem = 0;
  1130. lvItem.iItem = *pnItem;
  1131. if( !ListView_GetItem(hListCtrl, &lvItem) )
  1132. return(FALSE);
  1133. ::PostMessage(hListCtrl, LVM_ENSUREVISIBLE, *pnItem, FALSE );
  1134. LPTSTR pszTitle = new TCHAR[STR_LEN_64];
  1135. ASSERT (pszTitle);
  1136. // Query user if they are sure!
  1137. VERIFY(LoadString(ghInstance, IDS_GEN_AREYOUSURE, pszTitle, STR_LEN_64));
  1138. // Get the name of the device for the message box!
  1139. //PREFIX #WI226554. Won't fix. Obsolete code, from Whistler on replaced with new version.
  1140. LPTSTR lptszTmp = new TCHAR[STR_LEN_64];
  1141. // Make sure the name isn't so long as to over-write the buffer!
  1142. if( GetItemText(hListCtrl, (BYTE)*pnItem, DEVICE_COLUMN, lptszTmp, STR_LEN_64) > 60 )
  1143. {
  1144. lptszTmp[60] = lptszTmp[61] = lptszTmp[62] = TEXT('.');
  1145. lptszTmp[63] = TEXT('\0');
  1146. }
  1147. LPTSTR pszMsg = new TCHAR[MAX_STR_LEN];
  1148. ASSERT (pszMsg);
  1149. wsprintf( pszMsg, pszTitle, lptszTmp);
  1150. if( lptszTmp )
  1151. delete[] (lptszTmp);
  1152. VERIFY(LoadString(ghInstance, IDS_GEN_AREYOUSURE_TITLE, pszTitle, STR_LEN_64));
  1153. BOOL bRet = (BOOL)(IDYES == MessageBox(GetFocus(), pszMsg, pszTitle, MB_ICONQUESTION | MB_YESNO | MB_APPLMODAL));
  1154. if( pszMsg ) delete[] (pszMsg);
  1155. if( pszTitle ) delete[] (pszTitle);
  1156. if( bRet )
  1157. {
  1158. HRESULT hr;
  1159. // Check for privileges!
  1160. if( SUCCEEDED(hr = pDIJoyConfig->Acquire()) )
  1161. {
  1162. char nIndex = (char)GetItemData(hListCtrl, (BYTE)*pnItem);
  1163. // Set the hour glass
  1164. SetCursor(LoadCursor(NULL, IDC_WAIT));
  1165. // Verify that you can delete the Config before you release the interface pointers!
  1166. if( SUCCEEDED(hr = pDIJoyConfig->DeleteConfig(pAssigned[nIndex]->ID)) )
  1167. {
  1168. // make sure VJOYD is initialized
  1169. if( !(nFlags & ON_NT) )
  1170. VERIFY (SUCCEEDED(pDIJoyConfig->SendNotify()));
  1171. ::SendMessage(hListCtrl, LVM_DELETEITEM, (WPARAM)(int)*pnItem, 0);
  1172. // Move the last assigned to the hole... if there is one!
  1173. if( nIndex != (nAssigned-1) )
  1174. {
  1175. // Before you move the tail to the hole,
  1176. // Release() the interfaces at the hole!
  1177. pAssigned[nIndex]->fnDeviceInterface->Unacquire();
  1178. pAssigned[nIndex]->fnDeviceInterface->Release();
  1179. // Move the tail to the hole.
  1180. CopyMemory(pAssigned[nIndex], pAssigned[nAssigned-1], sizeof (JOY));
  1181. pAssigned[nAssigned-1]->fnDeviceInterface = 0;
  1182. // Don't forget to set the index in the item data!
  1183. SetItemData(hListCtrl, nItem, nIndex);
  1184. // Assign the tail to the hole so it gets deleted!
  1185. nIndex = nAssigned-1;
  1186. // Don't forget to set the index in the item data!
  1187. // QZheng: This line is very wrong!!!
  1188. //SetItemData(hListCtrl, (BYTE)*pnItem, nIndex);
  1189. }
  1190. // delete the memory...
  1191. if( pAssigned[nIndex] )
  1192. {
  1193. delete (pAssigned[nIndex]);
  1194. pAssigned[nIndex] = 0;
  1195. }
  1196. // Set the focus before you corrupt iItem
  1197. SetListCtrlItemFocus(hListCtrl, nIndex);
  1198. pDIJoyConfig->SendNotify(); //do more to make sure
  1199. pDIJoyConfig->Unacquire();
  1200. // dec nAssigned
  1201. nAssigned--;
  1202. // if there's no items, tell iItem about it!
  1203. if( nAssigned == 0 )
  1204. *pnItem = NO_ITEM;
  1205. } else if( hr == DIERR_UNSUPPORTED )
  1206. {
  1207. Error((short)IDS_GEN_AREYOUSURE_TITLE, (short)IDS_GEN_NO_REMOVE_USB);
  1208. }
  1209. // Set the hour glass
  1210. SetCursor(LoadCursor(NULL, IDC_ARROW));
  1211. }
  1212. }
  1213. return(bRet);
  1214. }
  1215. ///////////////////////////////////////////////////////////////////////////////
  1216. // FUNCTION: DIEnumJoyTypeProc( LPCWSTR pwszTypeName, LPVOID pvRef )
  1217. //
  1218. // PARAMETERS: LPCWSTR pwszTypeName - Type name of the device enumerated
  1219. // LPVOID pvRef -
  1220. //
  1221. // PURPOSE: To Enumerate the types of devices associated with this system
  1222. //
  1223. // RETURN: TRUE if successfull, FALSE otherwise
  1224. ///////////////////////////////////////////////////////////////////////////////
  1225. BOOL CALLBACK DIEnumJoyTypeProc( LPCWSTR pwszTypeName, LPVOID pvRef )
  1226. {
  1227. // Type info
  1228. LPDIJOYTYPEINFO_DX5 lpdiJoyInfo = (LPDIJOYTYPEINFO_DX5)_alloca(sizeof(DIJOYTYPEINFO_DX5));
  1229. ASSERT (lpdiJoyInfo);
  1230. ZeroMemory(lpdiJoyInfo, sizeof(DIJOYTYPEINFO_DX5));
  1231. lpdiJoyInfo->dwSize = sizeof(DIJOYTYPEINFO_DX5);
  1232. // populate the Type Info
  1233. switch( pDIJoyConfig->GetTypeInfo(pwszTypeName, (LPDIJOYTYPEINFO)lpdiJoyInfo, DITC_REGHWSETTINGS) )
  1234. {
  1235. // errors to continue with...
  1236. case DIERR_NOTFOUND:
  1237. TRACE(TEXT("JOY.CPL: GetTypeInfo returned DIERR_NOTFOUND for type %s!\n"), pwszTypeName);
  1238. return(DIENUM_CONTINUE);
  1239. // errors to stop with...
  1240. case DIERR_INVALIDPARAM:
  1241. TRACE(TEXT("JOY.CPL: GetTypeInfo returned DIERR_INVALIDPARAM!\n"));
  1242. case DIERR_NOMOREITEMS:
  1243. return(DIENUM_STOP);
  1244. }
  1245. // a quick check to make sure we don't have the infamous array out of bounds problem!
  1246. #ifndef _UNICODE
  1247. if( nGameportDriver > MAX_GLOBAL_PORT_DRIVERS-1 )
  1248. {
  1249. #ifdef DEBUG
  1250. OutputDebugString(TEXT("JOY.CPL: Cpanel.cpp: DIEnumJoyTypeProc: Global Gameport Drivers have exceeded MAX_GLOBAL_PORT_DRIVERS!\n"));
  1251. #endif
  1252. return(DIENUM_STOP);
  1253. }
  1254. #endif
  1255. if( nGameportBus > MAX_BUSSES-1 )
  1256. {
  1257. #ifdef DEBUG
  1258. OutputDebugString(TEXT("JOY.CPL: Cpanel.cpp: DIEnumJoyTypeProc: Enumerated Gameport busses have exceeded MAX_BUSSES!\n"));
  1259. #endif // _DEBUG
  1260. return(DIENUM_STOP);
  1261. }
  1262. if( nGamingDevices > MAX_DEVICES-1 )
  1263. {
  1264. #ifdef DEBUG
  1265. OutputDebugString(TEXT("JOY.CPL: Cpanel.cpp: DIEnumJoyTypeProc: Enumerated Gameport busses have exceeded MAX_DEVICES!\n"));
  1266. #endif // _DEBUG
  1267. return(DIENUM_STOP);
  1268. }
  1269. // check to see if it's a global port driver
  1270. #ifndef _UNICODE
  1271. if( lpdiJoyInfo->hws.dwFlags & JOY_HWS_ISGAMEPORTDRIVER )
  1272. {
  1273. if( pwszGameportDriverArray[nGameportDriver] )
  1274. wcsncpy(pwszGameportDriverArray[nGameportDriver], pwszTypeName, wcslen(pwszTypeName)+1);
  1275. else
  1276. pwszGameportDriverArray[nGameportDriver] = _wcsdup(pwszTypeName);
  1277. nGameportDriver++;
  1278. } else
  1279. #endif // _UNICODE
  1280. if( lpdiJoyInfo->hws.dwFlags & JOY_HWS_ISGAMEPORTBUS )
  1281. {
  1282. if( pwszGameportBus[nGameportBus] )
  1283. wcscpy(pwszGameportBus[nGameportBus], pwszTypeName);
  1284. else
  1285. pwszGameportBus[nGameportBus] = _wcsdup(pwszTypeName);
  1286. nGameportBus++;
  1287. } else
  1288. {
  1289. if( !(lpdiJoyInfo->hws.dwFlags & JOY_HWS_AUTOLOAD) )
  1290. {
  1291. // it's a standard gaming device
  1292. if( pwszTypeArray[nGamingDevices] )
  1293. wcsncpy(pwszTypeArray[nGamingDevices], pwszTypeName, wcslen(pwszTypeName)+1);
  1294. else
  1295. pwszTypeArray[nGamingDevices] = _wcsdup(pwszTypeName);
  1296. nGamingDevices++;
  1297. }
  1298. }
  1299. return(DIENUM_CONTINUE);
  1300. }
  1301. ///////////////////////////////////////////////////////////////////////////////
  1302. // FUNCTION: DIEnumDevicesProc(LPDIDEVICEINSTANCE lpDeviceInst, LPVOID lpVoid)
  1303. //
  1304. // PARAMETERS: LPDIDEVICEINSTANCE lpDeviceInst - Device Instance
  1305. // LPVOID lpVoid -
  1306. //
  1307. // PURPOSE: To Enumerate the devices associated with this system
  1308. //
  1309. // RETURN: TRUE if successfull, FALSE otherwise
  1310. ///////////////////////////////////////////////////////////////////////////////
  1311. BOOL CALLBACK DIEnumDevicesProc(LPDIDEVICEINSTANCE lpDeviceInst, LPVOID lpVoid)
  1312. {
  1313. LPDIRECTINPUTDEVICE pdiDevTemp;
  1314. pDIJoyConfig->Acquire();
  1315. // First Create the device
  1316. if( SUCCEEDED(lpDIInterface->CreateDevice(lpDeviceInst->guidInstance, &pdiDevTemp, 0)) )
  1317. {
  1318. PJOY pNewJoy = new JOY;
  1319. ASSERT (pNewJoy);
  1320. // Query for a device2 object
  1321. if( FAILED(pdiDevTemp->QueryInterface(IID_IDirectInputDevice2, (LPVOID*)&pNewJoy->fnDeviceInterface)) )
  1322. {
  1323. #ifdef _DEBUG
  1324. OutputDebugString(TEXT("JOY.CPL: Cpanel.cpp: DIEnumDevicesProc: QueryInterface failed!\n"));
  1325. #endif
  1326. // release the temporary object
  1327. pdiDevTemp->Release();
  1328. return(FALSE);
  1329. }
  1330. DIPROPDWORD *pDIPropDW = new (DIPROPDWORD);
  1331. ASSERT (pDIPropDW);
  1332. ZeroMemory(pDIPropDW, sizeof(DIPROPDWORD));
  1333. pDIPropDW->diph.dwSize = sizeof(DIPROPDWORD);
  1334. pDIPropDW->diph.dwHeaderSize = sizeof(DIPROPHEADER);
  1335. pDIPropDW->diph.dwHow = DIPH_DEVICE;
  1336. // Get the device ID
  1337. VERIFY (SUCCEEDED(pdiDevTemp->GetProperty(DIPROP_JOYSTICKID, &pDIPropDW->diph)));
  1338. // release the temporary object
  1339. pdiDevTemp->Release();
  1340. pNewJoy->ID = (char)pDIPropDW->dwData;
  1341. if( pDIPropDW )
  1342. delete (pDIPropDW);
  1343. // Get the Type name
  1344. LPDIJOYCONFIG_DX5 lpDIJoyCfg = new (DIJOYCONFIG_DX5);
  1345. ASSERT (lpDIJoyCfg);
  1346. ZeroMemory(lpDIJoyCfg, sizeof(DIJOYCONFIG_DX5));
  1347. lpDIJoyCfg->dwSize = sizeof(DIJOYCONFIG_DX5);
  1348. VERIFY (SUCCEEDED(pDIJoyConfig->GetConfig(pNewJoy->ID, (LPDIJOYCONFIG)lpDIJoyCfg, DIJC_REGHWCONFIGTYPE | DIJC_CALLOUT)));
  1349. // Get the clsidConfig
  1350. LPDIJOYTYPEINFO lpDIJoyType = new (DIJOYTYPEINFO);
  1351. ASSERT(lpDIJoyType);
  1352. ZeroMemory(lpDIJoyType, sizeof(DIJOYTYPEINFO));
  1353. lpDIJoyType->dwSize = sizeof(DIJOYTYPEINFO);
  1354. VERIFY (SUCCEEDED(pDIJoyConfig->GetTypeInfo(lpDIJoyCfg->wszType, (LPDIJOYTYPEINFO)lpDIJoyType, DITC_CLSIDCONFIG | DITC_REGHWSETTINGS | DITC_FLAGS1 )));
  1355. if( lpDIJoyCfg )
  1356. delete (lpDIJoyCfg);
  1357. // if NULL, Leave as default.
  1358. if( !IsEqualIID(lpDIJoyType->clsidConfig, GUID_NULL) ) {
  1359. pNewJoy->fHasOemSheet = TRUE;
  1360. if( !(lpDIJoyType->dwFlags1 & JOYTYPE_DEFAULTPROPSHEET) ) {
  1361. pNewJoy->clsidPropSheet = lpDIJoyType->clsidConfig;
  1362. }
  1363. } else {
  1364. pNewJoy->fHasOemSheet = FALSE;
  1365. }
  1366. // Assign the number of buttons!
  1367. pNewJoy->nButtons = (BYTE)(lpDIJoyType->hws.dwNumButtons);
  1368. if( lpDIJoyType )
  1369. delete (lpDIJoyType);
  1370. // Set it's format!!!
  1371. if( SUCCEEDED(pNewJoy->fnDeviceInterface->SetDataFormat(&c_dfDIJoystick)) )
  1372. {
  1373. // Set it's Cooperative Level!
  1374. if( FAILED(pNewJoy->fnDeviceInterface->SetCooperativeLevel(GetParent((HWND)GetParent(hListCtrl)), DISCL_NONEXCLUSIVE | DISCL_BACKGROUND)) )
  1375. {
  1376. #ifdef _DEBUG
  1377. OutputDebugString(TEXT("JOY.CPL: Cpanel.cpp: DIEnumDevicesProc: SetCooperativeLevel Failed!\n"));
  1378. #endif
  1379. }
  1380. }
  1381. // Add the item to the tree!
  1382. pAssigned[nAssigned] = pNewJoy;
  1383. // If you're on the General page!
  1384. if( nFlags & ON_PAGE )
  1385. {
  1386. // add to tree
  1387. LVITEM lvItem = {LVIF_TEXT | LVIF_PARAM, nAssigned, 0, 0, 0, lpDeviceInst->tszInstanceName, lstrlen(lpDeviceInst->tszInstanceName), 0, (LPARAM)nAssigned, 0};
  1388. ::SendMessage(hListCtrl, LVM_INSERTITEM, 0, (LPARAM) (const LPLVITEM)&lvItem);
  1389. //InsertItem(hListCtrl, lpDeviceInst->tszInstanceName, nAssigned);
  1390. TCHAR sz[STR_LEN_32];
  1391. VERIFY(LoadString(ghInstance, IDS_GEN_STATUS_UNKNOWN, (LPTSTR)&sz, STR_LEN_32));
  1392. SetItemText(hListCtrl, nAssigned, STATUS_COLUMN, sz);
  1393. }
  1394. // Increment the array counter!
  1395. nAssigned++;
  1396. if( nAssigned == nTargetAssigned )
  1397. {
  1398. /*
  1399. * A new device arrived so assume there's no
  1400. * longer any point in checking on the timer.
  1401. */
  1402. nTargetAssigned = (BYTE)-1;
  1403. nReEnum = 0;
  1404. }
  1405. }
  1406. return(DIENUM_CONTINUE);
  1407. }
  1408. ///////////////////////////////////////////////////////////////////////////////
  1409. // FUNCTION: ClearArrays ( void )
  1410. //
  1411. // PARAMETERS:
  1412. //
  1413. //
  1414. // PURPOSE:
  1415. //
  1416. // RETURN:
  1417. ///////////////////////////////////////////////////////////////////////////////
  1418. void ClearArrays( void )
  1419. {
  1420. #ifndef _UNICODE
  1421. while( nGameportDriver )
  1422. {
  1423. free(pwszGameportDriverArray[--nGameportDriver]);
  1424. pwszGameportDriverArray[nGameportDriver] = L'\0';
  1425. }
  1426. #endif // _UNICODE
  1427. while( nGamingDevices )
  1428. {
  1429. free(pwszTypeArray[--nGamingDevices]);
  1430. pwszTypeArray[nGamingDevices] = L'\0';
  1431. }
  1432. while( nGameportBus )
  1433. {
  1434. free(pwszGameportBus[--nGameportBus]);
  1435. pwszGameportBus[nGameportBus] = L'\0';
  1436. memset( &guidOccupied[nGameportBus], 0, sizeof(GUID) );
  1437. }
  1438. }
  1439. ///////////////////////////////////////////////////////////////////////////////
  1440. // FUNCTION: UpdateListCtrl( HWND hDlg )
  1441. //
  1442. // PARAMETERS: HWND hDlg - Handle to window to update
  1443. //
  1444. // PURPOSE: Refreshes enumerated device list
  1445. //
  1446. // RETURN: TRUE if successfull, FALSE otherwise
  1447. ///////////////////////////////////////////////////////////////////////////////
  1448. static void UpdateListCtrl( HWND hDlg )
  1449. {
  1450. if( !(nFlags & ON_PAGE) )
  1451. return;
  1452. // Turn Redraw off here else it will flicker!
  1453. ::SendMessage(hListCtrl, WM_SETREDRAW, (WPARAM)FALSE, 0);
  1454. // delete all existing entries
  1455. ::SendMessage(hListCtrl, LVM_DELETEALLITEMS, 0, 0);
  1456. Enumerate( hDlg );
  1457. // turn the flag off!
  1458. if( nFlags & UPDATE_FOR_GEN )
  1459. nFlags &= ~UPDATE_FOR_GEN;
  1460. // Turn the redraw flag back on!
  1461. ::SendMessage (hListCtrl, WM_SETREDRAW, (WPARAM)TRUE, 0);
  1462. InvalidateRect(hListCtrl, NULL, TRUE);
  1463. }
  1464. //#ifdef _UNICODE
  1465. HRESULT Enumerate( HWND hDlg )
  1466. {
  1467. nFlags |= UPDATE_ALL;
  1468. // Clear pAssigned
  1469. while( nAssigned )
  1470. {
  1471. if( pAssigned[--nAssigned] )
  1472. {
  1473. delete (pAssigned[nAssigned]);
  1474. pAssigned[nAssigned] = 0;
  1475. }
  1476. }
  1477. // Enumerate the Joysticks and put them in the list... | DIEDFL_INCLUDEPHANTOMS
  1478. #ifdef _UNICODE
  1479. return(lpDIInterface->EnumDevices(DIDEVTYPE_JOYSTICK, (LPDIENUMDEVICESCALLBACK)DIEnumDevicesProc, (LPVOID)hDlg,
  1480. DIEDFL_ALLDEVICES ));
  1481. #else
  1482. return(lpDIInterface->EnumDevices(DIDEVTYPE_JOYSTICK, (LPDIENUMDEVICESCALLBACK)DIEnumDevicesProc, (LPVOID)hDlg,
  1483. DIEDFL_ALLDEVICES | DIEDFL_INCLUDEPHANTOMS));
  1484. #endif
  1485. }
  1486. /*
  1487. #else
  1488. HRESULT Enumerate( HWND hDlg )
  1489. {
  1490. // Clear pAssigned
  1491. while (nAssigned)
  1492. {
  1493. if (pAssigned[--nAssigned])
  1494. {
  1495. delete (pAssigned[nAssigned]);
  1496. pAssigned[nAssigned] = 0;
  1497. }
  1498. }
  1499. DIJOYCONFIG *pJoyConfig = new DIJOYCONFIG;
  1500. ASSERT (pJoyConfig);
  1501. pJoyConfig->dwSize = sizeof (DIJOYCONFIG);
  1502. LPDIJOYTYPEINFO pdiJoyTypeInfo = new DIJOYTYPEINFO;
  1503. ASSERT (pdiJoyTypeInfo);
  1504. pdiJoyTypeInfo->dwSize = sizeof (DIJOYTYPEINFO);
  1505. HRESULT hr;
  1506. // find and assign ID's
  1507. for (BYTE n = 0; n < NUMJOYDEVS; n++)
  1508. {
  1509. hr = pDIJoyConfig->GetConfig(n, pJoyConfig, DIJC_REGHWCONFIGTYPE | DIJC_GUIDINSTANCE);
  1510. if (hr == S_OK)
  1511. AddListCtrlItem(n, pJoyConfig);
  1512. }
  1513. // clean up, clean up... everybody do your share!
  1514. if (pJoyConfig) delete (pJoyConfig);
  1515. if (pdiJoyTypeInfo) delete (pdiJoyTypeInfo);
  1516. return hr;
  1517. }
  1518. BOOL AddListCtrlItem(BYTE nItemID, LPDIJOYCONFIG pJoyConfig)
  1519. {
  1520. LPDIRECTINPUTDEVICE pdiDevTemp;
  1521. pDIJoyConfig->Acquire();
  1522. // First Create the device
  1523. if (SUCCEEDED(lpDIInterface->CreateDevice(pJoyConfig->guidInstance, &pdiDevTemp, 0)))
  1524. {
  1525. PJOY pNewJoy = new JOY;
  1526. ASSERT (pNewJoy);
  1527. // Query for a device2 object
  1528. if (FAILED(pdiDevTemp->QueryInterface(IID_IDirectInputDevice2, (LPVOID*)&pNewJoy->fnDeviceInterface)))
  1529. {
  1530. #ifdef _DEBUG
  1531. OutputDebugString(TEXT("JOY.CPL: Cpanel.cpp: DIEnumDevicesProc: QueryInterface failed!\n"));
  1532. #endif
  1533. // release the temporary object
  1534. pdiDevTemp->Release();
  1535. return FALSE;
  1536. }
  1537. DIPROPDWORD *pDIPropDW = new (DIPROPDWORD);
  1538. ASSERT (pDIPropDW);
  1539. ZeroMemory(pDIPropDW, sizeof(DIPROPDWORD));
  1540. pDIPropDW->diph.dwSize = sizeof(DIPROPDWORD);
  1541. pDIPropDW->diph.dwHeaderSize = sizeof(DIPROPHEADER);
  1542. pDIPropDW->diph.dwHow = DIPH_DEVICE;
  1543. // Get the device ID
  1544. VERIFY (SUCCEEDED(pdiDevTemp->GetProperty(DIPROP_JOYSTICKID, &pDIPropDW->diph)));
  1545. // release the temporary object
  1546. pdiDevTemp->Release();
  1547. pNewJoy->ID = (char)pDIPropDW->dwData;
  1548. if (pDIPropDW)
  1549. delete (pDIPropDW);
  1550. // Get the Type name
  1551. LPDIJOYCONFIG_DX5 lpDIJoyCfg = new (DIJOYCONFIG_DX5);
  1552. ASSERT (lpDIJoyCfg);
  1553. ZeroMemory(lpDIJoyCfg, sizeof(DIJOYCONFIG_DX5));
  1554. lpDIJoyCfg->dwSize = sizeof(DIJOYCONFIG_DX5);
  1555. VERIFY (SUCCEEDED(pDIJoyConfig->GetConfig(pNewJoy->ID, (LPDIJOYCONFIG)lpDIJoyCfg, DIJC_REGHWCONFIGTYPE)));
  1556. // Get the clsidConfig
  1557. LPDIJOYTYPEINFO_DX5 lpDIJoyType = new (DIJOYTYPEINFO_DX5);
  1558. ASSERT(lpDIJoyType);
  1559. ZeroMemory(lpDIJoyType, sizeof(DIJOYTYPEINFO_DX5));
  1560. lpDIJoyType->dwSize = sizeof(DIJOYTYPEINFO_DX5);
  1561. VERIFY (SUCCEEDED(pDIJoyConfig->GetTypeInfo(lpDIJoyCfg->wszType, (LPDIJOYTYPEINFO)lpDIJoyType, DITC_CLSIDCONFIG)));
  1562. // if NULL, Leave as default.
  1563. if (!IsEqualIID(lpDIJoyType->clsidConfig, GUID_NULL))
  1564. pNewJoy->clsidPropSheet = lpDIJoyType->clsidConfig;
  1565. if (lpDIJoyType)
  1566. delete (lpDIJoyType);
  1567. // Set it's format!!!
  1568. if (FAILED(pNewJoy->fnDeviceInterface->SetDataFormat(&c_dfDIJoystick)))
  1569. {
  1570. #ifdef _DEBUG
  1571. OutputDebugString(TEXT("JOY.CPL: Cpanel.cpp: DIEnumDevicesProc: SetDataFormat() Failed!\n"));
  1572. #endif
  1573. }
  1574. // Set it's Cooperative Level!
  1575. if (FAILED(pNewJoy->fnDeviceInterface->SetCooperativeLevel(GetParent((HWND)GetParent(hListCtrl)), DISCL_NONEXCLUSIVE | DISCL_BACKGROUND)))
  1576. {
  1577. #ifdef _DEBUG
  1578. OutputDebugString(TEXT("JOY.CPL: Cpanel.cpp: DIEnumDevicesProc: SetCooperativeLevel Failed!\n"));
  1579. #endif
  1580. }
  1581. // Add the item to the tree!
  1582. pAssigned[nAssigned] = pNewJoy;
  1583. // Get the number of buttons!
  1584. LPDIDEVCAPS_DX3 lpDIDevCaps = new (DIDEVCAPS_DX3);
  1585. ASSERT (lpDIDevCaps);
  1586. ZeroMemory(lpDIDevCaps, sizeof(DIDEVCAPS_DX3));
  1587. lpDIDevCaps->dwSize = sizeof(DIDEVCAPS_DX3);
  1588. pAssigned[nAssigned]->fnDeviceInterface->Acquire();
  1589. if (SUCCEEDED(pAssigned[nAssigned]->fnDeviceInterface->GetCapabilities((LPDIDEVCAPS)lpDIDevCaps)))
  1590. pAssigned[nAssigned]->nButtons = (BYTE)lpDIDevCaps->dwButtons;
  1591. if (lpDIDevCaps)
  1592. delete (lpDIDevCaps);
  1593. // If you're on the General page!
  1594. if (nFlags & ON_PAGE)
  1595. {
  1596. DIPROPSTRING *pDIPropStr = new (DIPROPSTRING);
  1597. ASSERT (pDIPropStr);
  1598. ZeroMemory(pDIPropStr, sizeof(DIPROPSTRING));
  1599. pDIPropStr->diph.dwSize = sizeof(DIPROPSTRING);
  1600. pDIPropStr->diph.dwHeaderSize = sizeof(DIPROPHEADER);
  1601. pDIPropStr->diph.dwHow = DIPH_DEVICE;
  1602. pAssigned[nAssigned]->fnDeviceInterface->GetProperty(DIPROP_INSTANCENAME, &pDIPropStr->diph);
  1603. USES_CONVERSION;
  1604. // add to tree
  1605. LVITEM lvItem = {LVIF_TEXT | LVIF_PARAM, nAssigned, 0, 0, 0, W2A(pDIPropStr->wsz), lstrlen(W2A(pDIPropStr->wsz)), 0, (LPARAM)nAssigned, 0};
  1606. ::SendMessage(hListCtrl, LVM_INSERTITEM, 0, (LPARAM) (const LPLVITEM)&lvItem);
  1607. TCHAR sz[STR_LEN_32];
  1608. VERIFY(LoadString(ghInstance, IDS_GEN_STATUS_UNKNOWN, (LPTSTR)&sz, STR_LEN_32));
  1609. SetItemText(hListCtrl, nAssigned, STATUS_COLUMN, sz);
  1610. if (pDIPropStr)
  1611. delete (pDIPropStr);
  1612. }
  1613. // Increment the array counter!
  1614. nAssigned++;
  1615. }
  1616. return TRUE;
  1617. }
  1618. #endif
  1619. */
  1620. ///////////////////////////////////////////////////////////////////////////////
  1621. // FUNCTION: SetActive ( HWND hDlg )
  1622. //
  1623. // PARAMETERS:
  1624. //
  1625. //
  1626. // PURPOSE:
  1627. //
  1628. // RETURN:
  1629. ///////////////////////////////////////////////////////////////////////////////
  1630. BOOL SetActive(HWND hDlg)
  1631. {
  1632. // restore selection focus to nItemSelected
  1633. SetListCtrlItemFocus(hListCtrl, (BYTE)iItem);
  1634. BYTE i = (BYTE)::SendMessage(hListCtrl, LVM_GETITEMCOUNT, 0, 0);
  1635. // Acquire All Devices that are Attached!!!
  1636. char nIndex;
  1637. while( i-- )
  1638. {
  1639. // get joystick config of item
  1640. nIndex = (char)GetItemData(hListCtrl, i);
  1641. if( pAssigned[nIndex]->nStatus & JOY_US_PRESENT )
  1642. pAssigned[nIndex]->fnDeviceInterface->Acquire();
  1643. }
  1644. // create timer
  1645. SetTimer(hDlg, ID_MYTIMER, POLLRATE, 0);
  1646. UpdateButtonState( hDlg );
  1647. return(TRUE);
  1648. }
  1649. ///////////////////////////////////////////////////////////////////////////////
  1650. // FUNCTION: MsgSubClassProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  1651. //
  1652. // PARAMETERS: HWND hWnd
  1653. // UINT uMsg
  1654. // WPARAM wParam
  1655. // LPARAM lParam
  1656. //
  1657. // PURPOSE:
  1658. //
  1659. // RETURN:
  1660. ///////////////////////////////////////////////////////////////////////////////
  1661. BOOL WINAPI MsgSubClassProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  1662. {
  1663. // Only do this if you are ON THIS PAGE!
  1664. if( nFlags & ON_PAGE )
  1665. {
  1666. if( uMsg == JoyCfgChangedMsg )
  1667. {
  1668. if( !(nFlags & BLOCK_UPDATE) )
  1669. {
  1670. // kill status timer
  1671. KillTimer(hWnd, ID_MYTIMER);
  1672. nFlags |= UPDATE_ALL;
  1673. ClearArrays();
  1674. pDIJoyConfig->EnumTypes((LPDIJOYTYPECALLBACK)DIEnumJoyTypeProc, NULL);
  1675. UpdateListCtrl(hWnd);
  1676. SetActive(hWnd);
  1677. }
  1678. }
  1679. }
  1680. return(BOOL)CallWindowProc(fpMainWindowProc, hWnd, uMsg, wParam, lParam);
  1681. }
  1682. ///////////////////////////////////////////////////////////////////////////////
  1683. // FUNCTION: Error ( short nTitleID, short nMsgID )
  1684. //
  1685. // PARAMETERS: nTitleID - Resource ID for Message Title
  1686. // nMsgID - Resource ID for Message
  1687. //
  1688. // PURPOSE: Prompt user when error occurs
  1689. //
  1690. // RETURN: TRUE
  1691. ///////////////////////////////////////////////////////////////////////////////
  1692. void Error(short nTitleID, short nMsgID)
  1693. {
  1694. LPTSTR lptTitle = new TCHAR[STR_LEN_64];
  1695. ASSERT (lptTitle);
  1696. if( LoadString(ghInstance, nTitleID, lptTitle, STR_LEN_64) )
  1697. {
  1698. LPTSTR lptMsg = new TCHAR[MAX_STR_LEN];
  1699. ASSERT (lptMsg);
  1700. if( LoadString(ghInstance, nMsgID, lptMsg, MAX_STR_LEN) )
  1701. MessageBox(NULL, lptMsg, lptTitle, MB_ICONHAND | MB_OK | MB_APPLMODAL);
  1702. if( lptMsg )
  1703. delete[] (lptMsg);
  1704. }
  1705. if( lptTitle )
  1706. delete[] (lptTitle);
  1707. }
  1708. ///////////////////////////////////////////////////////////////////////////////
  1709. // FUNCTION: MoveOK ( HWND hParentWnd )
  1710. //
  1711. // PARAMETERS:
  1712. //
  1713. //
  1714. // PURPOSE:
  1715. //
  1716. // RETURN:
  1717. ///////////////////////////////////////////////////////////////////////////////
  1718. void MoveOK(HWND hParentWnd)
  1719. {
  1720. // Hide the Cancel and move the OK...
  1721. HWND hCtrl = GetDlgItem(hParentWnd, IDCANCEL);
  1722. // if there is no IDCANCEL, we've been here before!
  1723. if( hCtrl )
  1724. {
  1725. RECT rc;
  1726. GetWindowRect(hCtrl, &rc);
  1727. DestroyWindow(hCtrl);
  1728. //POINT pt = {rc.left, rc.top};
  1729. //ScreenToClient(hParentWnd, &pt);
  1730. // This should take care of Mirroring and work for normal windows
  1731. MapWindowPoints(NULL, hParentWnd, (LPPOINT)&rc, 2);
  1732. hCtrl = GetDlgItem(hParentWnd, IDOK);
  1733. ASSERT(hCtrl);
  1734. //SetWindowPos(hCtrl, NULL, pt.x, pt.y, NULL, NULL, SWP_NOSIZE | SWP_NOZORDER);
  1735. SetWindowPos(hCtrl, NULL, rc.left, rc.top, NULL, NULL, SWP_NOSIZE | SWP_NOZORDER);
  1736. LPTSTR lpszDone = new TCHAR[12];
  1737. ASSERT (lpszDone);
  1738. // Used to be IDS_DONE, but we changed it from DONE to OK
  1739. VERIFY(LoadString(ghInstance, IDS_GEN_STATUS_OK, lpszDone, 12));
  1740. ::SendMessage(hCtrl, WM_SETTEXT, 0, (LPARAM)(LPCTSTR)lpszDone);
  1741. if( lpszDone )
  1742. delete[] (lpszDone);
  1743. }
  1744. }
  1745. ///////////////////////////////////////////////////////////////////////////////
  1746. // FUNCTION: UpdateButtonState ( HWND hDlg )
  1747. //
  1748. // PARAMETERS:
  1749. //
  1750. //
  1751. // PURPOSE:
  1752. //
  1753. // RETURN:
  1754. ///////////////////////////////////////////////////////////////////////////////
  1755. void UpdateButtonState( HWND hDlg )
  1756. {
  1757. PostDlgItemEnableWindow(hDlg, IDC_BTN_REMOVE, (BOOL)nAssigned);
  1758. PostDlgItemEnableWindow(hDlg, IDC_BTN_PROPERTIES, (BOOL)nAssigned);
  1759. }
  1760. #ifdef WINNT
  1761. ///////////////////////////////////////////////////////////////////////////////
  1762. // FUNCTION: RunWDMJoy ( void )
  1763. //
  1764. // PURPOSE: Run wdmjoy.inf to install
  1765. //
  1766. ///////////////////////////////////////////////////////////////////////////////
  1767. void RunWDMJOY( void )
  1768. {
  1769. //Check if we have already placed the first value
  1770. //HKLM,SYSTEM\CurrentControlSet\Control\MediaProperties\PrivateProperties\Joystick\OEM\VID_045E&PID_01F0
  1771. HKEY hKey;
  1772. long lTest = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  1773. REGSTR_PATH_JOYOEM TEXT("\\VID_045E&PID_01F0"),
  1774. 0,
  1775. KEY_READ,
  1776. &hKey);
  1777. if (lTest == ERROR_SUCCESS)
  1778. {
  1779. RegCloseKey(hKey);
  1780. return;
  1781. }
  1782. LPTSTR lpszWDMJoy = new (TCHAR[STR_LEN_64]);
  1783. ASSERT (lpszWDMJoy);
  1784. // Check to see if the file is present
  1785. WIN32_FIND_DATA findData;
  1786. BYTE nLen = (BYTE)GetWindowsDirectory(lpszWDMJoy, STR_LEN_64);
  1787. VERIFY(LoadString(ghInstance, IDS_WDMJOY_INF, &lpszWDMJoy[nLen], STR_LEN_64-nLen));
  1788. HANDLE hFind = FindFirstFile(lpszWDMJoy, &findData);
  1789. // If you've found one... run it!
  1790. if( hFind != INVALID_HANDLE_VALUE )
  1791. {
  1792. LPTSTR lpStr = new (TCHAR[MAX_STR_LEN]);
  1793. ASSERT (lpStr);
  1794. // Copy the Windows directory to the buffer!
  1795. _tcsncpy(lpStr, lpszWDMJoy, nLen+1);
  1796. if( LoadString(ghInstance, IDS_WDMJOY, &lpStr[nLen], MAX_STR_LEN-nLen) )
  1797. {
  1798. // Put IDS_WDMJOY_INF on the end of the string!
  1799. _tcscpy(&lpStr[lstrlen(lpStr)], lpszWDMJoy);
  1800. LPSTARTUPINFO psi = new (STARTUPINFO);
  1801. ASSERT (psi);
  1802. ZeroMemory(psi, sizeof(STARTUPINFO));
  1803. psi->cb = sizeof(STARTUPINFO);
  1804. LPPROCESS_INFORMATION ppi = new (PROCESS_INFORMATION);
  1805. ASSERT (ppi);
  1806. ZeroMemory(ppi, sizeof(PROCESS_INFORMATION));
  1807. if( CreateProcess(0, lpStr, 0, 0, 0, 0, 0, 0, psi, ppi) )
  1808. {
  1809. CloseHandle(ppi->hThread);
  1810. CloseHandle(ppi->hProcess);
  1811. }
  1812. #ifdef _DEBUG
  1813. else OutputDebugString(TEXT("JOY.CPL: CPANEL.CPP: RunWDMJoy: CreateProcess Failed!\n"));
  1814. #endif
  1815. if( ppi )
  1816. delete (ppi);
  1817. if( psi )
  1818. delete (psi);
  1819. }
  1820. if( lpStr )
  1821. delete[] (lpStr);
  1822. }
  1823. FindClose(hFind);
  1824. if( lpszWDMJoy )
  1825. delete[] (lpszWDMJoy);
  1826. }
  1827. #endif
  1828. #ifdef _UNICODE
  1829. ///////////////////////////////////////////////////////////////////////////////
  1830. // FUNCTION: RegisterForDevChange ( HWND hDlg, PVOID *hNoditfyDevNode )
  1831. //
  1832. // PARAMETERS:
  1833. //
  1834. //
  1835. // PURPOSE:
  1836. //
  1837. // RETURN:
  1838. ///////////////////////////////////////////////////////////////////////////////
  1839. void RegisterForDevChange(HWND hDlg, PVOID *hNotifyDevNode)
  1840. {
  1841. DEV_BROADCAST_DEVICEINTERFACE *pFilterData = new (DEV_BROADCAST_DEVICEINTERFACE);
  1842. ASSERT (pFilterData);
  1843. ZeroMemory(pFilterData, sizeof(DEV_BROADCAST_DEVICEINTERFACE));
  1844. pFilterData->dbcc_size = sizeof(DEV_BROADCAST_DEVICEINTERFACE);
  1845. pFilterData->dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE;
  1846. pFilterData->dbcc_classguid = GUID_CLASS_INPUT;
  1847. *hNotifyDevNode = RegisterDeviceNotification(hDlg, pFilterData, DEVICE_NOTIFY_WINDOW_HANDLE);
  1848. if( pFilterData )
  1849. delete (pFilterData);
  1850. }
  1851. #endif
  1852. // BEGINNING OF LIST CONTROL FUNCTIONS!
  1853. ///////////////////////////////////////////////////////////////////////////////
  1854. // FUNCTION: SetListCtrlItemFocus ( HWND hCtrl, BYTE nItem )
  1855. //
  1856. // PARAMETERS: HWND hCtrl - Handle of ListControl to recieve the message
  1857. // BYTE nItem - Item to set focus to
  1858. //
  1859. // PURPOSE: Set focus to item in list control
  1860. //
  1861. // RETURN: NONE
  1862. ///////////////////////////////////////////////////////////////////////////////
  1863. void SetListCtrlItemFocus ( HWND hCtrl, BYTE nItem )
  1864. {
  1865. LPLVITEM plvItem = (LPLVITEM)_alloca(sizeof(LVITEM));
  1866. ASSERT (plvItem);
  1867. plvItem->lParam = plvItem->iSubItem = plvItem->iImage =
  1868. plvItem->cchTextMax = plvItem->iIndent = 0;
  1869. plvItem->mask = LVIF_STATE;
  1870. plvItem->iItem = nItem;
  1871. plvItem->state =
  1872. plvItem->stateMask = LVIS_FOCUSED | LVIS_SELECTED;
  1873. plvItem->pszText = NULL;
  1874. ::SendMessage(hCtrl, LVM_SETITEM, 0, (LPARAM)(const LPLVITEM)plvItem);
  1875. }
  1876. ///////////////////////////////////////////////////////////////////////////////
  1877. // FUNCTION: GetItemData(HWND hCtrl, BYTE nItem )
  1878. //
  1879. // PARAMETERS: HWND hCtrl - Handle of ListControl to recieve the message
  1880. //
  1881. // BYTE nItem - Item to retrieve data from
  1882. // PURPOSE: Retrieve the lower char of the item's data
  1883. //
  1884. // RETURN: Item's data cast to a char
  1885. ///////////////////////////////////////////////////////////////////////////////
  1886. DWORD GetItemData(HWND hCtrl, BYTE nItem )
  1887. {
  1888. LPLVITEM plvItem = (LPLVITEM)_alloca(sizeof(LVITEM));
  1889. ASSERT (plvItem);
  1890. ZeroMemory(plvItem, sizeof(LVITEM));
  1891. plvItem->mask = LVIF_PARAM;
  1892. plvItem->iItem = nItem;
  1893. VERIFY(::SendMessage(hCtrl, LVM_GETITEM, 0, (LPARAM)(LPLVITEM)plvItem));
  1894. return(DWORD)plvItem->lParam;
  1895. }
  1896. ///////////////////////////////////////////////////////////////////////////////
  1897. // FUNCTION: SetItemData(HWND hCtrl, BYTE nItem, DWORD dwFlag )
  1898. //
  1899. // PARAMETERS: HWND hCtrl - Handle of ListControl to recieve the message
  1900. // BYTE nItem - Item to send data to
  1901. // DWORD dwFlag - DWORD to send to nItem
  1902. // PURPOSE: Set the extra memory associated with nItem to dwFlag
  1903. //
  1904. // RETURN: TRUE if Successful, FALSE otherwise
  1905. ///////////////////////////////////////////////////////////////////////////////
  1906. BOOL SetItemData(HWND hCtrl, BYTE nItem, DWORD dwFlag )
  1907. {
  1908. LPLVITEM plvItem = (LPLVITEM)_alloca(sizeof(LVITEM));
  1909. ASSERT (plvItem);
  1910. ZeroMemory(plvItem, sizeof(LVITEM));
  1911. plvItem->mask = LVIF_PARAM;
  1912. plvItem->iItem = nItem;
  1913. plvItem->lParam = dwFlag;
  1914. return(BOOL)::SendMessage(hCtrl, LVM_SETITEM, 0, (LPARAM)(const LPLVITEM)plvItem);
  1915. }
  1916. ///////////////////////////////////////////////////////////////////////////////
  1917. // FUNCTION: InsertColumn (HWND hCtrl, BYTE nColumn, short nStrID, short nWidth)
  1918. //
  1919. // PARAMETERS: HWND hCtrl - Handle of ListControl to recieve the message
  1920. // BYTE nColumn - Column to place string
  1921. // short nStrID - Resource ID for string
  1922. // short nWidth - Width of column
  1923. //
  1924. // PURPOSE: Insert a column in a list control
  1925. //
  1926. // RETURN: NONE
  1927. ///////////////////////////////////////////////////////////////////////////////
  1928. void InsertColumn (HWND hCtrl, BYTE nColumn, USHORT nStrID, USHORT nWidth)
  1929. {
  1930. // Allocate the structure
  1931. LPLVCOLUMN plvColumn = (LPLVCOLUMN)_alloca(sizeof(LVCOLUMN));
  1932. ASSERT (plvColumn);
  1933. ZeroMemory(plvColumn, sizeof(LVCOLUMN));
  1934. plvColumn->mask = LVCF_FMT | LVCF_TEXT | LVCF_WIDTH;
  1935. plvColumn->fmt = LVCFMT_CENTER;
  1936. plvColumn->cx = nWidth;
  1937. plvColumn->pszText = (LPTSTR)_alloca(sizeof(TCHAR[STR_LEN_32]));
  1938. ASSERT (plvColumn->pszText);
  1939. plvColumn->cchTextMax = LoadString(ghInstance, nStrID, plvColumn->pszText, STR_LEN_32);
  1940. ::SendMessage(hCtrl, LVM_INSERTCOLUMN, (WPARAM)(int)nColumn, (LPARAM)(const LPLVCOLUMN)plvColumn);
  1941. }
  1942. ///////////////////////////////////////////////////////////////////////////////
  1943. // FUNCTION: SetItemText( HWND hCtrl, BYTE nItem, BYTE nSubItem, LPTSTR lpStr)
  1944. //
  1945. // PARAMETERS: HWND hCtrl - Handle of ListControl to recieve the message
  1946. // BYTE nItem - Item to set
  1947. // BYTE nSubItem - SubItem to set
  1948. // LPTSTR lpStr - String to set
  1949. //
  1950. // PURPOSE: Set list control item text
  1951. //
  1952. // RETURN: NONE
  1953. ///////////////////////////////////////////////////////////////////////////////
  1954. void SetItemText( HWND hCtrl, BYTE nItem, BYTE nSubItem, LPTSTR lpStr)
  1955. {
  1956. LPLVITEM plvItem = (LPLVITEM)_alloca(sizeof(LVITEM));
  1957. ASSERT (plvItem);
  1958. plvItem->lParam = plvItem->stateMask = plvItem->iImage =
  1959. plvItem->state = plvItem->iIndent = 0;
  1960. plvItem->mask = LVIF_TEXT;
  1961. plvItem->iItem = nItem;
  1962. plvItem->iSubItem = nSubItem;
  1963. plvItem->cchTextMax = lstrlen(lpStr);
  1964. plvItem->pszText = lpStr;
  1965. ::SendMessage(hCtrl, LVM_SETITEM, 0, (LPARAM)(const LPLVITEM)plvItem);
  1966. }
  1967. ///////////////////////////////////////////////////////////////////////////////
  1968. // FUNCTION: GetItemText( HWND hCtrl, BYTE nItem, BYTE nSubItem, LPTSTR lpszBuff, BYTE nLen )
  1969. //
  1970. // PARAMETERS: HWND hCtrl - Handle of ListControl to recieve the message
  1971. // BYTE nItem - Item to retrive text
  1972. // BYTE nSubItem - SubItem to retrieve text
  1973. // LPTSTR lpszBuff - Buffer for retrieved text
  1974. // BYTE nLen - Size of buffer
  1975. //
  1976. // PURPOSE: Retrieve text from a list control
  1977. //
  1978. // RETURN: length of retrieved string!
  1979. ///////////////////////////////////////////////////////////////////////////////
  1980. BYTE GetItemText( HWND hCtrl, BYTE nItem, BYTE nSubItem, LPTSTR lpszBuff, BYTE nLen )
  1981. {
  1982. LPLVITEM plvItem = (LPLVITEM)_alloca(sizeof(LVITEM));
  1983. ASSERT (plvItem);
  1984. plvItem->lParam = plvItem->stateMask = plvItem->iImage =
  1985. plvItem->state = plvItem->iIndent = 0;
  1986. plvItem->mask = LVIF_TEXT;
  1987. plvItem->iItem = nItem;
  1988. plvItem->iSubItem = nSubItem;
  1989. plvItem->pszText = lpszBuff;
  1990. plvItem->cchTextMax = nLen;
  1991. return(BYTE)::SendMessage(hCtrl, LVM_GETITEMTEXT, (WPARAM)nItem, (LPARAM)(const LPLVITEM)plvItem);
  1992. }
  1993. ///////////////////////////////////////////////////////////////////////////////
  1994. // FUNCTION: InsertItem(HWND hCtrl, LPTSTR lpszBuff )
  1995. //
  1996. // PARAMETERS: HWND hCtrl - Handle of ListControl to recieve the message
  1997. // BYTE nItem - Item to retrive text
  1998. // LPTSTR lpszBuff - Text to be inserted
  1999. //
  2000. // PURPOSE: Retrieve text from a list control
  2001. //
  2002. // RETURN: NONE BYTE nItem,
  2003. ///////////////////////////////////////////////////////////////////////////////
  2004. BYTE InsertItem( HWND hCtrl, LPTSTR lpszBuff, BYTE nItem )
  2005. {
  2006. LPLVITEM plvItem = (LPLVITEM)_alloca(sizeof(LVITEM));
  2007. ASSERT (plvItem);
  2008. plvItem->state = plvItem->stateMask = plvItem->iImage =
  2009. plvItem->iItem = plvItem->iIndent = plvItem->iSubItem = 0;
  2010. plvItem->mask = LVIF_TEXT | LVIF_PARAM;
  2011. plvItem->pszText = lpszBuff;
  2012. plvItem->cchTextMax = lstrlen(lpszBuff);
  2013. plvItem->lParam = ID_NONE | nItem;
  2014. return(BYTE)::SendMessage(hCtrl, LVM_INSERTITEM, (WPARAM)0, (LPARAM)(const LPLVITEM)plvItem);
  2015. }
  2016. ///////////////////////////////////////////////////////////////////////////////
  2017. // FUNCTION: Launch(HWND hWnd, BYTE nJoy, BYTE startpage)
  2018. //
  2019. // PARAMETERS: HWND hWnd - Handle to Dialog
  2020. // BYTE nJoy - Index into pAssigned global array of assigned devices
  2021. // BYTE nStartPage - Page to show first
  2022. //
  2023. // PURPOSE:
  2024. //
  2025. //
  2026. // RETURN:
  2027. ///////////////////////////////////////////////////////////////////////////////
  2028. HRESULT Launch(HWND hWnd, PJOY pJoy, BYTE nStartPage)
  2029. {
  2030. HRESULT hresRet;
  2031. ASSERT (::IsWindow(hWnd));
  2032. if( nStartPage > MAX_PAGES )
  2033. return(DIGCERR_STARTPAGETOOLARGE);
  2034. LPCDIGAMECNTRLPROPSHEET fnInterface;
  2035. /*
  2036. #ifdef _UNICODE
  2037. LPTSTR lpszWin32 = new (TCHAR[STR_LEN_64]);
  2038. ASSERT (lpszWin32);
  2039. _tcscpy(&lpszWin32[GetSystemDirectory(lpszWin32, STR_LEN_64)], TEXT("\\OLE32.DLL"));
  2040. //TEXT("OLE32.DLL")
  2041. HINSTANCE hOleInst = LoadLibrary(lpszWin32);
  2042. if (lpszWin32)
  2043. delete[] (lpszWin32);
  2044. if (!hOleInst)
  2045. {
  2046. return E_NOINTERFACE;
  2047. }
  2048. #endif
  2049. */
  2050. // Get the interface pointer if there is one!
  2051. // This reduces the memory footprint of the CPL but takes a bit more time to
  2052. // launch the property sheet pages!
  2053. /*
  2054. #ifdef _UNICODE
  2055. fnInterface = HasInterface(pJoy->clsidPropSheet, hOleInst);
  2056. if (!fnInterface)
  2057. {
  2058. // If the propsheet is not mine, try mine!
  2059. if (!IsEqualIID(pJoy->clsidPropSheet, CLSID_LegacyServer))
  2060. fnInterface = HasInterface(CLSID_LegacyServer, hOleInst);
  2061. }
  2062. FreeLibrary(hOleInst);
  2063. #else
  2064. */
  2065. HRESULT hr;
  2066. //if( SUCCEEDED(hr = CoInitializeEx(NULL, COINIT_DISABLE_OLE1DDE | COINIT_APARTMENTTHREADED| COINIT_SPEED_OVER_MEMORY)) )
  2067. // OLE32 on Win95 does not have CoInitializeEx.
  2068. if( SUCCEEDED(hr = CoInitialize(NULL)) )
  2069. {
  2070. IClassFactory* ppv_classfactory;
  2071. if( SUCCEEDED(hr = CoGetClassObject(pJoy->clsidPropSheet, CLSCTX_INPROC_SERVER, NULL, IID_IClassFactory, (void **)&ppv_classfactory)) )
  2072. {
  2073. VERIFY(SUCCEEDED(ppv_classfactory->CreateInstance(NULL, IID_IDIGameCntrlPropSheet, (LPVOID *)&fnInterface)));
  2074. ppv_classfactory->Release();
  2075. } else {
  2076. fnInterface = 0;
  2077. }
  2078. } else {
  2079. fnInterface = 0;
  2080. }
  2081. //#endif
  2082. // By this point, you've tried twice (possibly)...
  2083. // if you don't have an interface by this point...
  2084. // QUIT!
  2085. if( !fnInterface )
  2086. {
  2087. Error((short)IDS_INTERNAL_ERROR, (short)IDS_NO_DIJOYCONFIG);
  2088. return(E_NOINTERFACE);
  2089. }
  2090. // here's where we are sending the property sheet an ID describing the location of the installed device!
  2091. fnInterface->SetID(pJoy->ID);
  2092. LPDIGCSHEETINFO pServerSheet;
  2093. // Get the property sheet info from the server
  2094. if( FAILED(fnInterface->GetSheetInfo(&pServerSheet)) )
  2095. {
  2096. TRACE(TEXT("JOY.CPL: CPANEL.CPP: Launch: GetSheetInfo Failed!\n"));
  2097. return(E_FAIL);
  2098. }
  2099. // test to make sure the number of pages is reasonable
  2100. if( pServerSheet->nNumPages == 0 )
  2101. return(DIGCERR_NUMPAGESZERO);
  2102. else if( (pServerSheet->nNumPages > MAX_PAGES) || (pServerSheet->nNumPages < nStartPage) )
  2103. return(DIGCERR_NUMPAGESTOOLARGE);
  2104. LPDIGCPAGEINFO pServerPage;
  2105. // step 2 : get the information for all the pages from the server
  2106. if( FAILED(fnInterface->GetPageInfo(&pServerPage)) )
  2107. {
  2108. TRACE(TEXT("JOY.CPL: CPANEL.CPP: Launch: GetPageInfo Failed!\n"));
  2109. return(E_FAIL);
  2110. }
  2111. // Allocate Memory for the pages!
  2112. HPROPSHEETPAGE *pPages = new (HPROPSHEETPAGE[pServerSheet->nNumPages]);
  2113. ASSERT (pPages);
  2114. ZeroMemory(pPages, sizeof(HPROPSHEETPAGE)*pServerSheet->nNumPages);
  2115. if( !pPages ) return(E_OUTOFMEMORY);
  2116. // Allocate Memory for the header!
  2117. LPPROPSHEETHEADER ppsh = new (PROPSHEETHEADER);
  2118. ASSERT (ppsh);
  2119. ZeroMemory(ppsh, sizeof(PROPSHEETHEADER));
  2120. ppsh->dwSize = sizeof(PROPSHEETHEADER);
  2121. ppsh->hwndParent = hWnd;
  2122. ppsh->hInstance = pServerPage[0].hInstance;
  2123. if( pServerSheet->fSheetIconFlag )
  2124. {
  2125. if( pServerSheet->lpwszSheetIcon )
  2126. {
  2127. // check to see if you are an INT or a WSTR
  2128. if( HIWORD((INT_PTR)pServerSheet->lpwszSheetIcon) )
  2129. {
  2130. // You are a string!
  2131. #ifdef _UNICODE
  2132. ppsh->pszIcon = pServerSheet->lpwszSheetIcon;
  2133. #else
  2134. USES_CONVERSION;
  2135. ppsh->pszIcon = W2A(pServerSheet->lpwszSheetIcon);
  2136. #endif
  2137. } else ppsh->pszIcon = (LPCTSTR)(pServerSheet->lpwszSheetIcon);
  2138. ppsh->dwFlags = PSH_USEICONID;
  2139. } else return(DIGCERR_NOICON);
  2140. }
  2141. // do we have a sheet caption ?
  2142. if( pServerSheet->lpwszSheetCaption )
  2143. {
  2144. #ifdef _UNICODE
  2145. ppsh->pszCaption = pServerSheet->lpwszSheetCaption;
  2146. #else
  2147. USES_CONVERSION;
  2148. ppsh->pszCaption = W2A(pServerSheet->lpwszSheetCaption);
  2149. #endif
  2150. ppsh->dwFlags |= PSH_PROPTITLE;
  2151. }
  2152. ppsh->nPages = pServerSheet->nNumPages;
  2153. ppsh->nStartPage = nStartPage;
  2154. // set the property pages inofrmation into the header
  2155. ppsh->phpage = pPages;
  2156. // OK, sheet stuff is done... now, time to do the pages!
  2157. #ifndef _UNICODE
  2158. USES_CONVERSION;
  2159. #endif
  2160. LPPROPSHEETPAGE lpPropPage = new (PROPSHEETPAGE);
  2161. ASSERT(lpPropPage);
  2162. ZeroMemory(lpPropPage, sizeof(PROPSHEETPAGE));
  2163. lpPropPage->dwSize = sizeof(PROPSHEETPAGE);
  2164. // 3.2 Now proceed to fill up each page
  2165. BYTE nIndex = 0;
  2166. do
  2167. {
  2168. // Assign the things that there are not questionable
  2169. lpPropPage->lParam = pServerPage[nIndex].lParam;
  2170. lpPropPage->hInstance = pServerPage[nIndex].hInstance;
  2171. // Add the title...
  2172. if( pServerPage[nIndex].lpwszPageTitle )
  2173. {
  2174. lpPropPage->dwFlags = PSP_USETITLE;
  2175. // Check to see if you are a String!!!
  2176. if( HIWORD((INT_PTR)pServerPage[nIndex].lpwszPageTitle) )
  2177. {
  2178. #ifdef _UNICODE
  2179. lpPropPage->pszTitle = pServerPage[nIndex].lpwszPageTitle;
  2180. #else
  2181. lpPropPage->pszTitle = W2A(pServerPage[nIndex].lpwszPageTitle);
  2182. #endif
  2183. } else lpPropPage->pszTitle = (LPTSTR)pServerPage[nIndex].lpwszPageTitle;
  2184. } else lpPropPage->pszTitle = NULL;
  2185. // if icon is required go ahead and add it.
  2186. if( pServerPage[nIndex].fIconFlag )
  2187. {
  2188. lpPropPage->dwFlags |= PSP_USEICONID;
  2189. // Check to see if you are an INT or a String!
  2190. if( HIWORD((INT_PTR)pServerPage[nIndex].lpwszPageIcon) )
  2191. {
  2192. // You're a string!!!
  2193. #ifdef _UNICODE
  2194. lpPropPage->pszIcon = pServerPage[nIndex].lpwszPageIcon;
  2195. #else
  2196. lpPropPage->pszIcon = W2A(pServerPage[nIndex].lpwszPageIcon);
  2197. #endif
  2198. } else lpPropPage->pszIcon = (LPCTSTR)(pServerPage[nIndex].lpwszPageIcon);
  2199. }
  2200. // if a pre - post processing call back proc is required go ahead and add it
  2201. if( pServerPage[nIndex].fProcFlag )
  2202. {
  2203. if( pServerPage[nIndex].fpPrePostProc )
  2204. {
  2205. lpPropPage->dwFlags |= PSP_USECALLBACK;
  2206. lpPropPage->pfnCallback = (LPFNPSPCALLBACK) pServerPage[nIndex].fpPrePostProc;
  2207. } else return(DIGCERR_NOPREPOSTPROC);
  2208. }
  2209. // and the essential "dialog" proc
  2210. if( pServerPage[nIndex].fpPageProc )
  2211. lpPropPage->pfnDlgProc = pServerPage[nIndex].fpPageProc;
  2212. else return(DIGCERR_NODLGPROC);
  2213. // Assign the Dialog Template!
  2214. if( HIWORD((INT_PTR)pServerPage[nIndex].lpwszTemplate) )
  2215. {
  2216. #ifdef _UNICODE
  2217. lpPropPage->pszTemplate = pServerPage[nIndex].lpwszTemplate;
  2218. #else
  2219. lpPropPage->pszTemplate = W2A(pServerPage[nIndex].lpwszTemplate);
  2220. #endif
  2221. } else lpPropPage->pszTemplate = (LPTSTR)pServerPage[nIndex].lpwszTemplate;
  2222. pPages[nIndex++] = CreatePropertySheetPage(lpPropPage);
  2223. } while( nIndex < pServerSheet->nNumPages );
  2224. if( lpPropPage )
  2225. delete (lpPropPage);
  2226. // step 5 : launch modal property sheet dialog
  2227. hresRet = (HRESULT)PropertySheet(ppsh);
  2228. if( pPages )
  2229. delete[] (pPages);
  2230. if( ppsh )
  2231. delete (ppsh);
  2232. if( fnInterface )
  2233. fnInterface->Release();
  2234. CoFreeUnusedLibraries(); //to free gcdef.dll now
  2235. //#ifndef _UNICODE
  2236. // Let COM go... on Memphis!
  2237. CoUninitialize();
  2238. if( hresRet )
  2239. {
  2240. switch( hresRet )
  2241. {
  2242. // In the event that the user wants to reboot...
  2243. case ID_PSREBOOTSYSTEM:
  2244. case ID_PSRESTARTWINDOWS:
  2245. #ifdef _DEBUG
  2246. TRACE(TEXT("JOY.CPL: PropertySheet returned a REBOOT request!\n"));
  2247. #endif
  2248. ExitWindowsEx(EWX_REBOOT, NULL);
  2249. break;
  2250. }
  2251. } else {
  2252. ::PostMessage(hWnd, WM_COMMAND, (WPARAM)IDC_BTN_REFRESH, 0);
  2253. }
  2254. //#endif
  2255. // step 7 : return success / failure code back to the caller
  2256. return(hresRet);
  2257. }
  2258. /*
  2259. #ifdef _UNICODE
  2260. //////////////////////////////////////////////////////////////////////
  2261. // LPCDIGAMECNTRLPROPSHEET HasInterface(REFCLSID refCLSID, HINSTANCE hOleInst)
  2262. // Purpose: Tests for existance of rrid in refCLSID
  2263. LPCDIGAMECNTRLPROPSHEET HasInterface(REFCLSID refCLSID, HINSTANCE hOleInst)
  2264. {
  2265. typedef HRESULT (STDAPICALLTYPE * LPFNCOGETCLASSOBJECT)(REFCLSID, DWORD, COSERVERINFO *, REFIID, LPVOID *);
  2266. LPFNCOGETCLASSOBJECT fpCoGetClassObject = (LPFNCOGETCLASSOBJECT)GetProcAddress(hOleInst, "CoGetClassObject");
  2267. IClassFactory* ppv_classfactory;
  2268. LPCDIGAMECNTRLPROPSHEET fnInterface = 0;
  2269. if(SUCCEEDED(fpCoGetClassObject( refCLSID, CLSCTX_INPROC_SERVER, NULL, IID_IClassFactory, (void **)&ppv_classfactory)))
  2270. {
  2271. if(SUCCEEDED(ppv_classfactory->CreateInstance(NULL, IID_IDIGameCntrlPropSheet, (LPVOID *)&fnInterface)))
  2272. {
  2273. ppv_classfactory->Release();
  2274. }
  2275. else
  2276. {
  2277. #ifdef _DEBUG
  2278. OutputDebugString(TEXT("CPANEL.cpp: CreateInstance Failed!\n"));
  2279. #endif
  2280. // make sure the pointer is nulled
  2281. fnInterface = 0;
  2282. ppv_classfactory->Release();
  2283. }
  2284. }
  2285. else
  2286. #ifdef _DEBUG
  2287. else OutputDebugString(TEXT("CPANEL.cpp: LoadServerInterface Failed!\n"));
  2288. #endif
  2289. return fnInterface;
  2290. }
  2291. #endif // _UNICODE
  2292. */