PageRenderTime 49ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 0ms

/Visual Studio 2008/CppCOMClient/RawAPI.cpp

#
C++ | 237 lines | 126 code | 36 blank | 75 comment | 9 complexity | 5dd579c18b791096a756a58781c00cf6 MD5 | raw file
  1. /****************************** Module Header ******************************\
  2. * Module Name: RawAPI.cpp
  3. * Project: CppCOMClient
  4. * Copyright (c) Microsoft Corporation.
  5. *
  6. * This file demontrates the use of C/C++ and the COM APIs to automate a server.
  7. * C/C++ Automation is much more difficult, but sometimes necessary to avoid
  8. * overhead with MFC, or problems with #import. Basically, you work with such
  9. * APIs as CoCreateInstance(), and COM interfaces such as IDispatch and IUnknown.
  10. *
  11. * References
  12. * http://support.microsoft.com/kb/216686
  13. * http://support.microsoft.com/kb/238393
  14. * http://support.microsoft.com/kb/216388
  15. *
  16. * This source is subject to the Microsoft Public License.
  17. * See http://www.microsoft.com/opensource/licenses.mspx#Ms-PL.
  18. * All other rights reserved.
  19. *
  20. * THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND,
  21. * EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED
  22. * WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE.
  23. \***************************************************************************/
  24. #pragma region Includes
  25. #include <stdio.h>
  26. #include <tchar.h>
  27. #include "RawAPI.h"
  28. #pragma endregion
  29. /*!
  30. * \brief
  31. * The definition of RawConsumeSTAComponent in the header file
  32. *
  33. * \see
  34. * Separate RawAPI.h | RawConsumeSTAComponent
  35. */
  36. DWORD WINAPI RawConsumeSTAComponent(LPVOID lpParam)
  37. {
  38. HRESULT hr;
  39. IDispatch *pSimpleObj;
  40. // Initializes the COM library on the current thread and identifies
  41. // the concurrency model as single-thread apartment (STA).
  42. // [-or-] ::CoInitialize(NULL);
  43. // [-or-] ::CoCreateInstance(NULL);
  44. hr = ::CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
  45. if (FAILED(hr))
  46. {
  47. wprintf(L"CoInitializeEx failed w/hr 0x%08lx\n", hr);
  48. goto Cleanup;
  49. }
  50. // Create the ATLDllCOMServer.SimpleObject COM object using C++ and
  51. // the COM APIs.
  52. // Get CLSID of the server
  53. CLSID clsid;
  54. // Option 1. Get CLSID from ProgID using CLSIDFromProgID.
  55. LPCOLESTR progID = L"ATLDllCOMServer.SimpleObject";
  56. hr = ::CLSIDFromProgID(progID, &clsid);
  57. if (FAILED(hr))
  58. {
  59. wprintf(L"CLSIDFromProgID failed w/hr 0x%08lx\n", hr);
  60. goto Cleanup;
  61. }
  62. // Option 2. Build the CLSID directly.
  63. /*const IID CLSID_SimpleObject =
  64. {0x92FCF37F,0xF6C7,0x4F8A,{0xAA,0x09,0x1A,0x14,0xBA,0x11,0x80,0x84}};
  65. clsid = CLSID_SimpleObject;*/
  66. // Start the server and get the IDispatch interface
  67. hr = ::CoCreateInstance( // [-or-] CoCreateInstanceEx, CoGetObject
  68. clsid, // CLSID of the server
  69. NULL,
  70. CLSCTX_INPROC_SERVER, // CLSCTX_LOCAL_SERVER for ActiveX EXEs
  71. IID_PPV_ARGS(&pSimpleObj)); // Return IDispatch *
  72. if (FAILED(hr))
  73. {
  74. wprintf(L"CoCreateInstance failed w/hr 0x%08lx\n", hr);
  75. goto Cleanup;
  76. }
  77. //
  78. // Consume the properties and the methods of the COM object.
  79. //
  80. // Set the property: HRESULT FloatProperty([in] FLOAT newVal);
  81. {
  82. VARIANT x;
  83. x.vt = VT_R4; // 4-byte real.
  84. x.fltVal = 1.2f;
  85. wprintf(L"Set FloatProperty = %.2f\n", x.fltVal);
  86. hr = AutoWrap(DISPATCH_PROPERTYPUT, NULL, pSimpleObj, L"FloatProperty", 1, x);
  87. }
  88. // Get the property: HRESULT FloatProperty([out, retval] FLOAT* pVal);
  89. {
  90. VARIANT result;
  91. VariantInit(&result);
  92. hr = AutoWrap(DISPATCH_PROPERTYGET, &result, pSimpleObj, L"FloatProperty", 0);
  93. wprintf(L"Get FloatProperty = %.2f\n", result.fltVal);
  94. }
  95. // Call the method: HRESULT HelloWorld([out,retval] BSTR* pRet);
  96. {
  97. VARIANT result;
  98. VariantInit(&result);
  99. hr = AutoWrap(DISPATCH_METHOD, &result, pSimpleObj, L"HelloWorld", 0);
  100. wprintf(L"Call HelloWorld => %s\n", result.bstrVal);
  101. VariantClear(&result);
  102. }
  103. // Call the method: HRESULT GetProcessThreadID([out] LONG* pdwProcessId,
  104. // [out] LONG* pdwThreadId);
  105. {
  106. wprintf(L"The client process and thread: %ld, %ld\n",
  107. GetCurrentProcessId(), GetCurrentThreadId());
  108. VARIANT processId, threadId;
  109. // Step1. Find the proper VT for the parameter based on the table in
  110. // http://msdn.microsoft.com/en-us/library/ms891678.aspx
  111. // In this example, the param is long* plVal, so vt = VT_BYREF|VT_I4.
  112. processId.vt = VT_BYREF | VT_I4;
  113. threadId.vt = VT_BYREF | VT_I4;
  114. // Step2. Initialize the parameters and allocate the memory.
  115. processId.plVal = new long;
  116. threadId.plVal = new long;
  117. // Step3. Pass the parameters to the method from right to left.
  118. hr = AutoWrap(DISPATCH_METHOD, NULL, pSimpleObj, L"GetProcessThreadID",
  119. 2, threadId, processId);
  120. wprintf(L"Call GetProcessThreadID => %ld, %ld\n", *processId.plVal,
  121. *threadId.plVal);
  122. }
  123. wprintf(L"\n");
  124. Cleanup:
  125. // Release the COM objects.
  126. if (pSimpleObj)
  127. {
  128. pSimpleObj->Release();
  129. pSimpleObj = NULL;
  130. }
  131. // Uninitialize COM for this thread
  132. ::CoUninitialize();
  133. return hr;
  134. }
  135. /*!
  136. * \brief
  137. * The definition of AutoWrap in the header file
  138. *
  139. * \see
  140. * Separate RawAPI.h | AutoWrap
  141. */
  142. HRESULT AutoWrap(int autoType, VARIANT *pvResult, IDispatch *pDisp,
  143. LPOLESTR ptName, int cArgs...)
  144. {
  145. // Begin variable-argument list
  146. va_list marker;
  147. va_start(marker, cArgs);
  148. if (!pDisp)
  149. {
  150. _putts(_T("NULL IDispatch passed to AutoWrap()"));
  151. _exit(0);
  152. }
  153. // Variables used
  154. DISPPARAMS dp = { NULL, NULL, 0, 0 };
  155. DISPID dispidNamed = DISPID_PROPERTYPUT;
  156. DISPID dispID;
  157. HRESULT hr;
  158. char szName[200];
  159. // Convert down to ANSI
  160. WideCharToMultiByte(CP_ACP, 0, ptName, -1, szName, 256, NULL, NULL);
  161. // Get DISPID for name passed
  162. hr = pDisp->GetIDsOfNames(IID_NULL, &ptName, 1, LOCALE_USER_DEFAULT,
  163. &dispID);
  164. if (FAILED(hr))
  165. {
  166. _tprintf(_T(
  167. "IDispatch::GetIDsOfNames(\"%s\") failed w/err 0x%08lx\n"
  168. ), szName, hr);
  169. return hr;
  170. }
  171. // Allocate memory for arguments
  172. VARIANT *pArgs = new VARIANT[cArgs+1];
  173. // Extract arguments...
  174. for(int i=0; i<cArgs; i++)
  175. {
  176. pArgs[i] = va_arg(marker, VARIANT);
  177. }
  178. // Build DISPPARAMS
  179. dp.cArgs = cArgs;
  180. dp.rgvarg = pArgs;
  181. // Handle special-case for property-puts
  182. if (autoType & DISPATCH_PROPERTYPUT)
  183. {
  184. dp.cNamedArgs = 1;
  185. dp.rgdispidNamedArgs = &dispidNamed;
  186. }
  187. // Make the call
  188. hr = pDisp->Invoke(dispID, IID_NULL, LOCALE_SYSTEM_DEFAULT,
  189. autoType, &dp, pvResult, NULL, NULL);
  190. if (FAILED(hr))
  191. {
  192. _tprintf(_T(
  193. "IDispatch::Invoke(\"%s\"=%08lx) failed w/err 0x%08lx\n"
  194. ), szName, dispID, hr);
  195. return hr;
  196. }
  197. // End variable-argument section
  198. va_end(marker);
  199. delete[] pArgs;
  200. return hr;
  201. }