Bridge between COM and. Net (2) The P/invoke method of the COM Server Author: caeser2 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 the namespace to be used first Using namespace system: runtime: interopservices; Typedef intptr hwnd; // It is an unmanaged void *. On the Win32 platform, it is 4 bytes, so it can also be written as an int.
// 2. Use the dllimport attribute (that is, the dllimportattribute Attribute Class) "# import" to import the DLL file and identify the call 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. It is very simple to write the packaging class. The sample code for downloading is not written. ^_^ 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, and the sample code for downloading will not be written. Extern "C" Void sendarray ( [Financialas (unmanagedtype: lparray)] array <int> list, Int Length ); /* For the structure, for example, this function in user32.dll Bool ptinrect (const rect * LPRC, point pt ); Rect and point are two structures
Note: The following point is declared as _ value rather than _ GC, because the. NET V1.1 mail sending process will have problems (it may be the author's mistake, It may also be a. Net V1.1 bug). The content pointed to by the hosting pointer cannot be automatically copied to the unmanaged heap (not the _ Box package ). Function. */ // Structlayout is the structlayoutattribute class used to define the memory layout of objects. // Sequential indicates the memory layout of the object members in the defined order. [Structlayout (layoutkind: sequential)] Public _ value struct point { Public: Int X; Int y; }; // Explicit indicates that the object's members are laid out in memory according to the position specified by fieldoffset (that is, fieldoffsetattribute attribute class ). [Structlayout (layoutkind: explicit)] Public _ GC struct rect { Public: [Fieldoffset (0)] int left; // The number in fieldoffset () indicates the memory layout, [Fieldoffset (4)] int top; // it must not be written. Here it is all int, so every time it is + 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, reference is required for level 1 Indirect addressing /* If the parameters of the COM server contain char * text, it is best to define the attributes as follows: [Structlayout (layoutkind: sequential, charset = charset: ANSI)] ... (..., String * text ); Other types. */ }
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, this function in kernel32.dll Void getsystemtime (systemtime * systemtime ); Think of systemtime as a class. The structure and class are "same root ". */ [Structlayout (layoutkind: sequential)] Public _ GC class mysystemtime { Public: Unsigned short wyear; Unsigned short wmonth; Unsigned short wdayofweek; Unsigned short wday; Unsigned short whour; Unsigned short wminute; Unsigned short wsecond; 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; // Define 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 function, Explicit Window handle in the debugging window Bool report (INT hwnd, int lparam ){ System: Diagnostics: Trace: writeline (hwnd. tostring (), "window handle is :"); Return true; };
// Use // Instantiate a delegate mycallback Callback * 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. |