Tuesday, August 22, 2006
In one of my projects at work, I ran into a situation where Visual Studio 2005 didn't recognize my designer files (i.e. MainForm.Designer.vb) so all of the serialized designer code was getting stuck in a new InitializeComponent in my code file (i.e. MainForm.vb). Of course, because my Designer code was a partial class, I got an error out of it. In my experience, this behavior is sort of obscure, but here is an easy fix.

Open up the project file (which in my case was GUI.vbproj) in a text editor and do a search for your Designer file. You should see some tags that look like this:
<Compile Include="CustomControl.Designer.vb">
</Compile>
<Compile Include="CustomControl.vb">
<SubType>UserControl</SubType>
</Compile>
Now, what it SHOULD look like is this:
<Compile Include="CustomControl.Designer.vb">
<DependentUpon>CustomControl.vb</DependentUpon>
</Compile>
<Compile Include="CustomControl.vb">
<SubType>UserControl</SubType>
</Compile>
I've bolded the important part for you. Basically, my project file, for whatever reason, was missing the <DependentUpon> tag. If you add that back, Visual Studio should start behaving as expected again.
posted on Tuesday, August 22, 2006 3:23:40 PM (Central Standard Time, UTC-06:00)  #    Comments [0]
 Monday, August 21, 2006

(After yesterday's post on getting metadata from images in .NET, I've decided to continue to post some of the information I find regarding working with images in .NET.)

As I mentioned yesterday, I'm working on an application to export a folder of images over to a webpage or something (I haven't decided on the output format, whether to a database, XML, or what). I've been learning quite a bit about .NET image support (primarily from GDI+) and it really provides a lot right out of the box. Today's post is on resizing an image without losing too much quality in the process.

The first resource I found was System.Drawing.Image.GetThumbmailImage. My first thought was, "Surely it isn't this easy!" I was right - it wasn't that easy. Check out this quote from the remarks section of the documentation:

The GetThumbnailImage method works well when the requested thumbnail image has a size of about 120 x 120 pixels. If you request a large thumbnail image (for example, 300 x 300) from an Image that has an embedded thumbnail, there could be a noticeable loss of quality in the thumbnail image.

My first test was resizing an image that was originally 2580 x 1932 down to 640 x 483. It looked quite nasty after trying to call GetThumbnailImage. Back to Google I went, but thankfully I soon hit paydirt. I found the "Resizing a Photographic image width GDI+ for .NET" article by Joel Neubeck on CodeProject. The meat of the functions he provides are that they give examples on how to carry the resolution of the original image over and also how to use bicubic interpolation. With his code, my 640 x 483 picture still looks great - just as good as Picasa does for its export code!

I will say that I am still using the GetThumbnailImage method for what it was primarily designed for: thumbnails. As the documentation says, it works fine up to about 120 x 120. I'm personally using a max width/height of 90 for my thumbnails right now. Here's an example of a call to GetThumbnailImage just so we'll get some code in this post:

private static void CreateThumbnail(Image img, string path, Size imageSize)
{
    // Only call this to create thumbnails smaller than 120 x 120! Otherwise, check out 
    // http://www.codeproject.com/csharp/imageresize.asp.
    
Image thumbnail = img.GetThumbnailImage(
        imageSize.Width,
        imageSize.Height,
        (
delegate { return false; }),
        
IntPtr.Zero);
    thumbnail.Save(path);
}

As you can see, I'm using an anonymous delegate for the 3rd parameter, which presumably only exists for backwards compability, because it isn't called. It makes more sense to me to do it this way than to add a function that won't even be called.

posted on Monday, August 21, 2006 9:12:41 PM (Central Standard Time, UTC-06:00)  #    Comments [0]
 Sunday, August 20, 2006

So, this is a little off-topic compared to some of the other posts I have done lately, but it was something new to me and I thought I'd share it for information... and as a means of helping me remember it later!

At home, I have been using both Microsoft Digital Image Library 2006 and Picasa to manage my digital pictures because I like features in both. Microsoft's product provides some nice editing features and tagging while I've been using Picasa's export as a webpage in an XML format for mine and my wife's blog. One of the hassles between the two, though, is that they store captions for images differently. I was having to manually copy and paste captions between both programs, which is huge time waster. Because I wanted to continue using Digital Image Library, I decided to write a program to export the gallery. (I know there are programs out there that can do this for me... I've got the programmers' disease!)

To write this program correctly, I wanted to still be able to pull out information like the captions I had set for each picture. I ended up digging around a little bit researching the different implementations for storing metadata in the files and it would appear that Microsoft's implementation seems more standard than that of Picasa. In fact, some digging in one of my pictures using a hex editor shows the proprietary <picasastamp> enclosing a <caption> tag. At least that means it will be easier to pull the caption out.

Probably one of the best places to start for researching this is the MSDN how to: Read Image Metadata. It details the PropertyItem that you can get off of the System.Drawing.Image class. There is actually a collection of PropertyItem objects from the PropertyItems collection. Basically, you can loop through the collection and inspect each item's Id property until you find the one you are looking for. That's the easy part. The hard part is figuring out which Id you're interested in because they don't have user-friendly names like "Caption" or "Title" - they're in hex. Thanks to this sort of random post, I was able to find out that the captions I was looking for were 0x9c9b.

So, without further ado, here's a very simple GetCaption method that will return the caption/title based on an Image passed to you:

public static string GetCaption(Image img)
{
    if (img == null) 
        throw new ArgumentNullException("img");

    Encoding enc = Encoding.UTF8;

    foreach (PropertyItem prop in img.PropertyItems)
    {
        if (prop.Id == 0x9c9b)
        {
            return enc.GetString(prop.Value).Replace("\0", "").Trim();
        }
    }

    return string.Empty;
}

Let me know what you think!

If you're interested in more about the PropertyItem class, check out these pages - they've got some nice information on them as well.

- http://www.codeproject.com/cs/media/photoproperties.asp
- http://www.pixvillage.com/blogs/devblog/archive/2005/03/27/176.aspx

posted on Sunday, August 20, 2006 8:21:59 PM (Central Standard Time, UTC-06:00)  #    Comments [2]
 Friday, August 18, 2006
This post is just as much for me as it is to share...

I was attempting to create a automatically resizing GroupBox control that would let users drop controls on it and it would grow as the controls dropped. I also wanted to offer a FlowLayoutPanel-like ability so that it would slide controls that were lower up if higher controls were hidden. Doesn't sound too bad and we would use it enough that it made sense to encapsulate it in a custom control. I started looking into inheriting from GroupBox and adding a FlowLayoutPanel to it's control collection. Then I hooked into the ControlAdded event for the GroupBox so that I could move the control from the GroupBox to the FlowLayoutPanel. I'm just walking you through the steps in my thinking process here... this apparently isn't how it should be done, because though it worked if controls were added at run-time, it gave me a weird designer error that said "'child' is not a child control of this parent" (like these guys did).

What research I came up with looked like I would have to create my own custom designer to support code like this, that would also include code serialization into InitializeComponent. Yay. A little more research brought me this link, though. It details how to drop controls onto a UserControl at design time. It is a slightly different approach, but it provided what I needed. Basically, the solution also involves using a ControlDesigner, but the code seems much less involved than if I were handling code serialization.

Here's a code snippet to give you an idea of what I did:
<Designer(GetType(AutoResizeGroupBoxDesigner))> _
Public Class AutoResizeGroupBox
<DesignerSerializationVisibility(DesignerSerializationVisibility.Content)> _
Public ReadOnly Property FlowPanel() As FlowLayoutPanel
Get
' Where _flowPanel has already been added to the designer
Return _flowPanel
End Get
End Property

' code snipped...

End Class

Public Class AutoResizeGroupBoxDesigner
Inherits ControlDesigner
Public Overrides Sub Initialize(ByVal component As System.ComponentModel.IComponent)
MyBase.Initialize(component)
Dim autoGroupBox As AutoResizeGroupBox = DirectCast(component, AutoResizeGroupBox)
EnableDesignMode(autoGroupBox.FlowPanel, "FlowPanel")
End Sub
End Class
posted on Friday, August 18, 2006 6:58:52 AM (Central Standard Time, UTC-06:00)  #    Comments [0]
 Wednesday, August 16, 2006

I'm sorry... I've been bad about posting lately. So bad in fact, that I've only posted once this month! But you know what? I've got a good excuse... I was in Alaska on vacation! So there!

I plan on putting pictures on mine and my wife's blog soon if anyone is interested in seeing what Alaska looks like. It is a lot cooler there, which was a huge plus over the 100+ (Fahrenheit) temperature here.

Anyway, I wanted to also say that I've been a del.icio.us junkie lately, too. I didn't know until fairly recently that you could subscribe to OTHER users' bookmarks and see what they're watching. That feature is downright cool. It gives you a glimpse of what other people find interesting and it is even faster than watching blog posts, because people tend to bookmark things before posting about them. I do. My del.icio.us page is at http://del.icio.us/drmohundro if anyone is interested in checking it out. The RSS feed is at the bottom.

Does anyone else use del.icio.us regularly? If so, leave your del.icio.us IDs!

(PS - this post comes to you from Windows Live Writer... too bad it doesn't work through my corporate proxy, either...)

posted on Wednesday, August 16, 2006 9:38:24 PM (Central Standard Time, UTC-06:00)  #    Comments [0]
 Wednesday, August 02, 2006
wikiality (wi-ki-al-i-ty) - the process of creating "reality" (see reality) by making something up on Wikipedia enough that more and more people agree with you.

It looks like Stephen Colbert from the Colbert Report on Comedy Central had some fun with Wikipedia recently. Check it out.
posted on Wednesday, August 02, 2006 12:37:32 PM (Central Standard Time, UTC-06:00)  #    Comments [0]
 Wednesday, July 26, 2006

Recently, I've been experimenting with different console colors in PowerShell, primarily because the light gray on black is sort of boring (lame excuse, I know). I've been using Console and I had set the foreground color to green in the options. The only problem with doing this is that programs that output other colors, such as the error messages from MSBuild, are not displayed. I like seeing the color difference because the red text really jumps out at me and says that I have an error.

This got me curious about whether or not I could set a different color in PowerShell, instead of in Console. I stumbled across this TechNet article from way back when PowerShell was still MSH. Basically, you use the -foregroundcolor or -backgroundcolor switch against Write-Host to alter the color of the text you're outputting. That's certainly userful information if you're writing cmdlets, but I wanted to change the default color for the entire session.

If you've worked with .NET console applications, you may have seen System.Console.ForegroundColor. Well, this is available from PowerShell as well! .NET shell integration is great! So now, my PowerShell profile has a brand new line in it:

[System.Console]::ForegroundColor = [System.ConsoleColor]::Green

By doing this, whenever an application, cmdlet, function or whatever changes the default output color, like MSBuild does, you'll be able to see it. As a side note, I really like the PowerShell profile idea. Though options dialogs tend to be more user friendly, the PowerShell profile (try 'notepad $profile') is far more powerful and customizable.

posted on Wednesday, July 26, 2006 12:00:28 PM (Central Standard Time, UTC-06:00)  #    Comments [0]
 Thursday, July 20, 2006
Like many other users of Visual Studio 2005, I've occasionally received the WSoD (White Screen of Death) while using the designer. And like a typical user, I blamed it on Visual Studio. That's what users do, right? They blame the program, because the user is always right. The same behavior that frustrates me to no end when users enter invalid data into MY program and then blame MY program (of course, if my UI were better, it wouldn't be as difficult to use, but that is another story). Anyway, my frustrations with VS2005 crashing and the WSoD's were in fact a problem with the user - me.

In one of my forms, I had some background threading work that was started when the form loaded. Like a good programmer, I had wrapped this threading work in a check against Me.DesignMode to ensure that it wouldn't try to do this work while in the designer. What I didn't know at the time is that the DesignMode property isn't set until AFTER the constructor fires. I checked around with some guys at work and I discovered that I wasn't the first one to discover this. They had already put a check against Application.ExecutablePath to see if it was devenv.exe. If it is, then we're in DesignMode. Simple as that!

So, all of my VS crashes and weird WSoD's have now been tracked back to my OWN code. HOWEVER, I would like to say that it would have been nice if Visual Studio had given me a better message to inform me that my designer code was trying to run background threads or something - in much the same way that my own code should work better and give my users better messages.

Ah, the joys of user interaction.

Note: This fixed the problem suggested after sending error reports that link to this hotfix (http://support.microsoft.com/?kbid=915038). If you're running into this, check and double-check the code in your UI constructors, INCLUDING base class constructors!
posted on Thursday, July 20, 2006 10:22:10 AM (Central Standard Time, UTC-06:00)  #    Comments [0]
 Tuesday, July 18, 2006
Earlier today, Mark Russinovich announced that Microsoft had acquired Winternals and Sysinternals. In other words, some of the best administration tools available will be moving to Microsoft. Not only that, but by having Mark on board at Microsoft, they will have a great developer working with them. I think that this is a great move as far as bringing Mark on board. As far as acquiring Winternals and Sysinternals, I'm excited about that as well, so long as the products continue to be supported by Microsoft. I'm quite confident they will, too, because I know that Microsoft uses a lot of their tools as well (i.e. Process Explorer, RegMon, FileMon, etc).

Congratulations and I look forward to hearing more!
posted on Tuesday, July 18, 2006 11:11:58 AM (Central Standard Time, UTC-06:00)  #    Comments [0]