PageRenderTime 54ms CodeModel.GetById 18ms app.highlight 29ms RepoModel.GetById 1ms 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
 25#pragma region Includes
 26#include <stdio.h>
 27#include <tchar.h>
 28#include "RawAPI.h"
 29#pragma endregion
 30
 31
 32/*!
 33 * \brief
 34 * The definition of RawConsumeSTAComponent in the header file
 35 * 
 36 * \see
 37 * Separate RawAPI.h | RawConsumeSTAComponent
 38 */
 39DWORD WINAPI RawConsumeSTAComponent(LPVOID lpParam)
 40{
 41	HRESULT hr;
 42    IDispatch *pSimpleObj;
 43
 44	// Initializes the COM library on the current thread and identifies 
 45	// the concurrency model as single-thread apartment (STA). 
 46	// [-or-] ::CoInitialize(NULL);
 47	// [-or-] ::CoCreateInstance(NULL);
 48	hr = ::CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
 49    if (FAILED(hr))
 50    {
 51        wprintf(L"CoInitializeEx failed w/hr 0x%08lx\n", hr);
 52        goto Cleanup;
 53    }
 54
 55	// Create the ATLDllCOMServer.SimpleObject COM object using C++ and 
 56	// the COM APIs.
 57
 58	// Get CLSID of the server
 59	CLSID clsid;
 60
 61	// Option 1. Get CLSID from ProgID using CLSIDFromProgID.
 62	LPCOLESTR progID = L"ATLDllCOMServer.SimpleObject";
 63	hr = ::CLSIDFromProgID(progID, &clsid);
 64	if (FAILED(hr))
 65	{
 66		wprintf(L"CLSIDFromProgID failed w/hr 0x%08lx\n", hr);
 67		goto Cleanup;
 68	}
 69	// Option 2. Build the CLSID directly.
 70	/*const IID CLSID_SimpleObject = 
 71	{0x92FCF37F,0xF6C7,0x4F8A,{0xAA,0x09,0x1A,0x14,0xBA,0x11,0x80,0x84}};
 72	clsid = CLSID_SimpleObject;*/
 73
 74	// Start the server and get the IDispatch interface
 75	hr = ::CoCreateInstance(        // [-or-] CoCreateInstanceEx, CoGetObject
 76		clsid,                      // CLSID of the server
 77		NULL,
 78		CLSCTX_INPROC_SERVER,       // CLSCTX_LOCAL_SERVER for ActiveX EXEs
 79		IID_PPV_ARGS(&pSimpleObj)); // Return IDispatch *
 80	if (FAILED(hr))
 81	{
 82		wprintf(L"CoCreateInstance failed w/hr 0x%08lx\n", hr);
 83		goto Cleanup;
 84	}
 85
 86    //
 87	// Consume the properties and the methods of the COM object.
 88	// 
 89
 90	// Set the property: HRESULT FloatProperty([in] FLOAT newVal);
 91	{
 92		VARIANT x;
 93		x.vt = VT_R4;   // 4-byte real. 
 94		x.fltVal = 1.2f;
 95		wprintf(L"Set FloatProperty = %.2f\n", x.fltVal);
 96		hr = AutoWrap(DISPATCH_PROPERTYPUT, NULL, pSimpleObj, L"FloatProperty", 1, x);
 97	}
 98
 99	// Get the property: HRESULT FloatProperty([out, retval] FLOAT* pVal);
100	{
101		VARIANT result;
102		VariantInit(&result);
103		hr = AutoWrap(DISPATCH_PROPERTYGET, &result, pSimpleObj, L"FloatProperty", 0);
104		wprintf(L"Get FloatProperty = %.2f\n", result.fltVal);
105	}
106
107	// Call the method: HRESULT HelloWorld([out,retval] BSTR* pRet);
108	{
109		VARIANT result;
110		VariantInit(&result);
111		hr = AutoWrap(DISPATCH_METHOD, &result, pSimpleObj, L"HelloWorld", 0);
112		wprintf(L"Call HelloWorld => %s\n", result.bstrVal);
113		VariantClear(&result);
114	}
115
116	// Call the method: HRESULT GetProcessThreadID([out] LONG* pdwProcessId, 
117	//                                             [out] LONG* pdwThreadId);
118	{
119		wprintf(L"The client process and thread: %ld, %ld\n", 
120			GetCurrentProcessId(), GetCurrentThreadId());
121
122		VARIANT processId, threadId;
123
124		// Step1. Find the proper VT for the parameter based on the table in
125		// http://msdn.microsoft.com/en-us/library/ms891678.aspx
126		// In this example, the param is long* plVal, so vt = VT_BYREF|VT_I4.
127		processId.vt = VT_BYREF | VT_I4;
128		threadId.vt = VT_BYREF | VT_I4;
129
130		// Step2. Initialize the parameters and allocate the memory.
131		processId.plVal = new long;
132		threadId.plVal = new long;
133
134		// Step3. Pass the parameters to the method from right to left.
135		hr = AutoWrap(DISPATCH_METHOD, NULL, pSimpleObj, L"GetProcessThreadID", 
136			2, threadId, processId);
137		wprintf(L"Call GetProcessThreadID => %ld, %ld\n", *processId.plVal, 
138            *threadId.plVal);
139	}
140
141	wprintf(L"\n");
142
143Cleanup:
144
145	// Release the COM objects.
146
147	if (pSimpleObj)
148    {
149	    pSimpleObj->Release();
150        pSimpleObj = NULL;
151    }
152
153	// Uninitialize COM for this thread
154	::CoUninitialize();
155
156	return hr;
157}
158
159
160/*!
161 * \brief
162 * The definition of AutoWrap in the header file
163 * 
164 * \see
165 * Separate RawAPI.h | AutoWrap
166 */
167HRESULT AutoWrap(int autoType, VARIANT *pvResult, IDispatch *pDisp, 
168				 LPOLESTR ptName, int cArgs...) 
169{
170    // Begin variable-argument list
171    va_list marker;
172    va_start(marker, cArgs);
173
174    if (!pDisp) 
175	{
176        _putts(_T("NULL IDispatch passed to AutoWrap()"));
177        _exit(0);
178    }
179
180    // Variables used
181    DISPPARAMS dp = { NULL, NULL, 0, 0 };
182    DISPID dispidNamed = DISPID_PROPERTYPUT;
183    DISPID dispID;
184    HRESULT hr;
185    char szName[200];
186    
187    // Convert down to ANSI
188    WideCharToMultiByte(CP_ACP, 0, ptName, -1, szName, 256, NULL, NULL);
189    
190    // Get DISPID for name passed
191    hr = pDisp->GetIDsOfNames(IID_NULL, &ptName, 1, LOCALE_USER_DEFAULT,
192		&dispID);
193    if (FAILED(hr))
194	{
195        _tprintf(_T(
196			"IDispatch::GetIDsOfNames(\"%s\") failed w/err 0x%08lx\n"
197			), szName, hr);
198        return hr;
199    }
200    
201    // Allocate memory for arguments
202    VARIANT *pArgs = new VARIANT[cArgs+1];
203    // Extract arguments...
204    for(int i=0; i<cArgs; i++) 
205	{
206        pArgs[i] = va_arg(marker, VARIANT);
207    }
208    
209    // Build DISPPARAMS
210    dp.cArgs = cArgs;
211    dp.rgvarg = pArgs;
212    
213    // Handle special-case for property-puts
214    if (autoType & DISPATCH_PROPERTYPUT)
215	{
216        dp.cNamedArgs = 1;
217        dp.rgdispidNamedArgs = &dispidNamed;
218    }
219    
220    // Make the call
221    hr = pDisp->Invoke(dispID, IID_NULL, LOCALE_SYSTEM_DEFAULT,
222		autoType, &dp, pvResult, NULL, NULL);
223    if (FAILED(hr)) 
224	{
225        _tprintf(_T(
226			"IDispatch::Invoke(\"%s\"=%08lx) failed w/err 0x%08lx\n"
227			), szName, dispID, hr);
228        return hr;
229    }
230
231    // End variable-argument section
232    va_end(marker);
233    
234    delete[] pArgs;
235    
236    return hr;
237}