YOU CAN CODE!

 

With The Case Of UCanCode.net  Release The Power OF  Visual C++ !   HomeProducts | PurchaseSupport | Downloads  
View in English
View in Japanese
View in
참고
View in Français
View in Italiano
View in 中文(繁體)
Download Evaluation
Pricing & Purchase?
E-XD++Visual C++/ MFC Products
Overview
Features Tour 
Electronic Form Solution
Visualization & HMI Solution
Power system HMI Solution
CAD Drawing and Printing Solution

Bar code labeling Solution
Workflow Solution

Coal industry HMI Solution
Instrumentation Gauge Solution

Report Printing Solution
Graphical modeling Solution
GIS mapping solution

Visio graphics solution
Industrial control SCADA &HMI Solution
BPM business process Solution

Industrial monitoring Solution
Flowchart and diagramming Solution
Organization Diagram Solution

Graphic editor Source Code
UML drawing editor Source Code
Map Diagramming Solution

Architectural Graphic Drawing Solution
Request Evaluation
Purchase
ActiveX COM Products
Overview
Download
Purchase
Technical Support
  General Q & A
Discussion Board
Contact Us

Links

Get Ready to Unleash the Power of UCanCode .NET


UCanCode Software focuses on general application software development. We provide complete solution for developers. No matter you want to develop a simple database workflow application, or an large flow/diagram based system, our product will provide a complete solution for you. Our product had been used by hundreds of top companies around the world!

"100% source code provided! Free you from not daring to use components because of unable to master the key technology of components!"


VC++ .NET Programming, Writing a Wrapper for COM Components

By Alex Kravchenko

Introduction

Up until couple month ago, I was a convinced spectator to the whole .NET Revolution. I thought to myself that like any other new technology it would take some time until it becomes mature enough to use. But as I was learning more about .NET it became clear that this was something bigger then any of the previous Microsoft attempt's to revolutionize the whole industry.

By now, I am sure, that for many companies the typical architecture looks like this: presentation layer in VB or ASP, business layer in C++ / ATL / COM that talks to the database using ADO or OLEDB. Our company is no exception. So being a Microsoft software-based company you would have to adapt this technology eventually. Since we've decided to switch to .NET we took a gradual approach, meaning that we began to design and build all the new code in the .Net environment. Soon we had to face the main question: what do you do with all that "old" code. Specifically, what do you do with all the COM components written in C++? After all, we spent so much time in writing them, stabilizing, and tuning the performance.

Fortunately, Microsoft put a lot of time and effort in making sure that managed code can talk to non-managed code. You can still call your existing COM components from .NET program using RCW (Runtime Callable Wrapper). RCW will take care of marshalling the .NET calls into COM client calls. You can do this with very little development time. The performance hit should also be minimal in most cases. If your COM component is "heavy", i.e. if it does a lot of work inside, then the overhead is insignificant.

On the other hand, if your COM component contains some "chatty interfaces" where all it does just returns some values, the overhead can be significant compared to the component execution time. On the top of that, CLRs (Common Language Runtime) default behavior is to use Proxy / Stub combination for calling COM components, so even if your COM component is apartment-threaded you still pay the penalty of marshaling your calls. You can overwrite the CLRs default behavior with STAThreadAttribute, but not for all cases.

Moreover, if you create many .NET clients for your COM component it generates more problems because your managed code clients cannot take the full advantage of the .NET Framework features like: parametirized constructros, inheritance, or static methods.

Thus, if you decide not to use RCW there are basically two options: one is to fully migrate your code to .Net, and second option that works with C++ COM components is to write a managed code wrapper around it. I will give you an example of how easy it is to use the second option.

Writing a Wrapper for COM Components

Suppose that you have the following COM component written in C++ using ATL.

// SimpleATL.h : Declaration of the CSimpleATL

#ifndef __SIMPLEATL_H_
#define __SIMPLEATL_H_

#include "resource.h"       // main symbols
#include 

///////////////////////////////////////////////////////////
// CSimpleATL
class ATL_NO_VTABLE CSimpleATL :
  public CComObjectRootEx<CCOMSINGLETHREADMODEL>,
  public CComCoClass<CSIMPLEATL &CLSID_SimpleATL,>,
  public IDispatchImpl<ISIMPLEATL &LIBID_SIMPLECOMLib
                    &IID_ISimpleATL,,>
{
public:
  CSimpleATL()
  {
  }

DECLARE_REGISTRY_RESOURCEID(IDR_SIMPLEATL)

DECLARE_PROTECT_FINAL_CONSTRUCT()

BEGIN_COM_MAP(CSimpleATL)
  COM_INTERFACE_ENTRY(ISimpleATL)
  COM_INTERFACE_ENTRY(IDispatch)
END_COM_MAP()

// ISimpleATL
public:
  STDMETHOD(get_ThreadID)(/*[out, retval]*/ long *pVal);
  STDMETHOD(GetManagerName)(/*[out, retval]*/ BSTR* pbstrName);
  STDMETHOD(SetManagerName)(/*[in]*/ BSTR bstrName);
private:
  _bstr_t     _bstrName;
};

#endif //__SIMPLEATL_H_

In order to write a managed code wrapper around your class, here is what you have to do:

1. In Visual Studio .Net create a blank solution; lets say it called COM Wrapper.

2. Add a new Visual C++ project to the solution using Managed C++ Class Library Template. Let's call it Simple .Net

3. Copy both SimpleATL.h and SimpleATL.cpp from your old ATL project directory to the new Simple.Net project directory.

4. Add the files to your project by selecting Add Existing Item from your project contact menu. Both files should appear in Solution Explorer window under the Simple.Net project.

5. Now it is time to do some modifications to the SimpleATL.h and SimpleATL.cpp. Specifically, you would have to delete a bunch of stuff, like macros and all the inheritance relationship. You dont need that anymore in your header file. What you need instead is additional include files -- atlctl.h and atlbase.h. Here is what the header looks like after the editing:

// SimpleATL.h : Declaration of the CSimpleATL

#ifndef __SIMPLEATL_H_
#define __SIMPLEATL_H_

#include <atlbase.h>
#include <atlctl.h>
#include <comdef.h>
////////////////////////////////////////////////////////////
// CSimpleATL
class CSimpleATL
{
public:
  CSimpleATL(){}

// ISimpleATL
public:
  STDMETHOD(get_ThreadID)(/*[out, retval]*/ long *pVal);
  STDMETHOD(SetManagerName)(/*[in]*/ BSTR bstrName);
  STDMETHOD(GetManagerName)(/*[out, retval]*/ BSTR* pbstrName);

private:
  _bstr_t     _bstrName;
};

#endif //__SIMPLEATL_H_

As you can see it became a lot smaller than it used to be.
The only editing you have to do with the SimpleATL.cpp file is to delete the reference to SimpleCOM.h file, so the line: #include "SimpleCOM.h" should be gone.

6. Now it is time to create the actual wrapper class. Notice that Visual Studio .Net created the initial class definition with the key __gc, which means that this class considered a managed code. Add the #include statement for the SimpleATL.h file just above the using namespace System; statement. Add another namespace: using namespace System::Runtime::InteropServices; You need InteropServices for converting types from managed to unmanaged code and vice versa.

7. Add a private pointer to the CSimpleATL class. Class1 has to handle the lifetime of the object by instantiating CSimpleATL pointer in the constructor and deleting it inside the destructor.

8. Add a proxy function for every function that you would like to call from the CSimpleATL class. Here is how it turns out:

// SimpleNet.h

#pragma once

#include "SimpleATL.h"

using namespace System;
using namespace System::Runtime::InteropServices;

namespace SimpleNet
{
  public __gc class Class1
  {
  public:
    Class1() {_pSimpleATL = new CSimpleATL();}
    ~Class1() {delete _pSimpleATL;}

  public:
    void get_ThreadID (/*[out, retval]*/ Int32* pVal) {

      long res;
      HRESULT hRes = _pSimpleATL->get_ThreadID(&res);

      if(FAILED(hRes)) {
        Marshal::ThrowExceptionForHR(hRes);
      }
      else {
        IntPtr ptrInt((void*)&res);
        *pVal = Marshal::ReadInt32(ptrInt);
      }
    }
    void SetManagerName (/*[in]*/ String* bstrName) {

      IntPtr ptrBstr = Marshal::StringToBSTR(bstrName);

      HRESULT hRes =
         _pSimpleATL->SetManagerName((BSTR)ptrBstr.ToPointer());
      if(FAILED(hRes)) {
        Marshal::ThrowExceptionForHR(hRes);
      }
    }
    void GetManagerName(/*[out, retval]*/ String** pbstrName) {

      BSTR pbstrTemp;
      HRESULT hRes = _pSimpleATL->GetManagerName(&pbstrTemp);
      if(FAILED(hRes)) {
        Marshal::ThrowExceptionForHR(hRes);
      }
      else {
        (*pbstrName) = Marshal::PtrToStringBSTR(pbstrTemp);
        Marshal::FreeBSTR(pbstrTemp);
      }
    }

  private:
    CSimpleATL*   _pSimpleATL;
  };
}

All the parameters to Class1 functions are of managed types now. There is some conversion required from managed to non-managed types and vice versa for what is called non-blittable types. VB BSTR for example, is considered a non-blittable type, therefore it requires conversion. This is where the Marshal class becomes handy. Not only it can convert types but it also can throw a .NET type exception based on COM HRESULT return. Pretty cool.

You can now call this code from any .NET application. All you have to do is to add a reference to the Simple.Net.dll in your .NET project, declare and instantiate the object for Class1, and start calling functions.

You have to decide for yourself whether you need to use RCW and call your components from managed code, merge your code into .NET, or write a wrapper. Note however, that the last option is only available for code written in C++. New Visual C++ compiler is the only compiler that can compile managed and unmanaged code at the same time.

References

Microsoft Corporation
.NET Framework Developer's Guide
Blittable and Non-Blittable Types

Steve Busby and Edward Jezierksi
Microsoft Corporation
August 2001
Microsoft .NET/COM Migration and Interoperability
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnbda/html/bdadotnetarch001.asp

Stanley B. Lippman
MSDN Magazine
February 2002
Still in Love with C++
Modern Language Features Enhance the Visual C++ .NET Compiler
http://msdn.microsoft.com/msdnmag/issues/02/02/ModernC/ModernC.asp

Jeffrey Richter
Applied Microsoft .Net Framework Programming
Microsoft Press 2002

Downloads

Download demo project - 814 Kb

 

 

 

Copyright ?1998-2024 UCanCode.Net Software , all rights reserved.
Other product and company names herein may be the trademarks of their respective owners.

Please direct your questions or comments to webmaster@ucancode.net