Clearing the Console Screen using API

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

Code: Geming.Suite.Console.zip

What you learn?

In addition to clearing the console screen, this lesson teaches you some about PInvoking, marshaling, and memory management. Also you will learn additional techniques like clearing a specific portion of the screen, and changing the cursor position. Moreover, you will dig into IL and see how System.Console.Clear() method do it. More than that you will learn how to reverse-engineer a .NET assembly and discover the code inside.

In addition, the example shows how to perform I/O operations on console using Win32 API calls, and how to show/hide the console cursor. In addition, it demonstrates how to move a text around the console screen.

Foreword

I am one of the huge supporters of console when it comes to the fact that we need simple and fast application such as tools and utilities.

One of the common needs of console is performing clear-screens (CLSs) when necessary.

When dealing with the Command Prompt you can order it to clear the screen by submitting the command “cls” and pressing Enter.

But, programmatically, you have no way to order the command “cls,” so you must find a substitute (or more.)

Starting from version 2.0 of the .NET Framework, System.Console has been added a new method, it is the Clear() method for clearing the console screen.

For versions before 2.0, or if you need to do it the hard-way, or even if you want to have more control over the clearing progress such as clearing a specific portion of the screen, you must dig into Win32 API and call special functions for doing so.

Clearing the console screen done through four Win32 API functions, GetStdHandle(), GetConsoleScreenBufferInfo(), FillConsoleOutputCharacter() and SetConsoleCursorPosition(). It is worth noting that all these functions located in Kernel32.dll library.

Be sure that the System.Console.Clear() method in .NET 2.0 and descendant call these four functions -and more- initially.

GetStdHandle() function

This method is the gate for dealing with console via the API. Almost every console operation requires a call to GetStdHandle() first.

GetStdHandle() simply returns the handle for the standard input, output, error device (“stream” in .NET methodology.) This function takes a single argument specifies which standard device (stream) we wish to retrieve the handle for.

The syntax of this function -in C- is as following:

HANDLE GetStdHandle(
    DWORD nStdHandle
    );

The nStdHandle argument can take one of three values:

  • STD_INPUT_HANDLE = -10
    Specifies the standard input device (stream.)
  • STD_OUTPUT_HANDLE = -11
    Specifies the standard output device (stream.)
  • STD_ERROR_HANDLE = -12
    Specifies the standard error device (stream.) It is always the output device (stream.)

As its names implies, input device used for receiving user input, output device used for writing output to the user, and error device used too for writing error information to the user. In .NET, you access these devices (streams) via nice wrappers. They are the static properties In, Out, and Error of the Console class. I guess that after playing with these nice wrappers you now know what standard devices are.

Because there’s no such way for .NET to interoperate with Win32 API directly, you need to create wrappers for the Win32 API functions you use, and this is done through PInvoking.

PInvoke stands for Platform Invocations. It is the mechanism for the .NET to interoperate with its “girlfriend” Win32 API.

The PInvoke method for GetStdHandle is as following – code assumes that you add a using statement for the System.Runtime.InteropServices namespace:

[DllImport("Kernel32.dll")]
public static extern IntPtr GetStdHandle(int nStdHandle);

Code explanation:

The DllImport attribute is required for PInvoke methods so that you can specify the DLL which the function resides in. Also DllImport have a very important role when you need to change the name of the method. If you need to change the name of the PInvoke method then you must set the property EntryPoint of DllImportAttribute to the original name of the function in the DLL. If you have not set this property, .NET will search the DLL for the method and will throw a System.EntryPointNotFoundException exception if it is not found.
“static” and “extern” are modifiers required for PInvoke methods.
Because some data types do not exist in .NET, you need to find a substitute. In other words, you need to marshal unmanaged Win32 data types to the new managed .NET types. So we have marshaled HANDLE to System.IntPtr and DWORD to System.Int32.

Only a single output handle serves the console application (the same for input and error devices,) so do not close that opened handle using the CloseHandle() function because it will result that you cannot write to the console any more, unless you open it again.

A note about marshaling

Because there’re plenty of Win32 data types that do not have correspondents in .NET, you must do Marshaling. Marshaling is the process of creating a bridge between .NET types and unmanaged types. Marshaling converts .NET types into unmanaged types. As we have seen in the last code, .NET does not contain DWORD, and because DWORD is a 32-bit unsigned integer we have to marshal it as System.UInt32. However, we marshaled it in GetStdHandle() as System.Int32! While unsigned integers (inculding DWORD) do not accept negative numbers, GetStdHandle() requires DWORD. Actually, it is OK because negative values can be stored in DWORD in a special way. For example, -10 stored as FFFFFFF6, -11 stored as FFFFFFF5, and so on. And that what GetStdHandle() actually does.

In addition, you may notice that we have marshaled HANDLE as System.IntPtr, because IntPtr is the best type fits to any Win32 handle. Moreover, .NET supports managed handles via the abstract SafeHandle and CriticalHandle classes.

It is worth mentioning that System.Runtime.InteropServices.MarshalAsAttribute attribute can have a noticeable effect over the marshaling process.

Good resources describe the marshaling process and the Win32 data types can be found in the references section.

Managed code is the .NET code that runs inside the CLR (Common Language Runtime,) because CLR manages and controls this code. Conversely, unmanaged code is the code other than the managed code. It is legal that you write code in .NET that runs outside the CLR such as direct memory management and that code called Unsafe Code because it is error-prone and may result to an unpredictable behavior. Also, MC++ allows you to write unmanaged code together with the managed code.

GetConsoleScreenBufferInfo() function

The third method we will use is the GetConsoleScreenBufferInfo(). This method retrieves information about a specific console screen buffer (in other words, device.) This information is like console screen buffer size, the location and bounds of the console window, and the cursor position inside the screen.

The definition of this function is as following:

BOOL GetConsoleScreenBufferInfo(
    HANDLE hConsoleOutput,
    [out] SCREEN_BUFFER_INFO lpConsoleScreenBufferInfo
    );

typedef struct CONSOLE_SCREEN_BUFFER_INFO {
    COORD dwSize;
    COORD dwCursorPosition;
    WORD wAttributes;
    SMALL_RECT srWindow;
    COORD dwMaximumWindowSize;
};

typedef struct COORD {
    SHORT X;
    SHORT Y;
};

typedef struct SMALL_RECT {
    SHORT Left;
    SHORT Top;
    SHORT Right;
    SHORT Bottom;
};

Lengthy, isn’t it? Yeah, that’s true. Beside the GetConsoleScreenBufferInfo(), there’re three more structures, because the type of second argument of the function is the first structure, and the first structure in turn references the second and third structures.

The CONSOLE_SCREEN_BUFFER_INFO structure represents the console information. This information is:

  • The size of the console screen buffer in character rows and columns.
  • The position of the cursor in the console screen in character rows and columns.
  • Characteristics of the character written to the console like the fore color and back color.
  • The location and bounds of the console window.
  • The maximum size for the console window if we take into account the font size and the screen buffer size.

What is screen buffer and window size and what is the difference? Start the Command Prompt and right click its icon in the taskbar and go to the layout tab of the properties dialog box. Take some time playing with the values in this tab.
Window size is the size of the console window -like any other window.- Screen buffer size determines the amount of text which the console screen can hold, so you always see the vertical scroll bar because the buffer height is bigger than the window height.

Here’s the PInvoke method and the marshaling types because .NET does not have such those three structures:

[DllImport("Kernel32.dll")]
public static extern int GetConsoleScreenBufferInfo
    (IntPtr hConsoleOutput,
    out CONSOLE_SCREEN_BUFFER_INFO lpConsoleScreenBufferInfo);

[StructLayout(LayoutKind.Sequential)]
public struct CONSOLE_SCREEN_BUFFER_INFO
{
    public COORD dwSize;
    public COORD dwCursorPosition;
    public ushort wAttributes;
    public SMALL_RECT srWindow;
    public COORD dwMaximumWindowSize;
}

[StructLayout(LayoutKind.Sequential)]
public struct COORD
{
    public short X;
    public short Y;
}

[StructLayout(LayoutKind.Sequential)]
public struct SMALL_RECT
{
    public short Left;
    public short Top;
    public short Right;
    public short Bottom;
}

Code explanation:

Because .NET does not contain such these three structures, and we do not have any substitutes, so we have to marshal it, we have created it manually and mapped unmanaged to the managed data types. And because memory layout of such these object is very important, we added the StructLayout attribute and specified LayoutKind.Sequential that informs the marshaller that this structure will laid-out in memory sequentially so the first field comes before the second and so on. Also you might notice that WORD unmanaged data type is an unsigned 32-bit integer so we marshaled it as UInt32. Also SHORT is signed 16-bit integer so it is very easy to marshal it as Int16. Refer to the references section for more information about Win32 data types.

BOOL defined as a 32-bit signed integer, so we have marshaled the return value of the function as Int32 not Boolean because Boolean reserves 4-bits only. It will work well with Boolean, but it is better using Int32. Though, if you want to use Boolean, is helpful decorating the return value with the MarshalAs attribute.

Also, it is very efficient to use the System.Runtime.InteropServices.InAttribute and System.Runtime.InteropServices.OutAttribute to give a notation to the marshaller. The code sample demonstrates this.

A note about memory management

You already know that every object reserves space in memory. And the memory itself divided into two parts, Heap and Stack. Objects -directly or indirectly- inherit from System.ValueType are stack-based (like structures, enumerations and primitive data types.) Conversely, most objects  -directly or indirectly- inherit from System.Object are heap-based (like most objects.) And you know also that heap objects managed by the Garbage Collector (GC) and they may remain in the memory for a long time -actually even if you called System.GC many times.- On the other hand, stack objects are removed from the memory immediately when their scope ends. In addition, you need to know that stack is filled downwards. See figure 1.

Stack Memory

When interoperating with unmanaged code and marshaling types between the .NET and Win32 API (for instance) you need to know how to layout your type in memory. Unmanaged code assumes that types are laid sequentially based on the order of fields. For our example, the CONSOLE_SCREEN_BUFFER_INFO must be laid-out so dwSize comes before dwCursorPosition and so on. See figure 2.

CONSOLE_SCREEN_BUFFER_INFO in Memory

We can dig into more details and see how Windows will store the CONSOLE_SCREEN_BUFFER_INFO structure in the stack and how it will be rendered. See figure 3.

console_screen_buCONSOLE_SCREEN_BUFFER_INFO in Memory _ DetailsCONSOLE_SCREEN_BUFFER_INFO in Memory _ Details

From the diagrams we learn that:

  • Objects are stored downwards in the stack by the order they were created.
  • Object containing objects also stored downwards by the order they were declared.
  • Every object has a size. And this size determined by its containing objects -if it is not a primitive type of course.-

You can get the size of an object using two ways, the sizeof keyword, and System.Runtime.InteropServices.Marshal.SizeOf method. The second method is preferred. Do you know why? Try, think, and then answer.

Now, we know why the StructLayout attribute is required. And why sequential layout is required. But what if you prefer to change the order of fields? Answer is very simple. Change the LayoutKind to Explicit and decorate every field with FieldOffset attribute and specify its location from the beginning of the structure. In the following code fields are reversed but they perfectly laid-out in memory using the FieldOffset attribute:

[StructLayout(LayoutKind.Explicit)]
public struct CONSOLE_SCREEN_BUFFER_INFO
{
    [FieldOffset(18)]
    public COORD dwMaximumWindowSize;
    [FieldOffset(10)]
    public SMALL_RECT srWindow;
    [FieldOffset(8)]
    public ushort wAttributes;
    [FieldOffset(4)]
    public COORD dwCursorPosition;
    [FieldOffset(0)]
    public COORD dwSize;
}

If you set the LayoutKind to Auto, you will not be able to interoperate with unmanaged code using the type. Also if you have omitted the whole StructLayoutAttribute.

Also, from the diagrams illustrated -specially the last one- we can also write our CONSOLE_SCREEN_BUFFER_INFO structure to be as following and remove the other two structures:

[StructLayout(LayoutKind.Sequential)]
public struct CONSOLE_SCREEN_BUFFER_INFO
{
    public short dwSizeX;
    public short dwSizeY;
    public short dwCursorPositionX;
    public short dwCursorPositionY;
    public ushort wAttributes;
    public short srWindowLeft;
    public short srWindowTop;
    public short srWindowRight;
    public short srWindowBottom;
    public short dwMaximumWindowSizeX;
    public short dwMaximumWindowSizeY;
}

Sounds odd, isn’t it? You can also set the LayoutKind to Explicit and start working.

It is also possible to union two fields -or more- into one. For example, merging the two 16-bit integers dwSizeX and dwSizeY into one 32-bit integer, dwSize. It will work very well! In addition, you can divide them in your code using System.Collections.Specialized.BitVector32 structure.

A look inside the memory

Now, this time we are going to do something interesting. We are going to look on our structure in the memory.

For simplicity, we are going to use these types:

[StructLayout(LayoutKind.Sequential)]
public struct CONSOLE_SCREEN_BUFFER_INFO
{
    public COORD dwSize;
    public COORD dwCursorPosition;
    public ushort wAttributes;
    public SMALL_RECT srWindow;
    public COORD dwMaximumWindowSize;
}

[StructLayout(LayoutKind.Sequential)]
public struct COORD
{
    public short X;
    public short Y;
}

[StructLayout(LayoutKind.Sequential)]
public struct SMALL_RECT
{
    public short Left;
    public short Top;
    public short Right;
    public short Bottom;
}

Next, we will initialize the structures with some data to see how it stored in the memory.

unsafe static void Main()
{
    CONSOLE_SCREEN_BUFFER_INFO info
        = new CONSOLE_SCREEN_BUFFER_INFO();

    info.dwSize = new COORD();
    info.dwSize.X = 0xA1;
    info.dwSize.Y = 0xA2;

    info.dwCursorPosition = new COORD();
    info.dwCursorPosition.X = 0xB1;
    info.dwCursorPosition.Y = 0xB2;

    info.wAttributes = 0xFFFF;

    info.srWindow = new SMALL_RECT();
    info.srWindow.Left = 0xC1;
    info.srWindow.Top = 0xC2;
    info.srWindow.Right = 0xC3;
    info.srWindow.Bottom = 0xC4;

    info.dwMaximumWindowSize = new COORD();
    info.dwMaximumWindowSize.X = 0xD1;
    info.dwMaximumWindowSize.Y = 0xD2;

    uint memoryAddress = (uint)&info;

    Console.WriteLine(
        "Memory Address: 0x{0:X}",
        memoryAddress);

    Console.WriteLine("Press any key . . .");
    Console.ReadKey(true);

    // You can add a break point on the last line,
    // or you can use this function to break the code.
    System.Diagnostics.Debugger.Break();
}

This code assumes that you enabled the unsafe code from the Build tab of the project properties. Also, it assumes that you run your code in the debugging mode by pressing F5, or by clicking Start Debugging from the Debug menu.

Now, and after breaking the code, click Debug -> Windows -> Memory -> Memory 1 to open a memory window. Figure 4 shows how to open a memory window. And figure 5 shows the memory window opened. Click on the figures to enlarge.

Showing Memory Window

Memory Window

Now, you can locate your structure in memory by typing its memory address. Figure 6 shows the structure in the memory window.

Memory Window + CONSOLE_SCREEN_BUFFER_INFO

Now, take your time looking on how the structure -and its contained structures- laid-out in memory.

FillConsoleOutputCharacter() function

Last but not least, this is the fourth function we will use. This function fills a specific console buffer portion with a specific character. Passing a white space as the character means clearing this portion.

The syntax of this function is as following:

BOOL FillConsoleOutputCharacter(
    HANDLE hConsoleOutput,
    TCHAR cCharacter,
    DWORD nLength,
    COORD dwWriteCoord,
    [out] LPDWORD lpNumberOfCharsWritten
    );

This function takes four input arguments and a single output one, and it returns a value determines whether the function succeeded or failed. If the return value is non-zero (true) then the function succeeded, otherwise failed (that’s for GetConsoleBufferInfo() and SetConsoleCursorPosition() also.)

The five arguments are:

  • hConsoleOutput:
    A handle to an opened console output device to write to.
  • cCharacter:
    The character which to fill the buffer portion with.
  • nLength:
    The number of characters to write.
  • dwWriteCoord:
    A COORD structure defines where to begin writing (the first cell.)
  • lpNumberOfCharsWritten:
    An output parameters determines the number of characters written.

Here’s the PInvoke method of this function:

We have omitted the COORD structure because we have created it earlier.

[DllImport("Kernel32.dll")]
public static extern int FillConsoleOutputCharacter
    (IntPtr hConsoleOutput, char cCharacter, uint nLength,
    COORD dwWriteCoord, out uint lpNumberOfCharsWritten);

Notice that the unmanaged data types DWORD and LPDOWRD are marshaled to System.UInt32. For more information about unmanaged data types see the references section.

SetConsoleCursorPosition() function

This function is used to set the cursor position in the console screen buffer.

The syntax of this function is as following:

BOOL SetConsoleCursorPosition(
    HANDLE hConsoleOutput,
    COORD dwCursorPosition
    );

This function takes two arguments the first is a handle for an opened console output device. The second is a value specifies the new cursor position. Note that the new cursor position must be inside the console screen buffer.

The PInvoke method for this function is:

[DllImport("Kernel32.dll")]
public static extern int SetConsoleCursorPosition
    (IntPtr hConsoleOutput, COORD dwCursorPosition);

Putting things together

After all, we have learned the required functions and created the PInvoke method, so we can mix it up and start coding. Here’s the full code:

public const int STD_OUTPUT_HANDLE = -11;
public const char WHITE_SPACE = ' ';

[DllImport("Kernel32.dll")]
public static extern IntPtr GetStdHandle(int nStdHandle);

[DllImport("Kernel32.dll")]
public static extern int GetConsoleScreenBufferInfo
    (IntPtr hConsoleOutput,
    out CONSOLE_SCREEN_BUFFER_INFO lpConsoleScreenBufferInfo);

[DllImport("Kernel32.dll")]
public static extern int FillConsoleOutputCharacter
    (IntPtr hConsoleOutput, char cCharacter, uint nLength,
    COORD dwWriteCoord, out uint lpNumberOfCharsWritten);

[DllImport("Kernel32.dll")]
public static extern int SetConsoleCursorPosition
    (IntPtr hConsoleOutput, COORD dwCursorPosition);

[StructLayout(LayoutKind.Sequential)]
public struct CONSOLE_SCREEN_BUFFER_INFO
{
    public COORD dwSize;
    public COORD dwCursorPosition;
    public ushort wAttributes;
    public SMALL_RECT srWindow;
    public COORD dwMaximumWindowSize;
}

[StructLayout(LayoutKind.Sequential)]
public struct COORD
{
    public short X;
    public short Y;
}

[StructLayout(LayoutKind.Sequential)]
public struct SMALL_RECT
{
    public short Left;
    public short Top;
    public short Right;
    public short Bottom;
}

Clearing the console screen

And this is the code that clears the console screen:

static void Main()
{
    Console.WriteLine("Writing some text to clear.");

    Console.WriteLine("Press any key to clear . . . ");
    Console.ReadKey(true);

    ClearConsoleScreen();
}

public static void ClearConsoleScreen()
{
    // Getting the console output device handle
    IntPtr handle = GetStdHandle(STD_OUTPUT_HANDLE);

    // Getting console screen buffer info
    CONSOLE_SCREEN_BUFFER_INFO info;
    GetConsoleScreenBufferInfo(handle, out info);

    // Discovering console screen buffer info
    Console.WriteLine("Console Buffer Info:");
    Console.WriteLine("--------------------");
    Console.WriteLine("Cursor Position:");
    Console.WriteLine("t{0}, {1}",
    info.dwCursorPosition.X, info.dwCursorPosition.Y);
    // Is this information right?
    Console.WriteLine("Maximum Window Size:");
    Console.WriteLine("t{0}, {1}",
    info.dwMaximumWindowSize.X,
    info.dwMaximumWindowSize.Y);
    // Is this information right?
    Console.WriteLine("Screen Buffer Size:");
    Console.WriteLine("t{0}, {1}",
    info.dwSize.X, info.dwSize.Y);
    Console.WriteLine("Screen Buffer Bounds:");
    Console.WriteLine("t{0}, {1}, {2}, {3}",
    info.srWindow.Left, info.srWindow.Top,
    info.srWindow.Right, info.srWindow.Bottom);
    Console.WriteLine("--------------------");

    // Location of which to begin clearing
    COORD location = new COORD();
    location.X = 0;
    location.Y = 0;
    // What about clearing starting from
    // the second line
    // location.Y = 1;

    // The number of written characters
    uint numChars;

    FillConsoleOutputCharacter(handle, WHITE_SPACE,
    (uint)(info.dwSize.X * info.dwSize.Y),
    location, out numChars);

    // The new cursor location
    COORD cursorLocation = new COORD();
    cursorLocation.X = 0;
    cursorLocation.Y = 0;

    SetConsoleCursorPosition(handle, cursorLocation);
}

Also we can step further and write code that clears a specific portion of the console screen buffer, try this code:

static void Main()
{
    // Require the user to enter his password
    AuthenticateUser();
}

public static void AuthenticateUser()
{
    Console.WriteLine("Please enter your password:");
    Console.Write("> "); // Two characters right

    string input = Console.ReadLine();

    while (input != "MyPassword")
    {
        COORD location = new COORD();
        // The third character
        location.X = 2;
        // The second line
        location.Y = 1;
        ClearConsoleScreen(location);
        input = Console.ReadLine();
    }

    // User authenticated
    Console.WriteLine("Authenticated!");
}

public static void ClearConsoleScreen(COORD location)
{
    // Getting the console output device handle
    IntPtr handle = GetStdHandle(STD_OUTPUT_HANDLE);

    // Getting console screen buffer info
    CONSOLE_SCREEN_BUFFER_INFO info;
    GetConsoleScreenBufferInfo(handle, out info);

    // The number of written characters
    uint numChars;

    FillConsoleOutputCharacter(handle, WHITE_SPACE,
        (uint)(info.dwSize.X * info.dwSize.Y),
        location, out numChars);

    SetConsoleCursorPosition(handle, location);
}

A look inside the .NET library

Here we will look inside the library mscorlib.dll and see how it implements System.Console.Clear() method. This library is the core library that every .NET application must reference, it defines the core classes and components that are essential for every application. Also, it contains classes that are required by the CLR (Common Language Runtime.)

If you are using .NET 2.0 or higher you can continue this section, otherwise, you may pass this section because the Clear() method is new with the .NET 2.0.

MSIL, CIL, and IL all refer to the same thing the intermediate Language.

MSCORLIB stands for Microsoft Common Object Runtime Library.

Using the IL Disassembler

.NET Framework comes with a tool that allows you to reverse-engineer any assembly and view its MSIL (Microsoft Intermediate Language) instructions. This tool called IL Disassembler (ILDasm). You can find this tool in the .NET install directory in %ProgramFiles%Microsoft SDKsWindowsBin for the version 3.5, and Common7bin for versions before.

After opening ILDasm.exe you can open the file mscorlib.dll inside. Click File -> Open and select the library file which located in %WinDir%Microsoft.NETFramework. Figure 7 shows IL Disassembler with the mscorlib.dll opened.

ILDASM + mscorlib_dll

Now open the namespace System, then step down to the System.Console class and double-click the Clear() method to show the IL instructions. Take a look on how the Clear() method do it.

Using another tools

If MSIL seems odd, you may try another perfect tools that can reverse-engineer your assembly to your preferred language (like C# or VB.NET for instance.)

Some famous tools are Lutz Roeder’s .NET Reflector and XenoCode Fox.

For me, I prefer the first tool because it is faster, simpler, and supports many features.

Of course you can reflect (reverse-engineer) an assembly and learn nice tricks from the code inside.

References

Code Sample

Download the Console Library here.

Programmatically Swapping Mouse Buttons

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

Swapping mouse buttons means swapping the two buttons, making the right button acts like the left one and vice versa. This is done -for normal users of course- using the Mouse properties dialog in the control panel. See the next figure.

For we developers you need to do this programmatically, and this is done by a very very trivial -not a joke- Win32 API function, SwapMouseButton (resides on user32.dll). The syntax of the function -in C- is as follows:

BOOL SwapMouseButton(
    BOOL fSwap
    );

This function simply takes a single BOOL argument and returns a BOOL value too.

If fSwap is TRUE then the right mouse button will do the primary functions like the left button -by default- does, and the left button will do the secondary functions that the right button -by default- does.

If the function swapped the buttons, then it will return FALSE, otherwise TRUE.

BOOL can take one of values TRUE (non-zero) or FALSE (zero).

In .NET Framework, you need to write a wrapper to this API function and this wrapper is like this:

// C# Code
[DllImport("user32.dll")]
static extern bool SwapMouseButton(bool fSwap);
' VB.NET
Declare Auto Function SwapMouseButton Lib "user32.dll" _
    (ByVal fSwap As Boolean) As Boolean

The DllImport attribute defines the DLL that contains the function.

The MarshalAs attributes defines how .NET types will be mapped to Win32 types (this process called marshaling). We applied this attribute to the return value of the function and to the single argument of the function.

The static extern modifiers are required for any PInvoke function.

PInvoke stands for Platform Invokation. It’s the process of wrapping an API function to .NET code.

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

For unmanaged BOOL, .NET makes the marshaling process automatically, so you can safely remove the MarshalAsAttribute attributes.

Now it’s the time for the code for calling the function.

// C# Code

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

public void MakeLeftButtonPrimary()
{
    SwapMouseButton(false);
}
' VB.NET Code

Public Sub MakeRightButtonPrimary()
    SwapMouseButton(True)
End Sub

Public Sub MakeLeftButtonPrimary()
    SwapMouseButton(False)
End Sub

Creating Transacted Files

Lastly but not last, and after a long while, Windows Vista introduced a way to create transacted files or even to write to registry.

While market grows remarkably in the last years, its requirements increase as well. And every day you face a new problem that you must overcome to accommodate market requirements.

Transacted operations are one of the commonly demanded requirements by market.

While it’s true that you can easily do database operations transactionally, it’s not enough. Sometimes you will need to write files or make changes to registry in a transactional way.

With previous versions of Windows, you weren’t able to create a file transactionally without writing a huge amount of disorganized code to create it manually. You couldn’t use normal transactions or even COM+ Enterprise Services to create this type of transactions.

With Windows Vista you can easily create transacted files the common way you used to create normal files.

Unfortunately, from .NET 3.5 you cannot create transacted files. So you need to dive into API to create it.

Not Windows Vista only that supports this type of transactions, Windows Server 2008 also supports it.

Creating a transacted file function

To create a transacted file you can use the Kernel23.dll new function CreateFileTransacted.

This function takes the same arguments as the normal CreateFile function plus three more arguments that we are interested of the first one of them, the transaction handle that will be used while creating the file and writing to it.

The definition of this function in C is as follows:

HANDLE CreateFileTransacted(
    LPCTSTR lpFileName,
    DWORD dwDesiredAccess,
    DWORD dwShareMode,
    LPSECURITY_ATTRIBUTES lpSecurityAttributes,
    DWORD dwCreationDisposition,
    DWORD dwFlagsAndAttributes,
    HANDLE hTemplateFile,
    HANDLE hTransaction,
    PUSHORT pusMiniVersion,
    PVOID pExtendedParameter);

We are interested in 6 parameters of these 9.

  • lpFileName:
    The path of the file being created.
  • dwDesiredAccess:
    Defines how file will be accessed. Read only (0x80000000), right only (0x40000000), or both read and write (0xC0000000).
  • dwShareMode:
    Defines the sharing mode -during the operation- for the file. Enabling reading file contents (0x1), writing to it (0x2), reading and writing (0x3), or deleting the file (0x4).
  • dwCreationDisposition:
    Action to take if file exist or do not exist. This argument can take one of the values:
    0x1: Create the file and throw an error if it exists.
    0x2: Always create the file even if it exists.
    0x3: Open the file and throw an error if it doesn’t exist.
    0x4: Open the file or create it if it doesn’t exist.
    0x5: Open the file and clear its contents. Or throw an error if it doesn’t exist.
  • dwFlagsAndAttributes:
    Any additional options. This can be a combination of file attributes like Archive, Hidden, and Encrypted. Also it supports combining options like deleting the file after closing it.
  • hTransaction:
    A handle to our created transaction that we wish to use it in this operation. To get the handle you may take a step further into COM.

Also there’re three arguments that we are not interested on, so you can safely pass it a NULL value:

  • lpSecurityAttributes:
    A SECURITY_ATTRIBUTES object contains an optional security descriptor information for the file.
  • hTemplateFile:
    A handle to a file to read it’s attributes and options to fill the arguments automatically.
  • pusMiniVersion:
    The miniversion to be opened. When creating transacted file -by specifying the hTransaction argument, this must be NULL.
  • pExtendedParameter:
    Reserved.

For a complete discussion of this API function, see MSDN Library.

PInvoking CreateFileTransacted API function

PInvoke is a service that enables you to call unmanaged functions in DLLs, such as those in the Win32 API like the CreateFileTransacted API function last mentioned.

PInvoke stands for Platform Invokation.

In order to PInvoke a function you need to know some things:

  1. Where this function resides (which DLL).
  2. Function definition and order of arguments -if found.-
  3. How to marshal between unmanaged types in .NET types.

Marshaling in .NET is the process of creating a bridge between new .NET types and legacy COM types. This is done by finding equivalents for those legacy types in the new data types or creating it if needed.

Most of the COM data types have equivalents in .NET, also it’s very easy to create your own.

For the function on hands we could write it in C# as following:

[DllImport("kernel32.dll")]
    public static extern
    IntPtr CreateFileTransacted(
    string lpFileName,
    uint dwDesiredAccess,
    uint dwShareMode,
    IntPtr lpSecurityAttributes,
    uint dwCreationDisposition,
    uint dwFlagsAndAttributes,
    IntPtr hTemplateFile,
    IntPtr hHandle,
    IntPtr pusMiniVersion,
    IntPtr pExtendedParameter);

Code explanation:
static extern modifiers are required for creating PInvoke functions.
DllImport attribute used to define the DLL that contains the function.
System.IntPtr is the managed type equivalent to unmanaged HANDLE.
LPCSTR can be easily replaced by the managed System.String.
In unmanaged code DWORD is a 32-bit unsigned integer, so we could safely replace it with System.UInt32.

Because we need to pass a NULL value to the LPSECURITY_ATTRIBUTES argument we marshaled it as IntPtr, so we can use IntPtr.Zero to pass NULL values.
We did that too with the last two arguments.

For creating the PInvoke methods easily, you could use the Red Gate’s PInvoke.NET Visual Studio add-in.
Also you should visit the interop wiki.

After we create our PInvoke method we can call it. But after that we need to create the transaction and get its handle to fill the arguments of the method.

To get a transaction handle we need to dive into COM and call a method to get the handle. This method is wrapped to .NET using COM Interop.

[ComImport]
[Guid("79427A2B-F895-40e0-BE79-B57DC82ED231")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IKernelTransaction
{ void GetHandle(out IntPtr ktmHandle); }

Don’t forget adding a using System.Runtime.InteropServices statement.

Now we can call the method:

private const uint FILE_ATTRIBUTE_NORMAL = 0x80;
private const uint GENERIC_WRITE = 0x40000000;
private const uint CREATE_ALWAYS = 0x2;
private const uint FILE_SHARE_NONE = 0x0;

static void Main()
{
    using (TransactionScope scope = new TransactionScope())
    using (FileStream stream = CreateTransactedFile("D:SampleFile.txt"))
    using (StreamWriter writer = new StreamWriter(stream))
    {
        writer.WriteLine("Hello, World!");

        // To commit the transaction use the followind line
        scope.Complete();
    }
}

public static FileStream CreateTransactedFile(string fileName)
{
    IKernelTransaction ktx = (IKernelTransaction)
        TransactionInterop.GetDtcTransaction(Transaction.Current);

    IntPtr txHandle;
    ktx.GetHandle(out txHandle);

    IntPtr fileHandle =
        CreateFileTransacted(fileName,
        GENERIC_WRITE, FILE_SHARE_NONE, IntPtr.Zero,
        CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL,
        IntPtr.Zero, txHandle, IntPtr.Zero, IntPtr.Zero);

    return new FileStream(fileHandle, FileAccess.Write);
}

Don’t forget adding a reference to System.Transactions and a using statement.

Code explanation:
Constants define the input for the function arguments.
In method CreateTransactedFile() we get the handle of the ambient transaction created in method Main(). Then we call the CreateFileTransacted() function which returns a pointer to the create file. Lastly we created the FileStream object with the created the file handle and used it to create a StreamWriter object to write textual data to the file.

Calling Commit() of the transaction object ensures that all operations completed successfully and now we can apply it. Otherwise, nothing would be done. That’s the main characteristic of transactions. All or nothing.

You don’t need to close the transaction handle manually because when disposing the TransactionScope object it will close its handle automatically.
If you are interested in closing it manually you can use the .NET wrapper System.Runtime.InteropServices.Marshal.Release() method. Or try the difficult way using the CloseHandle unmanaged handle.

Transactional support not limited to creating a file only. Most file system operation now support transactions, some examples are CopyFileTransacted, CreateDirectoryTransacted, CreateHardLinkTransacted, DeleteFileTransacted, MoveFileTransacted, RemoveDirectoryTransacted, and SetFileAttributesTransacted.

The complete example can be downloaded here.

Creating a Message Box Directly using API

Download the example (C#)

.NET Framework contains holes that you can’t overcome using the managed code. Then you must dig into the API to overcome this.

Some of the overcomes in the .NET is the way that you can’t show a message box that contains a Help button!

Figure 1 shows an error message box while loading a project in Visual Basic 6.

Visual Basic File Could Not Be Loaded

To overcome this, API provides you with two functions for creating a message box.

These functions are MessageBox and MessageBoxEx.
Confused?
Yeah, They are two distinct functions, but they’re the same on how they work, and also they share the same input parameters, except that the MessageBoxEx includes a parameter in the last called wLanguageId. But it’s reserved. Means that you can safely ignore this parameter.

The syntax of both functions (in C) is as follows:

int MessageBox(
    HWND hWnd,
    LPCTSTR lpText,
    LPCTSTR lpCaption,
    UINT uType);

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

Parameters:
hWnd:
A handle to the owner window of the message box. If this parameter is NULL, the message box has no owner window.
lpText:
A string contains the message to be displayed.
lpCaption:
A string contains the message box caption. If this parameter is null, the Default title Error is used.
uType:
Specifies the contents and behavior of the dialog box. (we will return to discuss this later)
wLanguageId (MessageBoxEx):
Reserved.

uType:
This parameter specifies the contents and behavior of the message box, and can be a combination of flags from the following groups of flags:

  • To indicate the buttons displayed in the message box, specify one of the following values:
    MB_OK = 0x0 (default)
    OK button.
    MB_OKCANCEL = 0x1
    OK and Cancel buttons.
    MB_ABORTRETRYIGNORE = 0x2
    Abort, Retry, and Ignore buttons.
    MB_YESNOCANCEL = 0x3
    Yes, No, and Cancel buttons.
    MB_YESNO = 0x4
    Yes and No buttons.
    MB_RETRYCANCEL = 0x5
    Retry and Cancel buttons.
    MB_HELP = 0x4000
    Help button. This flag is the only that can be used with a combination with any other buttons flag.
  • To display an icon in the message box, specify one of the following values:
    MB_ICONHAND = 0x10
    A stop-sign icon appears in the message box.
    MB_ICONQUESTION = 0x20
    A stop-sign icon appears in the message box.
    MB_ICONEXCLAMATION = 0x30
    An exclamation-point icon appears in the message box.
    MB_ICONASTERISK = 0x40
    An icon consisting of a lowercase letter i in a circle appears in the message box.
    MB_ICONERROR = MB_ICONHAND
    MB_ICONSTOP = MB_ICONHAND
    MB_ICONWARNING = MB_ICONEXCLAMATION
    MB_ICONINFORMATION = MB_ICONASTERISK
  • To indicate the default button, specify one of the following values:
    MB_DEFBUTTON1 = 0x0 (default)
    The first button is the default.
    MB_DEFBUTTON2 = 0x100
    The second button is the default.
    MB_DEFBUTTON3 = 0x200
    The third button is the default.
    MB_DEFBUTTON4 = 0x300
    The fourth button is the default. (Will be the Help button if you specify MB_HELP)
  • To indicate the modality of the dialog box, specify one of the following values:
    MB_APPLMODAL = 0x0 (default)
    The user must respond to the message box before continuing work in the window identified by the hWnd parameter. However, the user can move to the windows of other threads and work in those windows.
    MB_SYSTEMMODAL = 0x1000
    Same as MB_APPLMODAL except that the message box has the is shown as top most. Use system-modal message boxes to notify the user of serious, potentially damaging errors that require immediate attention (for example, running out of memory). This flag has no effect on the user’s ability to interact with windows other than those associated with hWnd.
    MB_TASKMODAL = 0x2000
    Same as MB_APPLMODAL except that all the top-level windows belonging to the current thread are disabled if the hWnd parameter is NULL. Use this flag when the calling application or library does not have a window handle available but still needs to prevent input to other windows in the calling thread without suspending other threads.
  • To specify other options, use one or more of the following values:
    MB_DEFAULT_DESKTOP_ONLY = 0x20000
    The message is displayed on the default desktop.
    MB_TOPMOST = 0x40000
    The message is shown top most. (with the WS_EX_TOPMOST window style)
    MB_RIGHT = 0x80000
    The text is right-justified.
    MB_RTLREADING = 0x100000
    Displays message and caption text using right-to-left reading order on Hebrew and Arabic systems.
    MB_SERVICE_NOTIFICATION = 0x200000
    The message is displayed on the active desktop, even if no user logged on to the computer.

Return Value:
Both MessageBox and MessageBoxEx return an integer.
If the function fails, the return value is zero.
If the function succeeds, the return value is one of the following value:

  • IDOK = 1
    The user clicked the OK button.
  • IDCANCEL = 2
    The user clicked the Cancel button or pressed the ESC key.
  • IDABORT = 3
    The user clicked the Abort button.
  • IDRETRY = 4
    The user clicked the Retry button.
  • IDIGNORE = 5
    The user clicked the Ignore button.
  • IDYES = 6
    The user clicked the Yes button.
  • IDNO = 7
    The user clicked the No button.
  • IDTRYAGAIN = 10
    The user clicked the Try Again button.
  • IDCONTINUE = 11
    The user clicked the Continue button.

But what if user clicked the Help button?
There’s no return value named for clicking the help button! That’s because clicking the Help button doesn’t close the message box! Instead it’s sending a WM_HELP message to the owner which equals pressing F1.
So, You can handle this in .NET using the HelpRequested event.

Creating a .NET Example
First, Create the flags that can be used to specify message box options.

// Flags

public static class MBIcons
{
    public const int MB_ICONHAND = 0x10;
    public const int MB_ICONQUESTION = 0x20;
    public const int MB_ICONEXCLAMATION = 0x30;
    public const int MB_ICONASTERISK = 0x40;

    public const int MB_ICONERROR = MB_ICONHAND;
    public const int MB_ICONSTOP = MB_ICONHAND;
    public const int MB_ICONWARNING = MB_ICONEXCLAMATION;
    public const int MB_ICONINFORMATION = MB_ICONASTERISK;
}
public static class MBDefButton
{
    public const int MB_DEFBUTTON1 = 0x0;
    public const int MB_DEFBUTTON2 = 0x100;
    public const int MB_DEFBUTTON3 = 0x200;
    public const int MB_DEFBUTTON4 = 0x300;
}
public static class MBButton
{
    public const int MB_OK = 0x0;
    public const int MB_OKCANCEL = 0x1;
    public const int MB_ABORTRETRYIGNORE = 0x2;
    public const int MB_YESNOCANCEL = 0x3;
    public const int MB_YESNO = 0x4;
    public const int MB_RETRYCANCEL = 0x5;

    public const int MB_HELP = 0x4000;
}
public static class MBModal
{
    public const int MB_APPLMODAL = 0x0;
    public const int MB_SYSTEMMODAL = 0x1000;
    public const int MB_TASKMODAL = 0x2000;
}
public static class MBOptions
{
    public const int MB_DEFAULT_DESKTOP_ONLY = 0x20000;
    public const int MB_TOPMOST = 0x40000;
    public const int MB_RIGHT = 0x80000;
    public const int MB_RTLREADING = 0x100000;
    public const int MB_SERVICE_NOTIFICATION = 0x200000;
}

Second, Create the message box return value enumeration.

public enum MBReturn
{
    IDOK = 1,
    IDCANCEL = 2,
    IDABORT = 3,
    IDRETRY = 4,
    IDIGNORE = 5,
    IDYES = 6,
    IDNO = 7,
    IDTRYAGAIN = 10,
    IDCONTINUE = 11,
}

Third, Create the P/Invoke methods.
P/Invoke stands for Platform Invocation a way for calling unmanaged functions.

[DllImport("user32.dll")]
public static extern int MessageBox(
    IntPtr hWnd, string lpText,
    string lpCaption, uint uType);

[DllImport("user32.dll")]
public static extern int MessageBoxEx(
    IntPtr hWnd, string lpText,
    string lpCaption, uint uType,
    ushort wLanguageId);

Code Explanation:
DllImport Attribute:
This attribute is added to the P/Invoke method to indicate the DLL that expose that function. In the case of these functions the DLL is user32.dll.
static extern modifiers:
P/Invoke methods must specify the two modifiers.
extern means that the method is implemented externally, while static means that that method belongs to the type itself not the object.
IntPtr struct:
The managed type that can be used to represent a pointer or an handle in the unmanaged code.

Marshaling
In unmanaged code there’s some types that doesn’t exist in the managed environment, But using marshaling you can overcome this problem.
Marshaling is the process of converting a managed type into unmanaged type.
We have seen in the last code some examples of this.
An example is HWND which is a pointer to a handle in the memory. Which .NET doesn’t provide this type! But, It provides a similar type named IntPtr.
Another example is the WORD which is 16-bit unsigned integer. But, The .NET Framework includes an equivalent thats UInt16 or simply ushort (in C#).

Finally, Call the unmanaged function.

static void Main()
{
    // You can replace IntPtr.Zero
    // with Form.Handle if you want to
    // specify the form as an owner
    MBReturn ret = (MBReturn)MessageBoxEx(IntPtr.Zero,
        "'C:StockPrjcrviewer.dll' could not be loaded" +
        "--Continue Loading Project?", "Microsoft Visual Basic",
        MBButton.MB_YESNO | MBButton.MB_HELP |
        MBIcons.MB_ICONQUESTION | MBSpecial.MB_TOPMOST |
        MBDefButton.MB_DEFBUTTON1, 0);
    Console.WriteLine("User clicked: {0}", ret.ToString());
}

Congratulations!

You have completed the lesson.

Download the example (C#)