Archive

Archive for the ‘.NET Code Samples’ Category

C# Code Sample: Rendering images in Microsoft Excel

July 25th, 2010 No comments

You may have seen examples of pixel art in Excel like these examples here and here. The way this is done is by setting the background color of each cell of the worksheet just as you would set pixel colors in a graphics editor.

I always wondered how much work it would be to import photographic images into Excel this way. Our code would have to perform these basic steps:

  • Iterate over all lines of the image
  • Iterate over all pixels in each line of the image
  • Get the color of the currently iterated pixel
  • Set the background color of the worksheet cell with the currently iterated x/y coordinates to the color of the image’s pixel
  • Set the column width and row height of the worksheet cell so that it is approximately 1 pixel big
    As it turns out, you can do this with less than 30 lines of C# code:
            private const String _bitmapFile = @"C:\Users\Public\Pictures\Wallpapers\Photo.jpg";
            private const int xlAutomatic = -4105;
            private const int xlSolid = 1;
    
            private void ThisAddIn_Startup(object sender, System.EventArgs e) {
    
                try {
                    Application.ScreenUpdating = false;
    
                    using (Bitmap bitmap = (Bitmap)Bitmap.FromFile(_bitmapFile)) {
                        // Set row heights to 1
                        for (int y = 1; y <= bitmap.Height; y++) {
                            Application.ActiveSheet.Rows[y].RowHeight = 1;
                        }
                        // Set column widths to 0.1
                        for (int x = 1; x <= bitmap.Width; x++) {
                            Application.ActiveSheet.Columns[x].ColumnWidth = 0.1;
                        }
    
                        for (int y = 1; y <= bitmap.Height; y++) {
                            for (int x = 1; x <= bitmap.Width; x++) {
                                var color = bitmap.GetPixel(x - 1, y - 1);
                                var range = Application.ActiveSheet.Cells[y, x];
                                range.Select();
                                dynamic interior = Application.Selection.Interior;
                                interior.Pattern = xlSolid;
                                interior.PatternColorIndex = xlAutomatic;
                                interior.Color = ((int)color.B * 65536) + ((int)color.G * 256) + ((int)color.R);
                                interior.TintAndShade = 0;
                                interior.PatternTintAndShade = 0;
                            }
                        }
                    }
                }
                finally {
                    Application.ScreenUpdating = true;
                }
            }

    Simply create a new Excel 2010 Add-In project in Visual Studio 2010 and paste the above code over the ThisAddIn_Startup method stub. After you have compiled the project Excel will import the image file _bitmapFile on the next startup (give it some time).

Here’s a sample of what it looks like:

Image in Excel

I know it’s not very sophisticated but it was fun to do and I learned something about VSTO 2010. If you’re looking for some really cool stuff to do with Excel I recommend you check out this 3D rendering engine made with Excel.

Categories: .NET Code Samples

WHS Developer Tip: How to communicate between your SettingsTab and your ConsoleTab

April 8th, 2010 3 comments

As an avid Windows Home Server AddIn developer you probably followed the steps from the Windows Home Server SDK which explain how to implement your own console tab and a settings tab for the WHS console settings dialog.

Now when the user makes changes to the settings on your settings tab and ultimately clicks OK or Apply you may need a way to notify your console tab of the new settings.

settings_notify

The easiest way to accomplish this is by using a singleton object which provides the necessary means of communication:

public sealed class ChangeNotifier {
    public event EventHandler Changed;

    private ChangeNotifier() {
    }
    public static readonly ChangeNotifier Instance = new ChangeNotifier();

    public void Notify() {
        OnChanged(new EventArgs());
    }

    void OnChanged(EventArgs e) {
        EventHandler handler = Changed;
        // Make a temporary copy of the event to avoid possibility of
        // a race condition if the last subscriber unsubscribes
        // immediately after the null check and before the event is raised.
        if (handler != null) {
            handler(this, e);
        }
    }
}

Simple enough! Now we can access a common instance (the singleton) from everywhere in our code by calling on ChangeNotifier.Instance. Note: If you’re not familiar with the singleton design pattern you can read more about it in this Wikipedia article.

Now there’s two things left to do: First we need to subscribe to the ChangeNotifier’s Changed event in our console tab and second we have to call the Notify() method (which will fire the Changed event) from our settings tab when setting changes are committed.

Place this code in your console tab:

ChangeNotifier.Instance.Changed += new EventHandler(ChangeNotifier_Changed);

void ChangeNotifier_Changed(object sender, EventArgs e) {
    // TODO: Apply changed settings to your console tab here
}

And this line of code could be the last statement of your ISettingsTab.Commit() implementation:

ChangeNotifier.Instance.Notify();

This is pretty much it. Every time the user clicks OK or Apply on the settings dialog of the Windows Home Server your ISettingsTab.Commit() method is called where you now call Notify() on your ChangeNotifier singleton. This will raise the Changed event which will be handled by your event handler in your console tab (or any other class in your addin) so that you instantly can apply the settings changes the user has just made.

How to implement an update check in your Windows Home Server AddIn

March 21st, 2010 No comments

So you’ve written your Windows Home Server AddIn, made it available for download and are happy that people all over the world start using it on their Windows Home Servers. But shortly after you’ve put your work out in the wild users send you emails or start complaining on WHS related forums about weird behavior of your addin or WHS console crashes. You look at your code again, determine the culprit, fix the bug and compile a new version of your addin and put it in the download section of your website or blog. But how can you notify all users of older versions of your software about the availability of the new bugfix release? Of course the easiest way to do this is by having your addin check for available updates from time to time.

I want to show you the simplest form of an update check in less than 20 lines of C# code. Before we can have a look at the code we have to ask ourselves which steps are required to perform:

  1. Determine the version of our addin that is currently running
  2. Retrieve information about the latest version of our addin from the web
  3. Compare these two versions and decide whether the currently running version is outdated
    Step one is fairly easy: By the use of System.Reflection.Assembly we can determine the version of the assembly the currently executing code resides in like so:
    // Determine the Version of your addin by getting the assembly version
    // of the assembly that contains the code that's currently being executed.
    Version currentVersion = Assembly.GetExecutingAssembly().GetName().Version;

Before we can implement Step 2 we have to decide how and where we want to store the version information of out addin on the web. For this example we simply create a single-line text file (.txt) with the version number of our latest addin build:

image

Next we place this file on our web space so that our addin can retrieve it from there. For instance the URL to the file could be http://ourwhsaddin.com/OurAddInVersion.txt.

Now we can write the code that will download the version information file and parse its contents:

// URL of the file containing the version number of the latest available
// version of your addin
String versionURL = "http://ourwhsaddin.com/OurAddInVersion.txt";

// Prepare the HttpWebRequest object for downloading the version information
// file
HttpWebRequest req = (HttpWebRequest)WebRequest.Create(versionURL);
// Set the current addin + version number as user agent so that
// the web server logs it as the "user's browser"
req.UserAgent = "My WHS AddIn Version " + currentVersion.ToString();
// Set the cache policy so that the version informatin file is always
// downloaded and not retrieved from the local cache.
req.CachePolicy = new RequestCachePolicy(RequestCacheLevel.NoCacheNoStore);
// Get the version information file by executing the web request
WebResponse resp = req.GetResponse();
Version availableVersion;
using (StreamReader sr = new StreamReader(resp.GetResponseStream())) {
    // Read and parse the version information
    string availableVersionString = sr.ReadLine();
    availableVersion = new Version(availableVersionString);
    sr.Close();
}

As you probably know web servers usually log all activity for hosted content like client IP addresses, users’ web browsers (= User Agent) locations of accessed files and so on. If you want to be able to determine which versions of your addin are performing update checks you can set the addin name and current version as user agent (see above) and you will find this information in your server logs.

The code above is pretty self-explanatory (I think). We create System.Net.HttpWebRequest object from our version file URL, set the user agent string and cache policy and execute the request by calling GetResponse() on it. We then set a System.IO.Streamreader on the response stream and read the first (and only) line from the stream (= our version information file). The next step is to convert the version string into a System.Version object by creating a new System.Version object passing the version string to the constructor.

So we have the version of our currently running code in currentVersion and the version of the latest available release in availableVersion. Our last step (Step 3) is to compare these two in order to determine whether the latest release is newer than what’s currently running:

if (availableVersion > currentVersion) {
    // A new version is available for download

}

Tadaa! That’s it! Of course you’d have to do proper exception handling which I omitted from the example in order to make the code look simple and clean.

Like I said this is the most basic form of an update check mechanism. Instead of downloading a simple text file we could set up a web service and submit more information about the current addin version when we call it. But be sure that you respect the user’s privacy, when doing this! We could also include the download URL and version history in the text file (or the web service response) and display it to the user when we notify them about the availability of an update. The possibilities are endless!

While it’s a nice feature to get update notifications I believe it would be best if the operating system would handle this and users would have a central place where they can go to update their software. However, Windows Home Server does not have such a place but the upcoming AddIn Central from HomeServerLand looks very promising and I hope that it will become this central place of addin administration.

UPDATE:

I just got notified by Björn Bürstinghaus that they are still looking for beta testers for the german version of AddIn Central. If you speak german and want to participate in the beta please visit http://blog.buerstinghaus.net/add-in-central-beta-fur-den-home-server/ and leave a comment. You’ll then be contacted by the AddIn Central team via email.

Code Sample: Navigating special folders with the .NET WebBrowser control

March 23rd, 2008 4 comments

With the .NET Framework 2.0, Microsoft introduced the WebBrowser control, a managed code wrapper for the WebBrowser ActiveX control. Unfortunately, compared to the ActiveX version, the .NET version of the control lacks some functionality. You can navigate websites, local HTML documents and folder locations using respective protocol handler prefixes (“http://”, “file://”). What you cannot do with the .NET WebBrowser control is navigate special folders like “My Computer” or the control panel, as these folders are not identified by a path but by CSIDLs. So my goal was to extend the existing WebBrowser class to provide this ability.

First of all I did some research on the topic and found a Knowledge Base article describing the necessary steps to navigate a PIDL (pointer to an ITEMIDLIST) with the ActiveX version of the WebBrowser control. So all I had to do was convert the code sample to C#.

Here’s my resulting Navigate2CSIDL method:

public void Navigate2CSIDL(ShellEnums.CSIDLValues csidl) {

    const int S_OK = 0;

    IntPtr pidl = IntPtr.Zero;

    if (SHGetSpecialFolderLocation(IntPtr.Zero, (int)csidl, ref pidl) == S_OK) {
        uint cbpidl = LocalSize(pidl);
        if (cbpidl > 0) {
            byte[] abpidl = new byte[cbpidl];
            Marshal.Copy(pidl, abpidl, 0, ((int)cbpidl - 1));
            object location = (object)abpidl;
            Marshal.FreeCoTaskMem(pidl);

            try {
                object nil = Type.Missing;
                ((SHDocVw.WebBrowser)base.ActiveXInstance).Navigate2 (
                  ref location, ref nil, ref nil, ref nil, ref nil);
            }
            catch (COMException exception) {
                if (exception.ErrorCode != -2147023673
                    /*Operation was canceled by the user*/) {
                    throw;
                }
            }
        }
    }
    else {
        throw new ArgumentOutOfRangeException();
    }
}

The method takes only one parameter: the CSIDL of the special folder to navigate to. First of all, I use SHGetSpecialFolderLocation() to obtain the PIDL of the desired special folder. Since the Navigate2() method of the ActiveX WebBrowser control takes the PIDL wrapped in a SAFEARRAY, we can copy the PIDL to a byte array. Next we call Navigate2() to navigate the WebBrowser control to the folder. ComInterop handles the marshalling of the byte array to a SAFEARRAY for us. And that’s all we have to do.

To be able to conveniently use this funcionality, I created a new class (“WebBrowserExt”) which inherits from System.Windows.Forms.WebBrowser. As the control consumer might want to interact with the special folder, I added two properties (FolderView and Folder) in analogy to the Document property of the WebBrowser control class:

/// <summary>
/// Returns the shell folder object displayed in the webbrowser control.
/// </summary>
public Shell32.Folder2 Folder {
    get {
        IShellFolderViewDual2 folderview = this.FolderView;
        if (folderview != null) {
            return folderview.Folder as Folder2;
        }
        else {
            return null;
        }
    }
}

/// <summary>
/// Returns the shell folderview object displayed in the webbrowser control.
/// </summary>
public Shell32.IShellFolderViewDual2 FolderView {
    get {
        return ((SHDocVw.WebBrowser)base.ActiveXInstance).Document
                 as IShellFolderViewDual2;
    }
}

See the documentation of IShellFolderViewDual2 and Folder2 to find out what you can do with these. These interfaces are supplied by adding references to ShDocVw.dll and Shell32.dll to the project. I put together a small sample project to demonstrate the capabilities of my WebBrowserExt control. This is a Visual Studio 2008 project, so you need at least the free Visual C# 2008 Express Edition to open it.

Here’s a screenshot of the sample project showing the control panel:

Webbrowser_control

Download the sample project here. I also posted this on Channel9.

Related Posts with Thumbnails
Categories: .NET Code Samples