Use Win32 libraries in C # programming

xiaoxiao2021-04-11  1.2K+

C # users often ask two questions: "Why do I have to write code to use the function built in Windows? Why don't you complete this task in the framework?" When the frame team builds their .NET section When they evaluated the work that the .NET programmers can use to complete the work, it was found that the Win32 API set was very large. They don't have enough resources to write hosting interfaces for all Win32 APIs, test and write documents, so they can only deal with the most important part. Many common operations have a hosted interface, but there are still many complete Win32 parts without a hosted interface. Platform call (P / invoke) is the most common method of completing this task. To use P / Invoke, you can write a prototype describing how to call the function, and then use this information to be called. Another method is to use Managed Extensions to C to package functions, which will be introduced in later columns. To understand how to complete this task, the best way is to pass an example. In some examples, I only give some code; the complete code can be downloaded. Simple example In the first example, we will call the Beep () API to make a sound. First, I need to write appropriate definitions for beep (). View the definition in MSDN, I found it has the following prototype: BOOL Beep (DWord Dwfreq, // Sound Frequency DWord Dwduration // Sound Duration); Use C # to write this prototype, you need to convert Win32 type into corresponding C # Types of. Since DWORD is an integer of 4 bytes, we can use int or UINT as a C # corresponding type. Since int is a CLS compatible type (you can be used for all .NET languages), this is more common than UINT, and in most cases, the difference between them is not important. The BOOL type corresponds to BOOL. Now we can write the following prototype with C #: Public Static Extern Bool Beep; This is a quite standard definition, but we use extern to indicate the actual code of the function. This prototype will tell the rule how to call the function; now we need to tell where to find the function. We need to review the code in the MSDN. In the reference information, we found that beep () is defined in kernel32.lib. This means that the runtime code is included in the kernel32.dll. We add DLLIMPORT attributes in the prototype to tell this information: [DLLIMPORT ("kernel32.dll")] This is all our work we have to do. Here is a complete example, which is common in science fiction movies in the 1960s.

using System; using System.Runtime.InteropServices; namespace Beep {class Class1 {[DllImport ( "kernel32.dll")] public static extern bool Beep (int frequency, int duration); static void Main (string [] args) {Random Random = new random (); for (int i = 0; i <10000; i) {beep ( (10000), 100);}}}} It is enough to stimulate any listener! Since Dllimport allows you to call any code in Win32, there is a possibility to call malicious code. So you must be a completely trusted user, running the P / Invoke call when running. Enumeration and constant beep () can be used to make any sound, but sometimes we want to issue a specific type of sound, so we switch to MessageBeep (). MSDN gives the following prototype: BOOL MessageBeep (uint utype // sound type); this looks very simple, but you can find two interesting facts from the comment. First, the UTYPE parameter actually accepts a set of predefined constants. Second, the possible parameter values ​​include -1, which means that although it is defined as an UINT type, INT will be more suitable. For uType parameters, use the Enum type is reasonable. MSDN lists the named constant, but does not give any prompts for the specific value. Due to this, we need to view the actual API. If you have Visual Studio? And C, Platform SDK is located under / program files / Microsoft Visual Studio .NET / VC7 / PlatformSDK / Include. In order to find these constants, I executed a FINDSTR in this directory. Findstr "MB_ICONHAND" * .h it determines that constant is located in Winuser.h, and then I use these constants to create my enum and prototype: public enum beepType {SimpleBeep = -1, iconasterisk = 0x00000040, iconExclamation = 0x00000030, iconhand = 0x00000010 IConquestion = 0x0000000020, OK = 0x00000000,} [DLLIMPORT ("User32.dll")] public static extern bool message; now I can call it with the following statement: messagebeep (beeptype.iconquest); processing structure Sometimes I need to determine the battery status of my notebook. Win32 provides power management functions for this. Search MSDN can find a getSystemPowerStatus () function. Bool getSystemPowerStatus (lpsystem_power_status lpsystempowerStatus); This function contains pointers pointing to a structure, we have not processed this. To handle the structure, we need to use the C # definition structure.

We start from an unmanaged definition: typedef struct _SYSTEM_POWER_STATUS {BYTE ACLineStatus; BYTE BatteryFlag; BYTE BatteryLifePercent; BYTE Reserved1; DWORD BatteryLifeTime; DWORD BatteryFullLifeTime;} SYSTEM_POWER_STATUS, * LPSYSTEM_POWER_STATUS; Then, to obtain the C # version by replacing the C type with C # type. struct SystemPowerStatus {byte ACLineStatus; byte batteryFlag; byte batteryLifePercent; byte reserved1; int batteryLifeTime; int batteryFullLifeTime;} In this way, you can easily write Prototype C #: [DllImport ( "kernel32.dll")] public static extern bool GetSystemPowerStatus (ref SystemPowerStatus SystemPowerStatus; in this prototype, we use "REF" to specify the conveying structure pointer instead of the structure value. This is a general method of processing structures passing through a pointer. This function is working well, but it is best to define the Aclinestatus and Batteryflag fields as enum: enum aclinestatus: byte {offline = 0, online = 1, unknown = 255,} enum batteryflag: BYTE {high = 1, low = 2, critical = 4, charging = 8, NOSYSTEMBATTERY = 128, unknown = 255,} Please note that since the field is some bytes, we use BYTE as the basic type of the enum. Other options for / [DLLIMPORT] DLLIMPORT and STRUCTLAYOUT attributes have some very useful options that help P / Invoke use. All of these options are listed below: DLLIMPORT CALLINGCONVENTION You can use it to tell the encapsulator, and the function uses which calls are used. You can set it to your function call agreement. Usually, if this setting is incorrect, the code will not be executed. However, if your function is a CDECL function, and use stdcall (default) to call this function, the function can be executed, but the function parameters will not be removed from the stack, which will cause the stack to be filled. CHARSET control calls A variants or calls W variants. EntryPoint This property is used to set the name of the snap-of-hinter in the DLL. Once this property is set, you can rename the C # function to any name. EXACTSPELING Set this property to True, and the encapsulator will turn off the findings of A and W. PreservesIG COM interoperates makes functions with the final output parameter appear to be returned by it. This property is used to close this feature. SetLastError ensures that Win32 API setLastError () so that you can find out the error.

The StructLayout Layoutkind structure is arranged in order by default and applies in most cases. If you need to fully control the location placed in the structure, you can use layoutkind.explicit, then add a fieldoffset property to each structure member. This usually needs to do when you need to create Union. Charset controls the default character type of Byvaltstr member. Pack Set the compression size of the structure. It controls the arrangement of the structure. If the C structure uses other compressed methods, you may need to set this property. Size sets the structure size. Not common; but if you need to assign additional space at the end of the structure, this property may be used. Loading from different locations You cannot specify where you want DLLIMPORT to find files while running, but you can use a technique to achieve this. DllImport calls loadLibrary () to complete its work. If a specific DLL has been loaded in the process, even if the specified load path is different, LoadLibrary () will succeed. This means that if loading loading directly () directly, you can load the DLL from any location, then DLLIMPORT LOADLIBRARY () will use the DLL. Due to this behavior, we can call LoadLibrary () in advance to point your call to other DLLs. If you are in writing a library, you can prevent this in this case by calling getModuleHandle () to ensure that the library is not loaded before the first call P / Invoke. P / Invoke Troubleshoot If your P / Invoke call fails, it is usually because some types of definitions are not correct. The following is a few common problems: 1.long! = Long. In C, long is an integer of 4 bytes, but in C #, it is an 8-byte integer. 2. String type setting is incorrect.

Reply to: Request (I have a problem) Reputation: 100 2006-2-12 1:39:28 Score: 0 API function is the cornerstone of the WindWS application, each Windows application development tool, which provides the underlying function The Windows API function is called indirectly or directly, and in order to implement functional extensions, the interface that calls the WindowsAPI function is generally provided, which means that the ability to call the dynamic connection library. Visual C # and other development tools can also call the dynamic link library API function. The .NET framework itself provides such a service that allows the code-up code to call the Dynamic Link Library, which includes the Windows API function provided by the operating system. It is capable of positioning and calling the output function, organizes each parameter (integer, string type, array, and structure, etc.) as needed, across the interoperability boundary. The following is a basic process of calling the API as an example: Dynamic Link Library functions must be declared before the dynamic link library function is used, relative to VB, C # function declaration is more commendable, after passing by API Viewer, you can use it directly And the latter needs to do additional changes in parameters. Dynamic Link Library Function Declaration Sections are generally composed of two parts of the following, one is a function name or an index number, and the other is the file name of the dynamic link library. For example, you want to call the Messagebox function in user32.dll, we must specify the name MessageBoxa or MessageBoxwwwa or MessageBoxwww, and library name user32.dll, we know that Win32 API has two versions of each of the functions involving strings and characters. The ANSI version of the single-byte character and the Unicode version of the double-byte character. Here is an example of the API function call: [DllImport ( "KERNEL32.DLL", EntryPoint = "MoveFileW", SetLastError = true, CharSet = CharSet.Unicode, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)] public static extern bool MoveFile (String SRC, STRING DST); where the entry point entrypoint identification function is in the entry position of the dynamic link library, in an jurisded engineering, the original name and serial number entry point of the target function not only identifies a function of the interoperability boundary. Moreover, you can also map this entry point into a different name, that is, rename the function. Rename can bring all kinds of convenience to the call function, by renaming, on the one hand, we don't have to write to the function of the function, and it can also ensure consistent with the existing naming rules, allowing a function with different parameter types. Coexistence, more importantly, it simplifies the call to ANSI and Unicode versions. Charset is used to identify function calls, which is Unicode or ANSI version. Exactspelling = false will tell the compiler to make the compiler decide to use Unicode or ANSI version. For other parameters, please refer to MSDN online help. In C #, you can declare a dynamic link library function through the name and serial number at the EntryPoint field, if the function name used in the method definition is the same as the DLL entry point, you don't need to be in the Entrypoint domain Display declaration function. 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 "#" in front of the digital serial number to replace it with MSGBOX examples MessageBox name: [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 jurisdictions of dynamic link library functions expect you to deliver a complex parameter type to function, such as a user-defined structural type member or a class member defined by the jurisdiction, and you must provide additional Information formatted this type to maintain the original layout and alignment of the parameters. C # provides a StructLayOutAttribute class, which you can define your own formatted type. In the jurisdiction code, the formatting type is a structure or class member with StructLayOutAttribute, which guarantees its internal member expected layout information. There are three options for the layout: layout option Description LayoutKind.automatic In order to improve efficiency allows the run state to reorder type members. Note: Never use this option to call unlicensed dynamic link library functions. LayoutKind.ExPlicit Sorting LayoutKind.SEQUENTIAL on the type member in the Fieldoffset property, LayoutKind.SEQUENTIAL is sorted by a type member that appears in the jurisdiction from the jurisdiction of the jurisdiction. The following examples below describe how to define a point and rectangle type in the jurisdiction and pass it to the PtinRect function in the user32.dll library as a parameter, the unlicensed prototype statement is as follows: BOOL PTIECT (Const Rect * LPRC, POINT PT); Note You must pass the Rect structural parameters by 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);} you can call GetSystemInfo similar 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 = n EW system_info (); getSystemInfo (Ref psi); the passage of the class member is also as long as the class has a fixed class member layout, you can also pass a class member to a dynamic link library function that is not jurisdiction, the following example mainly explains how Passing a Sequential order defined mysystemTIME class to the getSystemTime function of user32.dll, the function is used in the C / C call specification: void getSystemTime (SystemTime * SystemTime); unlike the value type, the class is always passed through the 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);} Password of the callback function: Calling most dynamic link library functions from the jurisdiction, you only need to create a derived function definition, then Call it, this process is very straightforward.

If a dynamic link library function requires a function pointer as a parameter, you still need to do the following steps: First, you must refer to the documentation about this function, determine if this function needs a callback; second, you must be in the jurisdiction code Create a callback function; Finally, you can deliver a pointer to this function as a parameter to the DLL function, callback function and its implementation: The callback function is often used in the task needs to be repeated, such as for enumeration functions, For example, EnumFontFamilies (font enumeration), enumprinters, enumwindows (printers), enumerations below as an example below, talk about how to divide all windows existing in the system by calling the EnumWindow function Steps: 1. Declaration Bool EnumWindows (WndenumProc LpenumFunc, LParmam iParam) before the call, clear this function requires a callback function address as a parameter. 2. Create an jurisded callback function, this example declares as a representative type (delegate), that is, what we call, with two parameters hWnd and lparam, the first parameter is a window handle, the second parameter is defined by the application, both of which are shaped. When this callback function returns a non-zero value, the indication is successful, and the ridge is hints, this example always returns the TRUE value for continuous enumeration. 3. Finally, create a representative object, and passed it as a parameter to the EnumWindows function, and the platform automatically converts the transformation into a function that can identify the callback format that can be identified. [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"); Console .Writeline (hwnd); Return True;}} pointer type parameter passed: When the Windows API function is called, most of the functions use pointer to pass parameters, for a structural variable pointer, in addition to using the above and structural methods to pass parameters We can sometimes use arrays to deliver parameters.


New Post(0)