17 Jan 2011

What's in Microsoft.VisualBasic for C# Developers: Part 5 - Hardware

monolith[This blog is part of a larger series, to find more parts in the series please see the Series Index]

Hardware isn’t just related to the computer information, like OS version and memory, but it also includes a variety of other types of devices such as audio, clocks, keyboards and many more. The VisualBasic library provides us with access to a lot of these pieces of hardware:

Audio

Microsoft.VisualBasic.Devices.Audio is a interesting class which allows us to play various sounds it has three functions that are key:

  • Play – This allows us to play a wave file, either by passing in the file name, a stream or byte array. There are a few overloads to allow you to control how the audio is played.
  • Stop – Stop the playing audio.
  • PlaySystemSound – This plays the sound associated with a specified system event.
string waveFile = @"C:\Windows\winsxs\amd64_microsoft-windows-speech-userexperience_31bf3856ad364e35_6.1.7600.16385_none_77fee1b2657da663\Speech Sleep.wav";

Audio audio = new Audio();
// play full file to wnd
audio.Play(waveFile, Microsoft.VisualBasic.AudioPlayMode.WaitToComplete);

// play first 300ms and stop
audio.Play(waveFile);
Thread.Sleep(300);
audio.Stop();

// play sound associated with a question
audio.PlaySystemSound(System.Media.SystemSounds.Question);
Console.ReadKey();

Clock

Microsoft.VisualBasic.Devices.Clock is rather pointless it has three properties which match to existing properties we know and love.

  • GmtTime equals DateTime.UtcNow
  • LocalTime equals DateTime.Now
  • TickCount equals Environment.TickCount

Keyboard

This provides us with an interesting mixed bag first we have 3 Boolean properties, one for each modifier key (Ctrl, Alt & Shift) which tell us if it is being pressed. Next we have 3 Boolean properties, one for each of the toggle keys (Caps lock, scroll lock & num lock) which tells you if they are enabled.

Keyboard keyboard = new Keyboard();
Console.WriteLine("Alt pressed: {0}", keyboard.AltKeyDown);
Console.WriteLine("Ctrl pressed: {0}", keyboard.CtrlKeyDown);
Console.WriteLine("Shift pressed: {0}", keyboard.ShiftKeyDown);

Console.WriteLine("Caps on: {0}", keyboard.CapsLock);
Console.WriteLine("Numlock on: {0}", keyboard.NumLock);
Console.WriteLine("Scroll lock on: {0}", keyboard.ScrollLock);

However the interesting piece of code is the SendKeys method which actually allows you to send key strokes to the active window, basically to simulate a user typing.

There is one thing to be aware of and that is if you are using something which does not handle window messages for example a console application. In this case you must use the overload which takes a boolean as a second parameter and set this to true.

// winforms
keyboard.SendKeys("Hello world!");
// console
keyboard.SendKeys("Hello world!", true);

Mouse

mat11Microsoft.VisualBasic.Devices.Mouse does not let you control Mouse from the Matrix, it merely provides status information to you on the hardware mouse you are using via three properties:

  • ButtonsSwapped – Are the left and right mouse buttons swapped?
  • WheelExists – Does the mouse have a mouse wheel?
  • WheelScrollLines – How many lines does a single notch of the mouse wheel to scroll?

Ports

Need to work with serial (COM) ports? The Microsoft.VisualBasic.Devices.Ports provides you with a simple way to do that, however nothing it provides you do not already get from System.IO.Ports.SerialPort except saving a few lines of code.
The OpenSerialPort method does the following:

  • Creates a new System.IO.Ports.SerialPort – OpenSerialPort does contain overloads which match to the constructors for SerialPort.
  • It then calls Open on the port.
  • It returns the port.

That three lines of code wrapped into one for you.

The other item provided on Ports is the SerialPortNames property which returns a ReadOnlyCollection<String> of the names of the port. It does this by calling the GetPortNames method from SerialPort, which returns an array and then converts that result to the collection. The only time you should use this is if you really need a ReadOnlyCollection<String> as calling the GetPortNames method directly and working with the array is much faster.

14 Jan 2011

What's in Microsoft.VisualBasic for C# Developers: Part 4 - Computer Info

monolith[This blog is part of a larger series, to find more parts in the series please see the Series Index]

For today we will be looking at a very useful class ComputerInfo, which provides a small set of information on the computer. It doesn’t provide a lot of info but the information it provides are key:

  • OSFullName: The “nice” name for the OS – like Windows 7 Ultimate
  • OSVersion: The OS version number
  • OSPlatform: The OS platform
  • TotalPhysicalMemory, AvailablePhysicalMemory, TotalVirtualMemory, AvailableVirtualMemory: Memory usage information
  • InstalledUICulture: The culture that was used during the install, this is the exact same as System.Globalization.CultureInfo.InstalledUICulture
ComputerInfo info = new ComputerInfo();
Console.WriteLine("You are running {0} ({1})", info.OSFullName, info.OSVersion);
Console.WriteLine("\t this is built on the {0} platform.", info.OSPlatform);

UInt64 usedPhysical = info.TotalPhysicalMemory - info.AvailablePhysicalMemory;
UInt64 usedVirtual = info.TotalVirtualMemory - info.AvailableVirtualMemory;

Console.WriteLine("Memory Information in Mb (Available | Used | Total)");
Console.WriteLine("\t  Virtual: {0} | {1} | {2}", info.AvailableVirtualMemory / 1048576, usedVirtual / 1048576, info.TotalVirtualMemory / 1048576);
Console.WriteLine("\t Physical: {0} | {1} | {2}", info.AvailablePhysicalMemory / 1048576, usedPhysical / 1048576, info.TotalPhysicalMemory / 1048576);

Console.WriteLine("You are running the following culture {0}", CultureInfo.CurrentCulture.EnglishName);
if (CultureInfo.CurrentCulture != info.InstalledUICulture)
{
    Console.WriteLine("BUT you installed with {0}", info.InstalledUICulture.EnglishName);
}
else
{
    Console.WriteLine("and you installed with that culture too");
}

This gives us:

image

This is isn’t the only way to get computer information, there is plenty in other locations in the framework – for example the System.Environment class from the mscorlib assembly has things like:

  • Environment.Is64BitOperatingSystem
  • Environment.Is64BitProcess
  • Environment.MachineName
  • Environment.OSVersion
  • Environment.ProcessorCount
  • Environment.Version
12 Jan 2011

Finally an AWESOME competition for South African Developers

logoI often find too many competitions from Microsoft ignore the southern tip of Africa or focus on specific markets, like education with the great ImagineCup event. Finally us hard working developers get a great competition: Internet Explorer 9 Top Developer Competition

This competition wants* developers to either create an awesome IE 9 add-on or light up a web site with some of the new awesome IE 9 features – so if you a web dev, html monkey, C++ or .NET developer you can take part!

The prize? A trip to PDC – the conference were two years ago everyone got hand build super laptops and last year Windows Phone 7 devices**, not to mention it is where the top Microsoft development speakers meet!

So get coding, you only have until March!!

Some things you may want to check out:

* Side note: “The competition wants” really sounds like the competition is a living entity and will punish you if you don’t do this… it isn’t and it won’t.

** My guess for this year at PDC is giving everyone tablets - just looking at what was announced at CES.

09 Dec 2010

Upgrade to SharePoint 2010 on Small Business Server: Field Guide

SharePoint2010_LogoRecently I needed to do an upgrade from SharePoint 2007, to be exact WSS 3.0, to SharePoint 2010 – “No big deal” I thought, “I’ve done it before”. Assumptions, they do make for interesting life experiences, because this was something different – this was an upgrade on a Small Business Server (SBS) deployment.

logo-ms-sbsFor those who do not know, SBS is a lightweight all in one server product. So when you install it you get Windows Server 2008, plus Exchange Server, plus ISA, plus SharePoint, plus plus plus – ALL PRE-CONFIGURED! It is fantastic to use in small companies.

Microsoft has produced a fantastic upgrade guide for this very scenario: http://technet.microsoft.com/en-us/library/ff959273(WS.10).aspx but I think is missing a few footnotes of things I found during my upgrades, which this blog post aims to share.

Check Lists

Blue Man Holding a Clipboard While Reviewing Employess Clipart IllustrationI’ve made two check lists of things you should do ahead of time:

Software

This is the software that you will need during the upgrade.

Environment

This is some prep for the environment you can do a head of time.

  • Get a service account created on the domain for SharePoint to use.
  • Get a service account created on the domain for SQL 2008 R2 to use as it can’t use network service on a domain controller.
  • Check if there is a public internet FQDN setup and get the details of that, will need this when setting up the AAM.
  • Get domain name used for email.
  • Check for a local domain name for the site, normally companyweb. Verify this can be access on the server and also from a workstation on the network.
  • Make sure it is a domain controller – there is some scenarios where you are not installing on a domain controller but it is SBS in which case a lot of the guide and process will be broken.

Notes

Here are my additional notes for the guide. For some steps I have no notes because there was nothing extra special about those processes that needed noting.

Step 1

  • It is easier to check the version number in add/remove programs by showing the version number column. Service Pack 2 has a version number of 12.0.0.6421 so we want that or higher.
  • Alternatively turn on show updates in add/remove programs and see if SP 2 is installed.

Step 4

  • It is not important to disable the service during the copy, provided your server will not be rebooted during step 4 and no one is accessing the SharePoint site.
  • It is VITAL to place these files in a backup location and then copy the content database files MDF/LDF to a secondary location. This location is where the database files will be used from in future.
  • Make sure the database files are NOT read only.

Step 6

  • It is a complete farm install, not a stand alone farm install

Step 7

  • It is ok for the site not to exist

Step 8

  • If the Central Admin “Getting Started Wizard” pop’s up, it is ok to cancel it wizard
  • Make sure the app pool is set to Network Service

Step 13

  • If you get a Default Web Error it is because the default and intranet names are the same – make sure they are not.
Additional steps post upgrade
07 Oct 2010

Internet Explorer 9 breaks with localhost

There is a known bug for this 601047 This is resolved with RTM!
You can hear Eric Lawrence talk about this bug in the Herding Code Podcast

Internet Explorer 9 works great, except when it doesn’t, and it seems to not work for developers more than most, or maybe it’s just me (could the IE9 team be targeting me?).

Paranoia aside, there is an issue where when testing web applications (ASP.NET, MVC) or Silverlight applications from Visual Studio (i.e. press F5) it just refuses to load. Thankfully this has been confirmed by other people Winking smile

image

What is going on and how do we solve this? Because it is really frustrating and it also makes for bad demos (especially with TechEd around the corner).

The first part of the problem is the ASP.NET Development Server which is what is hosting your websites when you hit F5.

image

Next part of the problem is Windows, especially since it assumes IPv6 is better than IPv4. Note in the picture below that when you ping localhost you get an IPv6 address.

image

So what appears to be happening is when IE9 tries to go to localhost it uses IPv6, and the ASP.NET Development Server is IPv4 only and so nothing loads and we get the error.

To solve this fire up notepad in administrator mode and navigate to <windows directory>\system32\drivers\etc\ and open the hosts file. Inside you will find a number of lines prefixed with a hash (which makes those lines comments). Remove the hash from the line which has 127.0.0.1 in it, as below and save.

image 

This will cause Windows to resolve localhost to IPv4 first (you can confirm by pinging localhost) which means that IE9 will do the same and now it just works every time.

image

27 Aug 2010

Pulled Apart - Part XI: Talking to yourself is ok, but answering back is a problem. Why IMPF destroyed CPUS?

onebit_26

Note: This is part of a series, you can find the rest of the parts in the series index.

Pull for me is as much about learning as it is about writing a useful tool that others will enjoy and often I head down a path to learn it was wrong. Sometimes I realise before a commit and no one ever knows, other times it is committed and reading the source history is like an example of how bad things can get and sometimes I even ship bad ideas. IMPF is one such area where I shipped a huge mistake which caused Pull to easily consume an entire core of CPU for doing zero work.

IMPF would check for messages as using the following process:

image 

The Thread.Sleep(0) is there to ensure application messages get processed, but it is zero so that as soon as a message arrives it is processed. This meant that the check, which did a lot of work, was running almost constantly. This means that Pull ended up eating 100% of a the power of a core Sad smile

The Solution

The solution to this was to change the process from constantly checking to getting notified when there is a new message.

image

This is also much simpler to draw than the other way, maybe that should be a design check, the harder to draw the less chance it works Winking smile

The only issue is how do I cause that trigger to fire from another application when it writes a message IMPF should read?

Windows Messaging

Windows internally has a full message system which you can use to send messages to various components in Windows, for example to turn the screen saver on or off, or to send messages to applications. I have used this previously in Pull to tell Windows to add the shield icon if needed (see Part IX) to the protocol handler buttons.

I can also use it to ping an application with a custom message which that application can act on. For Pull when I get that ping I know there is a new IMPF message.

The first part of this is finding the window handle of the primary instance that I want to ping. This I do by consulting the processes running on the machine and using a dash of LINQ filter it to the primary instance.

private static IntPtr GetWindowHandleForPreviousInstances()
{
    Process currentProcess = Process.GetCurrentProcess();
    string processName = currentProcess.ProcessName;

    List<Process> processes = new List<Process>(Process.GetProcessesByName(processName));
    IEnumerable<Process> matchedProcesses = from p in processes
                                            where (p.Id != currentProcess.Id) &&
                                            (p.ProcessName == processName)
                                            select p;

    if (matchedProcesses.Any())
    {
        return matchedProcesses.First().MainWindowHandle;
    }

    return IntPtr.Zero;
}

Now I know who to ping, I just need to send a ping. This is done by calling the Win32 API SendNotifyMessage:

public static int NotifyMessageID = 93956;

private static class NativeMethods
{
    [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
    [return:MarshalAs(UnmanagedType.Bool)]
    public static extern bool SendNotifyMessage(IntPtr hWnd, int Msg, IntPtr wParam, IntPtr lParam);
}

public static void PingPreviousInstance()
{
    IntPtr otherInstance = GetWindowHandleForPreviousInstances();
    if (otherInstance != IntPtr.Zero)
    {
        NativeMethods.SendNotifyMessage(otherInstance, NotifyMessageID, IntPtr.Zero, IntPtr.Zero);
    }
}

That takes care of sending, but how do I receive the ping? I need to do is override the WndProc method on my main form to check for the message and if I get the right ID (see line 1 about – the NotifyMessageID) I then act on it. In my case I use the bus to tell IMPF that there is a new message.

protected override void WndProc(ref Message message)
{
    if (message.Msg == WinMessaging.NotifyMessageID)
    {
        this.bus.Broadcast(DataAction.CheckIPMF);
    }

    base.WndProc(ref message);
}
This has enabled IMPF to only act when needed, removed a thread (since it no longer needs it’s own thread), simplified the IMPF code and made Pull a better citizen on your machine. Smile
25 Aug 2010

Pulled Apart - Part IX: Windows User Account Control

onebit_26

Note: This is part of a series, you can find the rest of the parts in the series index.

Windows Vista introduced a feature called User Account Control (UAC) which added the following to Windows (in addition to a lot of hair pulling by some users). Visually it brought a small shield overlay icon image which indicates to the user that when you click that icon or button you will be prompted to confirm your action and possibly to enter an administrators username and password. This was introduced to stop people from shooting themselves in the foot by making certain actions which could break Windows require special privileges (called administrator privileges, which I find is confusing with administrator users and groups. So I call it root privileges).

works-on-my-machine-starburstI have been a fan of this idea since it was launched and as a developer I have kept it turned on, mainly because the my customers may not have it turned off. Imagine the scenario where I have it off and something works and on a customers machine it fails because UAC is on. I see a Works on my machine scenario coming up. Sad smile

Pull has a part of it which actually bumps up against UAC – registering protocol handlers. I do not want the entire of Pull to need root privileges when running, I only want the small part where you can register or unregister a protocol handler to run in root privileges.

Multiple Processes

The first issue is that root privileges are given to an entire process, and you cannot give it to a thread or method or some sub part. To solve this for Pull, meant creating a second executable file named ProtocolHandler.exe, which takes a few command line parameters and handles the registering and unregistering of protocol handlers.

This enables Pull to launch this second executable with the required root privileges and have it do the dirty work without Pull needing any root privileges. 

image

Running with Root Privileges

Kicking off another process in C# is very easy thanks to the Process class which handles the launching with the Start method (line 11 below). The Process class knows which process to run thanks to the ProcessStartInfo class which is setup before hand and passed to the StartInfo property.

To enable root privileges in the new process all you need to do is set the Verb property of ProcessStartInfo to runas (line 6 below).

Something Pull wants is to wait for the process to finish running, so that the user is confused by it immediately returning and nothing has happened yet. This is solved by using the WaitForExit method on the Process (line 12 below).

private static void RunProtocolHandler(string arguments)
{
    ProcessStartInfo processStartInfo = new ProcessStartInfo();
    processStartInfo.FileName = Path.Combine(Directory.GetCurrentDirectory(), "ProtocolHandler.exe");
    processStartInfo.Arguments = arguments;
    processStartInfo.Verb = "runas";

    using (Process process = new Process())
    {
        process.StartInfo = processStartInfo;
        process.Start();
        process.WaitForExit();
    }
}

The Shield

imageThe final component was to follow the UI guidelines and place a shield icon on the buttons which launch the other application, so that the user is aware this will require root privileges. While you can just grab a shield image and place it on the button that is not recommended because:

  • What if the logo changes in future Windows versions? – you are out of date Sad smile
  • What if the shield is not needed, because the person is running with root privileges already?

To handle this for me I have a small class called UACShield which offers two methods:

  • IsAdmin: this simple method returns true if you have root privileges and false if you don’t. This is done using pure .NET and just checking if the user has the Administrator role (line 14 below).
  • AddShieldToButton: this method takes a button, and if a user is not an admin adds the shield icon. It does this by calling into the Win32 API and calling the SendMessage to update the button. One caveat of this is that the button’s flat style must match the system’s flat style. This means that if you have some special UI tweaks on the button this may break those tweaks.
internal class UACShield
{
    private class NativeMethods
    {
        [DllImport("user32")]
        public static extern UInt32 SendMessage(IntPtr hWnd, UInt32 msg, UInt32 wParam, UInt32 lParam);
        public const int BCM_SETSHIELD = 0x160C; //Elevated button
    }

    public static bool IsAdmin()
    {
        using (WindowsIdentity currentIdentity = WindowsIdentity.GetCurrent())
        {
            return new WindowsPrincipal(currentIdentity).IsInRole(WindowsBuiltInRole.Administrator);
        }
    }
                                                 
    public static void AddShieldToButton(Button button)
    {
        if (IsAdmin())
        {
            // no need for admins
            return;
        }

        button.FlatStyle = FlatStyle.System;
        NativeMethods.SendMessage(button.Handle, NativeMethods.BCM_SETSHIELD, 0, 0xFFFFFFFF);
    }
}
24 Aug 2010

Pulled Apart - Part VIII: Protocol handlers

onebit_26

Note: This is part of a series, you can find the rest of the parts in the series index.

I’ve mentioned previously about Pull’s support for protocol handlers (see part 4) which enable the application to subscribe to a feed easily just by clicking a link. Today I will look at how I to register protocol handlers.

image

Protocol Handlers

Registering a protocol handler is one of the simplest things I did in Pull, because it is merely a registry key which needs to be added to the system. The registry key follows the pattern below.

Key

  • blue = registry key
  • orange = key/value setting

image

The important points (numbered above) are:

  1. This is the protocol that you want to register, so if you want to register say zune:// then this is zune.
  2. This is a useful description on the default key.
  3. This is a setting named URL Protocol but the value must remain blank.
  4. This is path to the icon. So for Pull I just use the default program icon by setting the value to: E:\PortableApps\Pull\Pull.exe,1
  5. This is the command to execute when the URL is added. In Pull this is (note the %1 for the URL parameter): "E:\PortableApps\Pull\Pull.exe" "%1"

The code to do this is rather simple:

public static void Register(string executablePath, string uri)
{
    if (!OurProtocolHandler(uri))
    {
        return;
    }

    using (RegistryKey uriKey = Registry.ClassesRoot.CreateSubKey(uri, RegistryKeyPermissionCheck.ReadWriteSubTree, RegistryOptions.None))
    {
        uriKey.SetValue(string.Empty, Pull.Properties.Resources.PullPodcastURIHandler);
        uriKey.SetValue("URL Protocol", string.Empty, RegistryValueKind.String);
        using (RegistryKey iconKey = uriKey.CreateSubKey("DefaultIcon", RegistryKeyPermissionCheck.ReadWriteSubTree, RegistryOptions.None))
        {
            iconKey.SetValue(string.Empty, string.Format(CultureInfo.CurrentCulture, "{0},1", executablePath));
        }

        using (RegistryKey shellKey = uriKey.CreateSubKey("shell", RegistryKeyPermissionCheck.ReadWriteSubTree, RegistryOptions.None))
        {
            using (RegistryKey openKey = shellKey.CreateSubKey("open", RegistryKeyPermissionCheck.ReadWriteSubTree, RegistryOptions.None))
            {
                using (RegistryKey commandKey = openKey.CreateSubKey("command", RegistryKeyPermissionCheck.ReadWriteSubTree, RegistryOptions.None))
                {
                    commandKey.SetValue(string.Empty, string.Format(CultureInfo.CurrentCulture, "\"{0}\" \"%1\"", executablePath));
                }
            }
        }
    }
}

Being a good citizen

Pull is aware that some people may have other podcatchers installed, and to make sure I do not steal their protocol handlers I have a simple method, OurProtocolHandler, which checks if the protocol is in use and if a protocol is in use we do not override it.

private static bool OurProtocolHandler(string uri)
{
    using (RegistryKey uriKey = Registry.ClassesRoot.OpenSubKey(uri))
    {
        if (Registry.ClassesRoot.OpenSubKey(uri) != null)
        {
            return uriKey.GetValue(string.Empty).Equals(Pull.Properties.Resources.PullPodcastURIHandler);
        }
        else
        {
            return true;
        }
    }
}

Final Thoughts

This is one of the easiest parts to get working, however incorporating it in the application is not as simple which I will cover next.

Pages