If you are not sure which DLL defines the WINDOWS API function you want to use, the PLATFORM SDK documentation will provide you with the best help resources. At the end of the topic text of the WINDOWS API function, the SDK document specifies. The LIB file that the c application must link to in order to use this function. In almost all cases. The LIB file has the same name as the system DLL file that defines the function. For example, if the function needs a C application to link to KERNEL32. This function was defined in KERNEL32.DLL. You can find the PLATFORM SDK documentation topics about MESSAGEBEEP in MESSAGEBEEP. At the end of this topic, you will notice that it indicates that the library file is USER32. LIB; This indicates that MESSAGEBEEP was exported from USER32.DLL.
Optional DLLIMPORTATTRIBUTE attribute
In addition to pointing out the host DLL, DLLIMPORTATTRIBUTE also contains some optional attributes, among which four are particularly interesting: ENTRYPOINT, CHARSET, SETLASTERROR and CALLINGCONVENTION.
If you don't want the externally managed method to have the same name as the DLL export, you can set this property to indicate the entry point name of the exported DLL function. This is especially useful when you define two external methods that call the same unmanaged function. In addition, you can bind the exported DLL functions by their serial numbers in WINDOWS. If you need to do this, the entry point value (such as "# 1" or "# 129") indicates the ordinal value of the unmanaged function in the DLL, not the function name.
Character Set For character sets, not all versions of WINDOWS are the same. WINDOWS 9X series products lack important UNICODE support, while WINDOWS NT and WINDOWS CE series used UNICODE from the beginning. The CLR running on these operating systems uses UNICODE as the internal representation of string and character data. But don't worry-when calling the WINDOWS 9X API function, the CLR will automatically make the necessary conversion from UNICODE to ANSI.
If the DLL function does not process text in any way, you can ignore the CHARSET attribute of DLLIMPORTATTRIBUTE. However, when CHAR or STRING data is part of the equation, the CHARSET property should be set to CHARSET.AUTO, which enables the CLR to use the appropriate character set according to the host operating system. If the CHARSET property is not explicitly set, its default value is CHARSET.ANSI, which is flawed because for WINDOWS 2000, WINDOWS XP and WINDOWS NT? 0? 3, which will have a negative impact on the performance of marshaled text parameters.
The only time you should explicitly choose the CHARSET value of CHARSET. ANSI or character set. UNICODE instead of CHARSET. AUTO refers to explicitly specifying an export function specific to one of these two WIN32 operating systems. The READDIRECTORYCHANGESW API function is one such example, which only exists in WINDOWS NT-based operating systems and only supports UNICODE. In this case, CHARSET.UNICODE should be used explicitly.
Sometimes, it is not obvious whether the WINDOWS API has a character set relationship. A foolproof confirmation method is to check the C language header file of this function in PLATFORM SDK. (If you are not sure which header file to look at, you can look at the header file of each API function listed in the PLATFORM SDK document. If you find that an API function is really defined as a macro mapped to a function name ending in A or W, then this character set is related to the function you are trying to call. An example of a WINDOWS API function is the GETMESSAGE API declared in WINUSER. H you may be surprised to find that it has two versions, A and W.
SETLASTERROR error handling is very important, but it is often forgotten in programming. When you make a P/INVOKE call, you will also face other challenges-dealing with the difference between WINDOWS API error handling and exceptions in managed code. I can give you some advice.
If you use P/INVOKE to call the WINDOWS API function, and for this function, you use GETLASTERROR to find extended error information, you should set the SETLASTERROR property to TRUE in the DLLIMPORTATTRIBUTE of the external method. This applies to most external methods.
This will cause the CLR to cache the API function settings after each call to an external method. Then, in the wrapper method, you can get the cached error value by calling marshaling. GETLASTWIN32ERROR method defined in the system. Runtime. interopservices.marshal type of class library. It is recommended to check the expected error values of these API functions and throw a detectable exception for these values. WIN32EXCEPTION defined in the system for all other faults (including those that are not expected at all). The COMPONENTMODEL namespace is raised and returned by MARSHAL. GETLASTWIN32ERROR is passed to it. If you look back at the code in figure 1, you will find that this method is adopted in the male * * * wrapper of the EXTERN MESSAGEBEEP method.
The last and perhaps least important DLLIMPORTATTRIBUTE attribute that CALLINGCONVENTION will introduce here is CALLINGCONVENTION. Through this property, you can indicate to the CLR which function calling convention should be used for parameters in the stack. Default value of CALLINGCONVENTION. WINAPI is the best choice and is feasible in most cases. However, if the call is unsuccessful, you can check the declaration header file in the platform SDK to see if the API function you call is an abnormal API that does not meet the calling convention standard.
Usually, the calling convention of native functions (such as WINDOWS API function or C- runtime DLL function) describes how to push parameters into the thread stack or clear parameters from the thread stack. Most WINDOWS API functions first push the last parameter of the function onto the stack, and then the called function is responsible for emptying the stack. On the contrary, many C runtime DLL functions are defined to push method parameters onto the stack in the order in which they appear in the method signature, and leave the stack cleaning to the caller.
Fortunately, for P/INVOKE calls to work, only peripheral devices need to understand the calling convention. Generally speaking, it is the best choice to start with the default value of CALLINGCONVENTION.WINAPI, and then in the C runtime DLL function and a few functions, you may need to change the convention to CALLINGCONVENTION.CDECL.