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.

581 lines
15 KiB

  1. /*==========================================================================
  2. *
  3. * Copyright (C) 1996-1997 Microsoft Corporation. All Rights Reserved.
  4. *
  5. * File: serial.c
  6. * Content: Routines for serial I/O
  7. * History:
  8. * Date By Reason
  9. * ==== == ======
  10. * 6/10/96 kipo created it
  11. * 6/22/96 kipo added support for EnumConnectionData()
  12. * 6/25/96 kipo updated for DPADDRESS
  13. * 7/13/96 kipo added GetSerialAddress()
  14. * 7/16/96 kipo changed address types to be GUIDs instead of 4CC
  15. * 8/21/96 kipo move comport address into dplobby.h
  16. * 1/06/97 kipo updated for objects
  17. * 2/11/97 kipo pass player flags to GetAddress()
  18. * 2/18/97 kipo allow multiple instances of service provider
  19. * 3/17/97 kipo deal with errors returned by DialogBoxParam()
  20. * 5/07/97 kipo added support for modem choice list
  21. * 12/22/00 aarono #190380 - use process heap for memory allocation
  22. ***************************************************************************/
  23. #include <windows.h>
  24. #include <windowsx.h>
  25. #include "dplaysp.h"
  26. #include "comport.h"
  27. #include "resource.h"
  28. #include "macros.h"
  29. // constants
  30. typedef enum {
  31. ASCII_XON = 0x11,
  32. ASCII_XOFF = 0x13
  33. };
  34. // serial object
  35. typedef struct {
  36. DPCOMPORT comPort; // base object globals
  37. BOOL bHaveSettings; // set to TRUE after settings dialog has been displayed
  38. DPCOMPORTADDRESS settings; // settings to use
  39. } DPSERIAL, *LPDPSERIAL;
  40. // dialog choices for serial port settings
  41. static DWORD gComPorts[] = { 1, 2, 3, 4 };
  42. static DWORD gBaudRates[] = { CBR_110, CBR_300, CBR_600, CBR_1200, CBR_2400,
  43. CBR_4800, CBR_9600, CBR_14400, CBR_19200, CBR_38400,
  44. CBR_56000, CBR_57600, CBR_115200, CBR_128000, CBR_256000 };
  45. static DWORD gStopBits[] = { ONESTOPBIT, ONE5STOPBITS, TWOSTOPBITS };
  46. static DWORD gParities[] = { NOPARITY, EVENPARITY, ODDPARITY, MARKPARITY };
  47. static DWORD gFlowControls[] = { DPCPA_NOFLOW, DPCPA_XONXOFFFLOW, DPCPA_RTSFLOW, DPCPA_DTRFLOW, DPCPA_RTSDTRFLOW };
  48. // globals
  49. // this is defined in dllmain.c
  50. extern HINSTANCE ghInstance;
  51. // this is defined in dpserial.c
  52. extern GUID DPSERIAL_GUID;
  53. // prototypes
  54. static HRESULT DisposeSerial(LPDPCOMPORT baseObject);
  55. static HRESULT ConnectSerial(LPDPCOMPORT baseObject, BOOL bWaitForConnection, BOOL bReturnStatus);
  56. static HRESULT DisconnectSerial(LPDPCOMPORT baseObject);
  57. static HRESULT GetSerialAddress(LPDPCOMPORT baseObject, DWORD dwPlayerFlags,
  58. LPVOID lpAddress, LPDWORD lpdwAddressSize);
  59. static HRESULT GetSerialAddressChoices(LPDPCOMPORT baseObject,
  60. LPVOID lpAddress, LPDWORD lpdwAddressSize);
  61. static BOOL SetupConnection(HANDLE hCom, LPDPCOMPORTADDRESS portSettings);
  62. static BOOL FAR PASCAL EnumAddressData(REFGUID lpguidDataType, DWORD dwDataSize,
  63. LPCVOID lpData, LPVOID lpContext);
  64. static BOOL GetSerialSettings(HINSTANCE hInstance, HWND hWndParent, LPDPSERIAL globals);
  65. static UINT_PTR CALLBACK SettingsDialog(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam);
  66. static void InitDialog(HWND hDlg, LPDPCOMPORTADDRESS settings);
  67. static void GetSettingsFromDialog(HWND hDlg, LPDPCOMPORTADDRESS settings);
  68. static int ValueToIndex(LPDWORD buf, int bufLen, DWORD value);
  69. static void FillComboBox(HWND hDlg, int dlgItem, int startStr, int stopStr);
  70. /*
  71. * NewSerial
  72. *
  73. * Create new serial port object.
  74. */
  75. HRESULT NewSerial(LPVOID lpConnectionData, DWORD dwConnectionDataSize,
  76. LPDIRECTPLAYSP lpDPlay, LPREADROUTINE lpReadRoutine,
  77. LPDPCOMPORT *storage)
  78. {
  79. LPDPCOMPORT baseObject;
  80. LPDPSERIAL globals;
  81. HRESULT hr;
  82. // create base object with enough space for our globals
  83. hr = NewComPort(sizeof(DPSERIAL), lpDPlay, lpReadRoutine, &baseObject);
  84. if FAILED(hr)
  85. return (hr);
  86. // fill in methods we implement
  87. baseObject->Dispose = DisposeSerial;
  88. baseObject->Connect = ConnectSerial;
  89. baseObject->Disconnect = DisconnectSerial;
  90. baseObject->GetAddress = GetSerialAddress;
  91. baseObject->GetAddressChoices = GetSerialAddressChoices;
  92. // setup default settings
  93. globals = (LPDPSERIAL) baseObject;
  94. globals->settings.dwComPort = 1; // COM port to use (1-4)
  95. globals->settings.dwBaudRate = CBR_57600; // baud rate (100-256k)
  96. globals->settings.dwStopBits = ONESTOPBIT; // no. stop bits (1-2)
  97. globals->settings.dwParity = NOPARITY; // parity (none, odd, even, mark)
  98. globals->settings.dwFlowControl = DPCPA_RTSDTRFLOW; // flow control (none, xon/xoff, rts, dtr)
  99. // check for valid connection data
  100. if (lpConnectionData)
  101. {
  102. baseObject->lpDPlay->lpVtbl->EnumAddress(baseObject->lpDPlay, EnumAddressData,
  103. lpConnectionData, dwConnectionDataSize,
  104. globals);
  105. }
  106. // return object pointer
  107. *storage = baseObject;
  108. return (DP_OK);
  109. }
  110. /*
  111. * EnumConnectionData
  112. *
  113. * Search for valid connection data
  114. */
  115. static BOOL FAR PASCAL EnumAddressData(REFGUID lpguidDataType, DWORD dwDataSize,
  116. LPCVOID lpData, LPVOID lpContext)
  117. {
  118. LPDPSERIAL globals = (LPDPSERIAL) lpContext;
  119. LPDPCOMPORTADDRESS settings = (LPDPCOMPORTADDRESS) lpData;
  120. // this is a com port chunk
  121. if ( IsEqualGUID(lpguidDataType, &DPAID_ComPort) &&
  122. (dwDataSize == sizeof(DPCOMPORTADDRESS)) )
  123. {
  124. // make sure it's valid!
  125. if ((ValueToIndex(gComPorts, sizeof(gComPorts), settings->dwComPort) >= 0) &&
  126. (ValueToIndex(gBaudRates, sizeof(gBaudRates), settings->dwBaudRate) >= 0) &&
  127. (ValueToIndex(gStopBits, sizeof(gStopBits), settings->dwStopBits) >= 0) &&
  128. (ValueToIndex(gParities, sizeof(gParities), settings->dwParity) >= 0) &&
  129. (ValueToIndex(gFlowControls, sizeof(gFlowControls), settings->dwFlowControl) >= 0))
  130. {
  131. globals->settings = *settings; // copy the data
  132. globals->bHaveSettings = TRUE; // we have valid settings
  133. }
  134. }
  135. return (TRUE);
  136. }
  137. /*
  138. * DisposeSerial
  139. *
  140. * Dispose serial port object.
  141. */
  142. static HRESULT DisposeSerial(LPDPCOMPORT baseObject)
  143. {
  144. LPDPSERIAL globals = (LPDPSERIAL) baseObject;
  145. // make sure we are disconnected
  146. DisconnectSerial(baseObject);
  147. // free object
  148. SP_MemFree((HGLOBAL) baseObject);
  149. return (DP_OK);
  150. }
  151. /*
  152. * ConnectSerial
  153. *
  154. * Open serial port and configure based on user settings.
  155. */
  156. static HRESULT ConnectSerial(LPDPCOMPORT baseObject,
  157. BOOL bWaitForConnection, BOOL bReturnStatus)
  158. {
  159. LPDPSERIAL globals = (LPDPSERIAL) baseObject;
  160. HANDLE hCom;
  161. TCHAR portName[10];
  162. HRESULT hr;
  163. // see if com port is already connected
  164. hCom = baseObject->GetHandle(baseObject);
  165. if (hCom)
  166. return (DP_OK);
  167. // ask user for settings if we have not already
  168. if (!globals->bHaveSettings)
  169. {
  170. if (!GetSerialSettings(ghInstance, GetForegroundWindow(), globals))
  171. {
  172. hr = DPERR_USERCANCEL;
  173. goto Failure;
  174. }
  175. globals->bHaveSettings = TRUE;
  176. }
  177. // open specified com port
  178. CopyMemory(portName, "COM0", 5);
  179. portName[3] += (BYTE) globals->settings.dwComPort;
  180. hCom = CreateFile( portName,
  181. GENERIC_READ | GENERIC_WRITE,
  182. 0, /* comm devices must be opened w/exclusive-access */
  183. NULL, /* no security attrs */
  184. OPEN_EXISTING, /* comm devices must use OPEN_EXISTING */
  185. FILE_ATTRIBUTE_NORMAL |
  186. FILE_FLAG_OVERLAPPED, // overlapped I/O
  187. NULL /* hTemplate must be NULL for comm devices */
  188. );
  189. if (hCom == INVALID_HANDLE_VALUE)
  190. {
  191. hCom = NULL;
  192. hr = HRESULT_FROM_WIN32(GetLastError());
  193. goto Failure;
  194. }
  195. // configure com port to proper settings
  196. if (!SetupConnection(hCom, &globals->settings))
  197. {
  198. hr = HRESULT_FROM_WIN32(GetLastError());
  199. goto Failure;
  200. }
  201. // setup com port
  202. hr = baseObject->Setup(baseObject, hCom);
  203. if FAILED(hr)
  204. goto Failure;
  205. return (DP_OK);
  206. Failure:
  207. if (hCom)
  208. CloseHandle(hCom);
  209. return (hr);
  210. }
  211. /*
  212. * DisconnectSerial
  213. *
  214. * Close serial port.
  215. */
  216. static HRESULT DisconnectSerial(LPDPCOMPORT baseObject)
  217. {
  218. HANDLE hCom;
  219. HRESULT hr;
  220. hCom = baseObject->GetHandle(baseObject);
  221. // com port is already disconnected
  222. if (hCom == NULL)
  223. return (DP_OK);
  224. // shut down com port
  225. hr = baseObject->Shutdown(baseObject);
  226. // close com port
  227. CloseHandle(hCom);
  228. return (hr);
  229. }
  230. /*
  231. * SetupConnection
  232. *
  233. * Configure serial port with specified settings.
  234. */
  235. static BOOL SetupConnection(HANDLE hCom, LPDPCOMPORTADDRESS portSettings)
  236. {
  237. DCB dcb;
  238. dcb.DCBlength = sizeof(DCB);
  239. if (!GetCommState(hCom, &dcb))
  240. return (FALSE);
  241. // setup various port settings
  242. dcb.fBinary = TRUE;
  243. dcb.BaudRate = portSettings->dwBaudRate;
  244. dcb.ByteSize = 8;
  245. dcb.StopBits = (BYTE) portSettings->dwStopBits;
  246. dcb.Parity = (BYTE) portSettings->dwParity;
  247. if (portSettings->dwParity == NOPARITY)
  248. dcb.fParity = FALSE;
  249. else
  250. dcb.fParity = TRUE;
  251. // setup hardware flow control
  252. if ((portSettings->dwFlowControl == DPCPA_DTRFLOW) ||
  253. (portSettings->dwFlowControl == DPCPA_RTSDTRFLOW))
  254. {
  255. dcb.fOutxDsrFlow = TRUE;
  256. dcb.fDtrControl = DTR_CONTROL_HANDSHAKE;
  257. }
  258. else
  259. {
  260. dcb.fOutxDsrFlow = FALSE;
  261. dcb.fDtrControl = DTR_CONTROL_ENABLE;
  262. }
  263. if ((portSettings->dwFlowControl == DPCPA_RTSFLOW) ||
  264. (portSettings->dwFlowControl == DPCPA_RTSDTRFLOW))
  265. {
  266. dcb.fOutxCtsFlow = TRUE;
  267. dcb.fRtsControl = RTS_CONTROL_HANDSHAKE;
  268. }
  269. else
  270. {
  271. dcb.fOutxCtsFlow = FALSE;
  272. dcb.fRtsControl = RTS_CONTROL_ENABLE;
  273. }
  274. // setup software flow control
  275. if (portSettings->dwFlowControl == DPCPA_XONXOFFFLOW)
  276. {
  277. dcb.fInX = TRUE;
  278. dcb.fOutX = TRUE;
  279. }
  280. else
  281. {
  282. dcb.fInX = FALSE;
  283. dcb.fOutX = FALSE;
  284. }
  285. dcb.XonChar = ASCII_XON;
  286. dcb.XoffChar = ASCII_XOFF;
  287. dcb.XonLim = 100;
  288. dcb.XoffLim = 100;
  289. if (!SetCommState( hCom, &dcb ))
  290. return (FALSE);
  291. return (TRUE);
  292. }
  293. /*
  294. * GetSerialAddress
  295. *
  296. * Return current serial port info if available.
  297. */
  298. static HRESULT GetSerialAddress(LPDPCOMPORT baseObject, DWORD dwPlayerFlags,
  299. LPVOID lpAddress, LPDWORD lpdwAddressSize)
  300. {
  301. LPDPSERIAL globals = (LPDPSERIAL) baseObject;
  302. HRESULT hResult;
  303. // no settings yet
  304. if (!globals->bHaveSettings)
  305. return (DPERR_UNAVAILABLE);
  306. hResult = baseObject->lpDPlay->lpVtbl->CreateAddress(baseObject->lpDPlay,
  307. &DPSERIAL_GUID, &DPAID_ComPort,
  308. &globals->settings, sizeof(DPCOMPORTADDRESS),
  309. lpAddress, lpdwAddressSize);
  310. return (hResult);
  311. }
  312. /*
  313. * GetSerialAddressChoices
  314. *
  315. * Return current serial address choices
  316. */
  317. static HRESULT GetSerialAddressChoices(LPDPCOMPORT baseObject,
  318. LPVOID lpAddress, LPDWORD lpdwAddressSize)
  319. {
  320. LPDPSERIAL globals = (LPDPSERIAL) baseObject;
  321. // currently the serial provider does not support any choices
  322. return (E_NOTIMPL);
  323. }
  324. /*
  325. * GetComPortSettings
  326. *
  327. * Displays a dialog to gather and return the COM port settings.
  328. */
  329. static BOOL GetSerialSettings(HINSTANCE hInstance, HWND hWndParent, LPDPSERIAL globals)
  330. {
  331. INT_PTR iResult;
  332. iResult = (INT_PTR)DialogBoxParam(hInstance, MAKEINTRESOURCE(IDD_SETTINGSDIALOG), hWndParent, SettingsDialog, (LPARAM) globals);
  333. return (iResult > 0);
  334. }
  335. /*
  336. * SettingsDialog
  337. *
  338. * The dialog callback routine to display and edit the COM port settings.
  339. */
  340. static UINT_PTR CALLBACK SettingsDialog(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)
  341. {
  342. LPDPSERIAL globals = (LPDPSERIAL) GetWindowLongPtr(hDlg, DWLP_USER);
  343. HWND hWndCtl;
  344. BOOL msgHandled = FALSE;
  345. switch (msg)
  346. {
  347. case WM_INITDIALOG:
  348. // serial info pointer passed in lParam
  349. globals = (LPDPSERIAL) lParam;
  350. // save the globals with the window
  351. SetWindowLongPtr(hDlg, DWLP_USER, (LONG_PTR) globals);
  352. hWndCtl = GetDlgItem(hDlg, IDC_COMPORT);
  353. // make sure our dialog item is there
  354. if (hWndCtl == NULL)
  355. {
  356. EndDialog(hDlg, FALSE);
  357. msgHandled = TRUE;
  358. }
  359. else
  360. {
  361. InitDialog(hDlg, &globals->settings); // setup our dialog
  362. SetFocus(hWndCtl); // focus on com port combo box
  363. msgHandled = FALSE; // keep windows from setting input focus for us
  364. }
  365. break;
  366. case WM_COMMAND:
  367. if (HIWORD(wParam) == 0)
  368. {
  369. switch (LOWORD(wParam))
  370. {
  371. case IDOK: // return settings
  372. GetSettingsFromDialog(hDlg, &globals->settings);
  373. EndDialog(hDlg, TRUE);
  374. msgHandled = TRUE;
  375. break;
  376. case IDCANCEL: // cancel
  377. EndDialog(hDlg, FALSE);
  378. msgHandled = TRUE;
  379. break;
  380. }
  381. }
  382. break;
  383. }
  384. return (msgHandled);
  385. }
  386. /*
  387. * InitDialog
  388. *
  389. * Initialize the dialog controls to display the given COM port settings.
  390. */
  391. static void InitDialog(HWND hDlg, LPDPCOMPORTADDRESS settings)
  392. {
  393. // fill dialog combo boxes with items from string table
  394. FillComboBox(hDlg, IDC_COMPORT, IDS_COM1, IDS_COM4);
  395. FillComboBox(hDlg, IDC_BAUDRATE, IDS_BAUD1, IDS_BAUD15);
  396. FillComboBox(hDlg, IDC_STOPBITS, IDS_STOPBIT1, IDS_STOPBIT3);
  397. FillComboBox(hDlg, IDC_PARITY, IDS_PARITY1, IDS_PARITY4);
  398. FillComboBox(hDlg, IDC_FLOW, IDS_FLOW1, IDS_FLOW5);
  399. // select default values in combo boxes
  400. SendDlgItemMessage(hDlg, IDC_COMPORT, CB_SETCURSEL,
  401. ValueToIndex(gComPorts, sizeof(gComPorts), settings->dwComPort), 0);
  402. SendDlgItemMessage(hDlg, IDC_BAUDRATE, CB_SETCURSEL,
  403. ValueToIndex(gBaudRates, sizeof(gBaudRates), settings->dwBaudRate), 0);
  404. SendDlgItemMessage(hDlg, IDC_STOPBITS, CB_SETCURSEL,
  405. ValueToIndex(gStopBits, sizeof(gStopBits), settings->dwStopBits), 0);
  406. SendDlgItemMessage(hDlg, IDC_PARITY, CB_SETCURSEL,
  407. ValueToIndex(gParities, sizeof(gParities), settings->dwParity), 0);
  408. SendDlgItemMessage(hDlg, IDC_FLOW, CB_SETCURSEL,
  409. ValueToIndex(gFlowControls, sizeof(gFlowControls), settings->dwFlowControl), 0);
  410. }
  411. /*
  412. * GetSettingsFromDialog
  413. *
  414. * Get the COM port settings from the dialog controls.
  415. */
  416. static void GetSettingsFromDialog(HWND hDlg, LPDPCOMPORTADDRESS settings)
  417. {
  418. INT_PTR index;
  419. index = SendDlgItemMessage(hDlg, IDC_COMPORT, CB_GETCURSEL, 0, 0);
  420. if (index == CB_ERR)
  421. return;
  422. settings->dwComPort = gComPorts[index];
  423. index = SendDlgItemMessage(hDlg, IDC_BAUDRATE, CB_GETCURSEL, 0, 0);
  424. if (index == CB_ERR)
  425. return;
  426. settings->dwBaudRate = gBaudRates[index];
  427. index = SendDlgItemMessage(hDlg, IDC_STOPBITS, CB_GETCURSEL, 0, 0);
  428. if (index == CB_ERR)
  429. return;
  430. settings->dwStopBits = gStopBits[index];
  431. index = SendDlgItemMessage(hDlg, IDC_PARITY, CB_GETCURSEL, 0, 0);
  432. if (index == CB_ERR)
  433. return;
  434. settings->dwParity = gParities[index];
  435. index = SendDlgItemMessage(hDlg, IDC_FLOW, CB_GETCURSEL, 0, 0);
  436. if (index == CB_ERR)
  437. return;
  438. settings->dwFlowControl = gFlowControls[index];
  439. }
  440. /*
  441. * FillComboBox
  442. *
  443. * Add the specified strings to the combo box.
  444. */
  445. #define MAXSTRINGSIZE 200
  446. static void FillComboBox(HWND hDlg, int dlgItem, int startStr, int stopStr)
  447. {
  448. int i;
  449. TCHAR str[MAXSTRINGSIZE];
  450. for (i = startStr; i <= stopStr; i++)
  451. {
  452. if (LoadString(ghInstance, i, str, MAXSTRINGSIZE))
  453. SendDlgItemMessage(hDlg, dlgItem, CB_ADDSTRING, (WPARAM) 0, (LPARAM) str);
  454. }
  455. }
  456. /*
  457. * ValueToIndex
  458. *
  459. * Convert a settings value to a combo box selection index.
  460. */
  461. static int ValueToIndex(LPDWORD buf, int bufLen, DWORD value)
  462. {
  463. int i;
  464. bufLen /= sizeof(DWORD);
  465. for (i = 0; i < bufLen; i++)
  466. if (buf[i] == value)
  467. return (i);
  468. return (-1);
  469. }