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.

1644 lines
39 KiB

  1. /*++
  2. * File name:
  3. * tclientaxobj.cpp
  4. * Contents:
  5. * This module implements a scriptable COM interface to the TClient
  6. * APIs.
  7. *
  8. * Copyright (C) 2002 Microsoft Corp.
  9. --*/
  10. #include "stdafx.h"
  11. #define PROTOCOLAPI
  12. #include <malloc.h>
  13. #include <stdio.h>
  14. #include "tclient.h"
  15. #include <protocol.h>
  16. #include <extraexp.h>
  17. #include "tclientax.h"
  18. #include "tclientaxobj.h"
  19. #define LOG_BUFFER_SIZE 2048
  20. #define LOG_PREFIX "TClientApi: "
  21. //
  22. // Define Boolean values for Visual Basic.
  23. //
  24. #define VB_TRUE ((BOOL)-1)
  25. #define VB_FALSE ((BOOL)0)
  26. //
  27. // Define stubs for certain message handlers which may be enabled later, if
  28. // GUI support is added (e.g. for logging).
  29. //
  30. #if 0
  31. /*++
  32. * Function:
  33. * CTClientApi::
  34. * Description:
  35. * This routine...
  36. * Arguments:
  37. * ... - ...
  38. * Return value:
  39. * ...
  40. * Called by:
  41. * ...
  42. * Author:
  43. * ...
  44. --*/
  45. LRESULT
  46. CTClientApi::OnCreate (
  47. UINT uMsg,
  48. WPARAM wParam,
  49. LPARAM lParam,
  50. BOOL& bHandled
  51. )
  52. {
  53. UNREFERENCED_PARAMETER(uMsg);
  54. UNREFERENCED_PARAMETER(wParam);
  55. UNREFERENCED_PARAMETER(lParam);
  56. UNREFERENCED_PARAMETER(bHandled);
  57. return 0;
  58. }
  59. /*++
  60. * Function:
  61. * CTClientApi::
  62. * Description:
  63. * This routine...
  64. * Arguments:
  65. * ... - ...
  66. * Return value:
  67. * ...
  68. * Called by:
  69. * ...
  70. * Author:
  71. * ...
  72. --*/
  73. LRESULT
  74. CTClientApi::OnDestroy (
  75. UINT uMsg,
  76. WPARAM wParam,
  77. LPARAM lParam,
  78. BOOL& bHandled
  79. )
  80. {
  81. UNREFERENCED_PARAMETER(bHandled);
  82. UNREFERENCED_PARAMETER(lParam);
  83. UNREFERENCED_PARAMETER(wParam);
  84. UNREFERENCED_PARAMETER(uMsg);
  85. return 0;
  86. }
  87. /*++
  88. * Function:
  89. * CTClientApi::
  90. * Description:
  91. * This routine...
  92. * Arguments:
  93. * ... - ...
  94. * Return value:
  95. * ...
  96. * Called by:
  97. * ...
  98. * Author:
  99. * ...
  100. --*/
  101. LRESULT
  102. CTClientApi::OnLButtonDown (
  103. UINT uMsg,
  104. WPARAM wParam,
  105. LPARAM lParam,
  106. BOOL& bHandled
  107. )
  108. {
  109. UNREFERENCED_PARAMETER(uMsg);
  110. UNREFERENCED_PARAMETER(wParam);
  111. UNREFERENCED_PARAMETER(lParam);
  112. UNREFERENCED_PARAMETER(bHandled);
  113. return 0;
  114. }
  115. /*++
  116. * Function:
  117. * CTClientApi::
  118. * Description:
  119. * This routine...
  120. * Arguments:
  121. * ... - ...
  122. * Return value:
  123. * ...
  124. * Called by:
  125. * ...
  126. * Author:
  127. * ...
  128. --*/
  129. LRESULT
  130. CTClientApi::OnLButtonUp (
  131. UINT uMsg,
  132. WPARAM wParam,
  133. LPARAM lParam,
  134. BOOL& bHandled
  135. )
  136. {
  137. UNREFERENCED_PARAMETER(uMsg);
  138. UNREFERENCED_PARAMETER(wParam);
  139. UNREFERENCED_PARAMETER(lParam);
  140. UNREFERENCED_PARAMETER(bHandled);
  141. return 0;
  142. }
  143. /*++
  144. * Function:
  145. * CTClientApi::
  146. * Description:
  147. * This routine...
  148. * Arguments:
  149. * ... - ...
  150. * Return value:
  151. * ...
  152. * Called by:
  153. * ...
  154. * Author:
  155. * ...
  156. --*/
  157. LRESULT
  158. CTClientApi::OnMouseMove (
  159. UINT uMsg,
  160. WPARAM wParam,
  161. LPARAM lParam,
  162. BOOL& bHandled
  163. )
  164. {
  165. UNREFERENCED_PARAMETER(uMsg);
  166. UNREFERENCED_PARAMETER(wParam);
  167. UNREFERENCED_PARAMETER(lParam);
  168. UNREFERENCED_PARAMETER(bHandled);
  169. return 0;
  170. }
  171. /*++
  172. * Function:
  173. * CTClientApi::
  174. * Description:
  175. * This routine...
  176. * Arguments:
  177. * ... - ...
  178. * Return value:
  179. * ...
  180. * Called by:
  181. * ...
  182. * Author:
  183. * ...
  184. --*/
  185. HRESULT
  186. CTClientApi::OnDraw(
  187. ATL_DRAWINFO& di
  188. )
  189. {
  190. UNREFERENCED_PARAMETER(di);
  191. return S_OK;
  192. }
  193. #endif // 0
  194. //
  195. // Define scriptable interfaces to TClient APIs.
  196. //
  197. // In the initial version, the COM interfaces will not do any argument
  198. // validation, since they merely wrap the APIs, which must also validate.
  199. // This is equally true for synchronization of threads, therefore the COM
  200. // interfaces will not add any additional synchronisation code, with the
  201. // exception of the Error property.
  202. //
  203. /*++
  204. * Function:
  205. * CTClientApi::SaveClipboard
  206. * Description:
  207. * This routine provides a scriptable interface to SCSaveClipboard.
  208. * Arguments:
  209. * FormatName - Supplies the name of the clipboard format to use.
  210. * Return value:
  211. * S_OK if successful, an appropriate HRESULT otherwise.
  212. * Called by:
  213. * Exported via COM.
  214. * Author:
  215. * Alex Stephens (alexstep) 24-Jan-2002
  216. --*/
  217. STDMETHODIMP
  218. CTClientApi::SaveClipboard (
  219. IN BSTR FormatName,
  220. IN BSTR FileName
  221. )
  222. {
  223. PCSTR szFormatName;
  224. PCSTR szFileName;
  225. PCSTR szError;
  226. HRESULT hrResult;
  227. USES_CONVERSION;
  228. ATLTRACE(_T("ITClientApi::SaveClipboard\n"));
  229. //
  230. // Convert the OLE strings to ANSI strings for TClient. This will
  231. // allocate on the stack.
  232. //
  233. _try
  234. {
  235. szFormatName = OLE2A(FormatName);
  236. szFileName = OLE2A(FileName);
  237. }
  238. _except ((GetExceptionCode() == EXCEPTION_STACK_OVERFLOW ||
  239. GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION) ?
  240. EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH)
  241. {
  242. switch (GetExceptionCode())
  243. {
  244. case EXCEPTION_STACK_OVERFLOW:
  245. _resetstkoflw();
  246. return HRESULT_FROM_WIN32(ERROR_STACK_OVERFLOW);
  247. break;
  248. case EXCEPTION_ACCESS_VIOLATION:
  249. return E_POINTER;
  250. break;
  251. default:
  252. DebugBreak();
  253. return E_FAIL;
  254. break;
  255. }
  256. }
  257. //
  258. // Call the API and return the result.
  259. //
  260. ASSERT(m_pCI != NULL);
  261. ASSERT(szFormatName != NULL);
  262. ASSERT(szFileName != NULL);
  263. szError = SCSaveClipboard(m_pCI, szFormatName, szFileName);
  264. SaveError(szError, m_dwErrorIndex, &hrResult);
  265. return hrResult;
  266. }
  267. /*++
  268. * Function:
  269. * CTClientApi::IsDead
  270. * Description:
  271. * This routine provides a scriptable interface to SCIsDead.
  272. * Arguments:
  273. * Dead - Returns the current state of the client: TRUE if it is dead,
  274. * FALSE otherwise.
  275. * Return value:
  276. * S_OK if successful, an appropriate HRESULT otherwise.
  277. * Called by:
  278. * Exported via COM.
  279. * Author:
  280. * Alex Stephens (alexstep) 24-Jan-2002
  281. --*/
  282. STDMETHODIMP
  283. CTClientApi::IsDead (
  284. OUT BOOL *Dead
  285. )
  286. {
  287. BOOL fDead;
  288. ATLTRACE(_T("ITClientApi::IsDead\n"));
  289. //
  290. // Check to see if the connection is dead, and return the result.
  291. //
  292. RTL_SOFT_ASSERT(m_pCI != NULL);
  293. fDead = SCIsDead(m_pCI);
  294. _try
  295. {
  296. *Dead = fDead ? VB_TRUE : VB_FALSE;
  297. }
  298. _except (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ?
  299. EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH)
  300. {
  301. return E_POINTER;
  302. }
  303. return S_OK;
  304. }
  305. /*++
  306. * Function:
  307. * CTClientApi::SendTextAsMessages
  308. * Description:
  309. * This routine provides a scriptable interface to SCSendtextAsMsgs.
  310. * Arguments:
  311. * Text - Supplies a text string to send to the client.
  312. * Return value:
  313. * S_OK if successful, an appropriate HRESULT otherwise.
  314. * Called by:
  315. * Exported via COM.
  316. * Author:
  317. * Alex Stephens (alexstep) 24-Jan-2002
  318. --*/
  319. STDMETHODIMP
  320. CTClientApi::SendTextAsMessages (
  321. IN BSTR Text
  322. )
  323. {
  324. PCWSTR szText;
  325. PCSTR szError;
  326. HRESULT hrResult;
  327. USES_CONVERSION;
  328. ATLTRACE(_T("ITClientApi::SendTextAsMessages\n"));
  329. //
  330. // Convert the OLE string to a Unicode string for TClient. OLE strings
  331. // are already Unicode, so this will not allocate any storage.
  332. //
  333. _try
  334. {
  335. szText = OLE2W(Text);
  336. }
  337. _except (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ?
  338. EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH)
  339. {
  340. return E_POINTER;
  341. }
  342. //
  343. // Call the API and return the result.
  344. //
  345. ASSERT(m_pCI != NULL);
  346. ASSERT(szText != NULL);
  347. szError = SCSendtextAsMsgs(m_pCI, szText);
  348. SaveError(szError, m_dwErrorIndex, &hrResult);
  349. return hrResult;
  350. }
  351. /*++
  352. * Function:
  353. * CTClientApi::Connect2
  354. * Description:
  355. * This routine provides a scriptable interface to SCConnectEx.
  356. * Arguments:
  357. * ServerName - Supplies the name of the server to connect to.
  358. * UserName - Supples the name of the user to log on with.
  359. * Password - Supplied the user password.
  360. * Domain - Supples the domain to which the user belongs.
  361. * Shell - Supplies the name of the executable with which the shell
  362. * process will be created.
  363. * XResolution - Supplies the horizontal resolution to use for the
  364. * session.
  365. * YResolution - Supplies the vertical resolution to use for the
  366. * session.
  367. * ConnectionFlags Supplies the connection flags.
  368. * ColorDepth - Supplies the color depth to use for the session.
  369. * AudioOptions - Supplies the audio options.
  370. * Return value:
  371. * S_OK if successful, an appropriate HRESULT otherwise.
  372. * Called by:
  373. * Exported via COM.
  374. * Author:
  375. * Alex Stephens (alexstep) 24-Jan-2002
  376. --*/
  377. STDMETHODIMP
  378. CTClientApi::Connect2 (
  379. IN BSTR ServerName,
  380. IN BSTR UserName,
  381. IN BSTR Password,
  382. IN BSTR Domain,
  383. IN BSTR Shell,
  384. IN ULONG XResolution,
  385. IN ULONG YResolution,
  386. IN ULONG ConnectionFlags,
  387. IN ULONG ColorDepth,
  388. IN ULONG AudioOptions
  389. )
  390. {
  391. PCWSTR szServerName;
  392. PCWSTR szUserName;
  393. PCWSTR szPassword;
  394. PCWSTR szDomain;
  395. PCWSTR szShell;
  396. PCSTR szError;
  397. HRESULT hrResult;
  398. USES_CONVERSION;
  399. ATLTRACE(_T("ITClientApi::Connect2\n"));
  400. //
  401. // Convert the OLE strings to Unicode strings for TClient. OLE strings
  402. // are already Unicode, so this will not allocate any storage.
  403. //
  404. _try
  405. {
  406. szServerName = OLE2W(ServerName);
  407. szUserName = OLE2W(UserName);
  408. szPassword = OLE2W(Password);
  409. szDomain = OLE2W(Domain);
  410. szShell = OLE2W(Shell);
  411. }
  412. _except (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ?
  413. EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH)
  414. {
  415. return E_POINTER;
  416. }
  417. //
  418. // Call the API and return the result.
  419. //
  420. ASSERT(m_pCI == NULL);
  421. RTL_SOFT_ASSERT(szServerName != NULL);
  422. RTL_SOFT_ASSERT(szUserName != NULL);
  423. RTL_SOFT_ASSERT(szPassword != NULL);
  424. RTL_SOFT_ASSERT(szDomain != NULL);
  425. RTL_SOFT_ASSERT(szShell != NULL);
  426. szError = SCConnectEx(szServerName,
  427. szUserName,
  428. szPassword,
  429. szDomain,
  430. szShell,
  431. XResolution,
  432. YResolution,
  433. ConnectionFlags,
  434. ColorDepth,
  435. AudioOptions,
  436. &m_pCI);
  437. SaveError(szError, m_dwErrorIndex, &hrResult);
  438. return hrResult;
  439. }
  440. /*++
  441. * Function:
  442. * CTClientApi::GetFeedbackString
  443. * Description:
  444. * This routine provides a scriptable interface to SCGetFeedbackString.
  445. * Arguments:
  446. * FeedbackString - Returns the latest feedback string to the caller.
  447. * The underlying storage must be freed by the caller with
  448. * SysFreeString.
  449. * Return value:
  450. * S_OK if successful, an appropriate HRESULT otherwise.
  451. * Called by:
  452. * Exported via COM.
  453. * Author:
  454. * Alex Stephens (alexstep) 24-Jan-2002
  455. --*/
  456. STDMETHODIMP
  457. CTClientApi::GetFeedbackString (
  458. OUT BSTR *FeedbackString
  459. )
  460. {
  461. PCSTR szError;
  462. WCHAR szBuffer[MAX_STRING_LENGTH + 1];
  463. HRESULT hrResult;
  464. BSTR bstrFeedback;
  465. USES_CONVERSION;
  466. ATLTRACE(_T("ITClientApi::GetFeedbackString\n"));
  467. //
  468. // Get the feedback string and add a terminator.
  469. //
  470. ASSERT(m_pCI != NULL);
  471. szError = SCGetFeedbackString(m_pCI,
  472. szBuffer,
  473. sizeof(szBuffer) / sizeof(*szBuffer) - 1);
  474. szBuffer[sizeof(szBuffer) / sizeof(*szBuffer) - 1] = L'\0';
  475. SaveError(szError, m_dwErrorIndex, &hrResult);
  476. if (szError != NULL)
  477. {
  478. return hrResult;
  479. }
  480. //
  481. // If the feedback string is empty, use NULL.
  482. //
  483. if (*szBuffer == '\0')
  484. {
  485. bstrFeedback = NULL;
  486. }
  487. //
  488. // Convert the feedback string to a BSTR. This will allocate from the CRT
  489. // heap, and the storage must be freed by the caller, using
  490. // SysFreeString.
  491. //
  492. else
  493. {
  494. bstrFeedback = W2BSTR(szBuffer);
  495. if (bstrFeedback == NULL)
  496. {
  497. return E_OUTOFMEMORY;
  498. }
  499. }
  500. //
  501. // Set the output parameter. If the supplied argument is invalid, the
  502. // BSTR will not be returned, so free it.
  503. //
  504. hrResult = E_FAIL;
  505. _try
  506. {
  507. _try
  508. {
  509. *FeedbackString = bstrFeedback;
  510. hrResult = S_OK;
  511. }
  512. _except (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ?
  513. EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH)
  514. {
  515. hrResult = E_POINTER;
  516. }
  517. }
  518. _finally
  519. {
  520. if (FAILED(hrResult))
  521. {
  522. ASSERT(bstrFeedback != NULL);
  523. SysFreeString(bstrFeedback);
  524. }
  525. }
  526. return hrResult;
  527. }
  528. /*++
  529. * Function:
  530. * CTClientApi::GetFeedback
  531. * Description:
  532. * This routine provides a scriptable interface to SCGetFeedback.
  533. * Arguments:
  534. * FeedbackString - Returns the feedback strings to the caller. The
  535. * underlying storage must be freed by the caller with
  536. * SafeArrayDestroy.
  537. * Return value:
  538. * S_OK if successful, an appropriate HRESULT otherwise.
  539. * Called by:
  540. * Exported via COM.
  541. * Author:
  542. * Alex Stephens (alexstep) 24-Jan-2002
  543. --*/
  544. STDMETHODIMP
  545. CTClientApi::GetFeedback (
  546. OUT SAFEARRAY **Feedback
  547. )
  548. {
  549. PCSTR szError;
  550. PWSTR pStrings;
  551. UINT nCount;
  552. UINT nMaxStringLength;
  553. HRESULT hrResult;
  554. SAFEARRAY *pArray;
  555. LONG lIndex;
  556. BSTR bstrCurrentString;
  557. USES_CONVERSION;
  558. ATLTRACE(_T("ITClientApi::GetFeedback\n"));
  559. //
  560. // Clear the output argument.
  561. //
  562. _try
  563. {
  564. *Feedback = NULL;
  565. }
  566. _except (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ?
  567. EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH)
  568. {
  569. return E_POINTER;
  570. }
  571. //
  572. // Get the feedback strings.
  573. //
  574. ASSERT(m_pCI != NULL);
  575. szError = SCGetFeedback(m_pCI, &pStrings, &nCount, &nMaxStringLength);
  576. if (szError != NULL)
  577. {
  578. SaveError(szError, m_dwErrorIndex, &hrResult);
  579. return hrResult;
  580. }
  581. //
  582. // Always free the feedback strings.
  583. //
  584. hrResult = E_FAIL;
  585. pArray = NULL;
  586. _try
  587. {
  588. //
  589. // Allocate a safe-array of BSTRs, large enough to hold the feedback
  590. // strings. The storage must be freed by the caller with
  591. // SafeArrayDestroy.
  592. //
  593. ASSERT(nCount > 0);
  594. pArray = SafeArrayCreateVectorEx(VT_BSTR, 0, nCount, NULL);
  595. if (pArray == NULL)
  596. {
  597. hrResult = HRESULT_FROM_WIN32(GetLastError());
  598. _leave;
  599. }
  600. //
  601. // Always destroy the safe-array on failure.
  602. //
  603. _try
  604. {
  605. //
  606. // Copy each string to the array.
  607. //
  608. for (lIndex = 0; lIndex < (LONG)nCount; lIndex += 1)
  609. {
  610. //
  611. // Convert the current string to a BSTR. This will allocate
  612. // storage on the CRT heap, which must be freed with
  613. // SysFreeString before the next loop iteration.
  614. //
  615. bstrCurrentString = W2BSTR(pStrings + lIndex);
  616. if (bstrCurrentString == NULL)
  617. {
  618. hrResult = E_OUTOFMEMORY;
  619. _leave;
  620. }
  621. _try
  622. {
  623. //
  624. // Add the current string to the array. This will
  625. // allocate storage with SysAllocString and copy the
  626. // current string to it. The allocated storage will be
  627. // freed when the safe-array is destroyed.
  628. //
  629. hrResult = SafeArrayPutElement(pArray,
  630. &lIndex,
  631. (PVOID)bstrCurrentString);
  632. }
  633. //
  634. // Free the current string.
  635. //
  636. _finally
  637. {
  638. ASSERT(bstrCurrentString != NULL);
  639. SysFreeString(bstrCurrentString);
  640. }
  641. }
  642. ASSERT(lIndex == (LONG)nCount);
  643. }
  644. //
  645. // If an error occurred, free the array.
  646. //
  647. _finally
  648. {
  649. if (FAILED(hrResult))
  650. {
  651. ASSERT(pArray != NULL);
  652. RTL_VERIFY(SUCCEEDED(SafeArrayDestroy(pArray)));
  653. }
  654. }
  655. }
  656. //
  657. // Free the storage allocated by SCGetFeedback.
  658. //
  659. _finally
  660. {
  661. ASSERT(pStrings != NULL);
  662. SCFreeMem((PVOID)pStrings);
  663. }
  664. //
  665. // If the array was successfully allocated and filled in, set the output
  666. // argument. The caller is responsible for freeing the underlying
  667. // storage.
  668. //
  669. if (SUCCEEDED(hrResult))
  670. {
  671. ASSERT(pArray != NULL);
  672. _try
  673. {
  674. *Feedback = pArray;
  675. }
  676. _except (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ?
  677. EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH)
  678. {
  679. DebugBreak();
  680. RTL_VERIFY(SUCCEEDED(SafeArrayDestroy(pArray)));
  681. return E_POINTER;
  682. }
  683. }
  684. return hrResult;
  685. }
  686. /*++
  687. * Function:
  688. * CTClientApi::ClientTerminate
  689. * Description:
  690. * This routine provides a scriptable interface to SCClientTerminate.
  691. * Arguments:
  692. * None.
  693. * Return value:
  694. * S_OK if successful, an appropriate HRESULT otherwise.
  695. * Called by:
  696. * Exported via COM.
  697. * Author:
  698. * Alex Stephens (alexstep) 24-Jan-2002
  699. --*/
  700. STDMETHODIMP
  701. CTClientApi::ClientTerminate (
  702. VOID
  703. )
  704. {
  705. PCSTR szError;
  706. HRESULT hrResult;
  707. ATLTRACE(_T("ITClientApi::ClientTerminate\n"));
  708. ASSERT(m_pCI != NULL);
  709. szError = SCClientTerminate(m_pCI);
  710. SaveError(szError, m_dwErrorIndex, &hrResult);
  711. return hrResult;
  712. }
  713. /*++
  714. * Function:
  715. * CTClientApi::Check
  716. * Description:
  717. * This routine provides a scriptable interface to SCCheck.
  718. * Arguments:
  719. * Command - Supplies the SmClient Check command to execute.
  720. * Parameter - Supplies the argument to the Check command.
  721. * Return value:
  722. * S_OK if successful, an appropriate HRESULT otherwise.
  723. * Called by:
  724. * Exported via COM.
  725. * Author:
  726. * Alex Stephens (alexstep) 24-Jan-2002
  727. --*/
  728. STDMETHODIMP
  729. CTClientApi::Check (
  730. IN BSTR Command,
  731. IN BSTR Parameter
  732. )
  733. {
  734. PCSTR szCommand;
  735. PCWSTR szParameter;
  736. PCSTR szError;
  737. HRESULT hrResult;
  738. USES_CONVERSION;
  739. ATLTRACE(_T("ITClientApi::Check\n"));
  740. //
  741. // Convert the OLE strings to ANSI and Unicode strings for TClient. This
  742. // will allocate storage for the ANSI string on the stack.
  743. //
  744. if ( Command == NULL || Parameter == NULL) {
  745. return E_INVALIDARG;
  746. }
  747. _try
  748. {
  749. szCommand = OLE2A(Command);
  750. szParameter = OLE2W(Parameter);
  751. }
  752. _except ((GetExceptionCode() == EXCEPTION_STACK_OVERFLOW ||
  753. GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION) ?
  754. EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH)
  755. {
  756. switch (GetExceptionCode())
  757. {
  758. case EXCEPTION_STACK_OVERFLOW:
  759. _resetstkoflw();
  760. return HRESULT_FROM_WIN32(ERROR_STACK_OVERFLOW);
  761. break;
  762. case EXCEPTION_ACCESS_VIOLATION:
  763. return E_POINTER;
  764. break;
  765. default:
  766. DebugBreak();
  767. return E_FAIL;
  768. break;
  769. }
  770. }
  771. //
  772. // Call the API and return the result.
  773. //
  774. ASSERT(m_pCI != NULL);
  775. szError = SCCheck(m_pCI, szCommand, szParameter);
  776. SaveError(szError, m_dwErrorIndex, &hrResult);
  777. return hrResult;
  778. }
  779. /*++
  780. * Function:
  781. * CTClientApi::Clipboard
  782. * Description:
  783. * This routine provides a scriptable interface to SCClipboard.
  784. * Arguments:
  785. * Command - Supplies the clipboard command to execute.
  786. * FileName - Supplies the clipboard-data file on which to operate.
  787. * Return value:
  788. * S_OK if successful, an appropriate HRESULT otherwise.
  789. * Called by:
  790. * Exported via COM.
  791. * Author:
  792. * Alex Stephens (alexstep) 24-Jan-2002
  793. --*/
  794. STDMETHODIMP
  795. CTClientApi::Clipboard (
  796. IN ULONG Command,
  797. IN BSTR FileName
  798. )
  799. {
  800. CLIPBOARDOPS eCommand;
  801. PCSTR szFileName;
  802. PCSTR szError;
  803. HRESULT hrResult;
  804. USES_CONVERSION;
  805. ATLTRACE(_T("ITClientApi::Clipboard\n"));
  806. //
  807. // Convert the OLE string to an ANSI string for TClient. This will
  808. // allocate on the stack.
  809. //
  810. _try
  811. {
  812. szFileName = OLE2A(FileName);
  813. }
  814. _except ((GetExceptionCode() == EXCEPTION_STACK_OVERFLOW ||
  815. GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION) ?
  816. EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH)
  817. {
  818. switch (GetExceptionCode())
  819. {
  820. case EXCEPTION_STACK_OVERFLOW:
  821. _resetstkoflw();
  822. return HRESULT_FROM_WIN32(ERROR_STACK_OVERFLOW);
  823. break;
  824. case EXCEPTION_ACCESS_VIOLATION:
  825. return E_POINTER;
  826. break;
  827. default:
  828. DebugBreak();
  829. return E_FAIL;
  830. break;
  831. }
  832. }
  833. //
  834. // Convert the command to a clipboard operation.
  835. //
  836. switch (Command)
  837. {
  838. case COPY_TO_CLIPBOARD:
  839. eCommand = COPY_TO_CLIPBOARD;
  840. break;
  841. case PASTE_FROM_CLIPBOARD:
  842. eCommand = PASTE_FROM_CLIPBOARD;
  843. break;
  844. default:
  845. return E_INVALIDARG;
  846. break;
  847. }
  848. //
  849. // Call the API and return the result.
  850. //
  851. ASSERT(m_pCI != NULL);
  852. szError = SCClipboard(m_pCI, eCommand, szFileName);
  853. SaveError(szError, m_dwErrorIndex, &hrResult);
  854. return hrResult;
  855. }
  856. /*++
  857. * Function:
  858. * CTClientApi::Connect
  859. * Description:
  860. * This routine provides a scriptable interface to SCConnect.
  861. * Arguments:
  862. * ServerName - Supplies the name of the server to connect to.
  863. * UserName - Supples the name of the user to log on with.
  864. * Password - Supplied the user password.
  865. * Domain - Supples the domain to which the user belongs.
  866. * XResolution - Supplies the horizontal resolution to use for the
  867. * session.
  868. * YResolution - Supplies the vertical resolution to use for the
  869. * session.
  870. * Return value:
  871. * S_OK if successful, an appropriate HRESULT otherwise.
  872. * Called by:
  873. * Exported via COM.
  874. * Author:
  875. * Alex Stephens (alexstep) 24-Jan-2002
  876. --*/
  877. STDMETHODIMP
  878. CTClientApi::Connect (
  879. IN BSTR ServerName,
  880. IN BSTR UserName,
  881. IN BSTR Password,
  882. IN BSTR Domain,
  883. IN ULONG XResolution,
  884. IN ULONG YResolution
  885. )
  886. {
  887. PCWSTR szServerName;
  888. PCWSTR szUserName;
  889. PCWSTR szPassword;
  890. PCWSTR szDomain;
  891. PCSTR szError;
  892. HRESULT hrResult;
  893. USES_CONVERSION;
  894. ATLTRACE(_T("ITClientApi::Connect\n"));
  895. //
  896. // Convert the OLE strings to Unicode strings for TClient. OLE strings
  897. // are already Unicode, so this will not allocate any storage.
  898. //
  899. _try
  900. {
  901. szServerName = OLE2W(ServerName);
  902. szUserName = OLE2W(UserName);
  903. szPassword = OLE2W(Password);
  904. szDomain = OLE2W(Domain);
  905. }
  906. _except (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ?
  907. EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH)
  908. {
  909. return E_POINTER;
  910. }
  911. //
  912. // Call the API and return the result.
  913. //
  914. ASSERT(m_pCI == NULL);
  915. RTL_SOFT_ASSERT(szServerName != NULL);
  916. RTL_SOFT_ASSERT(szUserName != NULL);
  917. RTL_SOFT_ASSERT(szPassword != NULL);
  918. RTL_SOFT_ASSERT(szDomain != NULL);
  919. szError = SCConnect(szServerName,
  920. szUserName,
  921. szPassword,
  922. szDomain,
  923. XResolution,
  924. YResolution,
  925. (PVOID *)&m_pCI);
  926. SaveError(szError, m_dwErrorIndex, &hrResult);
  927. return hrResult;
  928. }
  929. /*++
  930. * Function:
  931. * CTClientApi::Disconnect
  932. * Description:
  933. * This routine provides a scriptable interface to SCDisconnect.
  934. * Arguments:
  935. * None.
  936. * Return value:
  937. * S_OK if successful, an appropriate HRESULT otherwise.
  938. * Called by:
  939. * Exported via COM.
  940. * Author:
  941. * Alex Stephens (alexstep) 24-Jan-2002
  942. --*/
  943. STDMETHODIMP
  944. CTClientApi::Disconnect (
  945. VOID
  946. )
  947. {
  948. PCSTR szError;
  949. HRESULT hrResult;
  950. //
  951. // Disconnecting frees the storage used for the connection information.
  952. //
  953. ATLTRACE(_T("ITClientApi::Disconnect\n"));
  954. RTL_SOFT_ASSERT(m_pCI != NULL);
  955. szError = SCDisconnect(m_pCI);
  956. if (szError == NULL)
  957. {
  958. m_pCI = NULL;
  959. }
  960. SaveError(szError, m_dwErrorIndex, &hrResult);
  961. return hrResult;
  962. }
  963. /*++
  964. * Function:
  965. * CTClientApi::Logoff
  966. * Description:
  967. * This routine provides a scriptable interface to SCLogoff.
  968. * Arguments:
  969. * None.
  970. * Return value:
  971. * S_OK if successful, an appropriate HRESULT otherwise.
  972. * Called by:
  973. * Exported via COM.
  974. * Author:
  975. * Alex Stephens (alexstep) 24-Jan-2002
  976. --*/
  977. STDMETHODIMP
  978. CTClientApi::Logoff (
  979. VOID
  980. )
  981. {
  982. PCSTR szError;
  983. HRESULT hrResult;
  984. //
  985. // Logging off frees the storage used for the connection information.
  986. //
  987. ATLTRACE(_T("ITClientApi::Logoff\n"));
  988. RTL_SOFT_ASSERT(m_pCI != NULL);
  989. szError = SCLogoff(m_pCI);
  990. if (szError == NULL)
  991. {
  992. m_pCI = NULL;
  993. }
  994. SaveError(szError, m_dwErrorIndex, &hrResult);
  995. return hrResult;
  996. }
  997. /*++
  998. * Function:
  999. * CTClientApi::SendData
  1000. * Description:
  1001. * This routine provides a scriptable interface to SCSendData.
  1002. * Arguments:
  1003. * Message - Supplies the window message to send.
  1004. * WParameter - Supplies the message's W parameter.
  1005. * LParameter - Supplies the message's L parameter.
  1006. * Return value:
  1007. * S_OK if successful, an appropriate HRESULT otherwise.
  1008. * Called by:
  1009. * Exported via COM.
  1010. * Author:
  1011. * Alex Stephens (alexstep) 24-Jan-2002
  1012. --*/
  1013. STDMETHODIMP
  1014. CTClientApi::SendData (
  1015. IN UINT Message,
  1016. IN UINT_PTR WParameter,
  1017. IN LONG_PTR LParameter
  1018. )
  1019. {
  1020. PCSTR szError;
  1021. HRESULT hrResult;
  1022. ATLTRACE(_T("ITClientApi::SendData\n"));
  1023. ASSERT(m_pCI != NULL);
  1024. szError = SCSenddata(m_pCI, Message, WParameter, LParameter);
  1025. SaveError(szError, m_dwErrorIndex, &hrResult);
  1026. return hrResult;
  1027. }
  1028. /*++
  1029. * Function:
  1030. * CTClientApi::Start
  1031. * Description:
  1032. * This routine provides a scriptable interface to SCStart.
  1033. * Arguments:
  1034. * AppName - Supplies the name of the executable to start.
  1035. * Return value:
  1036. * S_OK if successful, an appropriate HRESULT otherwise.
  1037. * Called by:
  1038. * Exported via COM.
  1039. * Author:
  1040. * Alex Stephens (alexstep) 24-Jan-2002
  1041. --*/
  1042. STDMETHODIMP
  1043. CTClientApi::Start (
  1044. IN BSTR AppName
  1045. )
  1046. {
  1047. PCWSTR szAppName;
  1048. PCSTR szError;
  1049. HRESULT hrResult;
  1050. USES_CONVERSION;
  1051. ATLTRACE(_T("ITClientApi::Start\n"));
  1052. //
  1053. // Convert the OLE string to a Unicode string for TClient. OLE strings
  1054. // are already Unicode, so this will not allocate any storage.
  1055. //
  1056. _try
  1057. {
  1058. szAppName = OLE2W(AppName);
  1059. }
  1060. _except (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ?
  1061. EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH)
  1062. {
  1063. return E_POINTER;
  1064. }
  1065. //
  1066. // Call the API and return the result.
  1067. //
  1068. ASSERT(m_pCI != NULL);
  1069. ASSERT(szAppName != NULL);
  1070. szError = SCStart(m_pCI, szAppName);
  1071. SaveError(szError, m_dwErrorIndex, &hrResult);
  1072. return hrResult;
  1073. }
  1074. /*++
  1075. * Function:
  1076. * CTClientApi::SwitchToProcess
  1077. * Description:
  1078. * This routine provides a scriptable interface to SCSwitchToProcess.
  1079. * Arguments:
  1080. * WindowTitle - Supplies the title of the top-level window belonging to
  1081. * the process to which the caller would like to switch.
  1082. * Return value:
  1083. * S_OK if successful, an appropriate HRESULT otherwise.
  1084. * Called by:
  1085. * Exported via COM.
  1086. * Author:
  1087. * Alex Stephens (alexstep) 24-Jan-2002
  1088. --*/
  1089. STDMETHODIMP
  1090. CTClientApi::SwitchToProcess (
  1091. IN BSTR WindowTitle
  1092. )
  1093. {
  1094. PCWSTR szWindowTitle;
  1095. PCSTR szError;
  1096. HRESULT hrResult;
  1097. USES_CONVERSION;
  1098. ATLTRACE(_T("ITClientApi::SwitchToProcess\n"));
  1099. //
  1100. // Convert the OLE string to a Unicode string for TClient. OLE strings
  1101. // are already Unicode, so this will not allocate any storage.
  1102. //
  1103. _try
  1104. {
  1105. szWindowTitle = OLE2W(WindowTitle);
  1106. }
  1107. _except (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ?
  1108. EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH)
  1109. {
  1110. return E_POINTER;
  1111. }
  1112. //
  1113. // Call the API and return the result.
  1114. //
  1115. ASSERT(m_pCI != NULL);
  1116. ASSERT(szWindowTitle != NULL);
  1117. szError = SCSwitchToProcess(m_pCI, szWindowTitle);
  1118. SaveError(szError, m_dwErrorIndex, &hrResult);
  1119. return hrResult;
  1120. }
  1121. /*++
  1122. * Function:
  1123. * CTClientApi::SendMouseClick
  1124. * Description:
  1125. * This routine provides a scriptable interface to SCSendMouseClick.
  1126. * Arguments:
  1127. * XPosition - Supplies the horizontal position of the mouse click.
  1128. * YPosition - Supplies the vertical position of the mouse click.
  1129. * Return value:
  1130. * S_OK if successful, an appropriate HRESULT otherwise.
  1131. * Called by:
  1132. * Exported via COM.
  1133. * Author:
  1134. * Alex Stephens (alexstep) 24-Jan-2002
  1135. --*/
  1136. STDMETHODIMP
  1137. CTClientApi::SendMouseClick (
  1138. IN ULONG XPosition,
  1139. IN ULONG YPosition
  1140. )
  1141. {
  1142. PCSTR szError;
  1143. HRESULT hrResult;
  1144. ATLTRACE(_T("ITClientApi::SendMouseClick\n"));
  1145. ASSERT(m_pCI != NULL);
  1146. szError = SCSendMouseClick(m_pCI, XPosition, YPosition);
  1147. SaveError(szError, m_dwErrorIndex, &hrResult);
  1148. return hrResult;
  1149. }
  1150. /*++
  1151. * Function:
  1152. * CTClientApi::GetSessionId
  1153. * Description:
  1154. * This routine provides a scriptable interface to SCGetSessionId.
  1155. * Arguments:
  1156. * SessionId - Returns the ID of the session associated with the current
  1157. * RDP client.
  1158. * Return value:
  1159. * S_OK if successful, an appropriate HRESULT otherwise.
  1160. * Called by:
  1161. * Exported via COM.
  1162. * Author:
  1163. * Alex Stephens (alexstep) 24-Jan-2002
  1164. --*/
  1165. STDMETHODIMP
  1166. CTClientApi::GetSessionId (
  1167. OUT ULONG *SessionId
  1168. )
  1169. {
  1170. UINT uiSessionId;
  1171. ATLTRACE(_T("ITClientApi::GetSessionId\n"));
  1172. //
  1173. // Get the session ID and return it.
  1174. //
  1175. ASSERT(m_pCI != NULL);
  1176. uiSessionId = SCGetSessionId(m_pCI);
  1177. _try
  1178. {
  1179. *SessionId = uiSessionId;
  1180. }
  1181. _except (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ?
  1182. EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH)
  1183. {
  1184. return E_POINTER;
  1185. }
  1186. return S_OK;
  1187. }
  1188. /*++
  1189. * Function:
  1190. * CTClientApi::CloseClipboard
  1191. * Description:
  1192. * This routine provides a scriptable interface to SCCloseClipboard.
  1193. * Arguments:
  1194. * None.
  1195. * Return value:
  1196. * S_OK if successful, an appropriate HRESULT otherwise.
  1197. * Called by:
  1198. * Exported via COM.
  1199. * Author:
  1200. * Alex Stephens (alexstep) 24-Jan-2002
  1201. --*/
  1202. STDMETHODIMP
  1203. CTClientApi::CloseClipboard (
  1204. VOID
  1205. )
  1206. {
  1207. ATLTRACE(_T("ITClientApi::CloseClipboard\n"));
  1208. return SCCloseClipboard() ? S_OK : E_FAIL;
  1209. }
  1210. /*++
  1211. * Function:
  1212. * CTClientApi::OpenClipboard
  1213. * Description:
  1214. * This routine provides a scriptable interface to SCOpenClipboard.
  1215. * Arguments:
  1216. * Window - Supplies the window with which the clipboard will be
  1217. * associated.
  1218. * Return value:
  1219. * S_OK if successful, an appropriate HRESULT otherwise.
  1220. * Called by:
  1221. * Exported via COM.
  1222. * Author:
  1223. * Alex Stephens (alexstep) 24-Jan-2002
  1224. --*/
  1225. STDMETHODIMP
  1226. CTClientApi::OpenClipboard (
  1227. IN HWND Window
  1228. )
  1229. {
  1230. ATLTRACE(_T("ITClientApi::OpenClipboard\n"));
  1231. return SCOpenClipboard(Window) ? S_OK : E_FAIL;
  1232. }
  1233. /*++
  1234. * Function:
  1235. * CTClientApi::SetClientTopmost
  1236. * Description:
  1237. * This routine provides a scriptable interface to SCSetClientTopmost.
  1238. * Arguments:
  1239. * Enable - Supplies a Boolean value indicating whether the top-level
  1240. * attribute will be set (true) or removed (false).
  1241. * Return value:
  1242. * S_OK if successful, an appropriate HRESULT otherwise.
  1243. * Called by:
  1244. * Exported via COM.
  1245. * Author:
  1246. * Alex Stephens (alexstep) 24-Jan-2002
  1247. --*/
  1248. STDMETHODIMP
  1249. CTClientApi::SetClientTopmost (
  1250. IN BOOL Enable
  1251. )
  1252. {
  1253. PCWSTR szEnable;
  1254. PCSTR szError;
  1255. HRESULT hrResult;
  1256. ATLTRACE(_T("ITClientApi::SetClientTopmost\n"));
  1257. //
  1258. // Convert the enable value to a Unicode string.
  1259. //
  1260. szEnable = Enable ? L"1" : L"0";
  1261. //
  1262. // Call the API and return the result.
  1263. //
  1264. ASSERT(m_pCI != NULL);
  1265. szError = SCSetClientTopmost(m_pCI, szEnable);
  1266. SaveError(szError, m_dwErrorIndex, &hrResult);
  1267. return hrResult;
  1268. }
  1269. /*++
  1270. * Function:
  1271. * CTClientApi::Attach
  1272. * Description:
  1273. * This routine provides a scriptable interface to SCAttach
  1274. * Arguments:
  1275. * Window - Supplies a handle identifying the client window to which
  1276. * TClient will attach.
  1277. * Cookie - Supplies a cookie with which the client will be identified.
  1278. * Return value:
  1279. * S_OK if successful, an appropriate HRESULT otherwise.
  1280. * Called by:
  1281. * Exported via COM.
  1282. * Author:
  1283. * Alex Stephens (alexstep) 24-Jan-2002
  1284. --*/
  1285. STDMETHODIMP
  1286. CTClientApi::Attach (
  1287. IN HWND Window,
  1288. IN LONG_PTR Cookie
  1289. )
  1290. {
  1291. PCSTR szError;
  1292. HRESULT hrResult;
  1293. ATLTRACE(_T("ITClientApi::Attach\n"));
  1294. //
  1295. // If a client is already attached, detach it. This will free all
  1296. // resources associated with the connection.
  1297. //
  1298. if (m_pCI != NULL)
  1299. {
  1300. szError = SCDetach(m_pCI);
  1301. SaveError(szError, m_dwErrorIndex, &hrResult);
  1302. if (szError != NULL)
  1303. {
  1304. return hrResult;
  1305. }
  1306. m_pCI = NULL;
  1307. }
  1308. szError = SCAttach(Window, Cookie, &m_pCI);
  1309. SaveError(szError, m_dwErrorIndex, &hrResult);
  1310. return hrResult;
  1311. }
  1312. /*++
  1313. * Function:
  1314. * CTClientApi::Detach
  1315. * Description:
  1316. * This routine provides a scriptable interface to SCDetach.
  1317. * Arguments:
  1318. * None.
  1319. * Return value:
  1320. * S_OK if successful, an appropriate HRESULT otherwise.
  1321. * Called by:
  1322. * Exported via COM.
  1323. * Author:
  1324. * Alex Stephens (alexstep) 24-Jan-2002
  1325. --*/
  1326. STDMETHODIMP
  1327. CTClientApi::Detach (
  1328. VOID
  1329. )
  1330. {
  1331. PCSTR szError;
  1332. HRESULT hrResult;
  1333. ATLTRACE(_T("ITClientApi::Detach\n"));
  1334. szError = SCDetach(m_pCI);
  1335. if (szError == NULL)
  1336. {
  1337. m_pCI = NULL;
  1338. }
  1339. SaveError(szError, m_dwErrorIndex, &hrResult);
  1340. return hrResult;
  1341. }
  1342. /*++
  1343. * Function:
  1344. * CTClientApi::GetIni
  1345. * Description:
  1346. * This routine provides scriptable access to the SmClient INI settings.
  1347. * Arguments:
  1348. * Ini - Returns the ITClientIni interface, which provides access to the
  1349. * SmClient INI settings.
  1350. * Return value:
  1351. * S_OK if successful, an appropriate HRESULT otherwise.
  1352. * Called by:
  1353. * Exported via COM.
  1354. * Author:
  1355. * Alex Stephens (alexstep) 24-Jan-2002
  1356. --*/
  1357. STDMETHODIMP
  1358. CTClientApi::GetIni (
  1359. OUT ITClientIni **Ini
  1360. )
  1361. {
  1362. ATLTRACE(_T("ITClientApi::GetIni\n"));
  1363. UNREFERENCED_PARAMETER(Ini);
  1364. return E_NOTIMPL;
  1365. }
  1366. /*++
  1367. * Function:
  1368. * CTClientApi::GetClientWindowHandle
  1369. * Description:
  1370. * This routine provides a scriptable interface to
  1371. * SCGetClientWindowHandle.
  1372. * Arguments:
  1373. * Window - Returns the client-window handle.
  1374. * Return value:
  1375. * S_OK if successful, an appropriate HRESULT otherwise.
  1376. * Called by:
  1377. * Exported via COM.
  1378. * Author:
  1379. * Alex Stephens (alexstep) 24-Jan-2002
  1380. --*/
  1381. STDMETHODIMP
  1382. CTClientApi::GetClientWindowHandle (
  1383. OUT HWND *Window
  1384. )
  1385. {
  1386. HWND hWindow;
  1387. ATLTRACE(_T("ITClientApi::GetClientWindowHandle\n"));
  1388. //
  1389. // Get the window handle and return it.
  1390. //
  1391. ASSERT(m_pCI != NULL);
  1392. hWindow = SCGetClientWindowHandle(m_pCI);
  1393. _try
  1394. {
  1395. *Window = hWindow;
  1396. }
  1397. _except (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ?
  1398. EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH)
  1399. {
  1400. return E_POINTER;
  1401. }
  1402. return S_OK;
  1403. }
  1404. //
  1405. // Define utility routines.
  1406. //
  1407. /*++
  1408. * Function:
  1409. * CTClientApi::PrintMessage
  1410. * Description:
  1411. * This routine prints a message to the standard output and to the
  1412. * debugger.
  1413. * Arguments:
  1414. * MessageType - Supplies the message category, e.g. error, warning,
  1415. * etc.
  1416. * Return value:
  1417. * None.
  1418. * Called by:
  1419. * Various routines.
  1420. * Author:
  1421. * Alex Stephens (alexstep) 24-Jan-2002
  1422. --*/
  1423. VOID
  1424. CTClientApi::PrintMessage (
  1425. MESSAGETYPE MessageType,
  1426. PCSTR Format,
  1427. ...
  1428. )
  1429. {
  1430. CHAR szBuffer[LOG_BUFFER_SIZE];
  1431. CHAR szDbgBuffer[LOG_BUFFER_SIZE +
  1432. sizeof(LOG_PREFIX) / sizeof(*LOG_PREFIX)];
  1433. va_list arglist;
  1434. ATLTRACE(_T("CTClientApi::PrintMessage\n"));
  1435. UNREFERENCED_PARAMETER(MessageType);
  1436. //
  1437. // Construct the output string.
  1438. //
  1439. va_start(arglist, Format);
  1440. _vsnprintf(szBuffer, LOG_BUFFER_SIZE - 1, Format, arglist);
  1441. szBuffer[LOG_BUFFER_SIZE - 1] = '\0';
  1442. va_end (arglist);
  1443. //
  1444. // Print the message to the output console.
  1445. //
  1446. printf( "%s", szBuffer);
  1447. //
  1448. // Print the message to the debugger window.
  1449. //
  1450. sprintf(szDbgBuffer, LOG_PREFIX "%s", szBuffer);
  1451. szDbgBuffer[LOG_BUFFER_SIZE +
  1452. sizeof(LOG_PREFIX) / sizeof(*LOG_PREFIX) -
  1453. 1] = '\0';
  1454. OutputDebugStringA(szDbgBuffer);
  1455. }