C # and API

Source: Internet
Author: User
Tags readfile

In the. Net Framework SDK documentation, instructions for invoking the Windows API are fragmented, and a little more comprehensive is the visual Basic. NETof the story. This article brings together the main points of calling APIs in C # to help a friend who has not used the API in C #. Also, if you have Visual Studio. NET installed, in C:\Program Files\Microsoft Visual Studio. Net\frameworksdk\samples\technologies\interop There are a number of examples of API invocation in the \platforminvoke\winapis\cs directory.

First, call format

Using System.Runtime.InteropServices; Reference this namespace to simplify the following code
...
Using the DllImportAttribute attribute to introduce API functions, notice that the empty method is declared, that is, the method body is empty.
[DllImport ("User32.dll")]
public static extern returntype functionname (type arg1,type arg2,...);
Call is not different from calling other methods

You can use fields to further illustrate attributes, separated by commas, such as:

[DllImport ("kernel32", entrypoint= "GetVersionEx")]

The public fields of the DllImportAttribute feature are as follows:

1. CallingConvention indicates the CallingConvention value used when passing method parameters to an unmanaged implementation.

CALLINGCONVENTION.CDECL: The caller cleans up the stack. It enables you to invoke a function that has varargs.
Callingconvention.stdcall: The callee cleans up the stack. It is frommanagedCode calls the default convention for unmanaged functions.

2. CharSet controls the name version of the calling function and indicates how to marshal 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 arguments are passed to the non-managedare converted to Unicode characters before they are implemented. This also causes the letter "W" to be appended to the name of the DLL entrypoint. If this field is set to ANSI, the string is converted to an ANSI string, and the letter "A" is appended to the name of the DLL entrypoint. Most Win32 APIs Use this convention to append "W" or "a". If CharSet is set to Auto, this conversion is platform-related (Unicode on Windows NT, Ansi on Windows 98). The default value for CharSet is Ansi. The CharSet field is also used to determine which version of the function 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, then "MyMethod" is returned. If there is no "MyMethod" in the DLL, but "Mymethoda" is present, then "Mymethoda" is returned. The opposite is true for Unicode. If EntryPoint is set to "MyMethod" and it exists, then "Mymethodw" is returned. If "Mymethodw" is not present in the DLL, but "MyMethod" is present, then "MyMethod" is returned. If you are using Auto, the matching rules are platform-related (Unicode on Windows NT, Ansi on Windows 98). If ExactSpelling is set to True, "MyMethod" is returned only if "MyMethod" is present in the DLL.

3. entrypoint indicates the name or ordinal of the DLL entry point to invoke.

If your method name does not want to have the same name as the API function, be sure to 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 CharSet Ansi value, the letter A is appended to the method name, and when the DllImportAttribute.CharSet field is set to CharSet U When the value is Nicode, the letter W is appended to the name of the method. The default value for this field is false.

5. PreserveSig InstructionsmanagedThe method signature should not be converted to a return HRESULT, and there may be an unmanaged signature that corresponds to the return value of the attached [out, retval] parameter.

6. SetLastError indicates that the callee will call the Win32 API SetLastError before returning from the attributed method. True indicates that the caller will call SetLastError, which defaults to false. The runtime marshaler calls GetLastError and caches the returned value in case it is overridden by another API call. The user can retrieve the error code by calling GetLastWin32Error.

Second, the parameter type:

1, numerical type directly with the corresponding can be. (DWORD, int, WORD, Int16)

2. String in. NET in the API pointer type

3. IntPtr. NET in the handle (DWord) in the API

4. Structure in API. NETMedium structure or class. Note that in this case, you must first qualify the declaration structure or class with the StructLayout attribute

The common language runtime leverages StructLayoutAttribute to control the data fields of a class or structmanagedPhysical layout in memory, where classes or structs need to be arranged in a certain way. If you are passing a class to unmanaged code that needs to specify a layout, it is important to explicitly control the class layout. A new instance of the StructLayoutAttribute class is initialized with the LayoutKind value in its constructor. LayoutKind.Sequential is used to force the layout of members sequentially in the order in which they appear.

The 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. Such as:

[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 (]public) ushort Wminute;
[FieldOffset (]public) ushort Wsecond;
[FieldOffset]]public ushort wmilliseconds;
}

The following is a OSVERSIONINFO structure for the API,. NETAn example of a corresponding class or struct is defined in:

/**********************************************
* The original structure declaration is defined in the API
* Osversioninfoa STRUCT
* dwOSVersionInfoSize DWORD?
* dwMajorVersion DWORD?
* dwMinorVersion DWORD?
* dwBuildNumber DWORD?
* dwPlatformId DWORD?
* szCSDVersion BYTE to DUP (?)
* Osversioninfoa ENDS
*
* osVersionInfo equ <OSVERSIONINFOA>
*********************************************/

Declared as class in. Net
[StructLayout (LayoutKind.Sequential)]
public class osVersionInfo
{
public int osversioninfosize;
public int majorversion;
public int minorversion;
public int BuildNumber;
public int platformid;

[MarshalAs (UnmanagedType.ByValTStr, sizeconst=128)]
Public String versionstring;
}
Or
//. NETDeclared as structure in
[StructLayout (LayoutKind.Sequential)]
public struct OSVERSIONINFO2
{
public int osversioninfosize;
public int majorversion;
public int minorversion;
public int BuildNumber;
public int platformid;

[MarshalAs (UnmanagedType.ByValTStr, sizeconst=128)]
Public String versionstring;
}

This example uses the Mashalas attribute, which is used to describe the marshaling format for a field, method, or parameter. Use it as the parameter prefix and specify the data type that the target requires. For example, the following code marshals a string of two parameters to a Windows API function as a long pointer to a data type (LPSTR):

[MarshalAs (UNMANAGEDTYPE.LPSTR)]
String Existingfile;
[MarshalAs (UNMANAGEDTYPE.LPSTR)]
String NewFile;

Note that when a struct is a parameter, it is generally preceded by a ref modifier, otherwise an error occurs: The object's reference does not specify an instance of the object.

[DllImport ("kernel32", entrypoint= "GetVersionEx")]
public static extern bool GetVersionEx2 (ref OSVersionInfo2 OSVI);

Third, how to ensure that the use of managed object platform invoke success?

If the managed object is not referenced anywhere after the call to platform invoke, the garbage collector may complete the managed object. This frees the resource and invalidates the handle, causing the platform invoke call to fail. Wrapping a handle with handleref guarantees that the managed object will not be garbage collected until the platform invoke call completes.

For example, the following:

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 ismanagedobject, it is possible that the platform call is not completed when theGarbage CollectionStation recycling. HandleRef a handle to a file streamPackaging, 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'll hold reference to HandleRef until call ends
ReadFile (HR, buffer, 5, out read, 0);

API functions are the cornerstone of building WINDWS applications, and each of the Windows Application development tools provides the underlying functions that call Windows API functions either indirectly or directly in C #, as well as in order to extend the functionality, and generally provide an interface for C # calls to Windows API functions , which means that you have the ability to invoke a dynamic connection library. Visual C #, like other development tools, can also invoke the API functions of a dynamic-link library. The NET Framework itself provides a service that allows governed code to invoke non-jurisdictional functions implemented in a dynamic-link library, including Windows API functions provided by the operating system. It can locate and invoke the output function and, as needed, organize its various parameters (integer, String type, array, and structure, etc.) across the interop boundary.

The basic procedure for invoking an API is briefly described in C # as an example:
Declaration of dynamic Link library functions

Dynamic link library functions must be declared before use, relative to the vb,c# function declaration is more verbose, the former through the Api viewer paste later, can be used directly, while the latter need to make some additional changes to the parameters of the work.

The Dynamic Link library function Declaration section generally consists of the following two parts, one is the function name or index number, and the other is the file name of the dynamic link library.
For example, if you want to call the MessageBox function in User32.DLL, we must indicate the function's name MessageBoxA or MessageBoxW, and the library name User32.dll, we know Win32 The API for each function that involves strings and characters generally exists in two versions, the ANSI version of single-byte characters, and the Unicode version of double-byte characters.

Here is an example of invoking an API function:

    1. [DllImport ("KERNEL32. DLL ",
    2. Entrypoint= "Movefilew", Setlasterror=true,
    3. CharSet=CharSet.Unicode, Exactspelling=true,
    4. Callingconvention=callingconvention.stdcall)]
    5. public static extern bool MoveFile (string src, string dst);

Where the entry point entrypoint identifies the function at the entry location of the dynamic link library, in a governed project, the original name and ordinal entry point of the target function not only identifies a function that crosses the interop boundary. Also, you can map the entry point to a different name, that is, to rename the function. Renaming can bring convenience to the calling function by renaming, on the one hand we do not have to bother about the size of the function, and it can also guarantee consistency with the existing naming rules, allowing functions with different parameter types to coexist, and more importantly, simplifying the invocation of ANSI and Unicode versions. CharSet is used to identify whether a function call is in Unicode or ANSI version, Exactspelling=false will tell the compiler to let the compiler decide to use Unicode or an ANSI version. Please refer to the MSDN Online Help for additional parameters.

In C #, you can declare a dynamic link library function in the entrypoint domain by name and ordinal, and if the function name used in the method definition is the same as the DLL entry point, you do not need to display the declaring function in the EntryPoint field. Otherwise, you must use the following attribute format to indicate a name and ordinal.

[DllImport ("Dllname", entrypoint= "functionname")]
[DllImport ("Dllname", entrypoint= "#123")]
It is important to note that you must add "#" before the number sequence
Here is an example of replacing the MessageBox name with MsgBox:

    1. Using System.Runtime.InteropServices;
    2. public class Win32 {
    3. [DllImport ("User32.dll", entrypoint= "MessageBox")]
    4. public static extern int MsgBox (
    5. int hWnd, string text, string caption, uint type);
    6. }

Many of the managed dynamic link library functions expect you to pass a complex parameter type to a function, such as a user-defined struct type member or a class member defined by the governing code, and you must provide additional information to format the type to maintain the original layout and alignment of the parameter.

C # provides a StructLayoutAttribute class that allows you to define your own format type, where the formatted type is a struct or class member that is described by StructLayoutAttribute, in the governed code. It guarantees the expected layout information of its internal members. There are three options for layout:

Layout options
Describe
Layoutkind.automatic
In order to improve efficiency, the type members are reordered by the run state.
Note: Never use this option to invoke a dynamic link library function that is not governed.
Layoutkind.explicit
Sort type members by FieldOffset property for each domain
LayoutKind.Sequential
Sorts members of the type that appear in the non-governed memory where the jurisdiction type is defined.

passing struct members

The following example shows how to define a point and rectangle type in the governed code and pass it as a parameter to the PtInRect function in the User32.dll library.
The non-jurisdictional prototype of a function is declared as follows:
BOOL ptinrect (const RECT *LPRC, point pt);
Note that you must pass the RECT structure parameter by reference because the function requires a RECT structure pointer.

  1. Using System.Runtime.InteropServices;
  2. [StructLayout (LayoutKind.Sequential)]
  3. Public struct, point {
  4. public int x;
  5. public int y;
  6. }
  7. [StructLayout (Layoutkind.explicit]
  8. public struct Rect {
  9. [FieldOffset (0)] public int left;
  10. [FieldOffset (4)] public int top;
  11. [FieldOffset (8)] public int right;
  12. [FieldOffset] public int bottom;
  13. }
  14. Class Win32API {
  15. [DllImport ("User32.dll")]
  16. public static extern Bool PtInRect (ref Rect. R, point P);
  17. }

Like you can call the GetSystemInfo function to get system information:

  1. Using System.Runtime.InteropServices;
  2. [StructLayout (LayoutKind.Sequential)]
  3. public struct System_info {
  4. public UINT Dwoemid;
  5. public UINT dwPageSize;
  6. public UINT lpminimumapplicationaddress;
  7. public UINT lpmaximumapplicationaddress;
  8. public UINT Dwactiveprocessormask;
  9. public UINT Dwnumberofprocessors;
  10. public UINT dwProcessorType;
  11. public UINT dwallocationgranularity;
  12. public UINT Dwprocessorlevel;
  13. public UINT Dwprocessorrevision;
  14. }
  15. [DllImport ("kernel32")]
  16. static extern void GetSystemInfo (ref system_info PSI);
  17. System_info PSI = new System_info ();
  18. GetSystemInfo (ref PSI);

When calling Windows API functions in C #, most functions use pointers to pass parameters, and for a struct variable pointer, we can sometimes use arrays to pass parameters in addition to using the class and struct methods above.

C # and API

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.