Prerequisites
Author: caeser2
The code in this article is written using the iso c ++ and. Net V1.1 frameworks (vs 2003), but its principle is suitable for all languages that support. Net frameworks.
I. Preface
Because traditional COM technology uses static unmanaged programming while. net uses dynamic hosted programming, this topic is essentially a special case in the interoperability between hosted and unmanaged code. Currently,. Net V2.0 provides the following three types of interoperability:
Module-level P/invoke Method
This method is suitable for calling unmanaged functions implemented in a dynamic link library (DLL) (such as a Win32 api dll. It will be discussed in the next section;
Component-level com InterOP Method
This is the highlight of this article. It consists of two parts:
1. Method of exporting the Type Library: the main character of this article;
2. encapsulation method: This method is unique to cli c ++ and is automatically generated by the framework (the header file code is not managed on the COM Client ), the principle is the same as that of the third type of interoperability;
Code-Level C ++ InterOP Method
This method is unique to cli c ++, that is, it can only be used in VS 2005 and later versions. The implementation is very simple. The packaging of external DLL is all generated by the wizard, and no code line is required, so this article will not describe it. (Another reason is that I have no conditions for using VS 2005 ^_^ !)
Ii. type conversion and sending
Since it is the interoperability between two platforms and two worlds, the information transmission between them must be converted to a type that can be understood by the peer. This conversion is called "Marshal" or "sending ". Sending and distributing data is an extremely complex process. Interested readers can search for the document "indexing aling details" describing its principles in msdn ". It is the principle of sending com InterOP messages.
Fortunately, the InterOP assembly Mechanism on the. NET platform can help us with some simple data encapsulation work and hide complicated Marshal details. This makes it very convenient for us to transmit some simple data when calling the COM server in the. NET client. However, if the transmitted data is customized, manual marshal is required. The principle of this mechanism is described in "com packaging" in msdn ".
This is an excerpt from msdn 2003. net V1.1 will convert our data from one platform to another. Any type without explicit identifiers in the table will be converted to int32 system type.
Well... it seems quite a lot, but it's too early to be happy. In actual use, only simple types such as int can ensure various flexible transmission methods without any problems... @_*. Note that the variant type on the com side (this is also the recommended type when writing com) will be converted to a specific type and encapsulated according to its VT value, therefore, when setting VT on the com side, you must set it up correctly! In addition, we recommend that you do not use or encapsulate the specific types not provided in the table as custom types.
For more information about data type conversion, see "com data type" in msdn. The description of custom types is "Custom Standard packaging ". If you want. the. NET Component implements the callback interface or connection point as the COM component, and requires communication between the hosted interface and the non-hosted implementation of the interface. In this case, you need to customize the marshal encapsulation for processing, the document implementing this function is "Custom sending and receiving ".
Iii. Error Handling
The. NET client does not have the hresult type, and the. NET Server does not have a return value when defining method functions. How can this problem be solved? In fact, this work was also done by the. NET platform's mail sending mechanism.
1. COM Server>. Net Client
The client directly uses try ()... the hresult information that has been translated can be obtained by using the catch () method. The error information defined by the system is in. net class libraries generally have well-defined off-the-shelf classes, which are easy to process.
2... NET Server-> COM Client
The client can get the error message in the way of hresult hR =...; as usual.
When the server does not support the ierrorinfo interface, the error information will be translated in two directions as shown in the following table.
When the server implements the ierrorinfo interface with rich error information, the error information will be translated in two directions according to the following table. Because the table contains too many contents, only one part of the error information is listed here.
This section describes "hresult" and exceptions in the msdn described in the above table. For details about. Net Exception Handling, refer to the msdn document "handling and triggering exceptions ".
Iv. Summary
The first article mainly introduces some concepts and provides you with a way of thinking about the problem. The specific details are not discussed in detail, but are given in the position in msdn. If you need them, you can refer to them, we recommend that you use at least the Chinese version of msdn2003 or later (the translation is good ^_^ ). This knowledge is mostly hidden by the compiler in practice, so it is not very useful. Just take a look. There is no sample code in this article, so we will start to practice in the next article ^_^
The P/invoke method of the COM Server
Download source code
1. COM server --> COM Client
This is a traditional com knowledge. If you are not clear about this part of the content, you can go to Miss Yang's personal column. There is a great tutorial there and I will not talk nonsense here. ^_^
If you are familiar with this part, you will find that almost all the subsequent content is in form imitating the traditional com call.
2. COM server -->. Net Client
Well, this is the focus. Is the principle of this part. Each COM object willYes and onlyA Runtime Library can call the packaging (RCW) proxy, regardless of how many references it has.
If no public interface (or none at all) is available
In this case, P/invoke is used. We must know at least two of the following:
- DLL file name
- Name or serial number of the function to be called;
Perform the following two steps:
- Identifies it in. net programs. It must be static and external
- C ++ has to do this: extern "C"; call it like calling a common function;
Pay attention to the following parameters:
- If it is a structure or class, note that the internal Member must be defined as public to make public.
- You can apply some attributes to achieve "personalization". For details, see the "personalization" attribute code below;
If you want to call many functions or want to make the function a member of The Managed class, you can use the packaging class:
- Directly declare the DLL function in the existing class;
- Functions are isolated from each other and easy to find. You can create a class for each DLL function;
- To form a logical grouping and reduce system overhead, you can write a set of related DLL functions into a class;
Let's take a look at the sample code. First, let's take a simple call step demonstration to call the MessageBox () provided by WIN32API ():
// 1. write down the namespace using namespace system: runtime: interopservices; typedef intptr hwnd; // It is an unmanaged void *. The Win32 platform contains four bytes, so you can also write it as int // 2. use the dllimport attribute (dllimportattribute class) "# import" to import the DLL file and identify the calling function [dllimport ("USER32", entrypoint = "messageboxa")] // 3. create a prototype. Please note that the data type changes. extern "C" int msgbox (hwnd, string * ptext, string * pcaption, unsigned int utype); // 4. call msgbox (this-> handle, "hello", "Hi", 0); // 5. the packaging class is easy to write in this way. The sample code provided for downloading will not be written into javas_^ public _ GC class sdkmsgbox: {public: [dllimport ("USER32", entrypoint = "messageboxa")]. extern "C" int msgbox (hwnd, string * ptext, string * pcaption, unsigned int utype );.......}
If the passed value is an array, structure, or class, it is not that simple. You need to customize the encapsulation (that is, Marshal for custom type conversion)
// For arrays, you only need to define the mail sending method. The example code for downloading is extern "C" Void sendarray ([exploralas (unmanagedtype: lparray)]. array <int> list, int length);/* for the structure, for example, the bool ptinrect (const rect * LPRC, point pt) function in user32.dll ); rect and point are two structures. The following point declaration is _ value rather than _ GC, because.. Net V1.1. net V1.1 bug), cannot automatically copy the content pointed to by the hosting pointer to the unmanaged heap (not the _ box packaging function ), therefore, the managed pointer is not used in actual use as the parameter (string *) in the preceding example. * // Structlayout is the structlayoutattribute class. It is used to define the memory layout of an object. // sequential indicates that the object's members perform the memory layout in the defined order. [structlayout (layoutkind :: sequential)] public _ value struct point {public: int X; int y ;}; // explicit indicates that the object's members follow the fieldoffset (fieldoffsetattribute class) memory layout at the specified location [structlayout (layoutkind: explicit)] public _ GC struct rect {public: [fieldoffset (0)] int left; // fieldoffset () the number in is in the memory layout. [fieldoffset (4)] int top; // it must not be written. Here it is an int, so every time we add 4 + [fieldoffset (8)] int right; [fieldoffset (12)] int bottom;}; [dllimport ("user32.dll")] extern "C" bool ptinrect (const rect & R, point P ); // If 1st parameters are defined as hosting, the reference must be used for level 1 Indirect addressing./* if the parameters of the COM server contain char * text, it is best to define the attribute [structlayout (layoutkind:: sequential, charset = charset: ANSI)]... (..., string * text); other types of push */}
There is nothing to say about the class transfer method. Naturally, it is the same as the structure transfer method. However, you must note that at least one level of indirect addressing, that is, pointers (the same as the rect in the above example), is usually required for class delivery ).
/* For example, the void getsystemtime (systemtime * systemtime) function in kernel32.dll treats systemtime as a class, and the structure and class are originally "same root". __^ */[structlayout (layoutkind :: sequential)] public _ GC class mysystemtime {public: Unsigned short wyear; unsigned short wmonth; unsigned short hour; unsigned short wday; unsigned short whour; unsigned short hour; unsigned short wmilliseconds;}; [dllimport ("kernel32.dll")] extern "C" Void getsystemtime (mysystemtime & St );
If you want to use the callback function, it is more troublesome. You need to use the Delegate/event mechanism to receive messages.
Using namespace system: runtime: interopservices; // defines a delegate _ delegate bool callback (INT hwnd, int lparam); [dllimport ("USER32")] extern "C" int enumwindows (callback * X, int y); // The callback parameter changes from a function pointer to a delegate. In fact, they are similar. // callback functions, handle bool report (INT hwnd, int lparam) {system: Diagnostics: Trace: writeline (hwnd. tostring (), "window handle is:"); Return true ;}; // use // instantiate a delegate mycallbackcallback * mycallback = new callback (this, & enumreport :: report); enumwindows (mycallback, 0); // transmits the function pointer (instantiated delegate) to the COM server, and the COM server automatically calls it to return the result.
If you want to clear the title of this section by using the callback interface or connection point, there is no interface at all. How can this problem be solved? Haha.
Well, P/invoke is almost capable. Below I will list some useful tables. Common Win32 API DLL
Available attributes, usually using dllimportattribute ([dllimport (...)]) to set the value
Most of the content in this section can be found in "using Unmanaged DLL Functions" in msdn2003 or later versions. For more information about personalized sending and writing (only the COM server -->. Net client), see "use platform call to mail data". Platform call is P/invoke.