The function of dynamic link library must be declared before use. Compared with VB, the declaration of C # function is more verbose. The former can be used directly after being pasted by Api Viewer, while the latter needs some additional modification of parameters.
The function declaration part of a dynamic link library 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 specify the function name MessageBoxA or MessageBoxW and the library name User32.dll. We know Win32.
Each function involving strings and characters generally has two versions of API, ANSI version of single-byte characters and UNICODE version of double-byte characters.
The following is an example of calling an API function:
[DllImport("KERNEL32。 DLL ",EntryPoint="MoveFileW ",SetLastError=true,
CharSet = character set. Unicode,ExactSpelling=true,
Call convention = call convention. StdCall)]
public static extern bool MoveFile(String src,String dst);
Where EntryPoint entrypoint identifies the entry position of the function in the dynamic link library. In the governed project, the original name and serial number entry point of the objective function not only identify the function that crosses the interoperability boundary. In addition, you can map this entry point to a different name, that is, rename the function. Renaming can bring convenience to calling functions. By renaming, on the one hand, you don't have to worry about the case of the function, and at the same time, you can ensure the consistency with the existing naming rules, allowing you to save functions with different parameter types. More importantly, it simplifies the call to ANSI and Unicode versions. CharSet is used to identify whether the function call uses Unicode or Ansi version, and ExactSpelling=false will tell the compiler to decide whether to use Unicode or ANSI version. For other parameters, please refer to the MSDN online help.
In C#, you can declare a DLL function by the name and serial number in the entry point field. If the function name used in the method definition is the same as the DLL entry point, there is no need to display the declared function in the entry point field. Otherwise, you must use the following attribute format to represent the name and serial number.
[DllImport("dllname ",EntryPoint="Functionname")]
[DllImport("dllname ",EntryPoint="# 123")]
It is worth noting that you must add "#" before the numerical serial number.
The following is an example of replacing the MessageBox name with MsgBox:
[C#]
Use the 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 DLL functions expect you to pass complex parameter types to the function, such as user-defined structural type members or class members defined by governed code. At this point, you must provide additional information to format this type to maintain the original layout and alignment of the parameters.
C# provides a StructureLayoutAttribute class, through which you can define your own format types. In governed code, a formatted type is a structure or class member described by StructureLayoutAttribute, through which the expected layout information of its internal members can be guaranteed. There are three layout options * * *:
Layout options
describe
Layout types. automatic
In order to improve efficiency, the running state allows reordering of type members.
Note: Never use this option to call unmanaged dynamic link library functions.
Layout types. specific
Sorts type members according to the FieldOffset property of each field.
Layout types. uninterrupted
Sorts type members that appear in unmanaged memory that define managed types.
Transfer structural member
The following example shows how to define the point and rectangle types in the governed code and pass them as parameters to the PtInRect function in the User32.dll Library.
The unadjusted prototype of the function is declared as follows:
Boolean function (constant RECT *lprc, point pt);
Note that the Rect structure parameter must be passed by reference, because the function requires a Rect structure pointer.
[C#]
Use the system. Runtime . InteropServices
[StructLayout(LayoutKind。 Continuous)]
Common structure point {
public int x;
public int y;
}
[StructLayout(LayoutKind。 Clear]
Common structure rectangle {
[field offset(0)]public int left;
[field offset(4)]public int top;
[field offset(8)]public int right;
[field offset( 12)]public int bottom;
}
Win32API class {
[DllImport("User32.dll")]
public static extern Bool PtInRect(ref Rect r,Point p);
}
Similarly, you can call the GetSystemInfo function to get system information:
Use the system. Runtime . InteropServices
[StructLayout(LayoutKind。 Continuous)]
Public structure SYSTEM_INFO {
Public uint dwOemId
Public uint dwPageSize
public uint lpminimumaapplicationaddress;
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 get system info (refsystem _ infopsi);
SYSTEM _ INFO pSI = new SYSTEM _ INFO();
getsystem info(ref pSI);
Passing of class members
Similarly, as long as the class has a fixed layout of class members, you can also pass class members to unmanaged dynamic link library functions. The following example mainly explains how to pass a sequentially defined MySystemTime class to User32.dll's GetSystemTime function.
The calling specifications of functions and C/C++ are as follows:
void get system time(system time * system time);
Unlike passing value types, classes always pass parameters by reference.
[C#]
[StructLayout(LayoutKind。 Continuous)]
Public class MySystemTime {
public ushort wYear
public ushort wMonth
public ushort wDayOfWeek
Public leisure day;
public ushort wHour
Public ushort minutes;
public ushort wSecond
public ushort wMilliseconds
}
Win32API class {
[DllImport("User32.dll")]
public static extern void get system time(MySystemTime ST);
}
Transfer of callback function:
To call most DLL functions from governed code, you only need to create a governed function definition and then call it. This process is very direct.
If a dynamic link library function needs a function pointer as a parameter, you need to do the following steps:
First, you must refer to the documentation about this function to determine whether this function needs a callback; Second, a callback function must be created in the governed code; Finally, you can pass a pointer to the function as a parameter to the DLL function.
Callback function and its implementation;
Callback functions are often used in situations where tasks need to be repeated, such as enumeration functions, such as Win32.
EnumFontFamilies (font enumeration), EnumPrinters (printer) and EnumWindows (window enumeration) functions in API.
Let's take window enumeration as an example to talk about how to traverse all windows in the system by calling EnumWindow function.
It is divided into the following steps:
1. Please refer to the declaration of the function before calling.
BOOL enum windows(WNDENUMPROC lpEnumFunc,LPARMAM IParam)
Obviously, this function needs a callback function address as a parameter.
2. Create a managed callback function. This example is declared as a delegate, which is what we call a callback. It has two parameters, hwnd and lparam. The first parameter is the window handle, and the second parameter is defined by the application. Both parameters are integers.
When this callback function returns a non-zero value, it means that the execution is successful, and zero means failure. For continuous enumerations, this example always returns a value of True.
3. Finally, create a delegate and pass it as a parameter to the EnumWindows function. The platform will automatically convert the delegate into a callback format that the function can recognize.
[C#]
Use the system;
Use the system. Runtime . InteropServices
Public delegate bool callback (int hwnd, intlparam);
Public class EnumReportApp {
[DllImport("user32")]
Public static extern intenum Windows (callback x, int y);
Public static void Main ()
{
CallBack my CallBack = new CallBack(EnumReportApp。 Report);
EnumWindows(myCallBack,0);
}
Common static boolean report (int hwnd, intlparam) (
Console. Write ("window handle is");
Console. Write line (hwnd);
Return true
}
}
Pointer type parameter passing:
When calling Windows API functions, most functions use pointers to pass parameters. For structural variable pointers, in addition to the above classes and structural methods, we can sometimes use arrays to pass parameters.
The following function gets the user name by calling GetUserName.
Boolean get user name (
LPTSTR lpBuffer,//username buffer
LPDWORD nSize // Address pointer for storing buffer size.
);
[DllImport("Advapi32.dll ",
EntryPoint="GetComputerName ",
ExactSpelling=false,
SetLastError=true)]
Static external boolean value GetComputerName (
[MarshalAs(UnmanagedType。 LPArray)] byte[] lpBuffer,
[MarshalAs(UnmanagedType。 LP array)]int 32[]nSize);
This function has two parameters, char.
* and int
*, because you must allocate a Stringbuffer area to accept string pointers, you can use the String class instead of this parameter type. Of course, you can also declare a byte array to pass an ANSI string. Similarly, you can declare an array of long integers with only one element and use the array name as the second parameter. The above functions can be called as follows:
Byte[]str = new byte [20];
int 32[]len = new int 32[ 1];
len[0]= 20;
GetComputerName (str,len);
MessageBox。 Display (system. text . encoding . ascii . getstring(str));
Finally, I need to remind you that before using each method, you must add:
Use the system. Runtime . InteropServices