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.

607 lines
18 KiB

  1. //@doc
  2. /******************************************************
  3. **
  4. ** @module DTRANS.CPP | DataTransmitter implementation file
  5. **
  6. ** Description:
  7. **
  8. ** History:
  9. ** Created 11/13/97 Matthew L. Coill (mlc)
  10. **
  11. ** (c) 1986-1997 Microsoft Corporation. All Rights Reserved.
  12. ******************************************************/
  13. #include "FFDevice.h"
  14. #include "DTrans.h"
  15. //#include <devioctl.h>
  16. #ifdef _DEBUG
  17. extern void DebugOut(LPCTSTR szDebug);
  18. #else !_DEBUG
  19. #define DebugOut(x)
  20. #endif _DEBUG
  21. const char cCommPortNames[4][5] = { "COM1", "COM2", "COM3", "COM4" };
  22. const unsigned short c1_16_BytesPerShot = 3;
  23. const DWORD c1_16_SerialSleepTime = 1;
  24. #define UART_FILTER_NAME TEXT("\\\\.\\.\\PortClass0\\Uart")
  25. const WORD c_LongMsgMax = 256;
  26. inline BOOL IsHandleValid(HANDLE handleToCheck)
  27. {
  28. return ((handleToCheck != NULL) && (handleToCheck != INVALID_HANDLE_VALUE));
  29. }
  30. #define CHECK_RELEASE_AND_NULL(pIUnknown) \
  31. if (pIUnknown != NULL) \
  32. { \
  33. pIUnknown->Release(); \
  34. pIUnknown = NULL; \
  35. }
  36. /************************** SerialDataTransmitter Class ******************************/
  37. /******************************************************
  38. **
  39. ** SerialDataTransmitter::SerialDataTransmitter()
  40. **
  41. ** @mfunc Constructor.
  42. **
  43. ******************************************************/
  44. SerialDataTransmitter::SerialDataTransmitter() : DataTransmitter(),
  45. m_SerialPort(INVALID_HANDLE_VALUE),
  46. m_SerialPortIDHack(0)
  47. {
  48. }
  49. /******************************************************
  50. **
  51. ** SerialDataTransmitter::~SerialDataTransmitter()
  52. **
  53. ** @mfunc Destructor.
  54. **
  55. ******************************************************/
  56. SerialDataTransmitter::~SerialDataTransmitter()
  57. {
  58. if (m_SerialPort != INVALID_HANDLE_VALUE) {
  59. if (::CloseHandle(m_SerialPort) == FALSE) {
  60. // ASSUME_NOT_REACHED();
  61. }
  62. m_SerialPort = INVALID_HANDLE_VALUE;
  63. }
  64. }
  65. /******************************************************
  66. **
  67. ** SerialDataTransmitter::Initialize()
  68. **
  69. ** returns: TRUE if initialized FALSE if not able to initialize
  70. ** @mfunc Initialize.
  71. **
  72. ******************************************************/
  73. BOOL SerialDataTransmitter::Initialize()
  74. {
  75. // If already open, close for reinitialization
  76. if (m_SerialPort != INVALID_HANDLE_VALUE) {
  77. if (CloseHandle(m_SerialPort) == FALSE) {
  78. // ASSUME_NOT_REACHED();
  79. }
  80. m_SerialPort = INVALID_HANDLE_VALUE;
  81. }
  82. for (int portNum = 0; portNum < 4; portNum++) {
  83. DebugOut(cCommPortNames[portNum]);
  84. DebugOut(":\r\n");
  85. m_SerialPort = ::CreateFile(cCommPortNames[portNum], GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
  86. if (m_SerialPort != INVALID_HANDLE_VALUE) {
  87. DCB CommDCB;
  88. if (::GetCommState(m_SerialPort, &CommDCB)) {
  89. #ifdef _DEBUG
  90. char dbgout[255];
  91. wsprintf(dbgout, "Baud Rate = 0x%08X (38400 = 0x%08X)\r\n", CommDCB.BaudRate, CBR_38400);
  92. ::OutputDebugString(dbgout);
  93. #endif _DEBUG
  94. CommDCB.BaudRate = CBR_38400;
  95. CommDCB.StopBits = ONESTOPBIT;
  96. CommDCB.ByteSize = 8;
  97. CommDCB.Parity = NOPARITY;
  98. if (!::SetCommState(m_SerialPort, &CommDCB)) {
  99. DebugOut("Unabled to set baud rate\r\n");
  100. }
  101. }
  102. ::GetCommState(m_SerialPort, &CommDCB);
  103. if (g_ForceFeedbackDevice.DetectHardware()) {
  104. m_SerialPortIDHack = portNum + 1;
  105. // Write to shared file
  106. DebugOut(" Opened and FFDev Detected\r\n");
  107. break; // Exit from for loop
  108. }
  109. // Not found
  110. ::CloseHandle(m_SerialPort);
  111. DebugOut(" Opened but FFDev NOT detected\r\n");
  112. m_SerialPort = INVALID_HANDLE_VALUE;
  113. } else {
  114. DebugOut(" Not able to open\r\n");
  115. }
  116. }
  117. return (m_SerialPort != INVALID_HANDLE_VALUE);
  118. }
  119. /******************************************************
  120. **
  121. ** SerialDataTransmitter::Send()
  122. **
  123. ** returns: TRUE if all data was successfully sent
  124. ** @mfunc Send.
  125. **
  126. ******************************************************/
  127. BOOL SerialDataTransmitter::Send(BYTE* data, UINT numBytes)
  128. {
  129. // Do we have a valid serial port (hopefully with MS FF device connected)
  130. if (m_SerialPort == NULL) {
  131. return FALSE;
  132. }
  133. /* char dbgOut[255];
  134. ::OutputDebugString("(SerialDataTransmitter::Send) : ");
  135. for (UINT i = 0; i < numBytes; i++) {
  136. wsprintf(dbgOut, " 0x%02X", data[i]);
  137. ::OutputDebugString(dbgOut);
  138. }
  139. ::OutputDebugString("\r\n");
  140. */
  141. if ((g_ForceFeedbackDevice.GetFirmwareVersionMajor() == 1) && (g_ForceFeedbackDevice.GetFirmwareVersionMinor() == 16)) {
  142. DWORD subTotalWritten;
  143. DWORD totalWritten = 0;
  144. DWORD numLeft = numBytes;
  145. while (numLeft > c1_16_BytesPerShot) {
  146. if (::WriteFile(m_SerialPort, (data + totalWritten), c1_16_BytesPerShot, &subTotalWritten, NULL) == FALSE) {
  147. return FALSE;
  148. }
  149. totalWritten += subTotalWritten;
  150. numLeft -= subTotalWritten;
  151. Sleep(c1_16_SerialSleepTime);
  152. }
  153. if (numLeft > 0) {
  154. if (::WriteFile(m_SerialPort, (data + totalWritten), numLeft, &subTotalWritten, NULL) == FALSE) {
  155. return FALSE;
  156. }
  157. totalWritten += subTotalWritten;
  158. }
  159. return (totalWritten == numBytes);
  160. }
  161. // Firmware other than 1.16
  162. DWORD numWritten;
  163. if (::WriteFile(m_SerialPort, data, numBytes, &numWritten, NULL) == FALSE) {
  164. return FALSE;
  165. }
  166. return (numWritten == numBytes);
  167. }
  168. /************************** DMusicTransmitter Class ******************************/
  169. /****************************************
  170. **
  171. ** DMusicTransmitter::DMusicTransmitter()
  172. **
  173. ** @mfunc Constructor for DirectMusic Transmitter
  174. **
  175. *****************************************/
  176. DMusicTransmitter::DMusicTransmitter() : DataTransmitter(),
  177. m_pIDirectMusic(NULL),
  178. m_pIDirectMusicPort(NULL),
  179. m_pIDirectMusicBuffer(NULL)
  180. {
  181. }
  182. /****************************************
  183. **
  184. ** DMusicTransmitter::~DMusicTransmitter()
  185. **
  186. ** @mfunc Destructor for DirectMusic Transmitter
  187. **
  188. *****************************************/
  189. DMusicTransmitter::~DMusicTransmitter()
  190. {
  191. CHECK_RELEASE_AND_NULL(m_pIDirectMusicBuffer);
  192. CHECK_RELEASE_AND_NULL(m_pIDirectMusicPort);
  193. CHECK_RELEASE_AND_NULL(m_pIDirectMusic);
  194. }
  195. /****************************************
  196. **
  197. ** BOOL DMusicTransmitter::Initialize()
  198. **
  199. ** @mfunc Intialize the Direct Music Transmission path
  200. **
  201. ** @rdesc TRUE if initialization was successful, FALSE otherwise
  202. **
  203. *****************************************/
  204. BOOL DMusicTransmitter::Initialize()
  205. {
  206. // Case they are reinitializing
  207. CHECK_RELEASE_AND_NULL(m_pIDirectMusicBuffer);
  208. CHECK_RELEASE_AND_NULL(m_pIDirectMusicPort);
  209. CHECK_RELEASE_AND_NULL(m_pIDirectMusic);
  210. // Create the global IDirectMusic Interface
  211. HRESULT hr = ::CoCreateInstance(CLSID_DirectMusic, NULL, CLSCTX_INPROC, IID_IDirectMusic, (void**)&m_pIDirectMusic);
  212. if (FAILED(hr) || m_pIDirectMusic == NULL)
  213. {
  214. return FALSE;
  215. }
  216. // Enumerate and create the port when valid one is found
  217. DMUS_PORTCAPS portCaps;
  218. portCaps.dwSize = sizeof portCaps;
  219. DWORD dwPortIndex = 0;
  220. for (;;)
  221. {
  222. HRESULT hr = m_pIDirectMusic->EnumPort(dwPortIndex, &portCaps);
  223. if (FAILED(hr) || hr == S_FALSE)
  224. { // Either we have failed or run out of ports
  225. return FALSE;
  226. }
  227. if (portCaps.dwClass == DMUS_PC_OUTPUTCLASS)
  228. {
  229. DMUS_PORTPARAMS portParams;
  230. portParams.dwSize = sizeof DMUS_PORTPARAMS;
  231. portParams.dwValidParams = DMUS_PORTPARAMS_CHANNELGROUPS;
  232. portParams.dwChannelGroups = 1;
  233. // hr = m_pIDirectMusic->CreatePort(portCaps.guidPort, GUID_NULL, &portParams, &m_pIDirectMusicPort, NULL);
  234. hr = m_pIDirectMusic->CreatePort(portCaps.guidPort, &portParams, &m_pIDirectMusicPort, NULL);
  235. break;
  236. }
  237. dwPortIndex++;
  238. }
  239. // Create the buffer
  240. DMUS_BUFFERDESC dmbd;
  241. dmbd.dwSize = sizeof DMUS_BUFFERDESC;
  242. dmbd.dwFlags = 0;
  243. // dmbd.guidBufferFormat = GUID_KSMusicFormat;
  244. dmbd.guidBufferFormat = GUID_NULL;
  245. dmbd.cbBuffer = 256;
  246. hr = m_pIDirectMusic->CreateMusicBuffer(&dmbd, &m_pIDirectMusicBuffer, NULL);
  247. if (FAILED(hr) || m_pIDirectMusicBuffer == NULL)
  248. {
  249. return FALSE;
  250. }
  251. return TRUE;
  252. }
  253. /****************************************
  254. **
  255. ** BOOL DMusicTransmitter::Send(BYTE* pData, UINT ulByteCount)
  256. **
  257. ** @mfunc Sends bytes via DirectMusic to the stick
  258. **
  259. ** @rdesc TRUE if send was successful, FALSE otherwise
  260. **
  261. *****************************************/
  262. BOOL DMusicTransmitter::Send
  263. (
  264. BYTE* pData, //@parm Data buffer to send
  265. UINT ulByteCount //@parm Number of bytes in buffer to send
  266. )
  267. {
  268. // Do sanity checks
  269. if ((pData == NULL) || (m_pIDirectMusicPort == NULL) || (m_pIDirectMusicBuffer == NULL) || (ulByteCount == 0))
  270. {
  271. return FALSE;
  272. }
  273. // Check if we need to pack sysex or channel message
  274. if (pData[0] == 0xF0)
  275. { // Create system exclusive
  276. /*
  277. // Pack the sysex-message into the buffer
  278. HRESULT hr = m_pIDirectMusicBuffer->PackSysEx(0, 1, ulByteCount, pData);
  279. if (FAILED(hr))
  280. { // Unable to pack the buffer
  281. return FALSE;
  282. }
  283. */ }
  284. else
  285. { // Channel Message (fix intel backwards byte order)
  286. DWORD channelMessage = pData[0];
  287. if (ulByteCount > 1)
  288. {
  289. channelMessage |= pData[1] << 8;
  290. if (ulByteCount > 2)
  291. {
  292. channelMessage |= pData[2] << 16;
  293. }
  294. }
  295. // Pack the channel-message into the buffer
  296. /* HRESULT hr = m_pIDirectMusicBuffer->PackChannelMsg(0, 1, channelMessage);
  297. if (FAILED(hr))
  298. { // Unable to pack the buffer
  299. return FALSE;
  300. }
  301. */ }
  302. // Send the buffer to the port
  303. HRESULT hr = m_pIDirectMusicPort->PlayBuffer(m_pIDirectMusicBuffer);
  304. if (FAILED(hr))
  305. { // Unable to send the data across the port
  306. return FALSE;
  307. }
  308. return TRUE;
  309. }
  310. #if 0
  311. /************************** PinTransmitter Class ******************************/
  312. /******************************************************
  313. **
  314. ** PinTransmitter::PinTransmitter()
  315. **
  316. ** @mfunc Constructor.
  317. **
  318. ******************************************************/
  319. PinTransmitter::PinTransmitter() : DataTransmitter(),
  320. m_UartFilter(INVALID_HANDLE_VALUE),
  321. m_MidiPin(INVALID_HANDLE_VALUE),
  322. m_MidiOutEvent(INVALID_HANDLE_VALUE)
  323. {
  324. }
  325. /******************************************************
  326. **
  327. ** PinTransmitter::~PinTransmitter()
  328. **
  329. ** @mfunc Destructor.
  330. **
  331. ******************************************************/
  332. PinTransmitter::~PinTransmitter()
  333. {
  334. // Close the send event
  335. if (IsHandleValid(m_MidiOutEvent)) {
  336. ::CloseHandle(m_MidiOutEvent);
  337. m_MidiOutEvent = NULL;
  338. }
  339. // Close the pin
  340. if (IsHandleValid(m_MidiPin)) {
  341. ::CloseHandle(m_MidiPin);
  342. m_MidiPin = INVALID_HANDLE_VALUE;
  343. }
  344. // Close the Uart
  345. if (IsHandleValid(m_UartFilter)) {
  346. ::CloseHandle(m_UartFilter);
  347. m_UartFilter = INVALID_HANDLE_VALUE;
  348. }
  349. }
  350. /******************************************************
  351. **
  352. ** PinTransmitter::Initialize()
  353. **
  354. ** returns: TRUE if initialized FALSE if not able to initialize
  355. ** @mfunc Initialize.
  356. **
  357. ******************************************************/
  358. BOOL PinTransmitter::Initialize()
  359. {
  360. // Load the ksUserLibrary and grab the create pin function
  361. HINSTANCE ksUserLib = ::LoadLibrary(TEXT("KsUser.dll"));
  362. if (ksUserLib == NULL) {
  363. return FALSE;
  364. }
  365. KSCREATEPIN pfCreatePin = (KSCREATEPIN)::GetProcAddress(ksUserLib, TEXT("KsCreatePin"));
  366. if (pfCreatePin == NULL) {
  367. ::FreeLibrary(ksUserLib);
  368. return FALSE;
  369. }
  370. // Open the Uart
  371. m_UartFilter = ::CreateFile(UART_FILTER_NAME, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING,
  372. FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, NULL);
  373. if (m_UartFilter == INVALID_HANDLE_VALUE) {
  374. ::FreeLibrary(ksUserLib);
  375. return FALSE;
  376. }
  377. // Create Overlapped event
  378. OVERLAPPED overlapped;
  379. ::memset(&overlapped, 0, sizeof(overlapped));
  380. overlapped.hEvent = ::CreateEvent(NULL, FALSE, FALSE, NULL);
  381. // Get the number of pins
  382. KSP_PIN ksPinProp;
  383. ::memset(&ksPinProp, 0, sizeof(ksPinProp));
  384. ksPinProp.Property.Set = KSPROPSETID_Pin;
  385. ksPinProp.Property.Id = KSPROPERTY_PIN_CTYPES;
  386. ksPinProp.Property.Flags = KSPROPERTY_TYPE_GET;
  387. DWORD numPins = 0;
  388. OverLappedPinIOCTL(overlapped, ksPinProp, &numPins, sizeof(numPins));
  389. // Check each pin for proper type, then try to create
  390. BOOL wasCreated = FALSE;
  391. for (UINT pinNum = 0; (pinNum < numPins) && (wasCreated == FALSE); pinNum++) {
  392. ksPinProp.PinId = pinNum;
  393. ksPinProp.Property.Id = KSPROPERTY_PIN_DATAFLOW;
  394. KSPIN_DATAFLOW dataFlow = (KSPIN_DATAFLOW)0;
  395. if (OverLappedPinIOCTL(overlapped, ksPinProp, &dataFlow, sizeof(dataFlow)) == TRUE) {
  396. if (dataFlow == KSPIN_DATAFLOW_IN) {
  397. ksPinProp.Property.Id = KSPROPERTY_PIN_COMMUNICATION;
  398. KSPIN_COMMUNICATION communication = KSPIN_COMMUNICATION_NONE;
  399. if (OverLappedPinIOCTL(overlapped, ksPinProp, &communication, sizeof(communication)) == TRUE) {
  400. if ((communication == KSPIN_COMMUNICATION_SINK) || (communication == KSPIN_COMMUNICATION_BOTH)) {
  401. wasCreated = CreatePinInstance(pinNum, pfCreatePin);
  402. }
  403. }
  404. }
  405. }
  406. }
  407. ::FreeLibrary(ksUserLib);
  408. ::CloseHandle(overlapped.hEvent);
  409. if (wasCreated == FALSE) {
  410. ::CloseHandle(m_UartFilter);
  411. m_UartFilter = INVALID_HANDLE_VALUE;
  412. return FALSE;
  413. }
  414. return TRUE;
  415. }
  416. /******************************************************
  417. **
  418. ** PinTransmitter::OverLappedPinIOCTL()
  419. **
  420. ** returns: TRUE if able to proform Pin Property IOCTL
  421. ** @mfunc OverLappedPinIOCTL.
  422. ******************************************************/
  423. BOOL PinTransmitter::OverLappedPinIOCTL(OVERLAPPED overlapped, KSP_PIN ksPinProp, void* pData, DWORD dataSize)
  424. {
  425. // IOCTL the Property
  426. if (::DeviceIoControl(m_UartFilter, IOCTL_KS_PROPERTY, &ksPinProp, sizeof(ksPinProp), pData, dataSize, NULL, &overlapped) == TRUE) {
  427. return TRUE;
  428. }
  429. // Failed IOCTL check if more time is needed
  430. if (::GetLastError() != ERROR_IO_PENDING) {
  431. return FALSE;
  432. }
  433. // Do wait
  434. if (::WaitForSingleObject(overlapped.hEvent, 3000) == WAIT_OBJECT_0) {
  435. return TRUE; // Waiting paid off
  436. }
  437. return FALSE; // Grew tired of waiting
  438. }
  439. /******************************************************
  440. **
  441. ** PinTransmitter::CreatePinInstance()
  442. **
  443. ** returns: TRUE if able to create the requested pin instance
  444. ** @mfunc CreatePinInstance.
  445. ******************************************************/
  446. BOOL PinTransmitter::CreatePinInstance(UINT pinNumber, KSCREATEPIN pfCreatePin)
  447. {
  448. // Set the pin format
  449. KSDATAFORMAT ksDataFormat;
  450. ::memset(&ksDataFormat, 0, sizeof(ksDataFormat));
  451. ksDataFormat.FormatSize = sizeof(ksDataFormat);
  452. ksDataFormat.MajorFormat = KSDATAFORMAT_TYPE_MUSIC;
  453. ksDataFormat.SubFormat = KSDATAFORMAT_SUBTYPE_MIDI;
  454. ksDataFormat.Specifier = KSDATAFORMAT_SPECIFIER_NONE;
  455. // Set the pin connection information
  456. KSPIN_CONNECT* pConnectionInfo = (KSPIN_CONNECT*) new BYTE[sizeof(KSPIN_CONNECT) + sizeof(ksDataFormat)];
  457. ::memset(pConnectionInfo, 0, sizeof(KSPIN_CONNECT));
  458. pConnectionInfo->Interface.Set = KSINTERFACESETID_Standard;
  459. pConnectionInfo->Interface.Id = KSINTERFACE_STANDARD_STREAMING;
  460. pConnectionInfo->Medium.Set = KSMEDIUMSETID_Standard;
  461. pConnectionInfo->Medium.Id = KSMEDIUM_STANDARD_DEVIO;
  462. pConnectionInfo->PinId = pinNumber;
  463. pConnectionInfo->Priority.PriorityClass = KSPRIORITY_NORMAL;
  464. pConnectionInfo->Priority.PrioritySubClass = 1;
  465. ::memcpy(pConnectionInfo + 1, &ksDataFormat, sizeof(ksDataFormat));
  466. DWORD status = pfCreatePin(m_UartFilter, pConnectionInfo, FILE_WRITE_ACCESS, &m_MidiPin);
  467. delete[] pConnectionInfo;
  468. if (status != NO_ERROR) {
  469. #ifdef _DEBUG
  470. TCHAR buff[256];
  471. wsprintf(buff, TEXT("Error Creating Pin: 0x%08X\r\n"), status);
  472. ::OutputDebugString(buff);
  473. #endif
  474. return FALSE;
  475. }
  476. SetPinState(KSSTATE_PAUSE);
  477. return TRUE;
  478. }
  479. /******************************************************
  480. **
  481. ** PinTransmitter::Send()
  482. **
  483. ** returns: TRUE if all data was successfully sent
  484. ** @mfunc Send.
  485. **
  486. ******************************************************/
  487. BOOL PinTransmitter::Send(BYTE* pData, UINT numBytes)
  488. {
  489. if (!IsHandleValid(m_MidiPin)) {
  490. return FALSE;
  491. }
  492. BYTE musicData[c_LongMsgMax + sizeof(KSMUSICFORMAT)];
  493. ::memset(musicData, 0, sizeof(musicData));
  494. ((KSMUSICFORMAT*)musicData)->ByteCount = numBytes;
  495. ::memcpy(((KSMUSICFORMAT*)musicData) + 1, pData, numBytes);
  496. KSSTREAM_HEADER ksStreamHeader;
  497. ::memset(&ksStreamHeader, 0, sizeof(ksStreamHeader));
  498. ksStreamHeader.Size = sizeof(ksStreamHeader);
  499. ksStreamHeader.PresentationTime.Numerator = 1;
  500. ksStreamHeader.PresentationTime.Denominator = 1;
  501. ksStreamHeader.FrameExtent = sizeof(musicData);
  502. ksStreamHeader.DataUsed = sizeof KSMUSICFORMAT + numBytes;
  503. ksStreamHeader.Data = (void*)musicData;
  504. if (!IsHandleValid(m_MidiOutEvent)) {
  505. m_MidiOutEvent = ::CreateEvent(NULL, FALSE, FALSE, NULL);
  506. }
  507. OVERLAPPED overlapped;
  508. ::memset(&overlapped, 0, sizeof(overlapped));
  509. overlapped.hEvent = m_MidiOutEvent;
  510. SetPinState(KSSTATE_RUN);
  511. if (!DeviceIoControl(m_MidiPin, IOCTL_KS_WRITE_STREAM, NULL, 0,
  512. &ksStreamHeader, sizeof(ksStreamHeader), NULL, &overlapped)) {
  513. if (GetLastError() == ERROR_IO_PENDING) {
  514. ::WaitForSingleObject(overlapped.hEvent, 3000);
  515. }
  516. }
  517. SetPinState(KSSTATE_PAUSE);
  518. return TRUE;
  519. }
  520. /******************************************************
  521. **
  522. ** PinTransmitter::SetPinState()
  523. **
  524. ** returns: Nothing
  525. ** @mfunc SetPinState.
  526. **
  527. ******************************************************/
  528. void PinTransmitter::SetPinState(KSSTATE state)
  529. {
  530. if (!IsHandleValid(m_MidiPin)) {
  531. return;
  532. }
  533. KSPROPERTY ksProperty;
  534. ::memset(&ksProperty, 0, sizeof(ksProperty));
  535. ksProperty.Set = KSPROPSETID_Connection;
  536. ksProperty.Id = KSPROPERTY_CONNECTION_STATE;
  537. ksProperty.Flags = KSPROPERTY_TYPE_SET;
  538. OVERLAPPED overlapped;
  539. ::memset(&overlapped, 0, sizeof(overlapped));
  540. overlapped.hEvent = ::CreateEvent(NULL, FALSE, FALSE, NULL);
  541. if (IsHandleValid(overlapped.hEvent)) {
  542. if( !DeviceIoControl(m_MidiPin, IOCTL_KS_PROPERTY, &ksProperty, sizeof ksProperty, &state, sizeof state, NULL, &overlapped )) {
  543. if (GetLastError() == ERROR_IO_PENDING) {
  544. WaitForSingleObject(overlapped.hEvent, 30000);
  545. }
  546. }
  547. ::CloseHandle(overlapped.hEvent);
  548. }
  549. }
  550. #endif