PageRenderTime 25ms CodeModel.GetById 2ms app.highlight 16ms RepoModel.GetById 1ms app.codeStats 0ms

/Visual Studio 2008/CppCOMClient/ImportDirective.cpp

#
C++ | 190 lines | 55 code | 27 blank | 108 comment | 1 complexity | f64d0c70528257a4c776053f71b52912 MD5 | raw file
  1/****************************** Module Header ******************************\
  2* Module Name:  ImportDirective.cpp
  3* Project:      CppCOMClient
  4* Copyright (c) Microsoft Corporation.
  5* 
  6* #import (http://msdn.microsoft.com/en-us/library/8etzzkb6.aspx), a new 
  7* directive that became available with Visual C++ 5.0, creates VC++ "smart 
  8* pointers" from a specified type library. It is very powerful, but often not 
  9* recommended because of reference-counting problems that typically occur when 
 10* used with the Microsoft Office applications. Unlike the direct API approach 
 11* in RawAPI.h/cpp, smart pointers enable us to benefit from the type info to 
 12* early/late bind the object. #import takes care of adding the messy guids to 
 13* the project and the COM APIs are encapsulated in custom classes that the 
 14* #import directive generates.
 15* 
 16* The differences between early binding and late binding via smart pointers:
 17* 
 18* Smart pointers make creating an object that supports early binding easy, so 
 19* does it make creating a late bound object. The only difference between early 
 20* binding and late binding via smart pointer is the .tlh and .tli files 
 21* generated by the #import directive. If the target object supports early 
 22* binding, the .tlh and .tli files will make use of the custom interface (not 
 23* IDispatch) to call the target property/method directly. If the target COM 
 24* object only support late binding, the smart pointer takes care of converting 
 25* your method calls into GetIDsOfNames()s and Invoke()s of the IDispatch 
 26* interface.
 27* 
 28* References
 29*  http://support.microsoft.com/kb/169496
 30* 
 31* This source is subject to the Microsoft Public License.
 32* See http://www.microsoft.com/opensource/licenses.mspx#Ms-PL.
 33* All other rights reserved.
 34* 
 35* THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, 
 36* EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED 
 37* WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE.
 38\***************************************************************************/
 39
 40#pragma region Includes
 41#include <stdio.h>
 42#include "ImportDirective.h"
 43#pragma endregion
 44
 45
 46#pragma region Import the type library
 47
 48// Importing mscorlib.tlb is necessary for .NET components
 49// see: 
 50//  http://msdn.microsoft.com/en-us/library/s5628ssw.aspx
 51#import "mscorlib.tlb" raw_interfaces_only				\
 52	high_property_prefixes("_get","_put","_putref")		\
 53	rename("ReportEvent", "InteropServices_ReportEvent")
 54using namespace mscorlib;
 55
 56// Option 1) #import the name of a file that contains a type library 
 57// 
 58// We can either specify the full path of the tlb/dll/ocx/exe file or add 
 59// the path of the file to the project's Additional Include Directories 
 60// setting.
 61// 
 62// For .NET components, importing the assembly file (dll/exe) fails because 
 63// the type library is not embedded in the .NET assemblies. There is a 
 64// stand-alone tlb file. For native components, the type library is embedded 
 65// into the executable by default, and we can #import the dll/ocx/exe module 
 66// directly.
 67
 68//#import "CSDllCOMServer.tlb" no_namespace named_guids
 69
 70// Option 2) #import the progid of the component in the type library
 71// 
 72// #import-ing the progid only works for native components because .NET 
 73// components do not register the typelib for its ProgID by default. As an
 74// evidence, please open the CLSID registry node and check the TypeLib key: 
 75// HKCR\CLSID\{xxxx}\TypeLib, which is lacked by .NET components.
 76
 77//#import "progid:CSDllCOMServer.SimpleObject" \
 78//	no_namespace \
 79//	named_guids
 80
 81// Option 3) #import the libid of the type library
 82// 
 83// In the type library of CSDllCOMServer, the library ID is
 84// F0998D9A-0E79-4F67-B944-9E837F479587
 85// 
 86//  [uuid(F0998D9A-0E79-4F67-B944-9E837F479587), version(1.0),
 87//  custom(90883F05-3D28-11D2-8F17-00A0C9A6186D,"CSDllCOMServer,...)] 
 88//  library CSDllCOMServer { ... } 
 89// 
 90// #importing the library ID works for both native an .NET components.
 91
 92#import "libid:F0998D9A-0E79-4F67-B944-9E837F479587" \
 93	no_namespace \
 94	named_guids
 95
 96#pragma endregion
 97
 98
 99/*!
100 * \brief
101 * The definition of ImportCSharpComponent in the header file
102 * 
103 * \see
104 * Separate ImportDirective.h | ImportCSharpComponent
105 */
106DWORD WINAPI ImportCSharpComponent(LPVOID lpParam)
107{
108	HRESULT hr = S_OK;
109
110	// Initializes the COM library on the current thread and identifies the
111	// concurrency model as single-thread apartment (STA). 
112	// [-or-] ::CoInitialize(NULL);
113	// [-or-] ::CoCreateInstance(NULL);
114	::CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
115
116	try
117	{
118        // Create the CSDllCOMServer.SimpleObject COM object using the 
119        // #import directive and smart pointers.
120
121        // Option 1) Create the object using the smart pointer's constructor
122        // 
123        // ISimpleObjectPtr is the original interface name, ISimpleObject, 
124        // with a "Ptr" suffix.
125        //ISimpleObjectPtr spSimpleObj(
126        //	__uuidof(SimpleObject)	// CLSID of the component
127        //	);
128
129        // Option 2) Create the object using the smart pointer's function,
130        // CreateInstance
131        ISimpleObjectPtr spSimpleObj;
132        hr = spSimpleObj.CreateInstance(__uuidof(SimpleObject));
133        if (FAILED(hr))
134        {
135            wprintf(L"ISimpleObjectPtr::CreateInstance failed w/err 0x%08lx\n", hr);
136            return hr;
137        }
138
139        //
140        // Consume the properties and the methods of the COM object.
141        // 
142
143		// Set the property: FloatProperty.
144		{
145			wprintf(L"Set FloatProperty = %.2f\n", 1.2f);
146			spSimpleObj->FloatProperty = 1.2f;
147		}
148
149		// Get the property: FloatProperty.
150		{
151			wprintf(L"Get FloatProperty = %.2f\n", spSimpleObj->FloatProperty);
152		}
153
154		// Call the method: HelloWorld, that returns a BSTR.
155		{
156			// the _bstr_t object and the underlying BSTR will be cleared 
157			// automatically in the destructor when the object is out of 
158			// the scope.
159			bstr_t bstrResult = spSimpleObj->HelloWorld();
160			wprintf(L"Call HelloWorld => %s\n", (PCWSTR)bstrResult);
161		}
162
163		// Call the method: GetProcessThreadID, that outputs two DWORDs.
164		{
165			wprintf(L"The client process and thread: %ld, %ld\n",
166				GetCurrentProcessId(), GetCurrentThreadId());
167			
168			DWORD dwProcessId, dwThreadId;
169			spSimpleObj->GetProcessThreadID(&dwProcessId, &dwThreadId);
170			wprintf(L"Call GetProcessThreadID => %ld, %ld\n", 
171				dwProcessId, dwThreadId);
172		}
173
174        // Release the COM objects.
175        // Releasing the references is not necessary for the smart pointers
176        // spSimpleObj.Release();
177
178        wprintf(L"\n");
179	}
180	catch (_com_error &err)
181	{
182		wprintf(L"The server throws the error: %s\n", err.ErrorMessage());
183		wprintf(L"Description: %s\n", (PCWSTR) err.Description());
184	}
185
186	// Uninitialize COM for this thread
187	::CoUninitialize();
188
189	return hr;
190}