Marshaling with C# – Chapter 2: Marshaling Simple Types

Read the full book here.

Chapter Contents

Contents of this chapter:

  • Chapter Contents
  • Overview
  • Simple and Compound data Types
  • Blittable and Non-Blittable Data Types
  • Marshaling Blittable Data Types
    • Numeric Data Types
    • Textual Data Types
    • Examining Type Definition
    • Variants
    • Try It Out!
  • A Rule of Thumb
  • Marshaling Booleans
    • The Two Types
    • Try It Out!
  • Marshaling Textual Data types
    • How to Marshal Strings and Buffers
    • Handling Character Encoding
    • Try It Out!
  • Marshaling Handles
    • Generic Handles
    • Safe Handles
    • Critical Handles
  • Passing Mechanism
  • Additional Techniques
    • Encapsulation
    • Creating Wrappers
    • Working with Nullable Arguments
    • Working out the CLS Problem
  • Real-World Examples
    • Programmatically Swapping Mouse Buttons
    • Programmatically Turning On the Screen Saver
    • Dragging a Form without a Title Bar
  • Summary

Overview

This chapter discusses the nitty-gritty part of marshaling process. It is the base for the rest of discussion about marshaling. It is about marshaling simple data types.

The first section of this chapter breaks data types into two categories, simple and compound. Simple types (integers, booleans, etc.) are those that are not made of other types. On the contrary, compound types (structures and classes) are those types that require special handling and made of other types.

After that, we will dig into the discussion of simple types and we will break them into two categories, blittable and non-blittable.

Before we end this chapter, we will discuss the passing mechanism and handles in .NET Framework.

Simple and Compound Data Types

There are two kinds of data types:

  • Simple (primitive/basic)
  • Compound (complex)

Primitive data types are those that are not defined in terms of other data types. They are the basis for all other types. Examples of managed primitives are numbers like System.Byte, System.Int32, System.UInt32, and System.Double, strings like System.Char and System.String, and handles like System.IntPtr.

Compound data types are those that built up of other data types. For example a class or a structure that encapsulates simple types and other compound types.

We will use terms simple, primitive, and basic types to refer to base types like integers, strings, etc. Terms compound, and complex types also will be used interchangeably to refer to classes and structures.

Some considers that strings are not primitives.

Blittable and Non-Blittable Data Types

Most data types have common representations in both managed and unmanaged memory and do not require special handling. These types are called blittable types because they do not require special handling when passed between managed and unmanaged code. Other types that require special handling are called non-blittable types. You can think that most of simple types are blittable and all of compound types are non-blittable.

The following table lists the blittable data types exist in .NET (their counterparts in unmanaged code will be covered soon):

Table 2.1 Blittable Types

Description Managed Type
8-bit signed integer. System.SByte
8-bit unsigned integer

System.Byte

16-bit signed integer.

System.Int16

16-bit unsigned integer

System.UInt16

32-bit signed integer

System.Int32

32-bit unsigned integer

System.UInt32

64-bit signed integer

System.Int64

64-bit unsigned integer

System.UInt64

Signed pointer

System.IntPtr

Unsigned pointer

System.UIntPtr

More information about pointers later in this chapter.

Marshaling Blittable Data Types

You can marshal an unmanaged simple data type by tracking its definition then finding its counterpart (marshaling type) in the managed environment based on its definition (we will see how soon.)

Numeric Data Types

The following table lists some of the unmanaged data types in Windows, their C/C++ keywords, and their counterparts (marshaling types) in .NET. As you might guess, by tracking each of these unmanaged types, we were able to find its managed counterpart. Notice that so

Table 2.2 Numeric Data Types

Description Windows Type C/C++ Keyword Managed Type C# Keyword
8-bit unsigned integer BYTE unsigned char System.Byte Byte
16-bit signed integer SHORT Short System.UInt16 ushort
16-bit unsigned integer WORD and USHORT unsigned short System.Int16 short
32-bit signed integer INT, INT32, LONG, and LONG32 int, long System.UInt32 Uint
32-bit unsigned integer DWORD, DWORD32, UINT, and UINT32 unsigned int, unsigned long System.Int32 int
64-bit signed integer INT64, LONGLONG, and LONG64 __int64, long long System.UInt64 ulong
64-bit unsigned integer DWORDLONG, DWORD64, ULONGLONG, and UINT64 unsigned __int64, unsigned long long System.Int64 long
Floating-point integer FLOAT float System.Double double

Notice that long and int defer from a platform to another and from a compiler to another. In 32-bit versions of Windows, most compilers refer to both long and int as 32-bit integers.

Know that there is no difference between Windows data types and C/C++ data types. Windows data types are just aliases for the actual C types.

Do not be confused with the many types that refer to one thing, they are all just names (aliases.) INT, INT32, LONG, and LONG32 are all 32-bit integers for instance.

To keep things simple, we will focus on Windows API in our examples.

Although, some unmanaged types have names similar to names of some managed types, they have different meanings. An example is LONG, it has similar name as System.Long. However, LONG is 32-bit and System.Long is 64-bit!

If you need to learn more about these types, check out the article Windows Data Types in MSDN library.

Textual Data Types

In addition to the numeric data types, you will need to know how to marshal unmanaged textual data types (a single character or a string.) However, these types are non-blittable, so they require special handling.

The following table lists briefly unmanaged textual data types.

Table 2.3 Textual Data Types

Description Unmanaged Type(s) Managed Type
8-bit ANSI character CHAR System.Char
16-bit Unicode character WCHAR System.Char
8-bit ANSI string of characters LPSTR, LPCSTR, PCSTR, and PSTR System.String
16-bit Unicode string of characters LPCWSTR, LPWSTR, PCWSTR, and PWSTR System.String

Soon we will cover textual data types in details.

Examining Type Definition

As we have said, for the sake of simplicity, we will use Windows API as the base for our discussion in this book. Therefore, you need to know that all Windows Data Types (INT, DWORD, etc.) are just names (technically, typedefs) for the actual C types. Therefore, many names may refer to one thing just as INT and LONG.

Thus, we can say that LONG is defined as C int and DWORD is defined as C unsigned long.

INT and LONG are easy to marshal. However, there are primitive types that you will need to track their definitions to know how to marshal it.

Remember that we will use MSDN documentation (specially the article €œWindows Data Types€) when tracking unmanaged data types (Windows data types specially.)

The next are some of the types defined as another types. You can think of these types as aliases for the base types. Yet, some are platform-specific, and others not.

  • HRESULT:
    As you will see, plenty of functions return a HRESULT to represent the status of the operation. If HRESULT equals to zero, then the function succeeded, otherwise it represents the error code or status information for the operation. HRESULT defined as LONG, and LONG in turn defined as a 32-bit signed integer. Therefore, you can marshal HRESULT as System.Int32.
  • BOOL and BOOLEAN:
    Both are Boolean types, that means that they take either TRUE (non-zero) or FALSE (zero.) The big difference between BOOL and BOOLEAN is that BOOL is defined as INT, thus occupies 4 bytes. BOOLEAN on the other hand is defined as BYTE, thus occupies only 1 byte. Booleans are covered soon.
  • HFILE:
    A handle to a file opened using one of the Windows File IO functions like OpenFile() function. This type is defined as INT, and INT in turn is defined as a 32-bit signed integer. Therefore, you can marshal HFILE as System.Int32. Although, HFILE defined as INT, handles should be marshaled as System.IntPtr, which is internally encapsulates the raw handle. To be clear, you would better marshal an unmanaged handle as a System.Runtime.InteropServices.SafeHandle or CriticalHandle, this is the ideal marshaling type for any handle. Hence, file handles best marshaled as Microsoft.Win32.SafeHandles.SafeFileHandle that is derived from SafeHandleZeroOrMinusOneIsInvalid that is in turn derived from the abstract class System.Runtime.InteropServices.SafeHandle. For more details about handles, refer to the section “Marshaling Handles” later in this chapter.

In addition, there are types that are variable based on the operating system. Examples are:

  • INT_PTR:
    A pointer to a signed integer. Defined as INT64 if this is a 64-bit OS, or INT otherwise.
  • LONG_PTR:
    A pointer to a signed long. Defined as INT64 if this is a 64-bit OS, or LONG otherwise.
  • UINT_PTR:
    A pointer to an unsigned integer. Defined as DWORD64 if this is a 64-bit OS, or DWORD otherwise.
  • ULONG_PTR:
    A pointer to an unsigned long. Defined as DWORD64 if this is a 64-bit OS, or DWORD otherwise.

Keep in mind that there is a big difference between a variable and a pointer to a variable. A variable refers directly to its value into the memory. However, a pointer contains an address of another value into the memory. Consider the following illustration, Figure 2.1:

Figure 2.1 - Pointers into Memory

Figure 2.1 - Pointers into Memory

In the illustration above, the variable i contains the value 320 and you can get the value from the variable directly. The pointer ptr on the other hand contains the address of the variable i. Thus, it indirectly contains the value of the variable i. That is why we cannot get the value of the pointer directly. We need to dereference it first before retrieving its value.

More on pointers later in this chapter. Memory management is discussed in details in chapter 6.

In addition, for textual data types, there are types variable based on Unicode definition (strings and buffers are covered soon.) Examples are:

  • TBYTE and TCHAR:
    Defined as WCHAR if UNICODE defined, otherwise CHAR.
  • LPCTSTR, LPTSTR, and PCTSTR:
    All defined as LPCWSTR if UNICODE defined, otherwise LPCSTR.
  • PTSTR:
    Defined as PWSTR if UNICODE defined, otherwise PSTR.

More on textual data types and Unicode later in this chapter.

Notice that some types have special characters in their names. For example, A in textual data types stands for ANSI, and W in stands for Wide, which means Unicode. In addition, the letter T in textual information too means it varies based on OS. Another example is the prefix P (lowercase,) it means a pointer, and LP means a long pointer. LPC stands for long pointer to a constant.

Variants

In addition, Win32 API defines the types VOID, LPVOID, and LPCVOID. VOID indicates that the function does accept no arguments. Consider the following function:

DWORD GetVersion(VOID);

It is required to tag the function with VOID if it does not accept any arguments (that is one of the specifications of C89.) Notice that VOID is defined as void.

LPVOID and LPCVOID are defined as any type (variant). That means that they can accept any value. They can be marshaled as integers, strings, handles, or even compound types, anything you want. In addition, you can marshal them as System.IntPtr, so you can set them to the address of any object in memory. In addition, you can marshal them as pointers to object. For example, marshaling a LPCVOID as System.Int32* (a pointer to an integer) in unsafe code. Moreover, you can use unsafe code and marshal them as void*. Furthermore, you can marshal them as System.Object, so you can set them to any type (refer to chapter 6 for more information about memory management and unsafe code.)

It is worth mentioning that when working with VOIDs it is recommended decorating your variable with MarshalAsAttribute attribute specifying UnmanagedType.AsAny which tells the compiler to work out the marshaling process and sets the type of the argument at runtime. Refer to the last chapter: “Controlling the Marshaling Process” for more information about this attribute.


If you have worked with traditional Visual Basic, thinking about LPVOID and LOCVOID as a Variant could help too much.

If you are interoperating with the traditional Visual Basic code, you can use the same way we did on marshaling LPVOID and LPCVOID in marshaling the type Variant.

Try It Out!

Now, we will try to create the PInvoke method for the MessageBoxEx() function. The example demonstrates how to control precisely the marshaling process using the MarshalAsAttribute attribute. We will cover this attribute and more in the last chapter of this book: “Controlling the Marshaling Process.” Handles are covered in the section: “Marshaling Handles” of this chapter.

The following example creates the PInvoke method for the MessageBoxEx() function and calls it to display a friendly message to the user.

The definition of the MessageBoxEx() function is as following:

Listing 2.1 MessageBoxEx() Unmanaged Signature

int MessageBoxEx(
    HWND hWnd,
    LPCTSTR lpText,
    LPCTSTR lpCaption,
    UINT uType,
    WORD wLanguageId);

And here is the managed signature (the PInvoke method) of this function:


In order for the example to run you must add a using statement to System.Runtime.InteropServices namespace. Be sure to add it for all examples throughout this book.

Listing 2.2 MessageBoxEx() Managed Signature

     // CharSet.Unicode defines the UNICODE.
     // Use either this way to control
     // the whole function, or you can control
     // the parameters individually using the
     // MarshalAsAttribute attribute
     [DllImport("User32.dll", CharSet = CharSet.Unicode)]
     [return: MarshalAs(UnmanagedType.I4)]
     static extern Int32 MessageBoxEx
         (IntPtr hWnd,
         // Marshaling as Unicode characters
         [param: MarshalAs(UnmanagedType.LPTStr)]
         String lpText,
         // Marshaling as Unicode characters
         [param: MarshalAs(UnmanagedType.LPTStr)]
         String lpCaption,
         // Marshaling as 4-bytes (32-bit) unsigned integer
         [param: MarshalAs(UnmanagedType.U4)]
         UInt32 uType,
         // Marshaling as 2-bytes (16-bit) unsigned integer
         [param: MarshalAs(UnmanagedType.U2)]
         UInt16 wLanguageId);

For more information about marshaling strings, see section €œMarshaling Strings and Buffers€ later in this chapter.

A Rule of Thumb

Keep in mind that. .NET Framework allows you to take a granular level of control over the marshaling process and that would be very complicated. However, things can be so simple.

You can ignore attributes in most cases and just use the counterparts and CLR will do its best. Likely, you are not required to use managed signed integers for unmanaged equivalents. You can use managed signed integers for unmanaged unsigned integers and vice versa. You can also marshal a SHORT as System.Char!

The key point is that as long as the managed marshal type occupies the same memory size as the unmanaged type, you are in safe. However, keeping things in its right position helps avoiding undesirable errors that maybe very difficult to know and handle.

Another thing that you should keep in mind that the information in this book can be applied to any unmanaged environment. You can apply this information when interoperating with Windows API, C/C++ libraries, Visual Basic, COM, OLE, ActiveX, etc. However, for the sake of simplicity, we will talk about the Windows API as the source of the unmanaged code.

Marshaling Booleans

The Two Types

In general, marshaling simple data types is very easy and booleans are no exception. However, Booleans are non-blittable types. Therefore, they require some handling.

There are some notes about marshaling booleans in the managed environment. The first thing to mention about is that Windows defines two types of Boolean variables:

  1. BOOL:
    Defined as INT, therefore, it is 4-bytes wide.
  2. BOOLEAN:
    Defined as BYTE, therefore it is only 1-byte.

Both can be set to non-zero to indicate a true (TRUE) value, and zero otherwise (FALSE.)

Again, the two types exist only in the Windows SDK. Other environments may define other types with similar names.

While it is true that BOOL and BOOLEAN are best marshaled as System.Boolean, BOOL can be marshaled as System.Int32 too, because it is defined as a 32-bit integer. On the other hand, BOOLEAN can be marshaled as System.Byte or System.U1, because it is defined as 8-bits integer. Do you remember the rule of thumb?

Take into consideration that whether you are marshaling your Boolean type to System.Boolean, System.Int32, or System.Byte, it is recommended that you apply MarshalAsAttribute attribute to the variable to specify the underlying unmanaged type. For example, to specify that the underlying type is BOOL, specify UnmanagedType.Bool (recommended) or UnmanagedType.I4 in the MarshalAsAttribute constructor. On the other hand, BOOLEAN can be specified as UnmanagedType.U1. If you omit MarshalAsAttribute, CLR assumes the default behavior for System.Boolean, which is 2 bytes wide. For more information about MarshalAsAttribute attribute, see the last chapter: “Controlling the Marshaling Process.”

Try It Out!

Fortunately, plenty of functions return BOOL indicating whether the function succeeded (TRUE) or failed (FALSE.)

The following is the definition of the famous CloseHandle() function:

Listing 2.3 CloseHandle() Unmanaged Signature

BOOL CloseHandle(HANDLE hObject);

The managed version of CloseHandle() is as following:

Listing 2.4 CloseHandle() Managed Signature

     [DllImport("Kernel32.dll")]
     [return: MarshalAs(UnmanagedType.Bool)]
     // In addition, you can marshal it as:
     // [return: MarshalAs(UnmanagedType.I4)]
     // Moreover, You can change System.Boolean to System.Int32
     static extern Boolean CloseHandle(IntPtr hObject)

Handles covered soon. For now, it is OK to know that all handles marshaled to System.IntPtr.

Marshaling Textual Data Types

How to Marshal Strings and Buffers

This section discusses how to marshal strings and buffers. We will use the terms string and buffer interchangeably to refer to a sequence of characters.

Two types exist in the managed environment for marshaling unmanaged string buffers. They are System.String and System.Text.StringBuilder. Of course, they both hold character sequences. However, StringBuilder is more advantageous because it is very efficient working with mutable strings than System.String.

Every time you use one of the methods of System.String class or you pass a System.String to a function, normally, you create a new string object in memory, which requires a new allocation of memory space for the new object. In addition, if the function changes the string you will not get the results back. That is why System.String is called immutable. On the other hand, StringBuilder does not require re-allocating of space unless you exceed its capacity. Besides the talk about marshaling, you should use StringBuilder to accommodate performance issues if you often change the same string many times.

To keep System.String immutable, the marshaler copies the contents of the string to another buffer before calling the function, and then it passes that buffer to the function. If you were passing the string by reference, the marshaler copies the contents of the buffer into the original string when returning from the function.

Conversely, when using StringBuilder, it passes a reference to the internal buffer of StringBuilder if passed by value. Passing a StringBuilder by reference actually passes a pointer to the StringBuilder object into memory to the function not a pointer to the buffer itself.

Read more about passing a type by value or by reference in the section “Passing Mechanism” later in this chapter.

Another feature of StringBuilder is its ability to specify buffer capacity. As we will see, this can be very helpful in plenty of cases.

To summarize, System.String is preferable when working with immutable strings, especially for input (In) arguments. On the other hand, System.Text.StringBuilder is preferable with changeable strings especially output (Out) arguments.

Noteworthy to say that StringBuilder cannot be used inside compound types. Therefore, you will need to use String instead.

Another point to mention is that you can pass array of System.Char in place of a System.String or System.Text.StringBuilder. In other words, you can marshal unmanaged strings as managed arrays of System.Char (or System.Int16, do you remember?)

Compound types discussed in the next chapter.

Handling Character Encoding

Encoding of a character is very important because it determines the value that the character can hold and the size it occupies into memory. For example, if the character is ANSI-encoded it can be one of only 256 characters. Likewise, if it is Unicode-encoded, it can hold one of 65536 characters, which is very good for most languages.

If you need more information about Unicode, you can check the official site of Unicode, www.Unicode.org. In addition, Programming Windows 5th by Charles Petzold includes a must-read introduction of Unicode and character sets.

For controlling character encoding when marshaling unmanaged types, you may take one of two approaches or you can combine them as needed. You can control the encoding of the overall function (i.e. at the function level,) or you can drill down and control the encoding process at a granular level by controlling every argument separately (the second approach is required in certain cases e.g. MultiByteToWideChar() function.)

For changing the encoding of the overall function, DllImportAttribute offers the property CharSet that indicates the encoding (character set) for the strings and arguments of the function. This property can take one of several values:

  • CharSet.Auto (CLR Default):
    Strings encoding varies based on operating system; it is Unicode-encoded on Windows NT and ANSI-encoded on other versions of Windows.
  • CharSet.Ansi (C# Default):
    Strings are always 8-bit ANSI-encoded.
  • CharSet.Unicode:
    Strings are always 16-bit Unicode-encoded.
  • CharSet.None:
    Obsolete. Has the same behavior as CharSet.Ansi.

Take into consideration that if you have not set the CharSet property, CLR automatically sets it to CharSet.Auto. However, some languages override the default behavior. For example, C# defaults to CharSet.Ansi.

It is worth mentioning that plenty of functions that accept strings and buffers are just names (technically typedefs)! They are not real functions, they are entry-points (aliases) for the real functions. For example, ReadConsole() function is nothing except an entry point redirects the call to the right function, either ReadConsoleA() if ANSI is defined, or ReadConsoleW() if Unicode is defined (A stands for ANSI, and W stands for Wide which means Unicode.) Therefore, you can actually bypass this entry-point by changing the PInvoke method name to match the right function or by changing DllImportAttribute.EntryPoint to the name of the required function. In both cases, setting DllImportAttribute.CharSet along with is no use.

If you want to control the encoding at a granular level, you can apply the MarshalAsAttribute attribute to the argument specifying the underlying unmanaged type.

Usually, you will need to unify the character encoding of all your native functions and types. This is, all the functions should be either Unicode or ANSI. Under rare occasions, some functions would be different in character encoding.

It is worth mentioning that, for fixed-length strings you will need to set the SizeConst property of MarshalAsAttribute to the buffer length.

These techniques are not limited to arguments only! You can use them with variables of compound types too. We will look at compound types in the following chapter.

Try It Out!

Now we will look on both ReadConsole() and FormatConsole() unmanaged functions and how to call them from your managed environment. Next is the definition of both functions and other functions required for the example:

Listing 2.5 GetStdHandle(), ReadConsole(), GetLastError(), and FormatMessage() Unmanaged Signature

HANDLE GetStdHandle(
  DWORD nStdHandle);

BOOL ReadConsole(
  HANDLE hConsoleInput,
  [out] LPVOID lpBuffer,
  DWORD nNumberOfCharsToRead,
  [out] LPDWORD lpNumberOfCharsRead,
  LPVOID lpReserved);

DWORD GetLastError(void);

DWORD FormatMessage(
  DWORD dwFlags,
  LPCVOID lpSource,
  DWORD dwMessageId,
  DWORD dwLanguageId,
  [out] LPTSTR lpBuffer,
  DWORD nSize,
  va_list* Arguments);

And this is the managed version along with the test code.

Listing 2.6 Reading from the Console Screen Buffer Example

        // For retrieving a handle to a specific console device
        [DllImport("Kernel32.dll")]
        static extern IntPtr GetStdHandle(
            [param: MarshalAs(UnmanagedType.U4)]
            int nStdHandle);

        // Used with GetStdHandle() for retrieving console input buffer
        const int STD_INPUT_HANDLE = -10;

        // Specifying the DLL along with the character set
        [DllImport("Kernel32.dll", CharSet = CharSet.Unicode)]
        [return: MarshalAs(UnmanagedType.Bool)]
        static extern bool ReadConsole(
            // Handle to the input device
            IntPtr hConsoleInput,
            // The buffer of which to write input to
            [param: MarshalAs(UnmanagedType.LPTStr), Out()]
            // [param: MarshalAs(UnmanagedType.AsAny)]
            StringBuilder lpBuffer,
            // Number of characters to read
            [param: MarshalAs(UnmanagedType.U4)]
            uint nNumberOfCharsToRead,
            // Outputs the number of characters read
            [param: MarshalAs(UnmanagedType.U4), Out()]
            out uint lpNumberOfCharsRead,
            // Reserved = Always set to NULL
            [param: MarshalAs(UnmanagedType.AsAny)]
            uint lpReserved);

        // For getting the code for the last error occurred
        [DllImport("Kernel32.dll")]
        [return: MarshalAs(UnmanagedType.U4)]
        static extern uint GetLastError();

        // Retrieves error messages
        [DllImport("Kernel32.dll", CharSet = CharSet.Unicode)]
        [return: MarshalAs(UnmanagedType.U4)]
        static extern uint FormatMessage(
            // Options
            [param: MarshalAs(UnmanagedType.U4)]
            uint dwFlags,
            // Source to get the message from
            // [param: MarshalAs(UnmanagedType.AsAny)]
            [param: MarshalAs(UnmanagedType.U4)]
            uint lpSource,
            // Message code = error code
            [param: MarshalAs(UnmanagedType.U4)]
            uint dwMessageId,
            // Language ID (Reserved)
            [param: MarshalAs(UnmanagedType.U4)]
            uint dwLanguageId,
            // Outputs the error message
            [param: MarshalAs(UnmanagedType.LPTStr), Out()]
            out string lpBuffer,
            // Size of error message
            [param: MarshalAs(UnmanagedType.U4)]
            uint nSize,
            // Additional options
            [param: MarshalAs(UnmanagedType.U4)]
            uint Arguments);

        // Message Options
        const uint FORMAT_MESSAGE_ALLOCATE_BUFFER = 0x0100;
        const uint FORMAT_MESSAGE_IGNORE_INSERTS = 0x0200;
        const uint FORMAT_MESSAGE_FROM_SYSTEM = 0x1000;
        const uint FORMAT_MESSAGE_FLAGS =
            FORMAT_MESSAGE_ALLOCATE_BUFFER |
            FORMAT_MESSAGE_IGNORE_INSERTS |
            FORMAT_MESSAGE_FROM_SYSTEM;

        // Message Source
        public const int FORMAT_MESSAGE_FROM_HMODULE = 0x0800;

        static void Main()
        {
            // Handle to input buffer
            IntPtr handle = GetStdHandle(STD_INPUT_HANDLE);

            const int maxCount = 256;

            uint noCharacters;
            StringBuilder builder = new StringBuilder(maxCount);

            if (ReadConsole(handle, builder, (uint)maxCount,
                out noCharacters, 0) == false) // false = non-zero = failed
            {
                string errMsg;
                FormatMessage(FORMAT_MESSAGE_FLAGS,
                    FORMAT_MESSAGE_FROM_HMODULE,
                    GetLastError(),
                    0,  // Means NULL
                    out errMsg,
                    0,  // Maximum length
                    0); // Means NULL

                Console.WriteLine("ERROR:n{0}", errMsg);
            }
            else // true = zero = succeeded
                // Writing user input withour the newline
                Console.WriteLine("User wroted: = " +
                    builder.ToString().Substring(0,
                    builder.Length - Environment.NewLine.Length));

            Console.WriteLine(new string('-', 25));

            builder = new StringBuilder(maxCount);

            // Invalid handle
            handle = GetStdHandle(12345);

            if (ReadConsole(handle, builder, (uint)maxCount,
                out noCharacters, 0) == false) // false = non-zero = failed
            {
                string errMsg;
                FormatMessage(FORMAT_MESSAGE_FLAGS,
                    FORMAT_MESSAGE_FROM_HMODULE,
                    GetLastError(),
                    0,  // Means NULL
                    out errMsg,
                    0,  // Maximum length
                    0); // Means NULL

                Console.WriteLine("ERROR: {0}", errMsg);
            }
            else // true = zero = succeeded
                // Exculding the newline characters
                Console.WriteLine("User wroted: = " +
                    builder.ToString().Substring(0,
                    builder.Length - Environment.NewLine.Length));
        }

The last code demonstrates other useful techniques:

  • Until now, handles should be marshaled as System.IntPtr. The following section talks in details about handles.
  • Because LPVOID and LPCVOID are both defined as a pointer to a variant (i.e. any type,) you can set them to any type you want. They are very similar to System.Object in the .NET methodology or Variant for people who are familiar with the traditional Visual Basic. In our example, we have marshaled LPVOID as System.UInt32 and set it to zero. Again, you are free to play with the marshaling types. LPVOID and LPCVOID are both 32-bit integer. Why not just marshaling them as any of the 32-bit managed types and forgetting about them? In addition, you can marshal it as System.IntPtr, and pass it System.IntPtr.Zero to indicate a NULL value. Moreover, you can marshal it as System.Object, and set it to any value, even null to indicate the NULL value. Variant has been discussed in details previously in the section €œMarshaling Blittable Data Types.€
  • va_list* is a pointer to an array of specific arguments. You can marshal it as an array, or System.IntPtr. System.IntPtr is preferred if you intend to pass it a NULL value.
  • If the function requires a parameter passed by value or by reference you can add the required modifiers like ref and out to the parameter, and decorate the parameter with either InAttribute or OutAttribute, or both. The section €œPassing an Argument by Value or by Reference€ later in this chapter discusses by-value and by-reference parameters.
  • While DWORD is defined as unsigned 32-bit integer and it should be marshaled as System.UInt32, we find that the GetStdHandle() can take one of three values: -10 for the input device, -11 for the output device, and -12 for the error device (usually is the output device.) Although System.UInt32 does not support negative values, Windows handles this for you. It converts the signed value to its equivalent unsigned value. Therefore, you should not worry about the value passed. However, keep in mind that the unsigned values are too different (from the perspective of most developers.) For example, the unsigned value of -11 is 0xFFFFFFF5! Does this seem strange for you? Start by consulting the documentation about binary notation.

Marshaling Handles

Generic Handles

What is a handle? A handle is a pointer to some resource loaded in memory, such as handles to the console standard input, output, and error devices, the handle for the window, and the handle to a device context (DC.)

There are plenty of type handles in unmanaged code, here is some of them:

  • HANDLE:
    This is the most widely used handle type in the unmanaged environment. It represents a generic handle.
  • HWND:
    Most widely used with Windows application. It is a handle to a window or a control.
  • HDC, HGDIOBJ, HBITMAP, HICON, HBRUSH, HPEN, and HFONT:
    If you have worked with GDI, you will be familiar with these handles. HDC is a handle to a device context (DC) object that will be used for drawing. HGDIOBJ is a handle for any GDI object. HBITMAP is a handle to a bitmap, while HICON is a handle to an icon. HBRUSH is a handle to a brush, HPEN is a handle to pen, and HFONT is a handle to a font.
  • HFILE:
    A handle to a file opened by any of Windows File IO functions like OpenFile() function.
  • HMENU:
    A handle to a menu or menu item.

Again, from all you have seen, you may have noticed that most types identified by a prefix or a suffix. For example, handles prefixed with the letter H, while some pointers have the suffix _PTR, or the prefix P or LP. While strings with letter W are Unicode-encoded, and strings with letter T are OS-based.

Handles can be marshaled as the managed type System.IntPtr that represents a pointer to an object into memory. It is worth mentioning that because System.IntPtr represents a pointer to an object no matter what the object is, you can use System.IntPtr for marshaling any type not handles only, but that is not recommended because it is more difficult to work with, and it is not very flexible, but it provides more control over the object in memory. For more information about memory management, see chapter 6: €œMemory Management.€

In addition, starting from version 2.0, new managed types for working with unmanaged handles added to the .NET Framework. A new namespace Microsoft.Win32.SafeHandles that contains most of the new types has been added too. Other types exist in System.Runtime.InteropServices. These types called managed handles.

Managed handles allow you to pass, to unmanaged code, a handle to an unmanaged resource (such as DC) wrapped by managed class.

There are two kinds of managed handles safe and critical handles.

Safe handles

Safe handles represented by the abstract System.Runtime.InteropServices.SafeHandle. Safe handles provide protection from recycling security attacks by perform reference counting (and that makes safe handles slower.) In addition, it provides critical finalization for handle resources. As a refresher, finalization means releasing the object and its resources from the memory, and critical finalization ensures object finalization under any circumstances. Figure 2.2 shows the definition of SafeHandle and its descendants.

Figure 2.2 SafeFileHandle and Descendants Class Definitions

Figure 2.2 SafeFileHandle and Descendants Class Definitions

As the diagram illustrates, SafeHandle is the base class that represents any safe handle. It inherits from System.Runtime.ConstrainedExecution.CriticalFinalizerObject that ensures the finalization process. The following are the most common members of SafeHandle:

  • IsClosed:
    Returns a value indicates whether the handle is closed.
  • IsInvalid:
    Abstract. If overridden, returns a value indicates whether the handle is invalid or not.
  • Close() and Dispose():
    Both close the handle and dispose its resources. Internally, they rely on the abstract method ReleaseHandle() for releasing the handle. Therefore, classes inherit from SafeHandle must implement this member. Be aware that Dispose() is inherited from System.IDispose interface that is implemented by SafeHandle, and Close() does not do anything except calling the Dispose() method. Therefore, you strictly should dispose (close) the handle as soon as you finish your work with it.
  • ReleaseHandle():
    Protected Abstract. Use to provide handle clean-up code. This function should returns true if successfully released, or false otherwise. In the case of false, it generates a ReleaseHandleFailed Managed Debugging Assistant (MDA) exception that will not interrupt your code but provides you with a bad sign about it. Keep in mind that ReleaseHandle() called internally by Dispose().
  • SetHandle():
    Protected. Sets the handle to the specified pre-existing handle.
  • SetHandleAsInvalid():
    Sets the handle as invalid so it is no longer used.
  • DangerousGetHandle():
    Returns System.IntPtr that represents the handle. Beware that if you have called SetHandleAsInvalid() before calling DangerousGetHandle(), it returns the original handle not the invalid one.
  • DangerousRelease():
    Manually releasing the handle in unsafe manner. It is recommended using Close() or Dispose() methods instead.
  • DangerousAddRef():
    Increments the reference count of the handle. It is not recommended using neither DangerousRelease() nor DangerousAddRef(), use safe methods instead. However, when working with COM, you will find yourself using these functions

Do not use unsafe methods unless you really need to use it because they pass the protection level offered by safe handles.

Because SafeHandle is abstract, you must either implement it or use one of its implementation classes. Only two classes from the new namespace Microsoft.Win32.SafeHandles implement SafeHandle, both are abstract too:

  • SafeHandleMinusOneIsInvalid:
    Represents a safe handle of which a value of -1 indicates that the handle is invalid. Therefore, IsInvalid returns true only if the handle equals to -1.
  • SafeHandleZeroOrMinusOneIsInvalid:
    Represents a safe handle of which a value of 0 or -1 indicates that the handle is invalid. So, IsInvalid returns true only if the handle equals to 0 or -1.

Notice that, choosing between the two implementations is up to the type of the underlying handle. If it considered invalid if set to -1, use SafeHandleMinusOneIsInvalid. If it considered invalid if set to 0 or -1, use SafeHandleZeroOrMinusOneIsInvalid. Using the right class for the handle ensures that methods like IsInvalid() returns correct results. It also ensures that CLR will mark the handle as garbage only if it is invalid.

If you need to provide a safe handle for your object, you will need to inherit from SafeHandleMinusOneIsInvalid, SafeHandleZeroOrMinusOneIsInvalid, or even from SafeHandle. Be aware that, you will always need to override the ReleaseHandle() method because neither SafeHandleMinusOneIsInvalid nor SafeHandleZeroOrMinusOneIsInvalid does override it.

As the diagram illustrates, two concrete classes inherit from SafeHandleZeroOrMinusOneIsInvalid:

  • SafeFileHandle:
    A wrapper class for an IO device handle (e.g. HFILE.) This class internally overrides the ReleaseHandle() and calls the unmanaged CloseHandle() function to close the handle. Use when working with HFILE handles in Windows File IO functions like OpenFile() and CreateFile(). Internally, System.FileStream uses a HFILE as SafeFileHandle, and it exposes a constructor that accepts SafeFileHandle.
  • SafeWaitHandle:
    If you are working with unmanaged thread synchronization objects like a Mutex or an Event, then this should be the desired marshaling type for synchronization objects’ handles.

Now, we are going to create a file using CreateFile() function with SafeFileHandle for the marshaling process. The definition of CreateFile() is as following:

Listing 2.7 CreateFile() Unmanaged Signature

HANDLE CreateFile(
  LPCTSTR lpFileName,
  DWORD dwDesiredAccess,
  DWORD dwShareMode,
  LPSECURITY_ATTRIBUTES lpSecurityAttributes,
  DWORD dwCreationDisposition,
  DWORD dwFlagsAndAttributes,
  HANDLE hTemplateFile
);

In addition, here is the .NET code:

Listing 2.8 Create File Example

    [DllImport("Kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    static extern SafeFileHandle CreateFile(
        string lpFileName,
        uint dwDesiredAccess,
        uint dwShareMode,
        // Because we are going to set the argument
        // to NULL we marshaled it as IntPtr
        // so we can set it to IntPtr.Zero
        // to represent a NULL value
        IntPtr lpSecurityAttributes,
        uint dwCreationDisposition,
        uint dwFlagsAndAttributes,
        // A handle for a template file
        // we are going to set it to NULL
        // so e can marshal it as System.IntPtr
        // and pass IntPtr.Zero for the NULL value
        // But, this is another way
        SafeFileHandle hTemplateFile);

    // Accessing the file for writing
    const uint GENERIC_WRITE = 0x40000000;
    // Do now allow file sharing
    const uint FILE_SHARE_NONE = 0x0;
    // Create the file and overwrites it if exists
    const uint CREATE_ALWAYS = 0x2;
    // Normal file, no attribute set
    const uint FILE_ATTRIBUTE_NORMAL = 0x80;

    static void Main()
    {
        SafeFileHandle handle =
            CreateFile("C:\MyFile.txt",
            GENERIC_WRITE,
            FILE_SHARE_NONE,
            IntPtr.Zero, // NULL
            CREATE_ALWAYS,
            FILE_ATTRIBUTE_NORMAL,
            new SafeFileHandle(IntPtr.Zero, true));

        // Because SafeFileHandle inherits
        // SafeHandleZeroOrMinusOneIsInvalid
        // IsInvalid returns true only if
        // the handle equals to 0 or -1
        if (handle.IsInvalid) // 0 or -1
        {
            Console.WriteLine("ERROR: {0}", Marshal.GetLastWin32Error());
            return;
            // Marshal.GetLastWin32Error() returns the last error only
            // if DllImportAttribute.SetLastError is set to true
        }

        FileStream stream = new FileStream(handle, FileAccess.Write);
        StreamWriter writer = new StreamWriter(stream);
        writer.WriteLine("Hello, World!");
        writer.Close();

        /*
         * Order of methods called by
         * StreamWriter by this example:
         *
         * StreamWriter.Close()
         * - StreamWriter.BaseStream.Close()
         * - - FileStream.SafeFileHandle.Close()
         * - - - SafeHandleZeroOrMinusOneIsInvalid
         *              .Close()
         * - - - - SafeHandle.Close()
         * - - - - - SafeHandle.ReleaseHandle()
         */
    }

Although, you can use IntPtr instead of SafeFileHandle, the FileStream constructor that accepts the IntPtr is considered obsolete (.NET 2.0 and higher) and you should use the constructor that accepts the SafeFileHandle.

The next example demonstrates how to create your custom safe handle. This custom safe handle represents a handle invalid only if equals to zero. Although, you can extend the functionality of either SafeHandleMinusOneIsInvalid or SafeHandleZeroOrMinusOneIsInvalid, we have inherited SafeHandle directly. Code is very simple:

Listing 2.9 Custom Safe Handle Example

    public sealed class SafeHandleZeroIsInvalid : SafeHandle
    {
        [DllImport("Kernel32.dll")]
        [return: MarshalAs(UnmanagedType.Bool)]
        private static extern bool CloseHandle(IntPtr hObject);

        // If ownsHandle equals true handle will
        // be automatically released during the
        // finalization process, otherwise, you
        // will have the responsibility to
        // release it outside the class.
        // Automatic releasing means calling
        // the ReleaseHandle() method.
        public SafeHandleZeroIsInvalid
            (IntPtr preexistingHandle, bool ownsHandle)
            : base(IntPtr.Zero, ownsHandle)
        {
            this.SetHandle(preexistingHandle);
        }

        public override bool IsInvalid
        {
            get
            {
                // this.handle.ToInt32() == 0
                // this.handle == new IntPtr(0)
                return this.handle == IntPtr.Zero;
            }
        }

        protected override bool ReleaseHandle()
        {
            return CloseHandle(this.handle);
        }
}

Until now, I do not have an answer for why a handle could be invalid only if it is set to zero! Maybe you will need this for your custom handles. However, this is just an illustration.

Critical Handles

Critical handles are the same as safe handles, except that they do not perform reference counting, so they do not provide protection from recycling security attacks.

Use critical handles instead of safe handles to address performance considerations, but you will be required to provide necessary synchronization for reference counting yourself.

Critical handles represented by the abstract System.Runtime.InteropServices.CriticalHandle. Figure 2.3 shows the definition of CriticalHandle and its descendants.

Figure 2.3 CriticalHandle and Descendants Class Definitions

Figure 2.3 CriticalHandle and Descendants Class Definitions

As the diagram illustrates, CriticalHandle is the base class that represents any critical handle. It inherits from System.Runtime.ConstrainedExecution.CriticalFinalizerObject that ensures the finalization process. The members of CriticalHandle are the same as SafeHandle, except that it does not include the Dangerous-prefixed methods because critical handles themselves are dangerous because they do not provide the necessary protection. For more information about CriticalHandle members, refer to members of SafeHandle discussed previously.

Because CriticalHandle is abstract, you must either implement it or use one of its implementation classes. Only two classes from the new namespace Microsoft.Win32.SafeHandles implement CriticalHandle, both are abstract too:

  • CriticalHandleMinusOneIsInvalid:
    Represents a critical handle of which a value of -1 indicates that the handle is invalid. Therefore, IsInvalid returns true only if the handle equals to -1.
  • CriticalHandleZeroOrMinusOneIsInvalid:
    Represents a critical handle of which a value of 0 or -1 indicates that the handle is invalid. So, IsInvalid returns true only if the handle equals to 0 or -1.

Examples are the same as SafeHandle, only to change the type name.

Passing Mechanism

When passing an argument to a function, the function may require either passing the argument by value or by reference. If the function intends to change argument value, it requires it to be passed by reference, otherwise, by value. This is what called passing mechanism.

Value arguments (i.e. input/In arguments,) when passed to a function, a copy of the argument is sent to the function. Therefore, any changes to the argument do not affect the original copy. On the other hand, reference arguments, when passed to a function, the argument itself is passed to the function. Therefore, the caller sees any changes happen inside the function.

Arguments passed by reference can be either In/Out (Input/Output) or only Out (Output.) In/Out arguments are used for passing input to the function and returning output. On the other hand, Out arguments used for returning output only. Therefore, In/Out arguments must be initialized before they are passed to the function. Conversely, Out arguments do not require pre-initialization.

When passing an argument by value, no changes to the PInvoke method are required. Conversely, passing an argument by reference requires two additional changes. The first is adding the ref modifier to the argument if it is In/Out argument, or the out modifier if it is Out argument. The second is decorating your argument with both InAttribute and OutAttribute attributes if it is In/Out argument or only OutAttribute if it is Out argument. To be honest, applying those attributes is not required, the modifiers are adequate in most cases. However, applying them gives the CLR a notation about the passing mechanism.

As you have seen, when marshaling a string, you can marshal it as a System.String or as a System.Text.StringBuilder. By default, StringBuilder is passed by reference (you do not need to apply any changes.) System.String on the other hand is passed by value.

It is worth mentioning that Windows API does not support reference arguments. Instead, if a function requires an argument to be passed by reference, it declares it as a pointer so that caller can see the applied changes. Other code such as COM libraries can require either a pointer or a reference argument. In either cases, you can safely apply the changes required. You can also marshal a pointer argument as System.IntPtr or as the unsafe void* for example.

Many of the previous examples demonstrated only functions those require arguments to be passed by value. Some functions require one or more arguments to be passed by reference. A good example of a function requires In/Out argument is GetVersionEx() which returns version information of the current system. It requires a single reference (In/Out) argument. The argument is of the structure OSVERSIONINFOEX. For our discussion, we will leave this function to the next chapter in the discussion of compound types.

A great deal of functions require Out arguments specially for returning results or status information. Good examples are ReadConsole() and WriteConsole() that require by-reference Out arguments for returning the characters read/written. The following is the unmanaged signature for the WriteConsole() function.

Listing 2.10 WriteConsole() Unmanaged Signature

BOOL WriteConsole(
  HANDLE hConsoleOutput,
  VOID lpBuffer,
  DWORD nNumberOfCharsToWrite,
  LPDWORD lpNumberOfCharsWritten,
  LPVOID lpReserved
);

And this is the managed version along with the test code:

Listing 2.11 Writing to Console Screen Example

    [DllImport("Kernel32.dll", CharSet = CharSet.Unicode)]
    [return: MarshalAs(UnmanagedType.Bool)]
    static extern bool WriteConsole(
        IntPtr hConsoleOutput,
        String lpBuffer,
        [param: MarshalAs(UnmanagedType.U4)]
        UInt32 nNumberOfCharsToWrite,
        [param: MarshalAs(UnmanagedType.U4)]
        out UInt32 lpNumberOfCharsWritten,
        [param: MarshalAs(UnmanagedType.AsAny)]
        object lpReserved);

    [DllImport("Kernel32.dll")]
    static extern IntPtr GetStdHandle(
        [param: MarshalAs(UnmanagedType.U4)]
        Int32 nStdHandle);

    const int STD_OUTPUT_HANDLE = -11;

    static void Main()
    {
        IntPtr handle = GetStdHandle(STD_OUTPUT_HANDLE);

        String textToWrite = "Hello, World!" + Environment.NewLine;
        uint noCharactersWritten;

        WriteConsole(handle,
            textToWrite,
            (uint)textToWrite.Length,
            out noCharactersWritten,
            null);

        Console.WriteLine("No. Characters written = {0}",
            noCharactersWritten);
    }

Finally yet importantly, chapter 6 provides you with more granular and down-level details about the memory management and the passing mechanism.

Additional Techniques

Here we will talk about techniques that should be taken into consideration when working with unmanaged code, they are encapsulation, creating wrappers, working with nullable arguments, and working out CLS problem.

Encapsulation

If the function requires an argument that can be set to a value or more, you can define these values (constants or typedefs) in an enumeration so you can easily access every set of values separately; that technique called encapsulation (grouping.) The following example shows the MessageBoxEx() example, the most suitable function for the example:

Listing 2.12 Message Box Example

    [DllImport("User32.dll", CharSet = CharSet.Unicode)]
    [return: MarshalAs(UnmanagedType.I4)]
    static extern UInt32 MessageBoxEx
        (IntPtr hWnd,
        [param: MarshalAs(UnmanagedType.LPTStr)]
        String lpText,
        [param: MarshalAs(UnmanagedType.LPTStr)]
        String lpCaption,
        [param: MarshalAs(UnmanagedType.U4)]
        UInt32 uType,
        [param: MarshalAs(UnmanagedType.U2)]
        UInt16 wLanguageId);

    public enum MB_BUTTON : uint
    {
        MB_OK = 0x0,
        MB_OKCANCEL = 0x1,
        MB_ABORTRETRYIGNORE = 0x2,
        MB_YESNOCANCEL = 0x3,
        MB_YESNO = 0x4,
        MB_RETRYCANCEL = 0x5,
        MB_HELP = 0x4000,
    }
    public enum MB_ICON : uint
    {
        MB_ICONHAND = 0x10,
        MB_ICONQUESTION = 0x20,
        MB_ICONEXCLAMATION = 0x30,
        MB_ICONASTERISK = 0x40,
        MB_ICONERROR = MB_ICONHAND,
        MB_ICONSTOP = MB_ICONHAND,
        MB_ICONWARNING = MB_ICONEXCLAMATION,
        MB_ICONINFORMATION = MB_ICONASTERISK,
    }
    public enum MB_DEF_BUTTON : uint
    {
        MB_DEFBUTTON1 = 0x0,
        MB_DEFBUTTON2 = 0x100,
        MB_DEFBUTTON3 = 0x200,
        MB_DEFBUTTON4 = 0x300,
    }
    public enum MB_MODAL : uint
    {
        MB_APPLMODAL = 0x0,
        MB_SYSTEMMODAL = 0x1000,
        MB_TASKMODAL = 0x2000,
    }
    public enum MB_SPECIAL : uint
    {
        MB_SETFOREGROUND = 0x10000,
        MB_DEFAULT_DESKTOP_ONLY = 0x20000,
        MB_SERVICE_NOTIFICATION_NT3X = 0x40000,
        MB_TOPMOST = 0x40000,
        MB_RIGHT = 0x80000,
        MB_RTLREADING = 0x100000,
        MB_SERVICE_NOTIFICATION = 0x200000,
    }
    public enum MB_RETURN : uint
    {
        IDOK = 1,
        IDCANCEL = 2,
        IDABORT = 3,
        IDRETRY = 4,
        IDIGNORE = 5,
        IDYES = 6,
        IDNO = 7,
        IDCLOSE = 8,
        IDHELP = 9,
        IDTRYAGAIN = 10,
        IDCONTINUE = 11,
    }

    static void Main()
    {
        UInt32 result = MessageBoxEx(IntPtr.Zero, // NULL
            "Do you want to save changes before closing?",
            "MyApplication",
            (UInt32)MB_BUTTON.MB_YESNOCANCEL |
            (UInt32)MB_ICON.MB_ICONQUESTION |
            (UInt32)MB_DEF_BUTTON.MB_DEFBUTTON3 |
            (UInt32)MB_SPECIAL.MB_TOPMOST,
            0);// Reserved

        if (result == 0) // error occurred
            Console.WriteLine("ERROR");
        else
        {
            MB_RETURN ret = (MB_RETURN)result;

            if (ret == MB_RETURN.IDYES)
                Console.WriteLine("User clicked Yes!");
            else if (ret == MB_RETURN.IDNO)
                Console.WriteLine("User clicked No!");
            else if (ret == MB_RETURN.IDCANCEL)
                Console.WriteLine("User clicked Cancel!");
        }
    }

You could also change the names of the constants to friendly names.

Figure 2.4 shows the message box resulted from running of the last code.

Figure 2.4 Message Box Example Result

Figure 2.4 Message Box Example Result

In addition, you can marshal an argument as an enumeration which of the argument type of course. The following example demonstrates this:

Listing 2.13 Console Standard Devices Example

    [DllImport("Kernel32.dll")]
    static extern IntPtr GetStdHandle(
        [param: MarshalAs(UnmanagedType.U4)]
        CONSOLE_STD_HANDLE nStdHandle);

    public enum CONSOLE_STD_HANDLE
    {
        STD_INPUT_HANDLE = -10,
        STD_OUTPUT_HANDLE = -11,
        STD_ERROR_HANDLE = -12
    }

    static void Main()
    {
        IntPtr handle;
        handle =
            GetStdHandle(CONSOLE_STD_HANDLE.STD_INPUT_HANDLE);
        if (handle == IntPtr.Zero)
            Console.WriteLine("Failed!");
        else
            Console.WriteLine("Succeeded!");
    }

Creating Wrappers

Exposing PInvoke methods to the outside the assembly is not a good practice. It is always recommended that you group your PInvoke methods into an internal class, and that class should be named as NativeMethods, SafeNativeMethods or UnsafeNativeMethods. For more information about this, check Code Analyzing Rules in MSDN documentation. Read €œMove PInvokes to Native Methods Class€ article.

The following code segment illustrates the wrapper method for our MessageBoxEx() function:

Listing 2.14 Message Box Example Revised

    public static MB_RETURN MessageBox
        (IntPtr handle, string text, string title,
        MB_BUTTON buttons, MB_ICON icon, MB_DEF_BUTTON defaultButton,
        MB_MODAL modality, MB_SPECIAL options)
    {
        UInt32 result = MessageBoxEx(handle,
            "Do you want to save changes before closing?",
            "MyApplication",
            (UInt32)buttons |
            (UInt32)icon |
            (UInt32)defaultButton |
            (UInt32)modality |
            (UInt32)options,
            0);

        if (result == 0)
            // Not recommended throwing System.Exception
            // throw a derived exception instead
            throw new Exception("FAILED");
        return (MB_RETURN)result;
    }

In addition, it is recommended changing the type of enumerations to any CLS-compliant type like System.Int32. Check the last technique in this section.

Working with Nullable Arguments

Some function arguments are nullable. Means that they can take a NULL (null in C#) value. To pass a NULL value to an argument, you can marshal this argument as System.IntPtr, so you can set it to System.IntPtr.Zero to represent a NULL value. Another trick here is creating an overload for the function, in which the first is marshaled as the argument type, and the other is marshaled as System.IntPtr. Thus, if you pass a System.IntPtr.Zero, CLR directs the call to the function with System.IntPtr. Conversely, passing a value to the argument, directs the call to the function with the correct type. The following code segment demonstrates this technique:

Code abbreviated for clarity.

Listing 2.15 ScrollConsoleScreenBuffer() Managed Signature

    [DllImport("Kernel32.dll", CharSet = CharSet.Auto)]
    [return: MarshalAs(UnmanagedType.Bool)]
    static extern bool ScrollConsoleScreenBuffer(
        IntPtr hConsoleOutput,
        SMALL_RECT lpScrollRectangle,
        SMALL_RECT lpClipRectangle,
        COORD dwDestinationOrigin,
        CHAR_INFO lpFill);

    [DllImport("Kernel32.dll", CharSet = CharSet.Auto)]
    [return: MarshalAs(UnmanagedType.Bool)]
    static extern bool ScrollConsoleScreenBuffer(
        IntPtr hConsoleOutput,
        SMALL_RECT lpScrollRectangle,
        IntPtr lpClipRectangle,
        COORD dwDestinationOrigin,
        CHAR_INFO lpFill);
    ...

Working Out the CLS Problem

You should know that some types are non-CLS-compliant and you should avoid exposing them outside the assembly. For example, the famous System.UInt32 is non-CLS-compliant, and you strictly should not expose it.

Being non-CLS-compliant means that the type violates with CLS (Common Language Specifications) specifications. Following CLS specifications helps the interoperation of .NET languages. It helps avoiding some actions like declaring specific types or following uncommon naming conventions.

Why to avoid such these acts? This helps the big goal of .NET Framework, the interoperation of .NET languages. Some languages for example does not support variable names beginning with an underscore (_) others do. Therefore, following the CLS specifications allows your assembly to be callable from any other assembly build with any language easily.

To force the check of CLS specification, you can decorate the assembly with System.CLSCompliantAttribute attribute -specifying true,– and that would result in compiler warnings whenever you try to expose non-CLS-compliant type out.

To work out this CLS dilemma, for functions require UInt32 as an argument, you can create a wrapper that behaves as an entry-point to the private non-CLS-compliant method. That wrapper method accepts, for instance, System.Int32 and converts it internally to System.UInt32.

For structures, you can declare the structure as internal and continue using it the normal way.

Again, you could replace all non-CLS-compliant types like System.UInt32 with CLS-compliant equivalents like System.Int32 and take advantage of easily distributing your types and assembly. However, that would not be easy in all cases.

It is very helpful consulting the documentation about System.CLSCompliantAttribute attribute.

Real-World Examples

In this chapter, we have covered many aspects of marshaling in many examples. However, most of all were just for illustration.

The following are some real-world examples that solve problems that you might face while developing your application. Those problems can be solved only via interoperability with unmanaged code.

Programmatically Swapping Mouse Buttons

The following code swaps mouse buttons programmatically. It makes the left button acts like the right button (e.g. opens the context menu) and vice versa.

Listing 2.16 Swapping Mouse Buttons Sample

[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool SwapMouseButton
    ([param: MarshalAs(UnmanagedType.Bool)] bool fSwap);

public void MakeRightButtonPrimary()
{
    SwapMouseButton(true);
}

public void MakeLeftButtonPrimary()
{
    SwapMouseButton(false);
}

Programmatically Turning On the Screen Saver

The following code shows how to turn on the screen saver programmatically.

Listing 2.19 Dragging a Form without a Title Bar Sample

[DllImport("User32.dll")]
public static extern int SendMessage
    (IntPtr hWnd,
    uint Msg,
    uint wParam,
    uint lParam);

public const uint WM_SYSCOMMAND = 0x112;
public const uint SC_SCREENSAVE = 0xF140;

public enum SpecialHandles
{
    HWND_DESKTOP = 0x0,
    HWND_BROADCAST = 0xFFFF
}

public static void TurnOnScreenSaver()
{
    SendMessage(
        new IntPtr((int)SpecialHandles.HWND_BROADCAST),
        WM_SYSCOMMAND,
        SC_SCREENSAVE,
        0);
}

Dragging a Form without a Title Bar

The following code allows the form to be dragged from its body. This code is a good example for the wrapper creating technique discussed earlier.

Listing 2.18 Dragging a Form without a Title Bar Sample

SafeNativeMethods.cs

internal static class SafeNativeMethods
{
    [DllImport("user32.dll")]
    [return: MarshalAs(UnmanagedType.I4)]
    public static extern int SendMessage(
        IntPtr hWnd,
        [param: MarshalAs(UnmanagedType.U4)]
        uint Msg,
        [param: MarshalAs(UnmanagedType.U4)]
        uint wParam,
        [param: MarshalAs(UnmanagedType.I4)]
        int lParam);

    [DllImport("user32.dll")]
    [return: MarshalAs(UnmanagedType.Bool)]
    public static extern bool ReleaseCapture();

    public const uint WM_NCLBUTTONDOWN = 0xA1; // 161
    public const uint HTCAPTION = 2;
}

HelperMethods.cs

internal static class HelperMethods
{
    public static void MoveObject(IntPtr hWnd)
    {
        SafeNativeMethods.ReleaseCapture();
        SafeNativeMethods.SendMessage
            (hWnd, SafeNativeMethods.WM_NCLBUTTONDOWN,
            SafeNativeMethods.HTCAPTION, 0);
    }
}

MainForm.cs

// In the form, write the following code
// in the handler of the MouseDown event

private void MainForm_MouseDown(object sender, MouseEventArgs e)
{
    HelperMethods.MoveObject(this.Handle);
}

Summary

The last word to say is that MarshalAsAttribute is not required all the time. Sometimes it is optional, and other times it is required.

For example, if you marshal blittable data types like DWORD, you can safely ignore MarshalAsAttribute. Conversely, if you are marshaling non-blittable data types like booleans and strings, you will need to use the MarshalAsAttribute to ensure correct marshaling process. However, it is always better giving the CLR and other developers a notation about the underlying data type by apply the MarshalAsAttribute attribute to blittable data types too.

Finally yet importantly, this chapter was the key for the gate to the interoperation with unmanaged environments. It discussed the most important part of the marshaling process, marshaling the simple types, which you will always need to keep it into your mind.

Next, you will learn how to work with compound types and marshal them in your managed environment.

Marshaling with C# – Chapter 1: Introducing Marshaling

Read the full book here.

What is Marshaling?

Marshaling is the process of creating a bridge between managed code and unmanaged code; it is the homer that carries messages from the managed to the unmanaged environment and reverse. It is one of the core services offered by the CLR (Common Language Runtime.)

Because much of the types in unmanaged environment do not have counterparts in managed environment, you need to create conversion routines that convert the managed types into unmanaged and vice versa; and that is the marshaling process.

As a refresher, we call .NET code “managed” because it is controlled (managed) by the CLR. Other code that is not controlled by the CLR is called unmanaged.

Why Marshaling?

You already know that there is no such compatibility between managed and unmanaged environments. In other words, .NET does not contain such the types HRESULT, DWORD, and HANDLE that exist in the realm of unmanaged code. Therefore, you need to find a .NET substitute or create your own if needed. That is what called marshaling.

An example is the unmanaged DWORD; it is an unsigned 32-bit integer, so we can marshal it in .NET as System.UInt32. Therefore, System.UInt32 is a substitute for the unmanaged DWORD. On the other hand, unmanaged compound types (structures, unions, etc.) do not have counterparts or substitutes in the managed environment. Thus, you’ll need to create your own managed types (structures/classes) that will serve as the substitutes for the unmanaged types you use.

When I Need to Marshal?

Marshaling comes handy when you are working with unmanaged code, whether you are working with Windows API or COM components. It helps you interoperating (i.e. working) correctly with these environments by providing a way to share data between the two environments. Figure 1 shows the marshaling process, where it fall, and how it is required in the communication process between the two environments.

Figure 1.1 - The Marshaling Process

Marshaling with C# Pocket Reference

Here, I’ll gather links for our book “Marshaling with C#: Pocket Reference”.

Author: Mohammad Elsheimy

Contents at a Glance

Book Download

Download the PDF version
Download the XPS version

Recommend a book proposal for us.

Marshaling Unions

Before You Start

If this is your first time you hear about unions or you need to know more about them, please refer to our article “A short speech about Unions” first.

How to Marshal a Union

You can marshal a union the same way you marshal structures. However, because of the way that unions laid-out into memory, you will need to explicitly set variable positions inside the type.

You can marshal a union in few steps:

  1. Create your marshaling type, no matter whether your marshaling type is a managed structure or class. However, you should consider the passing mechanism when working with reference types like classes.
  2. Decorate the type with the StructLayoutAttribute attribute specifying LayoutKind.Explicit to control exactly the memory location of every member inside the type.
  3. Add your required fields only. Because we are controlling the memory layout explicitly, order of fields is no important.
  4. Decorate every field with FieldOffsetAttribute attribute specifying the absolute position -in bytes- of the member from the start of the structure.

Example

Consider the following union:

union SOME_CHARACTER {
	int iCode;
	char cChar;
};

Now, it’s the time for the meat of our lesson. The following code snippets defines the marshaling type of our union:

    [StructLayout(LayoutKind.Explicit)]
    public struct SOME_CHARACTER
    {
        // Both members located on the same
        // position in the beginning of the union

        // This is the continer. it is 4 bytes
        [FieldOffset(0)]
        [MarshalAs(UnmanagedType.I4)]
        public int iCode;

        // This is only 1 byte.
        [FieldOffset(0)]
        public char cChar;
    }

    static void Main()
    {
        SOME_CHARACTER character = new SOME_CHARACTER();

        // The code for letter 'A'
        character.dwCode = 65;
        // Should prints 'A'
        Console.WriteLine("wcChar = {0}", character.wcChar);

        character.wcChar = 'B';
        // Should prints 66
        Console.WriteLine("Code = {0}", character.dwCode);
    }

From the previous code, we learn that€¦

  • Unions marshaled like structures, they can be marshaled as either managed structures or classes.
  • Setting StructLayoutAttribute.LayoutKind to LayoutKind.Explicit allows us to exactly control the memory location of the members.
  • We use the FieldOffsetAttribute to specify the starting location in bytes of the field into the type in memory.
  • To create the union between the fields, we set both the fields to the same memory location.
  • In the example, iCode begins from byte 0 to byte 4. And cChar begins from byte 0 to byte 1.
  • If we do not need to take advantage of the union, we can emit cChar because it is contained inside the range of iCode. But, we cannot emit iCode because it is the container.
  • When we change either one of the union variables, the other variable changes too because they share the same memory address. Notice that in our example, int is 4-bytes and char is only 1 byte. Therefore, iCode interprets the whole value, while cChar interprets only the first byte (8 bits) of the value.

Unions with Arrays

Now, consider the following union:

union UNION_WITH_ARRAY
{
    int nValue;
    char str[10];
};

This union must be marshaled in a special way because managed code does not permit value types and reference types to overlap.

As a refresher, a value-type is the type stored into the stack memory; it inherits from System.ValueType. Value-types represented in all primitive data types, structures, and enumerations. On the other hand, reference-types are types stored in the memory heap; they inherit from System.Object. Most types in .NET are reference-types (except System.ValueType of course.)

As a result, we cannot union both members of our example, because whether marshaling the second variable str as an array, a System.Text.StringBuilder, or a System.String, it is still a reference-type. Therefore, we have to leave the advantage of unions, and marshal only a single member. For our example, we will create two marshaling types for our union, one with the first member marshaled, and the other with the other member.

As we know, the layout and size of the type inside the memory is the most crucial. Therefore, we must preserve the layout and size of our union. This union has a 10-bytes array as a container and only one member contained, and this member is only 4-bytes. Therefore, we have two choices, to marshal the union with the container member, or to marshal it with the contained member but to extend it enough to be as large as the container. In this example, we will take the two approaches.

The following are two code segments. The first demonstrates how to marshal only the second member which is the container, while the second demonstrates how to marshal the first member.

    // Setting StructLayoutAttribute.CharSet
    // ensures the correct encoding for all
    // string members of the union in our example
    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
    public struct UNION_WITH_ARRAY_1
    {
        // As we know, character arrays can be marshaled
        // as either an array or as a string

        // Setting MarshalAsAttribute is required
        // for the array and the string

        // That is another way:
        //[MarshalAs(UnmanagedType.ByValArray, SizeConst = 128)]
        //public char[] charArray;

        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)]
        public string charArray;
    }

    // StructLayoutAttribute.Size determines
    // the size -in bytes- of the type.
    // If the size specified is larger than
    // members' size, the last member will be extended
    // Because this is only a single
    // member, we laid it out sequentially.
    [StructLayout(LayoutKind.Sequential, Size = 128)]
    public struct UNION_WITH_ARRAY_2
    {
        [MarshalAs(UnmanagedType.I2)]
        public short number;
    }

Try it out!

If you are brave enough, you might try to marshal DEVMODE structure; that is one of the most complex structures in the Windows API. If you are interested you can refer to the MSDN library for the documentation of DEVMODE structure. Don’t be shocked when you first see that structure. (My advice is to pray for God before you think about marshaling DEVMODE structure.)

Moving a Form without the Title Bar

هذه المقالة متوفرة أيضا باللغة العربية، اقرأها هنا.

Sample: Geming.Samples.FormDragging.zip

What is that?

Today, we are talking about how to move a form without its title bar.

You might have noticed that some applications with fancy UIs do not allow the user to move the window from its title bar. Honestly, some hide the overall title bar from the user. An example of these applications is Microsoft Windows Media Player -when in skin mode,- and Microsoft Windows Live Messenger. Both applications allow you to drag their windows using the client area not the title bar.

In this lesson, you will learn how to do this trick to move the form without its title bar.

At the end of this lesson, a sample application is available for download. It is a simple application with an outstanding UI illustrates how to move the form using its client area.

How?

Theoretically, you cannot drag any form without its title bar. However, we can simulate the dragging process which implies clicking with the left mouse button on the title bar and moving the cursor without releasing the left mouse button.

You can simulate this process using the SendMessage() function. This function is used to send a specific message (you can say command/order) to a specific object -specified by its handle.- This specific message can be attached with another messages (commands) to produce a new command. For example, in our lesson we will attach the message WM_NCLBUTTONDOWN with the message HTCAPTION to simulate the left mouse button clicking on the caption (title bar) of a window (form.)

Honestly, every object is a window. Every button -even the Close button- is a window, the menu item is a window, the status bar is a window, and the tooltip is another window!

The definition of SendMessage() is as following:

LRESULT SendMessage(
    HWND hWnd,
    UINT Msg,
    WPARAM wParam,
    LPARAM lParam
    );

This function takes four arguments:

  • hWnd:
    The handle of the object (window.) to send the message to. Can be set to a window handle, HWND_DESKTOP (to send the message to the desktop,) HWND_BROADCAST (to send the message to all windows.)
  • Msg:
    The primary message that will be sent.
  • wParam:
    A secondary message to be attached to the primary message. Set to 0 to indicate NULL.
  • lParam:
    Another message that can be attached to the primary message. Set to 0 to indicate NULL. If wParam was not set, you cannot set lParam.

The return value of this function depends on the message sent. In our example, the function may return 0 if succeeded, or non-zero if failed.

It is worth mentioning that, in our example, another function must be called before SendMessage(); it is the ReleaseCapture() function. This function releases the mouse capture from a window (object) and restores the normal mouse processing. A window (object) that has captured the mouse receives all mouse input. Therefore, calling the ReleaseCapture() allows our form to release this mouse input (left-clicking) simulated.

The ReleaseCapture() function is very simple; its definition is as following:

BOOL ReleaseCapture(VOID);

This function returns TRUE if succeeded, or FALSE otherwise.

Let’s Code!

Now, we are going to put things together and mix them up.

The first step is to hide the title bar of the form. This can be done through the FormBorderStyle property of the form. You can set this property to FormBorderStyle.None to hide the toolbar and borders of the form.

The next step to take is to create the PInvoke methods for the functions. Here is the full code:

    // C# Code

[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.I4)]
static extern int SendMessage(
    IntPtr hWnd,
    [param: MarshalAs(UnmanagedType.U4)]
    uint Msg,
    [param: MarshalAs(UnmanagedType.U4)]
    uint wParam,
    [param: MarshalAs(UnmanagedType.I4)]
    int lParam);

[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool ReleaseCapture();

const uint WM_NCLBUTTONDOWN = 0xA1; // 161
const uint HTCAPTION = 2;
' VB.NET
Declare Function SendMessage Lib "user32.dll" ( _
    ByVal hWnd As IntPtr, _
    ByVal Msg As Integer, _
    ByVal wParam As Integer, _
    ByVal lParam As Integer) As Integer

Declare Auto Function ReleaseCapture _
    Lib "user32.dll" () As Boolean

Const WM_NCLBUTTONDOWN As Integer = 161
Const HTCAPTION As Integer = 2

Again and again, PInvoke stands for Platform Invocation; it is the CLR service allows .NET to call unmanaged code. This service requires special changes to the PInvoke method. Also, specific rules applied when PInvoking an unmanaged function.

The last code demonstrates the PInvoke methods for the functions, and the constants required.

The last step is to add the implementation code required to the MouseDown event of any control that you wish to allow the user to drag the form from. For instance, you can add the code to the MouseDown event of a PictureBox control that will act as the new and fancy title bar. In addition, you can add the code to the form’s MouseDown event to allow the user to drag the form from any point of its client area.

The following code demonstrates how to allow the user to drag the form from its client area:

    // Code

private void MainForm_MouseDown
    (object sender, MouseEventArgs e)
{
    // Releasing the mouse capture
    // to allow the form to receive
    // the order
    ReleaseCapture();
    // Ordering the form
    // Simulating left mouse button clicking
    // on the title bar
    SendMessage(this.Handle, // Form handle
        WM_NCLBUTTONDOWN, // Simulating the click
        HTCAPTION, // Attaching it to the title bar
        0); // No further options required
}
' VB.NET
Private Sub Form1_Load(ByVal sender As Object,ByVal e As EventArgs) _
    Handles MyBase.Load
    ReleaseCapture()
    SendMessage(Me.Handle, WM_NCLBUTTONDOWN, HTCAPTION, 0)
End Sub

It is better to check the return value of every call to determine whether the operation succeeded or failed.

A problem occurred!

It is wonderful to allow the user to drag the form from its client area. But, what if the user tried to drag the form from a label on the client area? It will not be dragged.

To overcome this situation, you can add the same code to the MouseDown event of the label. In this case, for better code maintenance and to avoid code repetition, you can define a method that contains the code, and call it from the MouseDown event of every control that you need to allow the user to drag the form from such as a label or a PictureBox. Another solution is to create a single MouseDown event handler for all controls that you are interested in.

Well! What’s next?

You can use this technique when creating applications with hot skins to allow the user to drag the form from its client area or from a specific control like a PictureBox that acts as the new hot title bar.

It is worth mentioning that you would better follow the guidelines when interoperating with unmanaged code. For example, PInvoke methods and constants should be declared inside an internal class called -in our example- SafeNativeMethods. In addition, it is better creating a wrapper method for the PInvoke methods. For example, instead of calling many functions to drag the form, you can create a single function named -for instance- MoveForm() that acts as a wrapper for the PInvoke methods. And that results in code that is more readable and easier to maintain. Plus, it prevents code repetition.

For more information about the functions, consult the MSDN documentation:

WOW! A code sample!

This is a very simple application that illustrates moving a form using its client area.

This sample created using Microsoft Visual Studio 2008 and .NET Framework 2.0.

The following is a snapshot from the application:

Moving Form without Title Bar Sample Snapshot

Download Here

Changing Display Settings Programmatically

هذه المقالة متوفرة أيضا باللغة العربية، اقرأها هنا.

Code: Geming.DisplayMgr.msi

Introduction

Previously, we have talked about how to change screen resolution and color system via DirectX. Today, we are talking about how to change all display settings -not the resolution and color system only- via API. We will change screen resolution (bounds,) color system (bit count,) rotation (orientation,) and refresh rate (frequency) via API with C# and the .NET Framework.

Overview

This lesson firstly discusses the required functions and structures. Then, it focuses on how to retrieve current display settings. After that, it discusses how to get all modes supported by your display. As you already know, a mode is a combination of may display settings including bounds, bit count, orientation, and frequency; therefore, we will refer to display settings as display mode.

Finally, this lesson discusses how to change the current display settings. Along with the discussion, you will learn additional techniques like how to PInvoke Win32 API functions, and to marshal unmanaged data types.

In addition, this lesson comes with a sample application used for changing the display settings.

Now, we are going to discuss the required functions and structure and how to use them. After that, we will focus on the implementation code. Get ready.

EnumDisplaySettings() Function

This function resides in user32.dll. It is used to retrieve one of the modes supported by a graphics device.

The definition of this function is as following:

BOOL EnumDisplaySettings(
    LPCTSTR lpszDeviceName,  // display device
    DWORD iModeNum,          // graphics mode
    [In, Out] LPDEVMODE lpDevMode      // graphics mode settings
    );

This function accepts only three parameters:

  • lpszDeviceName:
    Specifies the display device name that will be used to retrieve its modes. This parameter can be either NULL to indicate the default device, or the name of the display device. You can enumerate display devices using the EnumDisplayDevices() function.
  • iModeNum:
    Specifies the type of information to retrieve. It could be either a mode index or one of these values:

    • ENUM_CURRENT_SETTINGS = -1
      Retrieves current display mode.
    • ENUM_REGISTRY_SETTINGS = -2
      Retrieves current display mode stored on the registry.
  • lpDevMode:
    A reference (In/Out) parameter represents the DEVMODE object encapsulates the retrieved display mode information. The DEVMODE’s dmSize member is used for input to represents the structure size, while other members are used for output.

As you might expect, to retrieve the current mode (settings) of the current display device, you will need to pass a NULL value as the lpszDeviceName parameter to indicate the current display, and the value -1 to the iModeNum parameter to indicate the current mode.

Unfortunately, EnumDisplaySettings() can return only one mode per call, and that mode is encapsulated into the DEVMODE object. To retrieve all modes (or few) supported by a display device, you need to call EnumDisplaySettings() many times specifying iModeNum as the mode index. Mode indexes start from zero. Therefore, to retrieve all modes, you will need to call the EnumDisplaySettings() function many times specifying 0 for iModeNum on the first time, and increment that index every call until EnumDisplaySettings() returns FALSE, which indicates that the previous mode was the last mode supported.

If you want to retrieve a mode (or all modes) supported by other display device, you will need to change the lpszDeviceName to the name of that device. You can get a list of all devices connected using the EnumDisplayDevices() function.

Now, it is the time for the PInvoke method. We can PInvoke this function in C# as following:

[DllImport("User32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern Boolean EnumDisplaySettings(
    [param: MarshalAs(UnmanagedType.LPTStr)]
    string lpszDeviceName,
    [param: MarshalAs(UnmanagedType.U4)]
    int iModeNum,
    [In, Out]
    ref DEVMODE lpDevMode);

What is Platform Invocation (PInvoke)? You already know, there is no such compatibility between managed code (.NET) and unmanaged code (Win32 API in our case.) Therefore, they cannot call each other directly. Rather, you make use of the PInvoke service to call unmanaged functions from the managed environment.

What is Marshaling? Marshaling is another service of the CLR. Again, there is no such compatibility between managed code and unmanaged code. Therefore, they cannot communicate directly. To send data between the managed client and unmanaged server, and vice versa, you will need to use marshaling to allow sending and receiving of the data. Marshaling converts managed data types to unmanaged data and vice versa.

As you suggested, now we are going to talk about the DEVMODE structure.

DEVMODE Structure

This structure encapsulates information about a printer or a display device.

This structure is fairly a complex structure, but we will try to break it down to be simple and easier to marshal.

The definition of this structure is as following:

typedef struct _devicemode {
  TCHAR dmDeviceName[CCHDEVICENAME];
  WORD  dmSpecVersion;
  WORD  dmDriverVersion;
  WORD  dmSize;
  WORD  dmDriverExtra;
  DWORD dmFields;
  union {
    struct {
      short dmOrientation;
      short dmPaperSize;
      short dmPaperLength;
      short dmPaperWidth;
      short dmScale;
      short dmCopies;
      short dmDefaultSource;
      short dmPrintQuality;
    } ;
    struct {
      POINTL dmPosition;
      DWORD  dmDisplayOrientation;
      DWORD  dmDisplayFixedOutput;
    } ;
  } ;
  short dmColor;
  short dmDuplex;
  short dmYResolution;
  short dmTTOption;
  short dmCollate;
  TCHAR dmFormName[CCHFORMNAME];
  WORD  dmLogPixels;
  DWORD dmBitsPerPel;
  DWORD dmPelsWidth;
  DWORD dmPelsHeight;
  union {
    DWORD dmDisplayFlags;
    DWORD dmNup;
  } ;
  DWORD dmDisplayFrequency;
#if (WINVER >= 0x0400)
  DWORD dmICMMethod;
  DWORD dmICMIntent;
  DWORD dmMediaType;
  DWORD dmDitherType;
  DWORD dmReserved1;
  DWORD dmReserved2;
#if (WINVER >= 0x0500) || (_WIN32_WINNT >= 0x0400)
  DWORD dmPanningWidth;
  DWORD dmPanningHeight;
#endif
#endif
} DEVMODE, *PDEVMODE, *LPDEVMODE

Really complex, Isn’t it? Yeah, DEVMODE is one of the large and complex structures.

You might have noticed that two unions defined inside the structure. In addition, a structure is defined inside the first union. Notice that this structure is only available if it is a printer device. Plus, the union defined the structure also is for printer devices only. Therefore, for display devices, you can omit the structure, and define other members of the union sequentially, no additional work is required.

In addition, the last eight members are not supported by Windows NT, while the last two members are not supported by Windows ME and its ascendants. To solve this dilemma and support all versions, you can define three versions of the structure, one for Windows ME and its ascendants, one for Windows NT, and the last for Windows 2000 and higher versions. In addition, you will need to create three overloads of the function for the three structures. For simplicity, we will marshal the whole structure as for Windows 2000 and higher versions.

Notice that there are arrays that are defined with the length CCHFORMNAME which equals 32.

Last but not least, the second union of the structure defined two members inside, dmDisplayFlags and dmNup. For simplicity, we will take away the union and one of its members and define the other. Because both members are 4-bytes wide, we can omit anyone of them.

We can marshal that structure in C# as following:

    [StructLayout(LayoutKind.Sequential,
CharSet = CharSet.Ansi)]
public struct DEVMODE
{
    // You can define the following constant
    // but OUTSIDE the structure because you know
    // that size and layout of the structure
    // is very important
    // CCHDEVICENAME = 32 = 0x50
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]
    public string dmDeviceName;
    // In addition you can define the last character array
    // as following:
    //[MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)]
    //public Char[] dmDeviceName;

    // After the 32-bytes array
    [MarshalAs(UnmanagedType.U2)]
    public UInt16 dmSpecVersion;

    [MarshalAs(UnmanagedType.U2)]
    public UInt16 dmDriverVersion;

    [MarshalAs(UnmanagedType.U2)]
    public UInt16 dmSize;

    [MarshalAs(UnmanagedType.U2)]
    public UInt16 dmDriverExtra;

    [MarshalAs(UnmanagedType.U4)]
    public UInt32 dmFields;

    public POINTL dmPosition;

    [MarshalAs(UnmanagedType.U4)]
    public UInt32 dmDisplayOrientation;

    [MarshalAs(UnmanagedType.U4)]
    public UInt32 dmDisplayFixedOutput;

    [MarshalAs(UnmanagedType.I2)]
    public Int16 dmColor;

    [MarshalAs(UnmanagedType.I2)]
    public Int16 dmDuplex;

    [MarshalAs(UnmanagedType.I2)]
    public Int16 dmYResolution;

    [MarshalAs(UnmanagedType.I2)]
    public Int16 dmTTOption;

    [MarshalAs(UnmanagedType.I2)]
    public Int16 dmCollate;

    // CCHDEVICENAME = 32 = 0x50
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]
    public string dmFormName;
    // Also can be defined as
    //[MarshalAs(UnmanagedType.ByValArray,
    //    SizeConst = 32, ArraySubType = UnmanagedType.U1)]
    //public Byte[] dmFormName;

    [MarshalAs(UnmanagedType.U2)]
    public UInt16 dmLogPixels;

    [MarshalAs(UnmanagedType.U4)]
    public UInt32 dmBitsPerPel;

    [MarshalAs(UnmanagedType.U4)]
    public UInt32 dmPelsWidth;

    [MarshalAs(UnmanagedType.U4)]
    public UInt32 dmPelsHeight;

    [MarshalAs(UnmanagedType.U4)]
    public UInt32 dmDisplayFlags;

    [MarshalAs(UnmanagedType.U4)]
    public UInt32 dmDisplayFrequency;

    [MarshalAs(UnmanagedType.U4)]
    public UInt32 dmICMMethod;

    [MarshalAs(UnmanagedType.U4)]
    public UInt32 dmICMIntent;

    [MarshalAs(UnmanagedType.U4)]
    public UInt32 dmMediaType;

    [MarshalAs(UnmanagedType.U4)]
    public UInt32 dmDitherType;

    [MarshalAs(UnmanagedType.U4)]
    public UInt32 dmReserved1;

    [MarshalAs(UnmanagedType.U4)]
    public UInt32 dmReserved2;

    [MarshalAs(UnmanagedType.U4)]
    public UInt32 dmPanningWidth;

    [MarshalAs(UnmanagedType.U4)]
    public UInt32 dmPanningHeight;
}

We will cover the PONTL structure soon.

Actually, these dozens of MarshalAsAttribute attributes are not all required. Honestly, it is not required for marshaling DWORD into UInt32 because they are counterparts. On the hand, MarshalAsAttribute attribute must be applied to arrays.

From all of those members, we are interested only in a few:

  • dmPelsWidth and dmPelsHeight:
    Represents the bounds (width and height) of the display. These values can be used also to determine whether the display orientation is portrait or landscape.
  • dmBitsPerPel:
    Represents the bit count (color system) of the display.
  • dmDisplayOrientation:
    Represents the orientation (rotation) of the display. This member can be one of these values:

    • DMDO_DEFAULT = 0
      The display is in the natural orientation. It is the default.
    • DMDO_90 = 1
      The display is rotated 90 degrees (measured clockwise) from DMDO_DEFAULT.
    • DMDO_180 = 2
      The display is rotated 180 degrees (measured clockwise) from DMDO_DEFAULT.
    • DMDO_270 = 3
      The display is rotated 270 degrees (measured clockwise) from DMDO_DEFAULT.
  • dmDisplayFrequency:
    Represents the frequency (refresh rate) of the display.

POINTL Structure

The DEVMODE’s dmPosition member represents the location that display device in reference to the desktop area. It is always located at (0, 0). This member is of the structure POINTL which represents the coordinates (x and y) of a point. As you might expect, this structure is very simple. It is defined as following:

typedef struct POINTL {
    LONG x;
    LONG y;
};

We can marshal this structure easily as following:

    [StructLayout(LayoutKind.Sequential)]
public struct POINTL
{
    [MarshalAs(UnmanagedType.I4)]
    public int x;
    [MarshalAs(UnmanagedType.I4)]
    public int y;
}

However, for code clarity, we have a workaround. You can omit the POINTL structure and replace the dmPosition member with two members, you can call them dmPositionX and dmPositionY, and that will work fine because you know that the size and layout (position of members) of structures is very important. And doing that will not break this rule.

ChangeDisplaySettings() Function

This function resides in user32.dll. It is used to change display settings to the mode specified, but only if the mode is valid.

The definition of this function is as following:

LONG ChangeDisplaySettings(
    LPDEVMODE lpDevMode,  // graphics mode
    DWORD dwflags         // graphics mode options
    );

This function accepts only two arguments:

  • lpDevMode:
    A reference (In/Out) argument of the type DEVMODE represents the new settings (mode) that will be applied to the display device. After retrieving the current settings using the EnumDisplaySettings() function, you can change the desired members of the DEVMODE object and use this function to change the display device to the new settings. Again, this argument is In/Out argument which means that it is used for input and output. DEVMODE’s dmSize member is used for input and other members are used for output.
  • dwflags:
    Indicates how the mode should be changed. Actually, in this example, we are not interested in this argument, so we will set it to zero. If you want more help on this argument, consult the MSDN documentation.

The return value of this function varies based on the success or failure of the settings change. This function can return one of several values including:

  • DISP_CHANGE_SUCCESSFUL = 0
    Indicates that the function succeeded.
  • DISP_CHANGE_BADMODE = -2
    The graphics mode is not supported.
  • DISP_CHANGE_FAILED = -1
    The display driver failed the specified graphics mode.
  • DISP_CHANGE_RESTART = 1
    The computer must be restarted for the graphics mode to work.

Consult MSDN documentation to know more about the ChangeDisplaySettings() return value. The last section of this lesson is devoted for this.

Another point of interest is that ChangeDisplaySettings() changes only the default display. If you want to change another display device, you can use the ChangeDisplaySettingsEx() function. It is very similar to ChangeDisplaySettings(). Consult MSDN documentation for more help.

Now, it is the time for creating the PInvoke method for the ChangeDisplaySettings() function.

    [DllImport("User32.dll")]
[return: MarshalAs(UnmanagedType.I4)]
public static extern int ChangeDisplaySettings(
    [In, Out]
    ref DEVMODE lpDevMode,
    [param: MarshalAs(UnmanagedType.U4)]
    uint dwflags);

Now, we are going to mix things together and talk about the implementation code. Get ready.

Retrieving Current Display Mode

The code that obtains the current display settings is very easy. We use the EnumDisplaySettings() function passing it ENUM_CURRENT_SETTINGS (-1) in the iModeNum parameter to get the current settings, and NULL in the lpszDeviceName parameter to indicate the current display device.

Here is the code.

Code abbreviated for clarity.

    public static void GetCurrentSettings()
{
    DEVMODE mode = new DEVMODE();
    mode.dmSize = (ushort)Marshal.SizeOf(mode);

    if (EnumDisplaySettings(null,
        ENUM_CURRENT_SETTINGS,
        ref mode) == true) // Succeeded
    {
        Console.WriteLine("Current Mode:nt" +
            "{0} by {1}, " +
            "{2} bit, " +
            "{3} degrees, " +
            "{4} hertz",
            mode.dmPelsWidth,
            mode.dmPelsHeight,
            mode.dmBitsPerPel,
            mode.dmDisplayOrientation * 90,
            mode.dmDisplayFrequency);
    }
}

Enumerating Supported Display Modes

As a refresher, to get the current mode or even another supported mode of the display device, you make use of the EnumDisplaySettings() function. If you pass ENUM_CURRENT_SETTINGS (-1) in the iModeNum parameter, you get the current mode. On the other hand, you can enumerate through the list of supported modes by passing the mode index in this parameter. We start by 0 which indicates the first mode, and increment it every call to enumerate through the list of the supported modes. If the function returns FALSE, that means that the mode with the index specified is not found. Therefore, the previous mode was the last one. Here is the code.

public static void EnumerateSupportedModes()
{
    DEVMODE mode = new DEVMODE();
    mode.dmSize = (ushort)Marshal.SizeOf(mode);

    int modeIndex = 0; // 0 = The first mode

    Console.WriteLine("Supported Modes:");

    while (EnumDisplaySettings(null,
        modeIndex,
        ref mode) == true) // Mode found
    {
        Console.WriteLine("t" +
            "{0} by {1}, " +
            "{2} bit, " +
            "{3} degrees, " +
            "{4} hertz",
            mode.dmPelsWidth,
            mode.dmPelsHeight,
            mode.dmBitsPerPel,
            mode.dmDisplayOrientation * 90,
            mode.dmDisplayFrequency);

        modeIndex++; // The next mode
    }
}

Changing Display Mode

Now, we are going to change the current display settings. This can be done through the ChangeDispalySettings() function.

Changing Screen Resolution and Bit Count

The following code example loads the current settings and changes only the resolution and the bit count. Actually, you are free to change all settings or few of them that is up to you. However, for the sake of simplicity, we are going to change the screen resolution and bit count in this section, and the orientation in the next section.

static void Main()
{
    // Changing the display resolution
    // to 800 by 600
    // and the color system (bit count)
    // to 16-bit
    ChangeDisplaySettings(800, 600, 16);
}

public static void ChangeDisplaySettings
    (int width, int height, int bitCount)
{
    DEVMODE originalMode = new DEVMODE();
    originalMode.dmSize =
        (ushort)Marshal.SizeOf(originalMode);

    // Retrieving current settings
    // to edit them
    EnumDisplaySettings(null,
        ENUM_CURRENT_SETTINGS,
        ref originalMode);

    // Making a copy of the current settings
    // to allow reseting to the original mode
    DEVMODE newMode = originalMode;

    // Changing the settings
    newMode.dmPelsWidth = (uint)width;
    newMode.dmPelsHeight = (uint)height;
    newMode.dmBitsPerPel = (uint)bitCount;

    // Capturing the operation result
    int result =
        ChangeDisplaySettings(ref newMode, 0);

    if (result == DISP_CHANGE_SUCCESSFUL)
    {
        Console.WriteLine("Succeeded.n");

        // Inspecting the new mode
        GetCurrentSettings();

        Console.WriteLine();

        // Waiting for seeing the results
        Console.ReadKey(true);

        ChangeDisplaySettings(ref originalMode, 0);
    }
    else if (result == DISP_CHANGE_BADMODE)
        Console.WriteLine("Mode not supported.");
    else if (result == DISP_CHANGE_RESTART)
        Console.WriteLine("Restart required.");
    else
        Console.WriteLine("Failed. Error code = {0}", result);
}

Changing Screen Orientation

Now we are going to change the screen orientation clockwise and anti-clockwise.

static void Main()
{
    // 0 degrees ( DMDO_DEFAULT = 0 )

    Console.WriteLine
        ("Press any key to rotate the screen . . .");
    Console.ReadKey(true);
    Console.WriteLine();

    RotateScreen(true); // 90 degrees (	DMDO_90 = 1 )
    Console.WriteLine
        ("Press any key to rotate the screen . . .");
    Console.ReadKey(true);
    Console.WriteLine();

    RotateScreen(true); // 180 degrees ( DMDO_180 = 2 )
    Console.WriteLine
        ("Press any key to rotate the screen . . .");
    Console.ReadKey(true);
    Console.WriteLine();

    RotateScreen(true); // 270 degrees ( DMDO_270 = 3 )
    Console.WriteLine
        ("Press any key to rotate the screen . . .");
    Console.ReadKey(true);
    Console.WriteLine();

    RotateScreen(true); // 0 degrees ( DMDO_DEFAULT = 0 )
}

public static void RotateScreen(bool clockwise)
{
    // Retrieving current settings
    // ...

    // Rotating the screen
    if (clockwise)
        if (newMode.dmDisplayOrientation  DMDO_DEFAULT)
            newMode.dmDisplayOrientation--;
        else
            newMode.dmDisplayOrientation = DMDO_270;

    // Swapping width and height;
    uint temp = newMode.dmPelsWidth;
    newMode.dmPelsWidth = newMode.dmPelsHeight;
    newMode.dmPelsHeight = temp;

    // Capturing the operation result
    // ...
}

Sample Application

The code sample is a simple application used to change display settings and to rotate the screen.

This is a snapshot of the application:

Display Settings Sample Snashot

Download Here

References

It is pleasure receiving your feedbacks and comments.

Programmatically Turning on the Screen Saver

هذه المقالة متوفرة أيضا باللغة العربية، اقرأها هنا.

Overview

This lesson focuses on how to programmatically turn on the screen saver.

Background

In Windows, you can turn it on automatically by leaving the machine inactive for a specific period. You can control this period from the Screen Saver options from the desktop properties dialog. The following figure shows the Screen Saver Settings dialog.

Screen Saver Settings

Programmatically turning on the screen saver

In this section we will learn how to turn on the screen saver in .NET and C#. Of course you can write the code in any language you prefer, but here we will write it in C#.

You can turn on the screen saver by sending the WM_SYSCOMMAND message with the parameter SC_SCREENSAVE.

Sending a message can be done using the SendMessage() function that resides in the User32.dll library.

The definition of this function is as follows:

LRESULT SendMessage(
    HWND hWnd,
    UINT Msg
    WPARAM wParam,
    LPARAM lParam
    );

This function takes four arguments:

  • hWnd:
    Handle to the window to send the message to. You can set this argument to a window handle, the desktop handle (HWND_DESKTOP), or the handle for all top-level windows (HWND_BROADCAST).
  • Msg:
    The message to send.
  • wParam:
    Additional message-specific options.
  • lParam:
    Additional message-specific options.

This function returns a value specific to the message sent. Usually, it returns non-zero if it succeed or zero otherwise.

Here is the full code:

// C# Code

[DllImport("User32.dll")]
static extern int SendMessage
    (IntPtr hWnd,
    uint Msg,
    uint wParam,
    uint lParam);

const uint WM_SYSCOMMAND = 0x112;
const uint SC_SCREENSAVE = 0xF140;
const uint HWND_BROADCAST = 0xFFFF;

static void Main()
{
    SendMessage(
    new IntPtr((int)HWND_BROADCAST),
    WM_SYSCOMMAND,
    SC_SCREENSAVE,
    0);
}
' VB.NET Code

Declare Auto Function SendMessage Lib "user32.dll" _
    (ByVal hWnd As IntPtr, _
    ByVal Msg As UInt32, _
    ByVal wParam As UInt32, _
    ByVal lParam As UInt32) As Int32

Const WM_SYSCOMMAND As UInt32 = &h212
Const SC_SCREENSAVE As UInt32 = &HF140
Const HWND_BROADCAST As UInt32 = &HFFFF

Sub Main()
    SendMessage( _
        New IntPtr(CInt(HWND_BROADCAST)), _
        WM_SYSCOMMAND, _
        SC_SCREENSAVE, _
        0)
End Sub

Code explanation

First, we created our PInvoke method. This method is decorated by the DllImportAttribute attribute specifying the library which the method resides in. Also PInvoke methods must be declared as “static” and “extern”.

Because LRESULT defined as a signed 32-bit integer, it is marshaled as System.Int32 in .NET. Also, because of System.IntPtr is the best type for marshaling any Win32 raw handle, we have used it for the first argument. UINT, WPARAM, AND LPARAM are all defined as an unsigned 32-bit integer, so we have marshaled them as System.UInt32. HWND_BROADCAST represents the handle for all top-level windows, so we have sent them the order to turn on the screen saver.

PInvoke stands for Platform Invocation, it is the process of creating a wrapper for the .NET to interact with unmanaged functions.

Marshaling is the process of creating a bridge between .NET types and unmanaged types.

You can use PostMessage() in place of SendMessage() if you want to send the message asynchronously and don’t want to wait for a response.

Read more about PInvoking and Marshaling in other API lessons.

Creating a Stack-Based Array

هذه المقالة متوفرة أيضا باللغة العربية، اقرأها هنا.

Introduction

By default, arrays are stored in the managed heap with all of the overhead involved and that’s because arrays simply are instances of type System.Array that inherits from System.Object. Storing an object into heap means that it will not be removed from the memory until a garbage collection (whether automatic or by calling System.GC.Collect()) occurs. Also, storing it into the heap means suffering from low-performance and the overhead (for the CLR) of storing and retrieving it into and from the heap.

To overcome those performance issues and to create short-lived high-performance arrays or even if you want to interoperate with other unmanaged code then you need to work with stack-based arrays. Stack-based arrays stored in the stack. Means high-performance and short-live for the array because we are stepping out the CLR and working with the memory directly.

It might be worth mentioning that types inherit -directly or indirectly- from System.Object are heap-based. Conversely, Types inherit -directly or indirectly- from System.ValueType are stack-based. Although, System.ValueType inherits from System.Object, it is stack-based. Examples of stack-based types are all enumerations, structures, and primitive data types (like Int32 and Boolean).

Creating stack-based arrays

Creating stack-based arrays is very simple. But first, you need to allow unsafe code for the project, and this can be done through the project properties in the Build tab. After that, you can write your code.

The code for creating the stack-based array is as follows:

// Methods that use unsafe code
// must declared as unsafe
// or its containing type
public unsafe static void CreateArray()
{
    int length = 10;

    // Creating Int32 stack-based array
    // with a specific length
    int* pArr = stackalloc int[length];

    // Setting the first value to 1
    *pArr = 1;

    // This code also sets the first value
    // but to 10
    pArr[0] = 10;

    // Setting the second value to 2
    *(pArr + 1) = 2;

    // This code also sets the second value
    // but to 20
    pArr[1] = 20;

    // Retrieving stored values
    Console.WriteLine("First value: {0}", *pArr);
    Console.WriteLine("First value: {0}", pArr[0]);
    Console.WriteLine("Second value: {0}", *(pArr + 1));
    Console.WriteLine("Second value: {0}", pArr[1]);
    Console.WriteLine();

    // Prints:
    // First value: 10
    // First value: 10
    // Second value: 20
    // Second value: 20

    // Setting all values
    for (int idx = 0; idx < length; idx++)
    {
        pArr[idx] = idx + 1;
        // Also this works well
        (pArr + idx) = idx + 1;
    }

    // Retrieving all values
    for (int idx = 0; idx < length; idx++)
        Console.WriteLine("Value {0} = {1}", idx, pArr[idx]);

    // Prints:
    // Value 0 = 1
    // Value 1 = 2
    // ............
    // Value 8 = 9
    //Value 9 = 10

    // The array removed from the memory here
    // Because the scope which
    // it was declared on ends here
} 

Code Explanation:

First, we created the array using the stackalloc keyword giving the length for the new array and the type of which is Int32 for our example (you can change it to any value type.) Because Int32 reserves 4-bytes in memory we end up reserving 40 bytes (length 10 multiplied by the Int32 size 4) memory block in the stack for our array.

Stack-Based Array

The last figure shows the pointer returned by the stackalloc, which is always a pointer to the first element of the array. Note that every block is an element of the array. In our example it is 4-bytes.
After creating our array putting the last figure into mind we have many ways for accessing array elements.

A note about scope

If you come to this point I think you know well what scope is and how it does affect the code flow. But, I think it is worth noting that you can create new scopes using just two curly brackets. See the following sample class:

public class ClassScope
{
    // Scope 1

    public void Method1()
    {
        // Scope 1.1

        {
            // Scope 1.1.1
            {
                // Scope 1.1.1.1
            }

            {
                // Scope 1.1.1.2
            }
        }
    }

    public void Method2()
    {
        // Scope 1.2

        if (true)
        {
            // Scope 1.2.1

            while (true)
            {
                // Scope 1.2.1.1
            }
        }
    }
}

Quickly copying arrays

It is very handful using pointers to pass the CLR and work directly with memory pointers to copy elements from an array to another the fastest we can. The following code segment does this:

unsafe static void Copy(int[] src, int srcIdx,
    int[] dst, int dstIdx, int count)
{
    // Because normal arrays are heap-based
    // garbage collector can move them
    // from time to time
    // so we use the fixed keyword
    // to stick them and tell
    // the garbage collection to not
    // to move them until fixed
    // statement closes
    fixed (int* pSrc = src, pDst = dst)
    {
        // Getting a pointer to the first
        // element of the array
        int* pSrcIdx = &srcIdx;
        int* pDstIdx = &dstIdx;

        // Ensuring copying the required count only
        for (int counter = 0; counter < count; counter++)
        {
            // Copying....
            // Because Int32 is stack-based
            // it is copied not referenced
            pDst[dstIdx] = pSrc[srcIdx];
            // Moving the pointer to the
            // next element
            dstIdx++;
            srcIdx++;
        }
    }
}

Code explanation:

Because normal arrays are heap-based, it can be moved from its location when a garbage collection occurs, so we tell the CLR that there’re references to it, so we do not need it to be moved any where until finishing up.

Honestly, you strictly should avoid using unsafe code when possible. Because, you are working with memory directly. At least you might by mistake overwrite any data stored in the memory without being notified about.

Programming Microsoft Agent in Windows Forms

هذه المقالة متوفرة أيضا باللغة العربية، اقرأها هنا.

App: Geming.PartIt.msi
Code: Geming.PartIt (Source).msi

Contents

Contents of this article:

  • Contents
  • Overview
  • Microsoft Agent Characters
  • Microsoft Agent SDK
  • Microsoft Agent Windows Forms Support
  • Loading Characters
  • Ordering the Character to Speak
  • Moving the Character
  • Character Animation
  • IAgentCtlCharacterEx Properties
  • AxAgent Control Events
  • Creating a Custom Popup Menu
  • Creating a Microsoft Agent Controller
  • Freeing up Resources
  • The Last Word
  • Microsoft Agent Compatibility
  • Where to Go Next?
  • A Real-World Example

Overview

Microsoft Agent is an unprecedented technology to create innovative, new conversational interfaces for applications and Web pages. It provides powerful animation capability, interactivity, and versatility, with incredible ease of development.

Microsoft Agent is a technology that provides a foundation for more natural ways for people to communicate with their computers. It is a set of software services that enable developers to incorporate interactive animated characters into their applications and Web pages. These characters can speak, via a Text-to-Speech (TTS) engine or recorded audio, and even accept spoken voice commands. Microsoft Agent empowers developers to extend the user interface beyond the conventional mouse and keyboard interactions prevalent today.

Enhancing applications and Web pages with a visible interactive personality will both broaden and humanize the interaction between users and their computers.

There are a limitless number of roles and functions that developers can create for these personalities to perform.

  • A welcome host could greet new users and provide a guided tour the first time a computer is turned on, an application is run, or a Web site is browsed.
  • A friendly tutor could lead someone through a task or a decision tree with instructions step-by-step along the way.
  • A messenger could deliver a notification or alert that a new e-mail has arrived and then offer to read it to you.
  • An assistant could perform tasks for you like looking up information on the Internet and then reading it out loud.

Although, this lesson focuses on Windows Forms, you can take advantage of Microsoft Agent in Web applications, and also XAML applications. For Web application, you can refer to the Microsoft Agent Platform SDK documentation. For XAML applications, it is the same as Windows Forms, except that you will need to add Microsoft Agent Control inside a Sysetm.Windows.Forms.Integration.WindowsFormsHost WPF control.

Microsoft Agent characters

Microsoft Agent characters can be found in various applications and Websites, including Office 2003 and its ascendants, it comes as the Office Assistant. Figure 1 shows the Clippit office assistant. And figure 2 shows Merlin the most widely-used Microsoft Agent character in Websites and applications.

Figure 1 - Clippit

Figure 1 - Clippit

Figure 2 - Merlin

Figure 2 - Merlin

There’re plenty of characters available for download. Though, Merlin is included by default in Windows. In addition, Office 2003 comes with many characters including Clippit.

Visit Microsoft Agent Ring for downloading plenty of characters.

Microsoft Agent SDK

Programming Microsoft Agent is very easy. But, in order to start programming you need to download the Microsoft Agent SDK. It’s available for downloadalong  with its documentation in the Microsoft Agent SDK download page on Microsoft. In addition, you need to download the Speech API and Text-to-Speech (TTS) Engine in order to enable the speech feature of Microsoft Agent. These packages are available in the Speech SDK in this page. The most recent version is 5.1.

The Text-to-Speech (TTS) Engine is used to translate text into voice.

It is worth mentioning that, if you need to extend speech feature of Microsoft Agent to support other languages other than English, you need to download your preferred language package from the Speech SDK page.

In addition, you are not end up using characters created for you. If you need to create your own characters you can download the Agent Character Editor and start using character creation.

Take into consideration that, for the application to run correctly on user’s machine, the user need to install two packages, Microsoft Agent and Microsoft TTS. Remember to inculde them as prerequisites in your application installer package.

After downloading and installing the Microsoft Agent SDK, you may notice that Microsoft Agent SDK offers you many components for many purposes. The most component that we are interested in is the ActiveX COM library AgentCtl.dll that contains the Microsoft Agent support features for Windows Forms. It contains the Microsoft Agent Control that’s the door for Microsoft Agent Windows Forms programming. This component -and many others- resides on %windir%MSAgent.

Microsoft Agent Windows Forms Support

Because AgentCtl.dll is an ActiveX component you cannot use it directly in your code. You need to create a RCW (Runtime-Callable Wrapper) component (assembly) that will act as a bridge between .NET and the COM component. This is done automatically while adding the ActiveX component control to your toolbox in Visual Studio. Another way is to use the AxImp.exe tool that comes with the .NET Framework SDK.

You might be wandering why we haven’t used the TlbImp.exe tool? Because this is an ActiveX COM component contains ActiveX controls. Therefore, we used the AxImp.exe.

Because .NET and COM cannot call each other directly, two types of wrapper components exist in the space, RCWs (Runtime-Callable Wrappers) and CCWs (COM-Callable Wrappers). RCWs are .NET assemblies act as the bridge between .NET and COM. Conversely, CCWs are COM components act as the bridge between COM and .NET.

To use Microsoft Agent in our Windows Forms application, simply, we’ll start by adding the Microsoft Agent Control to our toolbox. Figure 3 shows the Choose Toolbox Items dialog in the COM Components tab.

Figure 3 - Adding Microsoft Agent Control into Toolbox
Figure 3 – Adding Microsoft Agent Control into Toolbox

This component contains a single control Microsoft Agent Control that will be added automatically to the toolbox. After dragging it to the form, two components will be added automatically to the project references, AgentObjects and AxAgentObjects. These are the interoperability RCW wrapper components for the COM component. AxAgentObjects is the wrapper for the control and its related types. On the other hand, AgentObjects component is the wrapper for other types in the COM component. You might have noticed that a square-shaped control of type AxAgentObjects.AxAgent added to the form. This control will not be visible at runtime. Figure 4 shows the form.

Figure 4 - Microsoft Agent Control
Figure 4 – Microsoft Agent Control

AgentCtl uses STA (Single-Threaded Apartment) threading model. Means that the COM component supports -and bounds- only to a single thread.

To enable STA for your application you need to adorn the Main() function with the STAThreadAttribute attribute. Conversely, MTA (Multi-Threaded Apartment) threading model means that the COM component supports and can be accessed by multiple threads.

If neither STAThreadAttribute nor MTAThreadAttribute attributes has not been set, the threading model by default is MTA. Another way to set the threading model is the System.Threading.Thread.SetApartmentState instance (opposite of static) method.

To know whether a COM component supports STA, MTA, or both threading models, you can check the registry value ThreadingModel on HKCRCLSIDInprocServer32.

Loading Characters

After adding the AxAgent control to the form, you can now order the control to load the character(s) and show it.
AxAgent control contains a property Characters that’s of type AgentObjects.IAgentCtlCharacters that acts as a dictionary collection contains the loaded characters and its names.

For loading a character we use the Load() method of the Characters collection. For getting the loaded character we use the Character() method that returns an object of type AgentObjects.IAgentCtlCharacterEx that represents the loaded character.

Here’s the code for loading the character Merlin and showing it:

// Here I'll specify the character name
// and the character location.
this.axAgent1.Characters.Load("Merlin",
    @"C:WindowsMSAgentcharsmerlin.acs");

AgentObjects.IAgentCtlCharacterEx character = this.axAgent1.Characters.Character("Merlin");

// A single argument contains a value to whether
// to animate the character while showing it
// or skipping the animation.
// You should set this to null or false.
// Set it to True to skip the animation.
character.Show(null);

In addition to Load() and Character() methods of the IAgentCtlCharacters object, you can use the Unload() method to unload a given loaded character.

Also IAgentCtlCharacterEx supports the Hide() method for hiding the character, that’s opposite to the Show() method.

Ordering the Character to Speark

After creating the character and showing it you can order it to speak whether a specific text using the Text-to-Speech (TTS) Engine or a recorded audio file. The following code segment makes the character introduces itself using coded string first and a recorded audio file next:

character.Speak(
    "Hello everybody, I'm Merlin. I'll guide you throuh the application windows.",
    null);

character.Speak(null, @"D:Recorded Introduction.wav");

As you have noticed, the Speak() method can take either a text for the first argument or a file path for the second argument. Figure 5 shows Merlin while speaking the text.

Figure 5 - Merlin Speaks
Figure 5 – Merlin Speaks

Take a look at the Think() method, it is very similar to Speak().

Moving the character

You can move the character around the screen by using the MoveTo() method.

character.MoveTo(100, 100, null);

This method takes three arguments, the first and second argument is the location on the screen that you wish to move the character to. The third argument takes a value indicating the moving speed. If this argument is null, then the default value 1000 is used. If you specified the value 0 the character will move without playing an animation. Obviously, a value under 1000 will slow down the character move, and a value greater than 1000 will speed up the move.

I had reasons to merge this section with the animation section. But, I had reasons too  to put it in a single section, I think it’s a special type of animations!

Character Animation

Every character has its own animations. Although, many characters share many animation names but that’s not required.

Every animation has a name. And to get the animation names that a character supports, you need to dig into the AnimationNames property that’s of type AgentObjects.IAgentCtlAnimationNames which implements the System.Collections.IEnumerable interface.

The following code enumerates the animation names of the character:

IEnumerator enumerator = character.AnimationNames.GetEnumerator();
while (enumerator.MoveNext())
    this.listBox1.Items.Add(enumerator.Current.ToString());

Now, it’s time to have some fun with the character. Try the following code:

character.Play("DoMagic1");
character.Speak("I'm better than Harry Potter. Am not I?", null);

Figure 6 shows Merlin speaking while doing some magic. (Proud Merlin)

Fogure 6 - Merlin Does Magic
Fogure 6 – Merlin Does Magic

Be aware that animation names that contain directions like left and right, it’s the left and right of the character not you.

In addition to the Play() method, the character object supports two methods for stopping playing animations, Stop() and StopAll(). Stop() stops the animation that’s specified by its single argument. StopAll() stops all animation of a specific type. This method has a single argument that can takes a string value of three “Move”, “Play”, and “Speak” to stop moving, animation or speaking commands. In addition to the three values, StopAll() can take a null value, and that means stopping all types of animations.

You might have noticed that many methods of the character object returns an object of type AgentObjects.IAgentCtlRequest. This type encapsulates a request to the character. If IAgentCtlRequest.Status is non-zero then the operation failed, otherwise succeeded.

Pay attention to the methods that return IAgentCtlRequest object, and the methods that requires it as an argument like Stop() method.

Another type of animation is gesturing to a specific point. Try this animation using the GestureAt() method.

IAgentCtlCharacterEx Properties

This list contains the most common properties of the character object (IAgentCtlCharacterEx):

  • AutoPopupMenu:
    A Boolean property indicates whether to allow the character pop-up menu or not. Pop-up menu is the menu that is shown when the user right-clicks on the character or its icon -if exists- on the taskbar. Default value is False.
  • Balloon:
    This is a read-only property that’s in turn contains read-only properties that indicate the characteristics like the back color of the balloon displayed while the character talking. This property contains many properties that most are self-explained from its names.
  • Left and Top:
    Controls the character location on the screen. (It is better using the MoveTo() method instead of these two properties if you want to play an animation while moving the character).
  • MoveCause:
    A read-only property returns a value indicates what caused the character’s last move. This property can return one of 5 values:

    • 0:
      The character has not been moved.
    • 1:
      The user moved the character.
    • 2:
      Your application moved the character.
    • 3:
      Another client application moved the character.
    • 4:
      The Agent server moved the character to keep it onscreen after a screen resolution change.
  • Pitch:
    A read-only property returns a value indicates the Pitch setting of the TTS.
  • SoundEffectsOn:
    Set this property to True to enable the sound effects, of False to disable it. Default is True.
  • Speed:
    A read-only property indicates the speed of the character. (Also there’re some operations that supports specifying the speed like the MoveTo() method).
  • VisibilityCause:
    A read-only property returns a value indicates the character’s visibility state. This property can return one of 8 values:

    • 0:
      The character has not been shown.
    • 1:
      User hid the character using the command on the character’s taskbar icon pop-up menu or using speech input..
    • 2:
      The user showed the character.
    • 3:
      Your application hid the character.
    • 4:
      Your application showed the character.
    • 5:
      Another client application hid the character.
    • 6:
      Another client application showed the character.
    • 7:
      The user hid the character using the command on the character’s pop-up menu.

Agent Server is the hard-core component that controls the Microsoft Agent behind the scenes. It controls all the characters loaded by your application and other applications and Websites. It’s the one which servers all orders for every Microsoft Agent character. Worth mentioning, it’s contained in the executable file AgentSvr.exe located on %windir%MSAgent. This file will be launched automatically when the first character loaded, and will shuts down automatically when the last character unloaded. After all, you can think about the Agent Server as the hard-core internal component of the Microsoft Agent.

AxAgent Control Events

An odd behavior of that control is that it defines events that related to the character and most likely to be located in the character object itself. Maybe it’s a feature to be located here because AxAgent controls the birth and death of the characters, but most of the time you will find that annoying.

The most widely-used events are:

  • BalloonShow and BalloonHide:
    Occur when a balloon of a loaded character shown or hid.
  • ClickEvent and DblClick:
    Occur when a loaded character clicked or double-clicked.
  • DragStart and DragComplete:
    Occur when a user tries to drag a loaded character.
  • ShowEvent and HideEvent:
    Occur when a loaded character shown or hide, whether the user who made this or your code. If you want to check what caused the character to be shown check the IAgentCtlCharacterEx.VisibilityCause. As a refresher, read the last section to know about this property.
  • MoveEvent:
    Occurs when a loaded character moved whether the user moved it or it’s moved by your code. See the IAgentCtlCharacterEx.MoveCause in the previous section if you want to know what caused the character to be moved.
  • RequestStart and RequestComplete:
    Occur when a request being restarted or after it completed. Note that many methods accept and many others return IAgentCtlRequest objects that defines requests sent to the server.

Creating a Custom Popup Menu

After you have included your desired agent in your application, are you feeling bad with the default popup menu? If so, then you are in the right place.

First, create your System.Windows.Forms.ContextMenuStrip and add your required items (well, including “Hide” maybe) and complete the item event handlers.

Now, let’s get it. Get to the code that loads the agent character (e.g. calls the Characters.Load() method of the agent control object, AxAgentObjects.AxAgent) and just disable the AutoPopupMenu flag/property of the character object, AgentObjects.IAgentCtlCharacterEx. This flag/property determines whether to allow the default popup menu or not.

For example, the following code disables this property:

AxAgentObjects.AxAgent agentCtl;
AgentObjects.IAgentCtlCharacterEx agentChar;

// initializing 'agentCtl'
// . . .

agentCtl.Characters.Load("Merlin", "merlin.acs");
agentChar = agentCtl.Characters.Character("Merlin");
agentChar.AutoPopupMenu = false;

Next comes the interesting point. When the character is clicked, the ClickEvent event of the agent control (AxAgent) fires. So the next step is to handle this event and to provide your code that brings up your custom context menu. Consider the following code:

// agentCtl.ClickEvent += agent_ClickEvent;

public void agentCtl_ClickEvent(object sender, AxAgentObjects._AgentEvents_ClickEvent e)
{
    if (e.characterID == "Merlin")  // check for this if you have many characters
    {
        if (e.button == 2) // 1 = left, 2 = right
        {
            myContextMenu.Show(e.x, e.y);
        }
    }
}

Creating a Microsoft Agent controller

When dealing with Microsoft Agent, there’s recommended practices. One of is abstracting the Microsoft Agent implementation code from the UI code for achieving the maintainability and usability goals, and these goals can be achieved through a controller class that encapsulates the functionality that you need and provides easy access to lots of operations using a single call. A good controller class example is like this:

internal sealed class AgentController
{
    private AgentObjects.IAgentCtlCharacterEx _char;
    private AxAgentObjects.AxAgent _agent;

    public AgentController(AxAgentObjects.AxAgent agent,
        string characterLocation)
    {
        _agent = agent;
        _agent.Characters.Load("CHAR", characterLocation);
        _char = _agent.Characters.Character("CHAR");
        _char.Show(null);
    }

    public bool IsVisible() { return _char.Visible; }
    public void Animate(string animation, bool stopAll)
    {
        if (stopAll)
            _char.StopAll(null);
        _char.Play(animation);
    }
    public void Speak(string text, bool stopAll)
    {
        if (stopAll)
            _char.StopAll(null);
        _char.Speak(text, null);
    }
    public void MoveTo(int x, int y, bool stopAll)
    {
        if (stopAll)
            _char.StopAll(null);
        _char.MoveTo((short)x, (short)y, null);
    }
    // Encapsulating many operations into one
    public void Surprise()
    {
        _char.StopAll(null);
        _char.Play("Alert");
        _char.Play("Sad");
    }
}

Freeing up Resources

After finishing your work with Microsoft Agent you should first unload the character by calling AxAgent.Characters.Unload() method. Second, because all objects of the RCW (Runtime-Callable Wrapper) assemblies created earlier are just a wrapper around the unmanaged COM objects, they exhaust a great amount of unmanaged resources that can retain in memory for a long time, you strictly should always dispose these object when you have done with it.

Fortunately, AxAgent control inherits indirectly from the IDisposable interface, so you can easily dispose it by calling its Dispose() method. Conversely, most objects (like the character object IAgentCtlCharacterEx) in the RCWs do not implement this interface, so you need to do it the hard way and use the Marshal class to dispose it. Here’s the code that can do that:

while (System.Runtime.InteropServices.
Marshal.FinalReleaseComObject(_char) > 0);

The FinalReleaseComObject() simple tries to decrement the references of the COM object to 0. You need to call FinalReleaseComObject() again and again until it returns 0, means that no references remain.

FinalReleaseComObject() tries to decrement the reference count to 0 in one time, ReleaseComObject() tries to decrement it gradually. So ReleaseComObject() needs more calls than FinalReleaseComObject(). and FinalReleaseComObject() is faster than ReleaseComObject().

Decrementing object’s references means disposing it.

You learned how to free-up the resources. But, there’s a question now. At which point should you dispose objects? It depends! The point at which you need to dispose objects depends on your use of objects. First, if you finished working with the AxAgent control and you do not want it any more till the user closes your application, it’s recommended that you dispose it as soon as possible. Otherwise, add the Dispose() call to the protected Dispose(bool) method of the form, so that it disposed when the form closes (honestly, disposes). The following code snippet demonstrates this:

protected override void Dispose(bool disposing)
{
    try
    {
        if (disposing)
        {
            this.axAgent1.Dispose();
            if (components != null)
                components.Dispose();
        }
    }
    finally { base.Dispose(disposing); }
}

This code strictly follows the disposing design guidelines.

You can step to the Dispose() method from the Members combo box in the top-right of the Code Editor window of the form.

A programming extremist like me (one of the Qaeda squad programming team :P) always disposes his objects even if the application is shutting down. To be honest, when the application shuts down all resources and memory managed by the application will be released immediately, so you actually do not need to release objects while the application shuts down.

On the other hand, for some objects like IAgentCtlCharacterEx you should take the Marshal class approach. But where to use it?

A great location for the FinalReleaseComObject() method (or ReleaseComObject() as well) is in the controller class. You can make your controller class implements the IDisposable interface and add your code inside the Dispose() method. Check the following example:

Code abbreviated for clarity.

internal sealed class AgentController : IDisposable
{

    ............

    public void Dispose()
    {
        _char.StopAll(null);
        _char.Hide(null);
        _agent.Characters.Unload("CHAR");
        while (System.Runtime.InteropServices.Marshal.FinalReleaseComObject(_char) > 0) ;
    }
}

You should dispose the controller class as soon as you finish using your character, or even with the form disposal along with the disposing of the AxAgent control.

The Last Word

Needless to say that you can take advantage of the Microsoft Agent and TTS technology to produce applications that provide friendly tutor for the user.

You are not end up using existing Microsoft Agent characters, you can create your own characters and animations using the Microsoft Agent Character Editor that’s available for download in the Microsoft Agent SDK download page.

Microsoft Agent Compatibility

Microsoft announced that Windows 7 would not be compatible with Microsoft Agent. However, you still can install the SDK and run your applications correctly.

Where to Go Next?

Good references for Microsoft Agent are:

  • Microsoft Agent SDK Documentation. Available for download with the SDK, see “Micrososft Agent SDK” section on the top.
  • Book: Microsoft Agent Software Development Kit.
    ISBN: 0-7356-0567-X
  • Book: Developing for Microsoft Agent.
    ISBN: 1-5723-1720-5

A Real-world Application

This lesson does not contain a sample project, it contains a real-world application, Geming PartIt! that’s used for parting large files into small pieces for merging them later, so you can send them via e-mail or storing them on CDs and Floppy Disks. This application uses Microsoft Agent character Merlin to provide a friendly guide for the user through the application.

Download the sample app!
Download the sample source!


It is my pleasure receiving comments and feedbacks about my application (and code of course.)