Key points for calling Windows API in C #

xiaoxiao2021-03-06  64

In the .NET Framework SDK document, the indication of calling the Windows API is more zero, and a slightly comprehensive one is to tell Visual Basic .NET. This article brings together the point of the C # to the API, and I hope to give a little help for friends who have not used API in C #. In addition, if Visual Studio .NET is installed, there is a large number of examples of the API in the C: / Program Files / Microsoft Visual Studio .NET / FRAMEWORKSDK / SAMPLES / Technologies / Interop / PlatformInvoke / WinAPIS / CS directory.

First, call format

Using system.runtime.interopservices; // Reference this namespace, simplify the following code

...

// Use the DLLIMPORTATTRIBUTE characteristic to introduce the API function, pay attention to the empty method, that is, the method body is empty.

[DLLIMPORT ("User32.dll")]]]]]

Public Static Extern Returntype FunctionName (Type Arg1, Type Arg2, ...);

// When calling, there is no difference between calling other methods.

You can use the field to further explain the feature, separated by commas, such as:

[DLLIMPORT ("kernel32", entrypoint = "getversionex")]

The public field of the DLLIMPORTATTRIBUTE feature is as follows:

1. CallingConvention indicates the CallingConvention value used to deliver the method parameters to the non-hosting method.

Callingconvention.cdecl: The caller clensizes the stack. It allows you to call functions with VARARGS.

Callingconvention.stdcall: Clean up the stack by the memory. It is the default convention for calling the non-hosting function from the hosted code.

2, the name version of the CHARSET control call function and indicates how to block the String parameter to the method.

This field is set to one of the CharSet value. If the CHARSET field is set to Unicode, all string parameters are converted to Unicode characters before passing to the unmanaged implementation. This also results in adding letters "W" to the name of DLL EntryPoint. If this field is set to ANSI, the string will be converted to an ANSI string while adding letters "a" to the name of DLL Entrypoint. Most Win32 APIs use this agreed "W" or "a" agreement. If the Charset is set to Auto, this conversion is related to the platform (Unicode on Windows NT, ANSI on Windows 98). The default value of Charset is ANSI. The CHARSET field is also used to determine which version of the version will be imported from the specified DLL. Charset.ansi and charset.Unicode's name match rules are very different. For ANSI, if you set the entrypoint to "MyMethod" and it exist, return "MyMethod". If there is no "MyMethod" in the DLL, "MyMethoda" is existed, then "MyMethoda" is returned. For Unicode, it is just the opposite. Return "MyMethodw" if you exist in "MyMethod" and it exists. If "MyMethodw" does not exist in the DLL, there is "MyMethod", then return "MyMethod". If Auto is used, the matching rules are related to the platform (Unicode on Windows NT, which is ANSI on Windows 98). If Exactspelling is set to TRUE, only "MyMethod" is returned when "MyMethod" is present in the DLL. 3. EntryPoint indicates the name or serial number of the DLL entry point to be called.

If your method name does not want to be with the API function, 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 the name of the entry point in the unmanaged DLL should be modified to correspond to the CHARSET value specified in the Charset field. If true, when the DLLIMPORTATTRIBUTE.CHARSET field is set to the ANSI value of the CHARSET, the letter A is added to the method name. When the DLLIMPORTATTRIBUTE.CHARSET field is set to the Unicode value of the method, the letter W is added to the name of the method. The default value of this field is False.

5, preservesig indicates that the host signature should not be converted to return to HRESULT, and may have an unmanaged signature corresponding to the additional [OUT, RETVAL] parameter corresponding to the return value.

6, setLastError indicates that the Win32 API setLastError will call the win32 API SetLastError before returning from the property. TRUE Indicates the Compass to call SetLastError, which defaults to false. The runtime encapsulator will call the getLastError and cache the returned value to prevent it by other API calls. The user can retrieve the error code by calling getLastWin32error.

Second, the parameter type:

1, the numerical type is directly used. (DWORD -> INT, WORD -> INT16) 2, character string pointer type in API -> .NET String

3, the handle (dword) -> .NET in the API INTPTR

4, the structure in the API -> .NET structure or class. Note that in this case, you must first define a declarative structure or class with a structlayout feature.

The public language runtime uses the StructLayOutAttribute control class or structure data field in the physical layout in the managed memory, ie, the class or structure needs to be arranged in some way. If you want to pass the class to a non-hosting code that needs to be specified, the explicit control class layout is important. Its constructor initials a new instance of the StructLayOatttribute class with a layoutkind value. LayoutKind.sequential is used to enforce the member to sequentially in the order of its appearance.

Layoutkind.exPlicit is used to control the exact location of each data member. With Explicit, each member must use FieldOffsetAttribute to indicate the location of this field in the type. Such as:

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

Public Class MySystemTime, 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 wheh;

[Fieldoffset (10)] public ushort wminute;

[Fieldoffset (12)] public ushort wsecond;

[Fieldoffset (14)] public ushort wmilliseconds;

}

The following is an OSVersionInfo structure in the API, defining an example of a corresponding class or structure in .NET:

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

* API defines the original structure declaration

* OsversionInfoa Struct

* DWOSVERSIONFOSIZE DWORD?

* DWMAJORVERSION DWORD?

* DWMINORVERSION DWORD?

* DWBUILDNUMBER DWORD?

* DWPLATFORMID DWORD?

* SZCSDVERSION BYTE 128 DUP (?)

* OsversionInfoa Ends

*

* OsversionInfo EQU

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

//.Net declaration as class

[Structlayout (layoutkind.sequential)]

Public Class OsversionInfo

{

Public int ost osversioninfosize;

Public int majorversion;

Public int minorversion;

Public int buildnumber;

Public int platformi;

[Marshalas (UnmanagedType.Byvaltstr, SIZECONST = 128)]]]

Public String VersionString;

//or

//.NET declaration as a structure

[Structlayout (layoutkind.sequential)]

Public struct osversioninfo2

{

Public int ost osversioninfosize;

Public int majorversion;

Public int minorversion;

Public int buildnumber;

Public int platformi;

[Marshalas (UnmanagedType.Byvaltstr, SIZECONST = 128)]]]

Public String VersionString;

}

This example is used in the Mashalas property, which is used to describe the seal processing format of fields, methods, or parameters. Use it as a parameter prefix and specify the data type required for the target. For example, the following code sends two parameters as a string (LPSTR) of the Windows API function as the data type long pointer:

[Marshalas (UnmanagedType.lpstr)]

String existingfile;

[Marshalas (UnmanagedType.lpstr)]

String newfile;

Note that the structure is used as a parameter, generally in front to add a REF modifier, otherwise an error will occur: The reference is not specified for an object.

[DLLIMPORT ("kernel32", entrypoint = "getversionex")]

Public Static Extern Bool GetversionEx2 (Ref OsversionInfo2 OSVI);

Third, how to ensure that the platform call is successful?

If you do not quote managed objects after calling the platform INVOKE, the garbage collector may complete the hosting object. This will release resources and invalid the handle, resulting in failure of platform invoke calls. With the Handleref package handle, it can be guaranteed that the managed object is not trash recovery before the platform invoke call is completed.

For example, below:

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

Since FS is a managed object, it is possible to reclaim the garbage collection station when the platform call has not been completed. Once the handle of the file stream is packaged with the handleref, it will avoid being recycled by the garbage station:

[DLLIMPORT ("kernel32.dll")]]]]

Public Static Extern Bool Readfile

Handleref hndref,

StringBuilder Buffer,

Int Numberofbyteread,

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 EndSreadFile (HR, Buffer, 5, Out Read, 0);

转载请注明原文地址:https://www.9cbs.com/read-119023.html

New Post(0)