Conversion of COM component objects to. NET class objects

Source: Internet
Author: User
Tags definition command line constructor garbage collection object model uuid wrapper visual studio
Object | Transformation run Environment: Visual Studio.NET Beta2, VC7, C #
References: MSDN
Level: Entry level


First, the preface


COM component objects are completely different from. NET class objects, but to make a COM client call a. NET object like a COM component, the. NET program
Like to use. NET objects using COM components, MS uses the wrapper technology. This paper introduces two different wrapper techniques in detail, and gives
A simple code instance.


Ii. COM Wrapper Introduction


Traditional COM objects have the following differences from the. NET Framework Object Model:
(1) The customer of the COM object must manage the lifetime of the COM object themselves, while the lifetime of the. NET object is governed by the CLR (Common Language Runtime)
is automatically recycled by GC (garbage Collection) mechanism.

(2) The client of the COM object queries the COM object to see if it supports an interface and gets its interface pointer by calling QueryInterface, and the guest of the. NET Object
The user uses Reflection (system.reflection.*) to obtain a description of the object's function, including method attributes.

(3) The client of the COM object references the COM object through the pointer, and the location of the object in memory is unchanged, and the. NET object resides in memory by the. NET Box
Rack Execution Environment (execution environment) to manage the position of the object in memory is variable, for example, for optimal performance considerations, while
All references to objects are updated. This is also premised on the use of no pointers in the CLR.


To implement the invocation of traditional COM programs to. NET programs,. NET provides a wrapper class RCW (Runtime callable wrapper) and
CCW (COM callable Wrapper). Every time a. NET client to invoke a method of a COM object, an RCW object is created whenever a
A CCW object is created when a COM client invokes a method of a. NET object.

The concrete schematic diagram as shown in Figure 1:






Figure 1 COM Wrapper overview

Three. NET, calling COM components


1, RCW (Runtime callable Wrapper) Introduction
The schematic diagram is as shown in Figure 2:






Figure 2 Accessing COM objects through the runtime callable wrapper

The main features of the RCW:
(1) The RCW is actually a. NET class generated by runtime, which wraps the methods of COM components and implements calls to COM components internally.

(2) Lie (Marshal). NET Customer and COM objects, the object of the column set includes the parameter return value of the method, such as String in C # and
The conversion between BSTR in COM.

(3) The CLR creates an RCW for each COM object, regardless of the number of references on the object, which means that each COM object has and only one RCW object.

(4) The RCW contains the interface pointers for COM objects and manages the reference count of COM objects. The release of the RCW itself is managed through the GC mechanism.

2. Example Demo
(1) Use Vc7/atl to create one of the simplest COM objects. The component class is called Atlcomserver, and the implementation interface is called Iatlcomserver, and the library name
ATLServer. Add a property name and implement the Get/set function. The IDL looks like the following:

Import "Oaidl.idl";
Import "Ocidl.idl";

[
Object
UUID (77506E08-D9FB-4F45-85E0-376F5187AF21),
Dual
Nonextensible,
helpstring ("Iatlcomserver Interface"),
Pointer_default (Unique)
]

Interface iatlcomserver:idispatch{
[Propget, ID (1), helpstring ("Property Name")] HRESULT Name ([out, retval] bstr* pVal);
[PropPut, ID (1), helpstring ("Property Name")] HRESULT Name ([in] BSTR newval);
};

[
UUID (9136eee6-ecee-4237-90b6-c38275ef2d82),
Version (1.0),
helpstring ("ATLServer 1.0 Type Library")
]

Library Atlserverlib
{
Importlib ("Stdole2.tlb");

[
UUID (0e733e15-2349-4868-8f86-a2b7ff509493),
helpstring ("Atlcomserver Class")
]

CoClass Atlcomserver
{
[Default] interface Iatlcomserver;
};
};

(2) Create one of the simplest C # console programs. Execute menu Project/add Reference command, in the COM property page Select the
ATLServer 1.0 Type Library and add, the system prompts whether to add a wrapper, select ' Yes ', and then automatically in the C # program
The bin directory generates a file Interop.AtlServerLib_1_0.dll, which is the ATLServer RCW. Also use command line commands
TlbImp atlserver.tlb has the same effect.

(3) Add the code that invokes Altserver in the program, as follows:

Using System;
Using Atlserverlib; Reference libraries by namespace, defined in wrapper (that is, Interop.AtlServerLib_1_0.dll)

Namespace Csharpclient
{
Class Class1
{
static void Main (string[] args)
{
Atlcomserver Server = new Atlcomserver ();
Server. Name = "Chang Ming";
Console.WriteLine ("Hello, my Names is" + server.) Name);
}
}
}

As you can see from the above, Atlserverlib.atlcomserver represents the COM component atlcomserver. Through interfaces in traditional COM customers
Iatlcomserver to invoke, while in the. NET just treats it as an ordinary. NET class. Because it actually calls the class in the wrapper,
Rather than a real COM object.


Download sample code for the RCW (23KB)


Calling. NET objects in COM programs


1, CCW (COM callable Wrapper) Introduction
The schematic diagram is as shown in Figure 3:






Figure 3 Accessing. NET objects through COM callable Wrapper

The main functions of the CCW:
(1) The CCW is actually a COM component generated by runtime, which is registered in the registry, has CLSID and IID, implements the interface, and internally contains the
. NET object is called.

(2) Lie (Marshal). NET object to a COM customer.

(3) each. NET object has only one CCW and multiple COM clients invoke the same CCW.

(4) The COM client invokes the CCW as a pointer, so the CCW is allocated on the non-collected heap and is not managed by the runtime. and. NET objects are assigned
On the garbage-collected heap, managed by runtime, enjoying the benefits of the CLR.

(5) A CCW is actually a COM component, so it follows a reference-counting rule. When its reference count is 0 o'clock, it is freed from its administration. NET object's
Reference, and free up your own memory space. When the reference count on a. NET object is 0 o'clock, GC is recycled.

. NET controlled types (manages types) such as class, interface, struct, and enum can be seamlessly combined with COM types, but
Follow these rules:
(1) The controlled type must be a public type. Only types of public type are exported to the type library.

(2) Only public-type methods, properties, fields and events will be exported to the type library before being seen by COM clients.

(3) a managed type must have a public default constructor. This is because the COM component requires that a default constructor be required.

(4) strongly recommended. NET class to implement an interface explicitly. If one. NET class does not explicitly implement an interface, COM Interop automatically Lives
into an interface that contains this. NET class and all public members of its parent class. This automatically generated interface is called the "class interface".
However, Ms strongly recommends the use of explicit interface definitions, as explained below.

2, example demo one (does not show the definition interface)
(1) Create one of the simplest C # console works, which are shown in the following procedures:

Using System;
Using System.Runtime.InteropServices;

Namespace Csharpserver
{
The default is Classinterfacetype.autodispatch, which generates only the dispatch interface
Can only be used by COM clients using script, VB and other late binding methods
[ClassInterfaceAttribute (Classinterfacetype.autodual)]
public class Sharpobject
{
private string M_strname;

Public Sharpobject () {}

public string Name//property:name, Get/set
{
get {return m_strname; }
set {m_strname = value; }
}
}
}

(2) Set register for COM interop to True in the properties of the project. This will generate the CSharpServer.tlb file after compilation, and
Automatically register it. Command line command regasm has the same effect. The contents of the registry are as follows:

[Hkey_classes_root\clsid\{88994e22-e99f-320b-908c-96e32b7bfe56}]
@= "Csharpserver.sharpobject"
[\InProcServer32]
@= "C:\\winnt\\system32\\mscoree.dll"
"ThreadingModel" = "Both"
"Class" = "Csharpserver.sharpobject"
"Assembly" = "csharpserver, version=1.0.583.39183, culture=neutral, Publickeytoken=null"
"RuntimeVersion" = "v1.0.2914"
"CodeBase" = "File:///E:/cm/net/C%23/exer/CSharpServer/bin/Debug/CSharpServer.dll"
[\progid]
@= "Csharpserver.sharpobject"

The CSharpServer.tlb file contains the type library information for the component, including CLSID, IID, interface definitions, and so on. And the real implementation of the components, the. NET
The invocation of the object is done by the common language runtime library Mscoree.dll. It can be said that Mscoree.dll and csharpserver.tlb add up to be the CCW that runtime generates for Csharpserver this. NET class.

(3) write a simple VBScript program Test.vbs, as follows:

Dim obj
Set obj = CreateObject ("Csharpserver.sharpobject")
Obj. Name = "Chang Ming"
MsgBox "My Name is" & obj. Name

Double-click the file to run successfully.

(4) Create one of the simplest MFC dialog box projects, add the following code:


This should be done with raw_interfaces_only, because the Sharpobject defaults from OBJEC
If you do not add this option, you also generate wrapper functions for the common functions and properties of object.
The Object::gettype returns the type type and does not generate a wrapper interface for the class type, so there is an error at compile time
#import ". \csharpserver\bin\debug\csharpserver.tlb "Raw_interfaces_only no_namespace named_guids
...
{
CoInitialize (NULL);

Method One
Because raw_interfaces_only is used, no wrapper function is generated for the property name Getname,putname
_sharpobjectptr Psharpobject (__uuidof (sharpobject));
Psharpobject->put_name (_bstr_t ("Chang Ming"));
BSTR StrName;
Psharpobject->get_name (&strname);
AfxMessageBox ("My Name is" + _bstr_t (strName));


Method Two
/* _sharpobject *psharpobject = NULL;
HRESULT hr = CoCreateInstance (Clsid_sharpobject,
Null
Clsctx_inproc_server,
Iid__sharpobject,
(void**) &psharpobject);

if (SUCCEEDED (HR))
{
Psharpobject->put_name (_bstr_t ("Chang Ming"));
BSTR StrName;
Psharpobject->get_name (&strname);
AfxMessageBox ("My Name is" + _bstr_t (strName));
Psharpobject->release ();
}
Else
{
AfxMessageBox ("error");
}
*/

CoUninitialize ();
}

Automatically generated class interface, the interface name is ' _ ' + class name, that is, _sharpobject. In addition, the use of the method with the calling general COM pair
Like the exact same thing.

(5) The disadvantage of using class interface is that. NET class changes can affect COM customers. Specifically, for the use of script, VB and other late binding
The language of the way, such as the Test.vbs,net class, has no effect on it. And for early binding customers, because DISPID is in the. NET class
is related to the location, so. NET class changes are likely to change the members ' DISPID, which can affect the client program, and the client program needs to be recompiled.
For C + + client programs that are invoked directly through pointers, each time. NET recompile will cause it to recompile because the IID of class interface
It's randomly generated every time! So MS strongly requests not to use this way, class interface is not a real interface, it always
Constant change, which violates the spirit of the interface, violates the spirit of COM.

3, example demo two (display definition interface)
(1) Create one of the simplest C # console works, which are shown in the following procedures:

Using System;
Using System.Runtime.InteropServices;

Namespace CSharpServer2
{
If you do not specify a GUID, the IID is randomly generated each time
[Guid ("539448DE-9F3B-4781-A1F6-F3C852091FC9")]
public interface ISharpObject2
{
String Name//property:name, Get/set
{
Get
Set
}

void Test ();
}

If you do not specify a GUID, the CLSID is randomly generated each time
[Guid ("F5a31aab-faa9-47cc-9a73-e35606114ce8")]
public class Sharpobject2:isharpobject2
{
private string M_strname;

Public SharpObject2 () {}

public string Name//property:name, Get/set
{
get {return m_strname; }
set {m_strname = value; }
}

public void Test () {}
}
}

(2) Set register for COM interop to True in the properties of the project. This will generate the Csharpserver2.tlb file after compilation and
and automatically registers it. The contents of the registry are as follows:

[Hkey_classes_root\clsid\{f5a31aab-faa9-47cc-9a73-e35606114ce8}]
@= "Csharpserver2.sharpobject2"
[\InProcServer32]
@= "C:\\winnt\\system32\\mscoree.dll"
"ThreadingModel" = "Both"
"Class" = "Csharpserver2.sharpobject2"
"Assembly" = "CSharpServer2, version=1.0.583.38696, culture=neutral, Publickeytoken=null"
"RuntimeVersion" = "v1.0.2914"
"CodeBase" = "File:///E:/cm/net/C%23/exer/CSharpServer2/bin/Debug/CSharpServer2.dll"
[\progid]
@= "Csharpserver2.sharpobject2"

(3) Create one of the simplest MFC dialog box projects, add the following code:

This is not raw_interfaces_only because SharpObject2 only inherits from the interface ISharpObject2
ISharpObject2 does not have a parent class, so there is no Sharpobject-like compilation error
#import ". \csharpserver2\bin\debug\csharpserver2.tlb "No_namespace Named_guids
...
{
CoInitialize (NULL);

Method One
Isharpobject2ptr PSharpObject2 (__uuidof (SHARPOBJECT2));
Psharpobject2->putname ("Chang Ming");
AfxMessageBox ("My Name is" + psharpobject2->getname ());


Method Two
/* ISharpObject2 *psharpobject2 = NULL;
HRESULT hr = CoCreateInstance (Clsid_sharpobject2,
Null
Clsctx_inproc_server,
Iid_isharpobject2,
(void**) &psharpobject2);

if (SUCCEEDED (HR))
{
Psharpobject2->putname ("Chang Ming");
AfxMessageBox ("My Name is" + psharpobject2->getname ());
Psharpobject2->release ();
}
Else
{
AfxMessageBox ("error");
}
*/

CoUninitialize ();
}

The COM client will not be affected unless the interface ISharpObject2 remains unchanged.


Download the sample Code for the CCW (50KB)

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.