C # platform call

Source: Internet
Author: User
Tags readfile

C: \ ProgramFiles \ microsoftvisual studio. Net \ frameworksdk \ samples \ technologies \ InterOP \ platforminvoke \ winapis \ CS directory contains a large number of examples of calling APIs.

I. Call format

Using system. runtime. interopservices; // reference this namespace to simplifyCode

// Use the dllimportattribute feature to introduce API functions. Note that empty methods are declared, that is, the method body is empty.

[Dllimport ("user32.dll")]

Public static extern returntype functionname (type arg1, type arg2 ,...);

// There is no difference between calling and calling other methods

 

You can use fields to further describe features and separate them with commas, for example:

[Dllimport ("Kernel32", entrypoint = "getversionex")]

The common fields of the dllimportattribute feature are as follows:

1. callingconvention indicates the callingconvention value used to pass method parameters to an unmanaged implementation.

Callingconvention. cdecl: The caller clears the stack. It enables you to call functions with varargs.

Callingconvention. stdcall: the called party clears the stack. It is the default convention for calling unmanaged functions from managed code.

2. charset controls the name version of the called function and indicates how to mail the string parameter to the method.

This field is set to one of the charset values. If the charset field is set to Unicode, all string parameters are converted to unicode characters before being passed to an unmanaged implementation. This also causes the name of the DLL entrypoint to be appended with the letter "W ". If this field is set to ANSI, the string is converted to an ANSI string and the name of the DLL entrypoint is appended with the letter "". Most Win32 APIs use this APPEND "W" or "A" convention. If charset is set to Auto, the conversion is platform-related (Unicode on Windows NT and ANSI on Windows 98 ). The default value of charset is ANSI. The charset field is also used to determine which function version will be imported from the specified DLL. The name matching rules for charset. ANSI and charset. Unicode are very different. For ANSI, if entrypoint is set to "mymethod" and it exists, "mymethod" is returned ". If the DLL does not contain "mymethod", but "mymethoda" exists, "mymethoda" is returned ". The opposite is true for Unicode. If you set entrypoint to "mymethod" and it exists, "mymethodw" is returned ". If "mymethodw" does not exist in the DLL but "mymethod" exists, "mymethod" is returned ". If auto is used, the matching rule is related to the platform (Unicode on Windows NT and ANSI on Windows 98 ). If exactspelling is set to true, "mymethod" is returned only when "mymethod" exists in the DLL ".

 

 

3. entrypoint indicates the name or serial number of the DLL entry point to be called.

If you do not want the method name to be the same as the API function name, you must specify this parameter. For example:

[Dllimport ("user32.dll", charset = "charset. Auto", entrypoint = "MessageBox")]

Public static extern int msgbox (intptr hwnd, string txt, string caption, int type );

 

 

4. exactspelling indicates whether to modify the name of the entry point in the unmanaged DLL to correspond to the charset value specified in the charset field. If this parameter is set to true, the parameter is set to dllimportattribute. when the charset field is set to the ANSI value of charset, append the letter A to the method name, when dllimportattribute. when the charset field is set to the Unicode value of charset, W is appended to the method name. The default value of this field is false.

5. preservesig indicates that the signature of the managed method should not be converted to an unmanaged signature that returns hresult and may have an additional [out, retval] parameter corresponding to the returned value.

6. setlasterror indicates that the called party will call the Win32 API setlasterror before returning the property method. True indicates that the caller calls setlasterror. The default value is false. Getlasterror will be called by the mail collector during runtime and the returned value will be cached to prevent it from being overwritten by other API calls. You can call getlastwin32error to retrieve the error code.

 

Ii. Parameter type:

1. You can use the corresponding numeric type directly. (DWORD-> int, word-> int16)

2. String pointer type in API-> string in. net

3. Handle (DWORD) in API> intptr in. net

4. Structure in API>. net structure or class. Note that in this case, the structlayout feature should be used to limit the declared structure or Class

The Common Language Runtime library uses structlayoutattribute to control the physical layout of data fields of a class or structure in the managed memory, that is, the class or structure needs to be arranged in a certain way. If you want to pass the class to the unmanaged code that requires the specified layout, it is important to explicitly control the class layout. Its constructor uses the layoutkind value to initialize a new instance of the structlayoutattribute class. Layoutkind. Sequential is used to force members to be laid out in the order they appear.

Layoutkind. Explicit is used to control the exact location of each data member. With explicit, each member must use fieldoffsetattribute to indicate the position of this field in the type. For example:

[Structlayout (layoutkind. explicit, size = 16, charset = charset. ANSI)]

Public class mysystemtime

{

[Fieldoffset (0)] public ushort wyear;

[Fieldoffset (2)] public ushort wmonth;

[Fieldoffset (4)] public ushort wdayofweek;

[Fieldoffset (6)] public ushort wday;

[Fieldoffset (8)] public ushort whour;

[Fieldoffset (10)] public ushort wminute;

[Fieldoffset (12)] public ushort wsecond;

[Fieldoffset (14)] public ushort wmilliseconds;

}

The following is an example of defining the corresponding class or structure in. net for the osversioninfo structure in the API:

/*************************************** *******

* Define the original structure declaration in the API

* Osversioninfoa struct

* Dwosversioninfosize DWORD?

* Dwmajorversion DWORD?

* Dwminorversion DWORD?

* Dwbuildnumber DWORD?

* Dwplatformid DWORD?

* Szcsdversion byte 128 DUP (?)

* Osversioninfoa ends

*

* Osversioninfo equ <osversioninfoa>

**************************************** *****/

 

 

//. NET is declared as a class

[Structlayout (layoutkind. Sequential)]

Public class osversioninfo

{

Public int osversioninfosize;

Public int majorversion;

Public int minorversion;

Public int buildnumber;

Public int platformid;

 

 

[Financialas (unmanagedtype. byvaltstr, sizeconst = 128)]

Public String versionstring;

}

// Or

// The Declaration in. Net is a structure

[Structlayout (layoutkind. Sequential)]

Public struct osversioninfo2

{

Public int osversioninfosize;

Public int majorversion;

Public int minorversion;

Public int buildnumber;

Public int platformid;

 

 

[Financialas (unmanagedtype. byvaltstr, sizeconst = 128)]

Public String versionstring;

}

 

In this example, the mashalas feature is used to describe the sending format of fields, methods, or parameters. Use it as the parameter prefix and specify the data type required by the target. For example, the following code uses two parameters as the long pointer of the Data Type to block the string (lpstr) sent to the Windows API function ):

[Financialas (unmanagedtype. lpstr)]

String existingfile;

[Financialas (unmanagedtype. lpstr)]

String newfile;

 

Note that when the structure is used as a parameter, the ref modifier must be added before. Otherwise, an error occurs: the object reference does not include an instance of the specified object.

[Dllimport ("Kernel32", entrypoint = "getversionex")]

Public static extern bool getversionex2 (ref osversioninfo2 osvi );

 

3. How can we ensure that the platform with managed objects is successfully called?

If the hosted object is not referenced anywhere after the platform invoke is called, The Garbage Collector may complete the hosted object. This will release the resource and make the handle invalid, resulting in platform invoke call failure. Using handleref to wrap the handle ensures that the hosted object is not garbage collected before the platform's invoke call is complete.

For example:

Filestream FS = new filestream ("a.txt", filemode. Open );

Stringbuilder buffer = new stringbuilder (5 );

Int READ = 0;

Readfile (FS. Handle, buffer, 5, out read, 0); // call the readfile function in the win api

Because FS is a hosted object, it may be reclaimed by the spam Recycle Bin before the platform call is complete. After packaging the file stream handle with handleref, you can avoid being recycled by the garbage station:

[Dllimport ("kernel32.dll")]

Public static extern bool readfile (

Handleref hndref,

Stringbuilder buffer,

Int numberofbytestoread,

Out int numberofbytesread,

Ref overlapped flag );

......

......

Filestream FS = new filestream ("handleref.txt", filemode. Open );

Handleref hR = new handleref (FS, FS. Handle );

Stringbuilder buffer = new stringbuilder (5 );

Int READ = 0;

// Platform invoke will hold reference to handleref until call ends

Readfile (HR, buffer, 5, out read, 0 );

 

 

 

 

I have noticed a trend in my recent programming, which leads to the topic of this month. Recently, I am working on Microsoft? . NET Framework applicationsProgram? InterOP. I am not saying that my application is full of custom InterOP code, but sometimes I will. net Framework class library encountered some secondary but complex, inadequate content, by calling the windows? API, which can quickly reduce such troubles.

 

Therefore, I think that the. NET Framework 1.0 or 1.1 class libraries have any functional limitations that Windows does not have. After all, 32-bit windows (whatever version) is a mature operating system that has served customers for more than 10 years. In contrast,. NET Framework is a new thing.

 

As more and more developers move production applications to managed code, it is natural for developers to study the underlying operating system more frequently to figure out some key functions-at least for the moment.

 

Fortunately, the InterOP function (called platform call (P/invoke) of the Common Language Runtime Library (CLR) is very complete. In this column, I will focus on how to use P/invoke to call Windows API functions. When it refers to the com InterOP function of CLR, P/invoke is used as a noun. when it refers to the use of this function, it is used as a verb. I am not going to introduce com InterOP directly, because it is more accessible than P/invoke, but more complicated, which is a bit self-contradictory, this makes the discussion on com InterOP as a topic less concise.

 

Enter P/invoke

 

Start with a simple P/invoke example. Let's take a look at how to call the Win32 messagebeep function. Its unmanaged declaration is shown in the following code:

 

Bool messagebeep (

Uint utype // beep type

);

 

To call messagebeep, you need to add the following code to a class or structure definition in C:

 

[Dllimport ("user32.dll")]

Static extern Boolean messagebeep (uint32 beeptype );

 

Surprisingly, you only need this code to make the hosted Code call the unmanaged messagebeep API. It is not a method call, but an external method definition. (In addition, it is close to a direct port from C and C #, so it is helpful to introduce some concepts starting from it .) The possible calls from managed code are as follows:

 

Messagebeep (0 );

 

Note that the messagebeep method is declared as static. This is required by the P/invoke method, because there is no consistent instance concept in this Windows API. Next, note that this method is marked as extern. This prompts the compiler that this method is implemented through a function exported from the DLL, so the method body is not required.

 

Speaking of the lack of a method body, have you noticed that the messagebeep declaration does not contain a method body? And mostAlgorithmDifferent hosting methods consist of intermediate language (IL) commands. The P/invoke method is only metadata, real-time (JIT) the compiler connects the hosted code to a non-hosted DLL function at runtime. An important information required to execute a connection to the unmanaged world is to export the name of the DLL of the unmanaged method. This information is provided by the dllimport custom attribute before the messagebeep method declaration. In this example, we can see that messagebeep APIs are exported by user32.dll in windows.

 

So far, there have been two topics not introduced about calling messagebeep. Please review that the called code is very similar to the following code snippet:

 

[Dllimport ("user32.dll")]

Static extern Boolean messagebeep (uint32 beeptype );

 

The last two topics are related to data sending aling and actual method calls from managed code to unmanaged functions. The call of the unmanaged messagebeep function can be executed by any managed code that finds the extern messagebeep declaration in the scope. This call is similar to any other call to a static method. It shares the same with any other managed method call in that it brings the need for data sending and processing.

 

One of the C # rules is that its calling syntax can only access CLR data types, such as system. uint32 and system. boolean. C # clearly does not recognize the C-based data types used in Windows APIs (such as uint and bool). These types are only the definition of the C language type. Therefore, when the Windows API function messagebeep is compiled as follows:

 

Bool messagebeep (uint utype)

 

External methods must be defined using the CLR type, as shown in the previous code snippet. The CLR type that needs to be different from the basic API function type but is compatible with it is one of the hard-to-use aspects of P/invoke. Therefore, I will use the complete section below this column to introduce data sending and processing.

 

Style

 

In C #, it is very easy to call the Windows api p/invoke. But if the class library refuses to make your application beep, you should try to call windows to make it do the work, right?

 

Yes. But it is related to the method selected and has a great relationship! Generally, if a Class Library provides some way to implement your intent, it is best to use an API instead of directly calling the unmanaged code, because the CLR type and Win32 have very different styles. I can sum up my suggestions on this issue into one sentence. When you perform P/invoke, do not make the application logic directly belong to any external method or component. If you follow this small rule, you will often save a lot of trouble in the long run.

 

The code in Figure 1 shows the minimum additional code for the messagebeep external method I have discussed. No significant changes were made in Figure 1, but some general improvements were made to non-packaged external methods, which made the work easier. From the top, you will notice a complete type named sound, which is dedicated to messagebeep. If you need to use the Windows API function playsound to add support for playback waveforms, You can reuse the sound type. However, I am not angry with making public the type of a single public static method. After all, this is only the application code. It should also be noted that sound is sealed and an empty private constructor is defined. These are just some details, so that users do not mistakenly derive classes from sound or create its instances.

 

The next feature of the Code in Figure 1 is that the actual external method where P/invoke appears is the private method of sound. This method is only indirectly disclosed by the Public messagebeep method, which accepts parameters of the beeptypes type. This indirect extra layer is a key detail and provides the following benefits. First, you should introduce a future beep hosting method in the class library. You can repeatedly use the public messagebeep method to use managed APIs without changing the remaining code in the application.

 

Related Article

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.