Programmatically Taking a Screen Snapshot

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

Honestly, this lesson is not primarily focusing on how to take a screen snapshot! Instead, it is focusing on how to simulate keyboard strokes and send them to the active application.

In .NET, this is done using the System.Windows.Forms.Forms.SendKeys class. As you might guess it is located in System.Windows.Forms.dll.

Using the SendKeys class you can call static methods like SendWait() to send the keystrokes and wait for them to be processed, or you can send them via the Send() method if you do not care about whether they processed or not.

Both Send() and SendKeys() requires a single argument keys. This argument represents the keys to send it.  Each key is represented by one or more characters. To get list of all values supported for this argument visit the documentation for the SendKeys class, visit this page.

For our example we will try to combine two keys Alt + Print Screen. Alt represented by a percent (%) sign. Print Screen key is represented by the value PrtSc enclosed in curly brackets.

// C#

public static Image TakeScreenSnapshot(bool activeWindowOnly)
{
    // PrtSc = Print Screen Key
    string keys = "{PrtSc}";

    if (activeWindowOnly)
        keys = "%" + keys; // % = Alt

    SendKeys.SendWait(keys);

    return Clipboard.GetImage();
}
' VB.NET

Public Shared Function TakeScreenSnapshot(activeWindowOnly As Boolean) As Image
    ' PrtSc = Print Screen key
    Dim keys As String = "{PrtSc}"

    If (activeWindowOnly) Then
        keys = "%" & keys
    End If

    SendKeys.SendWait(keys)

    Return Clipboard.GetImage()
End Function

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.)

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.

Refactoring: Magic Numbers

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

Another type of refactoring patterns is the Magic Number pattern.

Magic numbers are numbers with special meaning and value that usually are not obvious, such as PI. They are really nasty when you need to reference the same number many times. If the number might ever change, making the change is a nightmare. Even if you don’t make a change, you have the difficulty of figuring out what is going on.

If you have a magic number into your code and you use it frequently, you can create a constant, name it after the meaning, and replace the number with it. Most languages support constants. There is no cost in performance and there is a great improvement in readability.

But, before you do this refactoring, you should always look for an alternative. Look at how the magic number is used. Often you can find a better way to use it. If the magic number is a type code, consider replace type code with a class. If the magic number is the length of an array, use anArray.length instead when you are looping through the array. Otherwise, you can go and create your constant.

For example, the following code converts between meters and feet, and it uses a magic number that’s the feet in one meter:

// C# Code

public static double ConvertMetersToFeet(double meters)
{
    return meters * 3.2808398950131233595800524934383;
}
public static double ConvertFeetToMeters(double feet)
{
    return feet / 3.2808398950131233595800524934383;
}
' VB.NET Code

Public Function ConvertMetersToFeet(meters As Double) As Double
    Return meters * 3.2808398950131233595800524934383
End Function

Public Function ConvertFeetToMeters(feet As Double) As Double
    Return feet / 3.2808398950131233595800524934383
End Function

So, we can refactor the code to be:

// C# Code

public const double MeterFeet = 3.2808398950131233595800524934383;

public static double ConvertMetersToFeet(double meters)
{
    return meters * MeterFeet;
}
public static double ConvertFeetToMeters(double feet)
{
    return feet / MeterFeet;
}
' VB.NET Code

Public Const MeterFeet As Double _
    = 3.2808398950131233595800524934383

Public Function ConvertMetersToFeet(meters As Double) As Double
    return meters * MeterFeet
End Function

Public Function ConvertFeetToMeters(feet As Double) As Double
    return feet / MeterFeet
End Function

The lesson quoted from the book “Refactoring: Improving the Design of Existing Code” by Martin Fowler. Code snippets by Just Like a Magic.

Programmatically Compress and Decompress Files

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

This lesson is very easy. This lesson focuses on how to compress and decompress files programmatically using .NET Framework and C# -or any language that supports .NET of course.

Currently .NET Framework supports two types of compression algorithms:

  • Deflate
    This is a very simple algorithm, used for simple compression and decompression operations. Don’t use this algorithm except if you intend to use compressed data only in your application because this algorithm is not compatible with any compression tool.
  • GZIP
    This algorithm uses internally the Deflate algorithm. This algorithm includes a cyclic redundancy check value for detecting data corruption. Also it’s compatible with most compression tools because it writes headers to the compressed file, so compression tools -like WinZip and WinRAR- can easily access the compressed file and decompress it as well. This algorithm also can be extended to use other algorithms internally other than Deflate.

For a complete GZIP reference see RFC 1952 (GZIP File Format Specification).

The most powerful compression tool now is WinRAR.

Fortunately, whether using Deflate or GZIP in .NET, code is the same; the only thing that needs to change is the class name.

Deflate and GZIP can be found in the namespace System.IO.Compression that resides on assembly System.dll. This namespace contains only three types, the two algorithms implementation classes DeflateStream and GZipStream -both inherit directly from System.IO.Stream class-, and an enumeration CompressionMode that defines the operation (compression or decompression).

Compressing a file

The code for compression is very simple:

Code snippets in this lesson rely on the fact that you added two using (Imports in VB) statements, System.IO and System.IO.Compression.

// C# Code

string fileToBeCompressed = "D:\My Great Word Document.doc";
string zipFilename = "D:\CompressedGreatDocument.zip";

using (FileStream target = new FileStream(zipFilename, FileMode.Create, FileAccess.Write))
using (GZipStream alg = new GZipStream(target, CompressionMode.Compress))
{
    byte[] data = File.ReadAllBytes(fileToBeCompressed);
    alg.Write(data, 0, data.Length);
    alg.Flush();
}

Code explanation:
If you are going to compress a file then you must specify the CompressionMode.Compress option, and also you must specify a Stream that will the data be written to.
After creating the class you can compress the data by using its Write() method.

If you intended to use the Deflate algorithm, just change the class name to DeflateStream.

Decompressing a file

The code that decompresses a compressed file is very similar:

// C# Code

string compressedFile = "D:\CompressedGreatDocument.zip";
string originalFileName = "D:\My Great Word Document.doc";

using (FileStream zipFile = new FileStream(compressedFile, FileMode.Open, FileAccess.Read))
using (FileStream originalFile = new FileStream(originalFileName, FileMode.Create, FileAccess.Write))
using (GZipStream alg = new GZipStream(zipFile, CompressionMode.Decompress))
{
    while (true)
    {
        // Reading 100bytes by 100bytes
        byte[] buffer = new byte[100];
        // The Read() method returns the number of bytes read
        int bytesRead = alg.Read(buffer, 0, buffer.Length);

        originalFile.Write(buffer, 0, returnedBytes);

        if (bytesRead != buffer.Length)
            break;
    }
}
' VB.NET Code

Dim compressedFile As String = "D:CompressedGreatDocument.zip"
Dim originalFileName As String = "D:My Great Word Document.doc"

Dim zipFile As New FileStream(compressedFile, FileMode.Open, FileAccess.Read)
Dim originalFile As New FileStream(originalFileName, FileMode.Create, FileAccess.Write)
Dim alg As New GZipStream(zipFile, CompressionMode.Decompress)

While (True)
    ' Reading 100bytes by 100bytes
    Dim buffer(100) As Byte

    ' The Read() method returns the number of bytes read
    Dim bytesRead As Integer = alg.Read(buffer, 0, buffer.Length)

    originalFile.Write(buffer, 0, bytesRead)

    If (bytesRead  buffer.Length) Then
        Exit While
    End If
End While

Code explanation:

First, we create a file stream to read the ZIP file, and then we created our algorithm class that encapsulates the file stream for decompressing it.

Then we created a file stream for the original file, for writing the decompressed data.
After that, we read the data compressed 100bytes after each other -you may prefer more- and write this data to the original file stream.

By encapsulating disposable objects into using statements you become assured that every object will be disposed in a certain point -end of the using statement- and no object will retain in memory.

Try it yourself

Develop a simple application that can be used to compress and decompress files.

This application can compress several files into one file and decompress them as well.

Besides algorithms classes you may use System.IO.BinaryWriter and System.IO.BinaryReader to get full control of how the file contents will be.

Enumerating SQL Server Instances

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

Starting from version 2.0, .NET supports a mechanism to enumerate the SQL Server instances in the local network. This is done by System.Sql.SqlDataSourceEnumerator class that resides on the assembly System.Data.

This class is a implements the singleton pattern, means that you can not instantiate it, and only a single instances serves all, accessed via the static property Instance.

Using the GetDataSources method of SqlDataSourceEnumerator, you get a DataTable object that contains four columns, ServerName, InstanceName, IsCulstered, and Version (Clear names, right?)

The following code retrieves information about all visible SQL Server instances in the local network:

// C# Code

static void Main()
{
    DataTable table =
        SqlDataSourceEnumerator.Instance.GetDataSources();

    DisplayTable(table);
}

private static void DisplayTable(DataTable table)
{
    foreach (DataRow row in table.Rows)
    {
        foreach (DataColumn col in table.Columns)
            Console.WriteLine("{0} = {1}", col.ColumnName, row[col]);
        Console.WriteLine(new string(' ', 30));
    }
}
 ' VB.NET Code

Sub Main()
    Dim table As DataTable = SqlDataSourceEnumerator.Instance.GetDataSources()

    DisplayTable(table)
End Sub

Sub DisplayTable(ByVal table As DataTable)
    For Each row As DataRow In table.Rows
        For Each col As DataColumn In table.Columns
            Console.WriteLine("{0} = {1}", col.ColumnName, row(col))
            Console.WriteLine(New String(" "c, 30))
        Next
    Next
End Sub

If you have a firewall installed on your machine, you will be asked to give permissions to the application.

GetDataSources() demands the FullTrust permission set.

Due to the nature of the mechanism used by SqlDataSourceEnumerator to locate data sources on a network, the method will not always return a complete list of the available servers, and the list might not be the same on every call.

Working with SQL Server BLOB Data in .NET

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

Code: Geming.Samples.Blob.zip

Binary Large Objects (BLOBs) are pieces of data that have -usually- exceptionally large size (such as pictures or audio tracks). These values stored in SQL Server in an image column.

Sometimes the term BLOB is also applied to large character data values, such as those stored in text or ntext columns.

Also you can store BLOB data in a binary column, but it doesn’t take larger than 8000 bytes. And image columns are more flexible.

Working with BLOB data is a bit strange because:

  1. You don’t know how much size will be the retrieved data.
  2. The data may be very large so we need to retrieve it in chunks.

Our example is fairly simple. This example stores files in a database (FileStore) and retrieves it by name. The example relies on a database that contains one table, MyFiles. And the table itself contains two columns one for filename (PK) and the other is an image column for the file itself.

Storing BLOB data

Storing BLOB data in a database is easiest part:

In order to run this code, you must add using statements to Sql.Data.SqlClient and System.IO.

// C# Code

static void StoreFile(string filename)
{
    SqlConnection connection = new SqlConnection
        ("Server=(local) ; " +
        "Initial Catalog = FileStore ; " +
        "Integrated Security = SSPI");

    SqlCommand command = new SqlCommand
        ("INSERT INTO MyFiles VALUES (@Filename, @Data)",
            connection);

    command.Parameters.AddWithValue("@Filename",
        Path.GetFileName(filename));
    command.Parameters.AddWithValue("@Data",
        File.ReadAllBytes(filename));

    connection.Open();

    command.ExecuteNonQuery();

    connection.Close();
}
' VB.NET Code

Sub StoreFile(ByVal filename As String)
    Dim connection As New SqlConnection( _
        "Server=(local) ; Initial Catalog = FileStore ; " & _
        "Integrated Security = SSPI")

    Dim command As New SqlCommand( _
        "INSERT INTO MyFiles VALUES " & _
        "(@Filename, @Data)", connection)

    command.Parameters.AddWithValue("@Filename", _
        Path.GetFileName(filename))
    command.Parameters.AddWithValue("@Data", _
        File.ReadAllBytes(filename))

    connection.Open()

    command.ExecuteNonQuery()

    connection.Close()
End Sub

Code explanation:
First, we created a connection to the SQL Server database. And then, we created the SqlCommand object that will hold the T-SQL Insert statement. After that, we filled the command parameters with required values. Finally, we executed the command.

Well, for avoiding SQL-Injection attacks, it’s recommended that you use parameters instead of hard-coding the argument. Moreover, you can’t represent binary values as strings.
Frankly, it’s recommended using stored procedures instead of coding the commands.

It’s highly recommended that you dispose disposable objects like SqlConnection and SqlCommand. Try encapsulating it in a using statement.

Retrieving BLOB data

Retrieving BLOB data is a bit complex than storing it. The following method demonstrates this:

// C# Code

static byte[] RetrieveFile(string filename)
{
    SqlConnection connection = new SqlConnection
        ("Server=(local) ; Initial Catalog = FileStore ; Integrated Security = SSPI");

    SqlCommand command = new SqlCommand
        ("SELECT * FROM MyFiles WHERE Filename=@Filename", connection);

    command.Parameters.AddWithValue("@Filename", filename);

    connection.Open();

    SqlDataReader reader = command.ExecuteReader(System.Data.CommandBehavior.SequentialAccess);

    reader.Read();

    MemoryStream memory = new MemoryStream();

    long startIndex = 0;
    const int ChunkSize = 256;
    while (true)
    {
        byte[] buffer = new byte[ChunkSize];

        long retrievedBytes = reader.GetBytes(1, startIndex, buffer, 0, ChunkSize);

        memory.Write(buffer, 0, (int)retrievedBytes);

        startIndex += retrievedBytes;

        if (retrievedBytes != ChunkSize)
            break;
    }

    connection.Close();

    byte[] data = memory.ToArray();

    memory.Dispose();

    return data;
}
' VB.NET Code
Function RetrieveFile(ByVal filename As String) As Byte()
    Dim connection As New SqlConnection( _
        "Server=(local) ; Initial Catalog = FileStore ; " & _
        "Integrated Security = SSPI")

    Dim command As New SqlCommand( _
        "SELECT * FROM MyFiles " & _
        "WHERE Filename=@Filename", connection)

    command.Parameters.AddWithValue("@Filename", filename)

    connection.Open()

    Dim reader As SqlDataReader = command.ExecuteReader _
        (System.Data.CommandBehavior.SequentialAccess)

    reader.Read()

    Dim memory As New MemoryStream()

    Dim startIndex As Long = 0
    Const ChunkSize As Integer = 256
    While (True)
        Dim buffer(ChunkSize) As Byte

        Dim retrievedBytes As Long = _
            reader.GetBytes(1, startIndex, buffer, 0, ChunkSize)

        memory.Write(buffer, 0, CInt(retrievedBytes))

        startIndex += retrievedBytes

        If (retrievedBytes  ChunkSize) Then
            Exit While
        End If
    End While

    connection.Close()

    Dim data() As Byte = memory.ToArray()

    memory.Dispose()

    Return data
End Function

Code explanation:
After connecting to the database and writing our query, we executed the query by calling ExecuteReader() method of the command object to get read-only forward-only pointer to the retrieved rows.

By default, SqlDataReader reads entire rows -that can be gigabytes of data.- By specifying CommandBehavior.SequentialAccess, it reads the data sequentially in a given chunk size by calling the GetBytes() -or GetChars for BLOB textual data- method.

Calling Read() of the SqlDataReader objects advances the pointer to the next row which is the first single row -if found- in our example.

The GetBytes() method takes five arguments:

  1. The column index.
  2. The index of which to start reading.
  3. The buffer object that will keep current retrieved data.
  4. Index in buffer of which to begin writing t.
  5. The length (chunk size) of the data to retrieve.

It it worth mentioning that this method returns number of bytes retrieved. After calling this method we used a MemoryStream object to write all data retrieved to.

Finally, we retrieve data by calling MemoryStream’s ToArray() function. (I think the code is now clear)

It’s not recommended using MemoryStream if the data is very huge.

SqlConnection, SqlCommand, SqlDataReader, and MemoryStream are all disposable objects.
Because the MemoryStream object may contain the retrieved data it’s highly recommended that you dispose it as soon as possible.

For a complete example download the sample project FileStore.
This project uses a database for storing files and retrieving it.
This database contains only one table, its definition is as follows:

FileStore File Table Definition

For creating the database, the project also inculdes a SQL Query file that contains the commands for creating it. Simply execute the file.

Download 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

Retrieving Motherboard Serial Number using WMI

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

A simple way to get system information is through Windows Management Instrumentation (WMI).

WMI was firstly introduced part of Windows 2000. It’s designed to help your system, applications, and networks.

WMI has amazing design; It’s implemented like a large database that contains several tables and types. And you can query it using SQL statements (really!).

.NET Framework includes a various classes for dealing with WMI. These classes reside on assembly System.Management that you can reference it into your project.

Querying WMI is very simple. First, create a ManagementObjectSearcher object that will hold the SQL query. Then you execute the query by calling the Get() method of the ManagementObjectSearcher object, returns a collection of ManagementObject objects. These object looks like rows in a database that you can access its columns -PropertyData objects- and retrieve its values.

In WMI tables called classes, rows called objects, and columns called properties.

The following example demonstrates how to get Motherboard information like its name and serial number:

// C# Code

// First we create the ManagementObjectSearcher that
// will hold the query used.
// The class Win32_BaseBoard (you can say table)
// contains the Motherboard information.
// We are querying about the properties (columns)
// Product and SerialNumber.
// You can replace these properties by
// an asterisk (*) to get all properties (columns).
ManagementObjectSearcher searcher =
    new ManagementObjectSearcher
    ("SELECT Product, SerialNumber FROM Win32_BaseBoard");

// Executing the query...
// Because the machine has a single Motherborad,
// then a single object (row) returned.
ManagementObjectCollection information = searcher.Get();
foreach (ManagementObject obj in information)
{
    // Retrieving the properties (columns)
    // Writing column name then its value
    foreach (PropertyData data in obj.Properties)
        Console.WriteLine("{0} = {1}", data.Name, data.Value);
    Console.WriteLine();
}

// For typical use of disposable objects
// enclose it in a using statement instead.
searcher.Dispose();
' VB.NET Code

' First we create the ManagementObjectSearcher that
' will hold the query used.
' The class Win32_BaseBoard (you can say table)
' contains the Motherboard information.
' We are querying about the properties (columns)
' Product and SerialNumber.
' You can replace these properties by
' an asterisk (*) to get all properties (columns).
Dim searcher As New ManagementObjectSearcher _
    ("SELECT Product, SerialNumber FROM Win32_BaseBoard")

' Executing the query...
' Because the machine has a single Motherborad,
' then a single object (row) returned.
Dim information As ManagementObjectCollection = searcher.Get()
For Each obj As ManagementObject In information
' Retrieving the properties (columns)
' Writing column name then its value
    For Each data As PropertyData In obj.Properties
        Console.WriteLine("{0} = {1}", data.Name, data.Value)
    Next
    Console.WriteLine()
Next

' For typical use of disposable objects
' enclose it in a using statement instead.
searcher.Dispose()
' VB6
Set colProcessList = GetObject("Winmgmts:") _
    .ExecQuery("SELECT SerialNumber, Product FROM Win32_BaseBoard")

For Each objprocess In colProcessList
    MsgBox ("Serial Number=" & objprocess.SerialNumber)
    MsgBox ("Product=" & objprocess.Product)
Next

To read more about WMI and get lists of classes and features that it supports, see WMI Reference.

A long time ago, I used that mechanism to protect my application from copying it from a PC to another. The application asks the user for the serial number if he changed his PC (frankly, Motherboard). Did you validate? The serial number itself is an encrypted hash of the Motherboard serial number!