Call Win32dll through P/invoke in C #

Source: Internet
Author: User
Tags define definition error handling functions numeric value string format thread versions

I've noticed a trend in my own recent programming that leads to this month's column theme. Recently, I've done a lot of win32®interop in applications based on the Microsoft®.net Framework. I'm not saying that my application is full of custom interop code, but sometimes I run into the. Net Framework class library with some minor but complicated, inadequate content that can be quickly reduced by invoking the WINDOWS®API.

So I think it's not surprising that there are any functionality limitations that Windows does not have in the. Net Framework version 1.0 or 1.1 class library. After all, 32-bit Windows (no matter what version) is a mature operating system, serving our customers for more than 10 years. In contrast, the. Net Framework is a new thing.

As more and more developers move production applications to managed code, it is natural for developers to look at the underlying operating system more frequently to figure out some key features-at least for now.

Thankfully, the interop capabilities of the common language runtime (CLR), called Platform Invoke (P/invoke), are perfect. In this column, I'll highlight how to actually use P/invoke to invoke Windows API functions. P/invoke is used as a noun when referring to the CLR's COM Interop functionality, and is used as a verb when the feature is used. I'm not going to introduce COM interop directly, because it's more accessible than p/invoke, but more complex, which is a bit paradoxical, which makes it less concise to discuss COM interop as a column topic.

Enter P/invoke

Start by examining a simple p/invoke example. Let's take a look at how to invoke the Win32 MessageBeep function, its unmanaged declaration as shown in the following code:

BOOL MessageBeep (  UINT utype   //beep type);

In order to invoke MessageBeep, you need to add the following code to a class or struct definition in C #:

[DllImport ("User32.dll")]static extern Boolean MessageBeep (UInt32 beeptype);

Surprisingly, this code alone allows managed code to call the unmanaged MessageBeep API. It is not a method call, but an external method definition. (Plus, it's close to a direct port from C and C #, so it's helpful to start by introducing concepts.) The possible calls from managed code are as follows:

MessageBeep (0);

Please note that the MessageBeep method is now declared static. This is required by the P/invoke method because there is no consistent instance concept in the Windows API. Next, note that the method is marked as extern. This is the prompt compiler this method is implemented through a function exported from the DLL, so no method body is required.

Speaking of missing method bodies, do you notice that the MessageBeep declaration does not contain a method body? Unlike most algorithms, which consist of a managed method consisting of intermediate language (IL) directives, the P/invoke method is simply metadata, which the Just-in-time (JIT) compiler connects managed code to an unmanaged DLL function at run time. One important information required to perform this connection to unmanaged worlds is the name of the DLL that exported the unmanaged method. This information is provided by the DllImport Custom attribute prior to the MessageBeep method declaration. In this example, you can see that the MessageBeep unmanaged API is exported by User32.dll in Windows.

So far, there are two topics left on the call MessageBeep. Recall that the code you invoked is very similar to the code snippet shown below:

[DllImport ("User32.dll")]static extern Boolean MessageBeep (UInt32 beeptype);

The last two topics are topics related to data marshaling (marshaling) and actual method calls from managed to unmanaged functions. Calling an unmanaged MessageBeep function can be performed by any managed code that finds an extern messagebeep declaration within the scope. The call is similar to any other call to a static method. What it does with any other managed method invocation is that it brings the need for data marshaling.

One of the rules of C # is that its invocation syntax can only access CLR data types, such as System.UInt32 and System.Boolean. C # Obviously does not recognize the type of data types (such as UINT and BOOL) that are used in the Windows API, and these types are just type definitions of the C language type. So when Windows API function MessageBeep is written in the following way

BOOL MessageBeep (UINT utype)

An external method must be defined with a CLR type, as you can see in the previous code fragment. The need to use a CLR type that is different but compatible with the underlying API function type is one aspect of p/invoke that is more difficult to use. So, later in this column, I'll cover data marshaling with a complete chapter.

Style

It is easy to make P/invoke calls to Windows APIs in C #. But if the class library refuses to beep your application, you should find ways to call Windows to make it work, right?

Yes. But it has to do with the method of choice, and it's a big relationship! In general, if the class library provides some way to implement your intent, it is best to use the API instead of calling unmanaged code directly because there is a big difference in style between CLR types and Win32. I can boil down the suggestion on the subject to a word. When you do P/invoke, do not make application logic directly part of any external method or artifacts. If you follow this small rule, in the long run will often save a lot of trouble.

The code in ASPX?FIG=TRUE#FIG1 "target=" _blank > Figure 1 shows the least additional code for the MessageBeep external method I'm talking about. Aspx?fig=true#fig1 "target=" _blank "> Figure 1 does not make any significant changes, but only some general improvements to the unpackaged external approach, which makes it easier to work. Starting at the top, you'll notice a complete type named Sound, which is dedicated to MessageBeep. If I need to use the Windows API function PlaySound to add support for the playback waveform, you can reuse the Sound type. However, I am not angry at exposing the type of a single public static method. After all, it's just an application code. It should also be noted that the Sound is sealed and an empty private constructor is defined. These are just a few details, so that the user does not mistakenly derive a class from Sound or create an instance of it.

The next feature of the code in ASPX?FIG=TRUE#FIG1 "target=" _blank > Figure 1 is that the actual external method of where the p/invoke occurs is the private method of the Sound. This method is only exposed indirectly by the public MessageBeep method, which accepts parameters of the Beeptypes type. This indirect extra layer is a critical detail that provides the following benefits. First, you should introduce a future beep managed method in the class library, and you can use the managed APIs repeatedly through the public MessageBeep method without having to change the rest of the code in your application.

The second benefit of this wrapper method is that when you make a p/invoke call, you waive the right to be protected from access violations and other low-level breaches, which are usually provided by the CLR. The buffering method protects the rest of your application from Access violations and similar problems (even if it does nothing but simply passes parameters). The buffering method will be localized by any potential errors introduced by the P/invoke invocation.

The third and final benefit of hiding private external methods behind public wrappers is that it provides the opportunity to add some minimal CLR styles to the method. For example, in Aspx?fig=true#fig1 "target=" _blank > Figure 1, I converted a Boolean failure returned by the Windows API function to a more CLR-like exception. I also defined an enumeration type named Beeptypes, whose members correspond to the defined values that are used with the Windows API. Because C # does not support definitions, you can use managed enumeration types to avoid the proliferation of magic numbers to the entire application code.

The last benefit of packaging methods is admittedly negligible for simple Windows API functions such as MessageBeep. But when you start calling more complex unmanaged functions, you'll find that the benefits of manually converting Windows API styles into a more user-friendly approach to the CLR will be more and more. The more you intend to reuse interop functionality throughout your application, the more serious you should consider packaging design. I also believe that using CLR-friendly parameters in non object-oriented static wrapper methods is not an option.

DLL Import Property

Now is the time to delve deeper into it. The DllImportAttribute type plays an important role when making p/invoke calls to managed code. The primary role of DllImportAttribute is to instruct the CLR which DLL exports the function you want to call. The name of the associated DLL is passed as a constructor parameter to the DllImportAttribute.

If you are not sure which DLL defines the Windows API functions you want to use, the Platform SDK documentation will provide you with the best help resources. In the location near the end of the Windows API function topic text, the SDK documentation specifies the. lib file that the C application must link to use the 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 requires a C application to link to Kernel32.lib, the function is defined in Kernel32.dll. You can find the Platform SDK documentation topic for MessageBeep in the ASP "target=" _blank >messagebeep. At the end of the topic, you'll notice that it indicates that the library file is User32.lib; This indicates that MessageBeep was exported from User32.dll.

Optional DllImportAttribute Property

In addition to pointing to the host DLL, DllImportAttribute contains optional properties, four of which are particularly interesting: entrypoint, CharSet, SetLastError, and CallingConvention.

entrypoint You do not want an external 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 also bind to exported DLL functions in Windows by their ordinal values. If you need to do this, the entrypoint value, such as "#1" or "#129", indicates the ordinal value of the unmanaged function in the DLL instead of the function name.

CharSet for character sets, not all versions of Windows are created the same way. The Windows 9x Family product lacks important Unicode support, while Windows NT and Windows CE series use Unicode from the outset. The CLR running on these operating systems uses Unicode for internal representations of String and Char data. But there's no need to worry-when you call the Windows 9x API function, the CLR automatically converts the necessary transformations from Unicode to ANSI.

If the DLL function does not process text in any way, you can ignore the DllImportAttribute CharSet property. However, when Char or String data is part of the equation, the CharSet property should be set to CharSet.Auto. This allows the CLR to use the appropriate character set based on the host OS. If the CharSet property is not explicitly set, its default value is CharSet.Ansi. This default value is flawed because it negatively affects the performance of text parameter marshaling for interop calls made on Windows 2000, Windows XP, and Windows NT®.

The only case where you should explicitly select CharSet.Ansi or CharSet.Unicode CharSet values instead of using CharSet.Auto is that you explicitly specify an export function that is specific to either of these two Win32 OS. An example of this is the READDIRECTORYCHANGESW API function, which exists only in Windows NT based operating systems and supports Unicode only, in which case you should explicitly use CharSet.Unicode.

Sometimes, it is not obvious whether the Windows API has character set relationships. A sure way to never be wrong is to check the C-language header file for the function in the Platform SDK. (If you are not sure which header file to look at, you can view the header file for each API function listed in the Platform SDK documentation.) If you find that the API function is really defined as a macro that maps to a function name that ends with a or W, the character set is related to the function that you are trying to call. An example of a Windows API function is the GetMessage API declared in WinUser.h, and you may be surprised to find that it has a and W two versions.

SetLastError error handling is important, but is often forgotten when programming. When you make a p/invoke call, you also face other challenges-handling the difference between Windows API error handling and exceptions in managed code. I can give you some advice.

If you are using P/invoke to invoke Windows API functions, and for that function, you use GetLastError to find extended error messages, you should set the SetLastError property to T in the DllImportAttribute of the external method Rue This applies to most external methods.

This causes the CLR to cache the error set by the API function after each call to the external method. Then, in the wrapper method, you can get the cached error value by calling the Marshal.GetLastWin32Error method defined in the System.Runtime.InteropServices.Marshal type of the class library. My advice is to check the error values that are expected from the API functions and to throw a perceptible exception for these values. For all other failures, including failure scenarios that are not expected at all, throws the Win32Exception defined in the System.ComponentModel namespace and passes the value returned by Marshal.GetLastWin32Error to it. If you look back at the code in ASPX?FIG=TRUE#FIG1 "target=" _blank > Figure 1, you'll see that I used this approach in the public packaging of the extern MessageBeep method.

callingconvention The last thing I'm going to introduce here is probably the least important one DllImportAttribute attribute is callingconvention. This property allows you to indicate to the CLR which function call convention should be used for the parameters in the stack. The default value for Callingconvention.winapi is the best choice, and it works in most cases. However, if the call does not work, you can check the declaration header file in the Platform SDK to see if the API function you are calling is an exception API that does not conform to the calling convention standard.

Typically, the calling convention for native functions, such as Windows API functions or C run-time DLL functions, describes how to push parameters onto the thread stack or clear it from the thread stack. Most Windows API functions first push the last parameter of a function onto the stack, and then the called function cleans up the stack. Instead, many C-run-time DLL functions are defined to push the stack cleanup to the caller in the order in which the method parameters appear in the method signature.

Fortunately, for P/invoke to invoke the job, only the perimeter device understands the calling convention. Typically, starting with the default value Callingconvention.winapi is the best option. Then, in the C run-time DLL function and a few functions, you may need to change the contract to CALLINGCONVENTION.CDECL.

Data marshaling

Data marshaling is a challenging aspect of P/invoke. When passing data between managed and unmanaged code, the CLR follows many rules, and few developers often encounter them until they can be remembered. Unless you are a class library developer, it is not usually necessary to master the details. For the most efficient use of p/invoke on the CLR, application developers who only occasionally need interop should still understand some of the basics of data marshaling.

In the remainder of this month's column, I'll discuss data marshaling for simple numbers and string data. I'll start with the most basic digital data marshaling, and then introduce simple pointer marshaling and string marshaling.

Marshaling numbers and Logical scalars

Most Windows OS is written in C. Therefore, the data type used by the Windows API is either type C or Type C that is marked by a type definition or macro definition. Let's look at data marshaling with no pointers. For simplicity's sake, the first focus is on numbers and Boolean values.

When passing a parameter to a Windows API function by value, you need to know the answer to the following questions:

Is the data fundamentally integral or floating-point?

If the data is an integral type, is it signed or unsigned?

If the data is integral, what is the number of digits?

If the data is floating-point, is it a single or double precision?

Sometimes the answer is obvious, but sometimes it's not obvious. The Windows API redefined the basic C data type in a variety of ways. Aspx?fig=true#fig2 "target=" _blank > Figure 2 lists some common data types and their specifications for C and Win32, as well as a common language runtime type with a matching specification.

Typically, your code works correctly as long as you select a CLR type whose specification matches the Win32 type of the parameter. But there are some exceptions. For example, the BOOL type defined in the Windows API is a signed 32-bit integer. However, BOOL is used to indicate a Boolean value of true or false. Although you do not have to marshal the BOOL parameter as a System.Int32 value, you will get a more appropriate mapping if you use the System.Boolean type. The mapping of character types is similar to BOOL, because a particular CLR type (System.Char) indicates the meaning of the character.

After you know this information, it may be helpful to step through the sample. Still using the Beep theme as an example, let's try the Kernel32.dll low-level beep, which beeps through the computer's speakers. The Platform SDK documentation for this method can be found in the ASP "target=" _blank >beep. The native APIs are logged in the following ways:

BOOL Beep (  DWORD dwfreq,      //Frequency  DWORD dwduration   //Duration in milliseconds);

In the area of parameter marshaling, your job is to understand what CLR data types are compatible with the DWORD and BOOL data types used by Beep API functions. Looking back at the chart in Aspx?fig=true#fig2 "target=" _blank > Figure 2, you'll see that the DWORD is a 32-bit unsigned integer value, like CLR type System.UInt32. This means that you can use the UInt32 value as the two parameters sent to the Beep. The bool return value is a very interesting case, because the graph tells us that in Win32, BOOL is a 32-bit signed integer. Therefore, you can use the System.Int32 value as the return value from the Beep. However, the CLR also defines the System.Boolean type as the semantics of a Boolean value, so you should use it instead. The CLR marshals the System.Boolean value to a 32-bit signed integer by default. The external method definition shown here is the result P/invoke method for Beep:

[DllImport ("Kernel32.dll", setlasterror=true)]static extern Boolean Beep (   UInt32 frequency, UInt32 duration);

Pointer parameters

Many Windows API functions use pointers as one or more of their parameters. Pointers increase the complexity of marshaling data because they add a layer of indirection. If there is no pointer, you can pass the data through the thread stack of values. With a pointer, you can pass data by reference by pushing the memory address of that data onto the thread stack. The function then accesses the data indirectly through the memory address. There are several ways to represent this additional indirect layer using managed code.

In C #, if a method parameter is defined as ref or out, the data is passed by reference rather than by value. This is true even if you do not use Interop, but only from one managed method to another managed method. For example, if you pass the System.Int32 parameter by ref, the address of the data is passed in the thread stack, not the integer value itself. The following is an example of a method defined to receive an integer value by reference:

void FlipInt32 (ref Int32 num) {   num =-num;}

Here, the FlipInt32 method gets the address of a Int32 value, accesses the data, and then negation it, and assigns the negation value to the original variable. In the following code, the FlipInt32 method changes the value of the calling program's variable x from 10 to 10:

Int32 x = 10; FlipInt32 (ref x);

This ability can be reused in managed code to pass pointers to unmanaged code. For example, the Fileencryptionstatus API function returns the file encryption state in the form of a 32-bit unsigned bitmask. The API is logged as follows:

BOOL fileencryptionstatus (  lpctstr lpfilename,  //file name  lpdword lpstatus     //encryption status);

Note that the function does not return a state using its return value, but instead returns a Boolean value indicating whether the call succeeded. In the case of success, the actual state value is returned through the second argument. It works by calling the program to pass a pointer to the function that points to a DWORD variable that populates the memory location with the state value. The following code fragment shows a possible external method definition that calls an unmanaged Fileencryptionstatus function:

[DllImport ("Advapi32.dll", CharSet=CharSet.Auto)]static extern Boolean fileencryptionstatus (String filename,    Out UInt32 status);

The definition uses the OUT keyword to indicate the by-ref parameter for the UInt32 state value. Here I can also select the REF keyword, which actually produces the same machine code at run time. The Out keyword is simply a specification of a by-ref parameter that indicates to the C # compiler that the data being passed is passed only outside the called function. Conversely, if you use the REF keyword, the compiler assumes that the data can be passed inside and outside of the called function.

Another good aspect of the out and ref parameters in managed code is that the variable passed by the address as the By-ref parameter can be a local variable in the thread stack, an element of a class or struct, or an element reference in an array of the appropriate data type. This flexibility of the calling program makes the BY-REF parameter a good starting point for marshaling buffer pointers and single value pointers. I consider marshaling a pointer to a more complex CLR type (such as a class or an array object) only if I find that the ref or out parameter does not meet my needs.

If you are unfamiliar with C syntax or call Windows API functions, it is sometimes difficult to know whether a method parameter requires a pointer. A common indicator is to see whether the parameter type starts with the letter P or LP, such as Lpdword or pint. In these two examples, LP and P indicate that the parameter is a pointer, and that the data types they point to are either DWORD or INT. However, in some cases, you can define an API function as a pointer directly using the asterisk (*) in the C language syntax. The following code fragment shows an example of this:

void Takesapointer (dword* pnum);

As you can see, the only argument to the above function is a pointer to a DWORD variable.

When marshaling pointers through P/invoke, ref and out are used only for value types in managed code. When the CLR type of a parameter is defined with the struct keyword, the argument is considered to be a value type. Out and ref are used to marshal pointers to these data types because the usual value type variable is an object or data, and there is no reference to a value type in managed code. In contrast, the ref and out keyword is not required when marshaling reference type objects because the variable is already a reference to the object.

If you are not familiar with the difference between a reference type and a value type, check out MSDN®magazine, published in December 2000, to find out more about the topics in the. Net column. Most CLR types are reference types, but except for System.String and System.Object, all primitive types (such as System.Int32 and System.Boolean) are value types.

Marshaling opaque (Opaque) pointers: A special case

Sometimes in the Windows API, the pointer passed or returned by a method is opaque, meaning that the pointer value is technically a pointer, but the code does not use it directly. Instead, the code returns the pointer to Windows for later reuse.

A very common example is the concept of a handle. In Windows, internal data structures (buttons from files to screens) are represented as handles in the application code. The handle is actually an opaque pointer or a numeric value with a pointer width that the application uses to represent the internal OS constructs.

In rare cases, the API function also defines an opaque pointer as a pvoid or lpvoid type. In the definition of the Windows API, these types mean that the pointer has no type.

When an opaque pointer returns to your application (or your application expects to get an opaque pointer), you should marshal the parameter or return value as a special type of-system.intptr in the CLR. When you use the INTPTR type, out or ref parameters are not usually used, because IntPtr means to hold the pointer directly. However, if you marshal a pointer as a pointer, it is appropriate to use the By-ref parameter for INTPTR.

In a CLR type system, the System.IntPtr type has a special attribute. Unlike other base types in the system, INTPTR does not have a fixed size. Instead, its size at run time depends on the normal pointer size of the underlying operating system. This means that in 32-bit Windows, the width of the INTPTR variable is 32 bits, whereas in 64-bit Windows, the Just-in-time compiler compiles code that considers the INTPTR value to be a 64-bit value. This automatic sizing feature is useful when marshaling opaque pointers between managed and unmanaged code.

Keep in mind that any API function that returns or accepts a handle actually operates on an opaque pointer. Your code should marshal the handle in Windows to a system.intptr value.

You can cast the INTPTR value into a 32-bit or 64-bit integer value in managed code, or cast the latter to the former. However, when using Windows API functions, because pointers should be opaque, they cannot be used in addition to storing and passing to external methods. The two exceptions to this "store-and-pass" rule are when you need to pass NULL pointer values to external methods and need to compare INTPTR values with null values. To do this, you cannot cast 0 to System.IntPtr, and you should use Int32.zero static public fields on the INTPTR type to get null values for comparison or assignment.

Marshaling text

Text data is often processed when programming. The text creates some trouble for interop, for two reasons. First, the underlying operating system may use Unicode to represent a string, or it may use ANSI. In rare cases, for example, the two parameters of the MultiByteToWideChar API function are inconsistent on the character set.

The second reason is that when p/invoke is needed, it is also necessary to work with the text in particular to see how the C and CLR handle the text differently. In C, a string is actually just an array of character values, usually with NULL as the Terminator. Most Windows API functions handle strings in terms of ANSI, as an array of character values and, for Unicode, as an array of wide-character values.

Fortunately, the CLR is designed to be quite flexible, and when marshaling text, the problem is easily resolved without caring what Windows API functions expect from your application. Here are some key considerations to keep in mind:

Is your application passing text data to an API function, or does the API function return string data to your application? or both?

What kind of managed type should your external method use?

What is the format of an unmanaged string that the API function expects to get?

Let's first answer the last question. Most Windows API functions have LPTSTR or LPCTSTR values. (from a functional standpoint) they are modifiable and unmodified buffers that contain a null-terminated array of characters. "C" represents a constant, meaning that the parameter information is not passed to the outside of the function. The "T" in LPTSTR indicates that the parameter can be Unicode or ANSI, depending on the character set you select and the character set of the underlying operating system. Because most string parameters in the Windows API are one of these two types, as long as you select Charset.auto,clr in DllImportAttribute, you work in the default way.

However, some API functions or custom DLL functions represent strings in different ways. If you want to use one of these functions, you can use MarshalAsAttribute to modify the string arguments of the external method and indicate a string format different from the default LPTSTR. For more information about MarshalAsAttribute, see the Platform SDK documentation topic in the ASP "target=" _blank >marshalasattribute Class.

Now let's look at the direction in which string information is passed between your code and unmanaged functions. There are two ways to know the direction in which information is passed when a string is processed. The first and most reliable method is to first understand the purpose of the parameter. For example, if you are calling a parameter with a name similar to CreateMutex and with a string, you can imagine that the string information is passed from the application to the API function. Also, if you call GetUserName, the name of the function indicates that the string information was passed from the function to your application.

In addition to this more reasonable approach, the second way to find the direction of information delivery is to look for the letter "C" in the API parameter type. For example, the first parameter of the GetUserName API function is defined as the LPTSTR type, which represents a long pointer to a Unicode or ANSI string buffer. However, the CreateMutex name parameter is typed as LTCTSTR. Note that the type definition here is the same, but add a letter "C" to indicate that the buffer is constant and the API function cannot be written.

Once you have clarified whether the text parameter is used only as input or as input/output, you can determine which CLR type is used as the parameter type. Here are some rules. If the string parameter is used only as input, the System.String type is used. In managed code, strings are invariant and are suitable for buffers that are not changed by native API functions.

If the string parameter can be used as input and/or output, the System.stringbuilder type is used. The StringBuilder type is a useful class library type that can help you build strings efficiently, and it is possible to pass buffers to native functions that populate string data for you by native functions. Once the function call returns, you only need to invoke the StringBuilder object's ToString to get a String object.

GetShortPathName API functions are good for showing when to use string and when to use StringBuilder because it takes only three parameters: an input string, an output string, and a parameter that indicates the character length of the output buffer.

Aspx?fig=true#fig3 "target=" _blank "> Figure 3 shows the annotated unmanaged GetShortPathName function document, which also points to input and output string parameters. It leads to a managed external method definition, as well as aspx?fig=true#fig3 "target=" _blank > Figure 3. Note that the first parameter is marshaled to System.String because it is a parameter that is used only as input. The second parameter represents an output buffer that uses System.stringbuilder.

Summary

The P/invoke feature described in this month's column is sufficient to invoke many API functions in Windows. However, if you use interop heavily, you end up finding yourself marshaling a complex data structure, and you may even need to access the memory directly through the pointer in managed code. In fact, interop in native code can be a real Pandora's box that hides details and low-level bits inside. CLR, C #, and managed C + + provide a number of useful features; maybe later I'll introduce the Advanced P/invoke topic in this column.

At the same time, as long as you feel that the. Net Framework class Library cannot play your voice or perform other functions for you, you can learn how to seek help from the original and excellent Windows API.

Figure 1 MessageBeep, Interop done.

namespace wintellect.interop.sound{   using System;   Using System.Runtime.InteropServices;   Using System.ComponentModel;   Sealed class sound{public      static void MessageBeep (Beeptypes type) {         if (! MessageBeep ((UInt32) type)) {            Int32 err = Marshal.GetLastWin32Error ();            throw new Win32Exception (err);         }      [DllImport ("User32.dll", Setlasterror=true)]      static extern Boolean MessageBeep (UInt32 beeptype);      Private Sound () {}   }   enum beeptypes{simple       =-1,      Ok                = 0x00000000,      iconhand          = 0x00000010,      iconquestion      = 0x00000020,      iconexclamation   = 0x00000030,      iconasterisk      = 0x00000040   }}
Figure 2 Non-pointer Data Types

 
 
Win32 Types Specification CLR Type
Char, INT8, SBYTE, char†8-bit signed integer System.SByte
short, short int, INT16, short 16-bit signed integer System.Int16
int, long, long int, INT32, LONG32, boolâ€, int 32-bit signed integer System.Int32
__int64, INT64, Longlong 64-bit signed integer System.Int64
unsigned char, UINT8, ucharâ€, BYTE 8-bit unsigned integer System.Byte
Unsigned short, UINT16, USHORT, WORD, ATOM, wcharâ€, __wchar_t 16-bit unsigned integer System.UInt16
unsigned, unsigned int, UINT32, ULONG32, DWORD32, ULONG, DWORD, UINT 32-bit unsigned integer System.UInt32
Unsigned __int64, UINT64, Dwordlong, Ulonglong 64-bit unsigned integer System.UInt64
float, float Single-precision floating Point System.Single
Double, long double, double Double-precision floating Point System.Double
€in Win32 This type is the integer with a specially assigned meaning; In contrast, the CLR provides a specific type devoted to this meaning.
 
  
Figure 3 GetShortPathName Declarations
* * documentation for WIN32 GetShortPathName () API function//DWORD getshortpathname (//   LPCTSTR Lpszlongpath,      file for which to get short path//   LPTSTR Lpszshortpath,      //short path name (output)/   DWORD cchbuffer
  
   //size of output buffer//); [DllImport ("Kernel32", CharSet = CharSet.Auto)]static extern Int32 getshortpathname (   String path,                //input String   StringBuilder ShortPath,    //output string   Int32 shortpathlength);     Stringbuilder.capacity
  


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.