/Visual Studio 2008/CppCOMClient/ImportDirective.cpp
C++ | 190 lines | 55 code | 27 blank | 108 comment | 1 complexity | f64d0c70528257a4c776053f71b52912 MD5 | raw file
- /****************************** Module Header ******************************\
- * Module Name: ImportDirective.cpp
- * Project: CppCOMClient
- * Copyright (c) Microsoft Corporation.
- *
- * #import (http://msdn.microsoft.com/en-us/library/8etzzkb6.aspx), a new
- * directive that became available with Visual C++ 5.0, creates VC++ "smart
- * pointers" from a specified type library. It is very powerful, but often not
- * recommended because of reference-counting problems that typically occur when
- * used with the Microsoft Office applications. Unlike the direct API approach
- * in RawAPI.h/cpp, smart pointers enable us to benefit from the type info to
- * early/late bind the object. #import takes care of adding the messy guids to
- * the project and the COM APIs are encapsulated in custom classes that the
- * #import directive generates.
- *
- * The differences between early binding and late binding via smart pointers:
- *
- * Smart pointers make creating an object that supports early binding easy, so
- * does it make creating a late bound object. The only difference between early
- * binding and late binding via smart pointer is the .tlh and .tli files
- * generated by the #import directive. If the target object supports early
- * binding, the .tlh and .tli files will make use of the custom interface (not
- * IDispatch) to call the target property/method directly. If the target COM
- * object only support late binding, the smart pointer takes care of converting
- * your method calls into GetIDsOfNames()s and Invoke()s of the IDispatch
- * interface.
- *
- * References
- * http://support.microsoft.com/kb/169496
- *
- * This source is subject to the Microsoft Public License.
- * See http://www.microsoft.com/opensource/licenses.mspx#Ms-PL.
- * All other rights reserved.
- *
- * THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND,
- * EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE.
- \***************************************************************************/
-
- #pragma region Includes
- #include <stdio.h>
- #include "ImportDirective.h"
- #pragma endregion
-
-
- #pragma region Import the type library
-
- // Importing mscorlib.tlb is necessary for .NET components
- // see:
- // http://msdn.microsoft.com/en-us/library/s5628ssw.aspx
- #import "mscorlib.tlb" raw_interfaces_only \
- high_property_prefixes("_get","_put","_putref") \
- rename("ReportEvent", "InteropServices_ReportEvent")
- using namespace mscorlib;
-
- // Option 1) #import the name of a file that contains a type library
- //
- // We can either specify the full path of the tlb/dll/ocx/exe file or add
- // the path of the file to the project's Additional Include Directories
- // setting.
- //
- // For .NET components, importing the assembly file (dll/exe) fails because
- // the type library is not embedded in the .NET assemblies. There is a
- // stand-alone tlb file. For native components, the type library is embedded
- // into the executable by default, and we can #import the dll/ocx/exe module
- // directly.
-
- //#import "CSDllCOMServer.tlb" no_namespace named_guids
-
- // Option 2) #import the progid of the component in the type library
- //
- // #import-ing the progid only works for native components because .NET
- // components do not register the typelib for its ProgID by default. As an
- // evidence, please open the CLSID registry node and check the TypeLib key:
- // HKCR\CLSID\{xxxx}\TypeLib, which is lacked by .NET components.
-
- //#import "progid:CSDllCOMServer.SimpleObject" \
- // no_namespace \
- // named_guids
-
- // Option 3) #import the libid of the type library
- //
- // In the type library of CSDllCOMServer, the library ID is
- // F0998D9A-0E79-4F67-B944-9E837F479587
- //
- // [uuid(F0998D9A-0E79-4F67-B944-9E837F479587), version(1.0),
- // custom(90883F05-3D28-11D2-8F17-00A0C9A6186D,"CSDllCOMServer,...)]
- // library CSDllCOMServer { ... }
- //
- // #importing the library ID works for both native an .NET components.
-
- #import "libid:F0998D9A-0E79-4F67-B944-9E837F479587" \
- no_namespace \
- named_guids
-
- #pragma endregion
-
-
- /*!
- * \brief
- * The definition of ImportCSharpComponent in the header file
- *
- * \see
- * Separate ImportDirective.h | ImportCSharpComponent
- */
- DWORD WINAPI ImportCSharpComponent(LPVOID lpParam)
- {
- HRESULT hr = S_OK;
-
- // Initializes the COM library on the current thread and identifies the
- // concurrency model as single-thread apartment (STA).
- // [-or-] ::CoInitialize(NULL);
- // [-or-] ::CoCreateInstance(NULL);
- ::CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
-
- try
- {
- // Create the CSDllCOMServer.SimpleObject COM object using the
- // #import directive and smart pointers.
-
- // Option 1) Create the object using the smart pointer's constructor
- //
- // ISimpleObjectPtr is the original interface name, ISimpleObject,
- // with a "Ptr" suffix.
- //ISimpleObjectPtr spSimpleObj(
- // __uuidof(SimpleObject) // CLSID of the component
- // );
-
- // Option 2) Create the object using the smart pointer's function,
- // CreateInstance
- ISimpleObjectPtr spSimpleObj;
- hr = spSimpleObj.CreateInstance(__uuidof(SimpleObject));
- if (FAILED(hr))
- {
- wprintf(L"ISimpleObjectPtr::CreateInstance failed w/err 0x%08lx\n", hr);
- return hr;
- }
-
- //
- // Consume the properties and the methods of the COM object.
- //
-
- // Set the property: FloatProperty.
- {
- wprintf(L"Set FloatProperty = %.2f\n", 1.2f);
- spSimpleObj->FloatProperty = 1.2f;
- }
-
- // Get the property: FloatProperty.
- {
- wprintf(L"Get FloatProperty = %.2f\n", spSimpleObj->FloatProperty);
- }
-
- // Call the method: HelloWorld, that returns a BSTR.
- {
- // the _bstr_t object and the underlying BSTR will be cleared
- // automatically in the destructor when the object is out of
- // the scope.
- bstr_t bstrResult = spSimpleObj->HelloWorld();
- wprintf(L"Call HelloWorld => %s\n", (PCWSTR)bstrResult);
- }
-
- // Call the method: GetProcessThreadID, that outputs two DWORDs.
- {
- wprintf(L"The client process and thread: %ld, %ld\n",
- GetCurrentProcessId(), GetCurrentThreadId());
-
- DWORD dwProcessId, dwThreadId;
- spSimpleObj->GetProcessThreadID(&dwProcessId, &dwThreadId);
- wprintf(L"Call GetProcessThreadID => %ld, %ld\n",
- dwProcessId, dwThreadId);
- }
-
- // Release the COM objects.
- // Releasing the references is not necessary for the smart pointers
- // spSimpleObj.Release();
-
- wprintf(L"\n");
- }
- catch (_com_error &err)
- {
- wprintf(L"The server throws the error: %s\n", err.ErrorMessage());
- wprintf(L"Description: %s\n", (PCWSTR) err.Description());
- }
-
- // Uninitialize COM for this thread
- ::CoUninitialize();
-
- return hr;
- }