Visual C # Call Windows API functions

Source: Internet
Author: User

Api functions are the cornerstone of building Windws applications. For every Windows application development tool, the underlying functions provided by API functions call Windows Api functions indirectly or directly, at the same time, in order to achieve function expansion, interfaces for calling WindowsAPI functions are generally provided, that is, they can call dynamic connection libraries. Visual C # can call the API functions of the dynamic link library like other development tools .. NET Framework itself provides such a service that allows governed code to call non-governed functions implemented in the dynamic link library, including Windows API functions provided by the operating system. It can locate and call the output function, and organize its parameters (integer, string type, array, and structure) to span the interoperability boundary as needed.

The following uses C # as an example to briefly introduce the basic process of calling an API:
Dynamic library function declaration
The function of the dynamic link library must be declared before use. Compared with VB, C # function declaration is even more difficult. The former can be directly used after being pasted through the Api Viewer, the latter requires extra parameter changes.

The function declaration part of the dynamic link library is generally composed 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, you must specify the function name MessageBoxA or MessageBoxW, and the library name User32.dll, we know that Win32 API generally has two versions for each function involving strings and characters, the ANSI version of single-byte characters and the UNICODE version of double-byte characters.

The following is an example of calling an API function:
[DllImport ("KERNEL32.DLL", EntryPoint = "MoveFileW", SetLastError = true,
CharSet = CharSet. Unicode, ExactSpelling = true,
CallingConvention = CallingConvention. StdCall)]
Public static extern bool MoveFile (String src, String dst );

The entry point EntryPoint identifies the function's entry position in the dynamic link library. In a governed project, the original name and serial number entry point of the target function not only identifies a function that spans the interoperability boundary. You can also map the entry point to a different name, that is, rename the function. Renaming can bring various conveniences to function calling. by renaming, on the one hand, we don't have to worry about the case sensitivity of the function, and it can also ensure that it is consistent with the existing naming rules, allows functions with different parameter types to coexist. More importantly, it simplifies calls to ANSI and Unicode versions. CharSet is used to identify the Unicode or ANSI version used for function calls. ExactSpelling = false tells the compiler to decide whether to use Unicode or Ansi. For other parameters, see the MSDN online help.

In C #, you can declare a Dynamic Linked Library Function in the EntryPoint field by name and serial number. If the function name used in the method definition is the same as the DLL entry point, you do not need to display the declaration function in the EntryPoint field. Otherwise, you must use the following attribute format to indicate a name and serial number.

[DllImport ("dllname", EntryPoint = "Functionname")]
[DllImport ("dllname", EntryPoint = "#123")]
It is worth noting that you must add "#" before the number
The following is an example of replacing the MessageBox name with MsgBox:
[C #]
Using System. Runtime. InteropServices;

Public class Win32 {
[DllImport ("user32.dll", EntryPoint = "MessageBox")]
Public static extern int MsgBox (int hWnd, String text, String caption, uint type );
}
Many governed Dynamic Linked Library functions expect you to pass a complex parameter type to the function, such as a user-defined structure type member or a class member defined by the governed code, in this case, you must provide additional information to format this type to maintain the original layout and alignment of the parameter.

C # provides a StructLayoutAttribute class through which you can define your own formatting type. In the governed code, the formatting type is a structure or class member described by StructLayoutAttribute, it ensures the expected layout information of its internal members. There are three layout options:

Layout options
Description
LayoutKind. Automatic
To improve efficiency, the running state can be reordered by type members.
Note: never use this option to call uncontrolled Dynamic Linked Library functions.
LayoutKind. Explicit
Sort type members by FieldOffset attribute for each domain
LayoutKind. Sequential
Sort the type members in the memory that are not under the jurisdiction of the type definition.
Transfer Structure Member
The following example shows how to define a vertex and a rectangle type in the governed code and pass it as a parameter to the PtInRect function in the User32.dll library,
The ungoverned prototype of a function is declared as follows:
BOOL PtInRect (const RECT * lprc, POINT pt );
Note that you must pass the Rect structure parameter through reference, because the function requires a Rect structure pointer.
[C #]
Using System. Runtime. InteropServices;

[StructLayout (LayoutKind. Sequential)]
Public struct Point {
Public int x;
Public int y;
}

[StructLayout (LayoutKind. Explicit]
Public struct Rect {
[FieldOffset (0)] public int left;
[FieldOffset (4)] public int top;
[FieldOffset (8)] public int right;
[FieldOffset (12)] public int bottom;
}

Class Win32API {
[DllImport ("User32.dll")]
Public static extern Bool PtInRect (ref Rect r, Point p );
}
Similarly, you can call the GetSystemInfo function to obtain system information:
? Using System. Runtime. InteropServices;
[StructLayout (LayoutKind. Sequential)]
Public struct SYSTEM_INFO {
Public uint dwOemId;
Public uint dwPageSize;
Public uint lpMinimumApplicationAddress;
Public uint lpMaximumApplicationAddress;
Public uint dwActiveProcessorMask;
Public uint dwNumberOfProcessors;
Public uint dwProcessorType;
Public uint dwAllocationGranularity;
Public uint dwProcessorLevel;
Public uint dwProcessorRevision;
}

[DllImport ("kernel32")]
Static extern void GetSystemInfo (ref SYSTEM_INFO pSI );

SYSTEM_INFO pSI = new SYSTEM_INFO ();
GetSystemInfo (ref pSI );

Transfer of Class Members
Similarly, as long as the class has a fixed class member layout, you can pass a class member to an uncontrolled Dynamic Linked Library function, the following example shows how to pass a sequential sequence-defined MySystemTime class to the GetSystemTime function of User32.dll. The Calling rules of the function using C/C ++ are as follows:

Void GetSystemTime (SYSTEMTIME * SystemTime );
Unlike the value type, the class always transmits parameters through reference.
[C #]
[StructLayout (LayoutKind. Sequential)]
Public class MySystemTime {
Public ushort wYear;
Public ushort wMonth;
Public ushort wDayOfWeek;
Public ushort wDay;
Public ushort wHour;
Public ushort wMinute;
Public ushort wSecond;
Public ushort wMilliseconds;
}
Class Win32API {
[DllImport ("User32.dll")]
Public static extern void GetSystemTime (MySystemTime st );
}
Transfer of callback functions:
To call most Dynamic Linked Library functions from governed code, you only need to create a function definition and then call it. This process is very direct.
If a Dynamic Linked Library function requires a function pointer as a parameter, You need to perform the following steps:
First, you must refer to the documentation on this function to determine whether a callback is required for this function. Second, you must create a callback function in the governed code. Finally, you can pass the pointer to this function as a parameter to the DLL function ,.

Callback Function and Its Implementation:
Callback functions are often used when tasks need to be executed repeatedly, such as enumeration functions, such as EnumFontFamilies (font enumeration), EnumPrinters (printer), and EnumWindows (window enumeration) functions in Win32 APIs. the following uses window enumeration as an example to describe how to call the EnumWindow function to traverse all windows in the system.

Perform the following steps:
1. Refer to the function declaration before implementing the call.
BOOL EnumWindows (WNDENUMPROC lpEnumFunc, LPARMAM IParam)
Obviously, this function requires a callback function address as a parameter.
2. create a governed callback function. The example is declared as a representative type (delegate), that is, the callback we call. It has two parameters: hwnd and lparam, the first parameter is a window handle, and the second parameter is defined by the application. Both parameters are integer.

When this callback function returns a non-zero value, it indicates that the execution is successful, and zero indicates that the operation fails. In this example, the value True is always returned for continuous enumeration.
3. Create an object (delegate) and pass it as a parameter to the EnumWindows function. The platform automatically converts the representation to a callback format that can be recognized by the function.

[C #]
Using System;
Using System. Runtime. InteropServices;

Public delegate bool CallBack (int hwnd, int lParam );

Public class EnumReportApp {

[DllImport ("user32")]
Public static extern int EnumWindows (CallBack x, int y );

Public static void Main ()
{
CallBack myCallBack = new CallBack (EnumReportApp. Report );
EnumWindows (myCallBack, 0 );
}

Public static bool Report (int hwnd, int lParam ){
Console. Write ("window handle is ");
Console. WriteLine (hwnd );
Return true;
}
}

Pointer type parameter transfer:
When calling Windows API functions, most functions use pointers to pass parameters. For a structure variable pointer, we use the above class and structure method to pass Parameters, sometimes we can use arrays to pass parameters.

The following function obtains the user name by calling GetUserName.
BOOL GetUserName (
LPTSTR lpBuffer, // User Name Buffer
LPDWORD nSize // address pointer for storing the buffer size
);
 
[DllImport ("Advapi32.dll ",
EntryPoint = "GetComputerName ",
ExactSpelling = false,
SetLastError = true)]
Static extern bool GetComputerName (
[Financialas (UnmanagedType. LPArray)] byte [] lpBuffer,
[Financialas (UnmanagedType. LPArray)] Int32 [] nSize );
This function accepts two parameters: char * and int *, because you must allocate a String buffer to accept the String pointer. You can use the String class to replace this parameter type, of course, you can also declare a byte array to pass the ANSI string, or you can declare a long integer array with only one element, using the array name as the second parameter. The above functions can be called as follows:

Byte [] str = new byte [20];
Int32 [] len = new Int32 [1];
Len [0] = 20;
GetComputerName (str, len );
MessageBox. Show (System. Text. Encoding. ASCII. GetString (str ));
Note that before using each method, you must add the following content to the file header:
Using System. Runtime. InteropServices;

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.