Friday, April 21, 2006
Continuing in the tradition of posts on Visual Studio WSoD's, I ran into another one today that gave me this error: "Object does not match target type."

Okay... super.

Luckily, I got some warnings with line numbers. They pointed me to a line in my designer code that looked like this:

CType(Me.MyUserControlInstance, System.ComponentModel.ISupportInitialize).BeginInit()

The other error was the same line except it was the matching EndInit call.

Similar to before, I was working with code that was in the process of being updated to the .NET 2.0 Framework. I had been working with a control that was inheriting from a .NET 1.1 control. The ISupportInitialize code had been in there for the 1.1 parent. The designer didn't mind at all until I moved the parent control over to 2.0. The solution was easy enough... just take the ISupportInitialize code out. I'm not sure if this is the recommended solution or not (I didn't Google it for too long), but it works.
posted on Friday, April 21, 2006 2:34:20 PM (Central Standard Time, UTC-06:00)  #    Comments [0]
 Friday, April 14, 2006

Ever seen this error in Visual Studio 2005?

I've seen it all too often and it is really annoying.

However, I did find a possible fix today. I was working in a project that had multiple assembly references. One of the references was using a 1.1 assembly, so it came along for the ride. By simply removing that reference, I was able to view my form without any problems. If I tried to add the reference back, I would get the designer error again. I reworked the assembly being referenced to not use any 1.1 components and... lo and behold... the designer errors stopped.

Is this just a really random bug or is this a subtle way to push people to migrate to .NET 2.0?

posted on Friday, April 14, 2006 2:09:51 PM (Central Standard Time, UTC-06:00)  #    Comments [3]
I had some code that I was porting from .NET 1.1 to .NET 2.0 today. The code I had was checking the version of comctl32.dll to see if it was version 6 or greater to determine if the application supported visual styles or not. As I didn't write that code, I'm not sure if that is a valid way to check for visual style support in .NET 1.1.

I DO know that in .NET 2.0, that check doesn't necessarily work correctly; however, there is a new way to check that is much easier and more reliable -- Application.RenderWithVisualStyles. If you call Application.EnableVisualStyles in your Sub Main method, this boolean will be set to true. That's all you need to check!

See MSDN documentation here.
posted on Friday, April 14, 2006 10:50:11 AM (Central Standard Time, UTC-06:00)  #    Comments [0]
 Thursday, April 13, 2006
Check out this article on ABC News. Or this press release from Winternals.

Apparently, a few members of Geek Squad have been using pirated versions of software from Winternals. In case you're unfamiliar with Winternals, they're the enterprise side of Sysinternals, which provides the excellent Process Explorer as well as a few other invaluable tools. Mark Russinovich, who discovered the original Sony DRM rootkit, is one of the people who established the company.

Way to go Best Buy.
posted on Thursday, April 13, 2006 12:06:37 PM (Central Standard Time, UTC-06:00)  #    Comments [0]
Mozilla Firefox 1.5.0.2 was released today. At first glance, it seems to be a lot more stable than 1.5.0.1. I had all sorts of issues with the last version randomly crashing on me. In their defense, it seemed to be a combination of some of the extensions I was using and the corporate proxy. I never had any problems at home using the same extensions.

Check it out.

(via Neowin.net Software)
posted on Thursday, April 13, 2006 11:51:05 AM (Central Standard Time, UTC-06:00)  #    Comments [0]
I stumbled across this post by Mike Woodring today. Apparently, the UserState property from the BackgroundWorker isn't accessible from the RunWorkerCompleted event. What in the world???

Anyway, I wasn't actually looking for information on the UserState property -- I was trying to find some information on the Error property off of RunWorkerCompletedEventArgs. It gets populated when an exception is thrown in your background thread. The weird thing is, I couldn't get my code to fall in there. The debugger kept popping up on the line where I was actually throwing the exception. Believe it or not, but that is actually the intended behavior... IF you're running in the debugger. Check out this post on the MSDN forums. If you're running standalone, then the Error property will be set as expected and you can check it. I wonder if you can continue on the exception and get to the RunWorkerCompleted event. I'll have to try that.

One last potential gotcha involving using the Error property: make sure it is the FIRST thing you check in your RunWorkerCompleted event handler. See this post on the MSDN forums for details there. According to Mike Woodring's post referenced above, if you access the Result property off of the RunWorkerCompletedEventArgs parameter and the Error property is populated or the Cancelled property is true, you'll get an invalid operation exception.

So now you know... and knowing is half the battle!
posted on Thursday, April 13, 2006 11:48:15 AM (Central Standard Time, UTC-06:00)  #    Comments [0]
 Tuesday, April 11, 2006

MSBuild is a great tool. If you're not familiar with it, it is Microsoft's new build engine which was released with .NET 2.0. Visual Studio 2005 uses it behind the scenes. If you'd like to see it in action, pull up a VS2005 Command Prompt and type "msbuild YourSolution.sln" and watch the magic. It provides a much faster way of recompiling solutions and projects than reopening Visual Studio.

MSBuild runs off XML files. If you'd like to see one, just open up one of your vbproj or csproj files. Visual Studio projects default to the MSBuild format. Unfortunately, the solution files still aren't in an XML format. Because it uses XML, you can extend a build to do any number of tasks. I'll walk you through a very simple example.

My task is a Replace task that simple takes an input string (likely a file path or assembly name), an old value, and a new value and returns a value with all old values replaced with new values. It works exactly like the Replace method off of String objects.

First off, create a new Class Library project in Visual Studio. You'll need to add a reference to Microsoft.Build.Framework and to Microsoft.Build.Utilities. Next, for your class, inherit from Microsoft.Build.Utilities.Task. You'll be forced to override an Execute method. That's really all it takes to get a custom task. Everything else is driven off of public properties that are described by specific MSBuild attributes like "Required" or "Output".

Here's the source for my Replace task:

using Microsoft.Build.Framework;
using Microsoft.Build.Utilities;

using System;
using System.Collections.Generic;
using System.Text;

namespace Tasks
{
    
/// <summary>
    /// Custom MSBuild task to perform String replacement. Primarily used for
    
/// Namespace to directory replacement (DTC.NRA.App -> DTC\NRA\App).
    
/// </summary>
    public class Replace : Task
    {
        
string _input;
        [
Required]
        
public string Input
        {
            
get { return _input; }
            
set { _input = value; }
        }

        
string _oldValue;
        [
Required]
        
public string OldValue
        {
            
get { return _oldValue; }
            
set { _oldValue = value; }
        }

        
string _newValue;
        [
Required]
        
public string NewValue
        {
            
get { return _newValue; }
            
set { _newValue = value; }
        }

        
string _results;
        [
Output]
        
public string Results
        {
            
get { return _results; }
            
set { _results = value; }
        }

        
public override bool Execute()
        {
            
bool success = true;
            
try
            {
                Results = Input.Replace(OldValue, NewValue);
            }
            
catch (Exception e)
            {
                Log.LogErrorFromException(e);
            }
            
return success;
        }
    }
}

The XML below is how I'm currently using this task.

<UsingTask TaskName="Tasks.Replace" AssemblyFile="C:\Development\References\MSBuildTasks.dll" />
<
PropertyGroup>
  <
RootDirectory>C:\Development\Build\</RootDirectory>
</
PropertyGroup>
<
Target Name="AfterBuild">
  <
Replace Input="$(RootNamespace)" OldValue="." NewValue="\">
    <
Output TaskParameter="Results" PropertyName="NamespaceDirectories" />
  </
Replace>
  <
CreateItem Include="$(OutputPath)\**\*.*">
    <
Output TaskParameter="Include" ItemName="FilesToArchive" />
  </
CreateItem>
  <
Copy SourceFiles="@(FilesToArchive)" DestinationFolder="$(RootDirectory)$(NamespaceDirectories)\%(FilesToArchive.RecursiveDir)" />
</
Target>

As you can see, I've got the UsingTask which references the assembly I built. Then you can use the Replace task like any other provided task. The above exactly can be copied into a Visual Studio project and it will copy the output files from your build into the RootDirectory you specify with the root namespace making up the folders beneath it (i.e. give the namespace System.Windows.Forms, this will copy your compiled assemblies to c:\Development\Build\System\Windows\Forms\*).

posted on Tuesday, April 11, 2006 11:43:25 AM (Central Standard Time, UTC-06:00)  #    Comments [0]
 Friday, March 31, 2006

Yesterday afternoon, I posted on ShellExecuteEx and executing files with unknown file extensions. I was really confused, though, because my feed just wouldn't show up in my aggregator (RSS Bandit). I knew it wasn't my reader, though, because I had navigated to my feed's address (http://feeds.feedburner.com/DavidMohundro) and it wasn't displaying my added post. I threw a few test posts out there but nothing would show up. I'll admit, I couldn't help but wonder if something had happened with FeedBurner. I shouldn't have doubted, though. It was indirectly my fault.

You see, FeedBurner has a nice report called FeedMedic (located under their Troubleshootize tab). I hadn't found that report until this afternoon. It informed me that my source feed was too large.

Wha???

Apparently, my last post on file extensions was too big. I ended up editing the last post and taking out a lot of the unnecessary HTML that came out of my code to HTML addin. I ended up using Jeff Atwood's great FormatToHtml VS2005 macro. The HTML it generates is a lot simpler, but also a lot cleaner. That solution alone dropped my post under the "large" size. Now everyone can happily see my posts again!

posted on Friday, March 31, 2006 5:04:26 PM (Central Standard Time, UTC-06:00)  #    Comments [0]

Recently, I was adding the ability to open files from an application at work. Luckily, I had run into this situation before, so I knew that you could run a Process.Start on the file in question and have Explorer open it for you. What I didn't know was that it would throw a Win32Exception if the file didn't have an associated program to open it. My next step was what any good developer would do: Google it.

Fairly early on in my searching, I came across a post by Ned Batchelder that described the EXACT same scenario I was working on! Ned wanted to open a file with an unknown extension from a managed application just like me. He details his Google search and explains how he discovered information about the API functions, ShellExecute and ShellExecuteEx. Basically, you can call ShellExecuteEx with an "open" verb and Explorer will attempt to open the file. If it fails with an SE_ERR_NOASSOC error, then call ShellExecuteEx again but using an "openas" verb. Doesn't sound too bad, though some code snippets still would've sped the process up for me :-) I did learn it better this way, though.

Anyway, here's where I started. First, I pulled in the definition for the SHELLEXECUTEINFO structure.

Friend Structure SHELLEXECUTEINFO
    
Public cbSize As Integer
    Public fMask As SEE_MASK
    
Public hwnd As IntPtr
    <MarshalAs(UnmanagedType.LPTStr)> _
    
Public lpVerb As String
    <MarshalAs(UnmanagedType.LPTStr)> _
    
Public lpFile As String
    <MarshalAs(UnmanagedType.LPTStr)> _
    
Public lpParameters As String
    <MarshalAs(UnmanagedType.LPTStr)> _
    
Public lpDirectory As String
    Dim nShow As Integer
    Dim hInstApp As SE_ERR
    
Dim lpIDList As IntPtr
    <MarshalAs(UnmanagedType.LPTStr)> _
    
Public lpClass As String
    Public hkeyClass As IntPtr
    
Public dwHotKey As Integer
    Public hIcon As IntPtr
    
Public hProcess As IntPtr
End Structure

Next, I created definitions for the SW, SEE_MASK, and SE_ERR constants.

#Region " SW Constants "
    Friend Enum SW As Integer
        HIDE = 0
        SHOWNORMAL = 1
        NORMAL = 1
        SHOWMINIMIZED = 2
        SHOWMAXIMIZED = 3
        MAXIMIZE = 3
        SHOWNOACTIVATE = 4
        SHOW = 5
        MINIMIZE = 6
        SHOWMINNOACTIVE = 7
        SHOWNA = 8
        RESTORE = 9
        SHOWDEFAULT = 10
        FORCEMINIMIZE = 11
        MAX = 11
    End Enum
#End Region

#Region " SEE_MASK Constants "
    Friend Enum SEE_MASK As Integer
        CLASSNAME = &H1
        CLASSKEY = &H3
        IDLIST = &H4
        INVOKEIDLIST = &HC
        ICON = &H10
        HOTKEY = &H20
        NOCLOSEPROCESS = &H40
        CONNECTNETDRV = &H80
        FLAG_DDEWAIT = &H100
        DOENVSUBST = &H200
        FLAG_NO_UI = &H400
        UNICODE = &H4000
        NO_CONSOLE = &H8000
        ASYNCOK = &H100000
        HMONITOR = &H200000
        NOZONECHECKS = &H800000
        NOQUERYCLASSSTORE = &H1000000
        WAITFORINPUTIDLE = &H2000000
        FLAG_LOG_USAGE = &H4000000
    End Enum
#End Region

#Region " SE_ERR Constants "
    Friend Enum SE_ERR As Integer
        SE_ERR_FNF = 2              ' file not found
        SE_ERR_PNF = 3              ' path not found
        SE_ERR_ACCESSDENIED = 5     ' access denied
        SE_ERR_OOM = 8              ' out of memory
        SE_ERR_DLLNOTFOUND = 32
        SE_ERR_SHARE = 26
        SE_ERR_ASSOCINCOMPLETE = 27
        SE_ERR_DDETIMEOUT = 28
        SE_ERR_DDEFAIL = 29
        SE_ERR_DDEBUSY = 30
        SE_ERR_NOASSOC = 31
    End Enum
#End Region

Finally, I created my definition for the ShellExecuteEx function.

<DllImport("shell32.dll", CharSet:=CharSet.Auto, SetLastError:=True)> _
Friend Shared Function ShellExecuteEx( _
        
ByRef lpExecInfo As SHELLEXECUTEINFO) As Boolean
End Function

I stuck all of this into a NativeMethods class and tried the code below:

Dim info As New NativeMethods.SHELLEXECUTEINFO
info.cbSize = Marshal.SizeOf(info)
info.lpDirectory = Path.GetDirectoryName(fileToStart)
info.lpFile = Path.GetFileName(fileToStart)
info.nShow = NativeMethods.SW.SHOWDEFAULT
info.lpVerb =
"open"
info.fMask = NativeMethods.SEE_MASK.FLAG_NO_UI Or NativeMethods.SEE_MASK.FLAG_DDEWAIT

If Not NativeMethods.ShellExecuteEx(info) Then
    If info.hInstApp = NativeMethods.SE_ERR.SE_ERR_NOASSOC Then
        Dim sinfo As New NativeMethods.SHELLEXECUTEINFO
        sinfo.cbSize = Marshal.SizeOf(info)
        sinfo.lpVerb =
"openas"
        sinfo.lpDirectory = Path.GetDirectoryName(fileToStart)
        sinfo.lpFile = Path.GetFileName(fileToStart)
        sinfo.nShow = NativeMethods.SW.SHOWDEFAULT
        NativeMethods.ShellExecuteEx(sinfo)
    
End If
End If

UPDATED (9/12/2006): Many thanks to Michael and his comment regarding using the SEE_MASK.FLAG_DDEWAIT. That fixed all of the problems I was running into regarding the above code. (see the usage on info.fMask)

A quick note about the code: Ned mentioned in his post that he got the ERROR_NO_ASSOCATION error instead of SE_ERR_NOASSOC. Well, the ERROR_NO_ASSOCATION is what is returned in the Win32 error (Marshal.LastWin32Error). The SE_ERR_NOASSOC is returned in the hInstApp (see MSDN documentation here).

See any problems with that? I certainly didn't (and still don't). It works like a charm for files with associations... however, it would only work one time for files without any associated program. Afterwards, it wouldn't give me anything... no errors, nada, zilch. After a few tries, an AccessViolationException would get thrown. Why? I have no idea. I tried various things to see if I should be cleaning up memory somewhere but I couldn't find anything. I did find out that if I just called ShellExecuteEx with the "openas" verb the first time, I wouldn't get any problems at all. What in the world???

As a result of the strange behavior, I changed my code slightly to look like this:

Try
    Using p As New Process
        p.StartInfo.FileName = fileToStart
        p.StartInfo.UseShellExecute =
True
        p.Start()
   
End Using
Catch win32Ex As Win32Exception
   
Dim sinfo As New NativeMethods.SHELLEXECUTEINFO
    sinfo.cbSize = Marshal.SizeOf(sinfo)
    sinfo.lpVerb =
"openas"
    sinfo.lpDirectory = Path.GetDirectoryName(fileToStart)
    sinfo.lpFile = Path.GetFileName(fileToStart)
    sinfo.nShow = NativeMethods.SW.SHOWDEFAULT

   
If Not NativeMethods.ShellExecuteEx(sinfo) Then
        Throw New Win32Exception
   
End If
End Try

The above code is working like a charm. I still have no idea why my first example won't work for me. If anyone has any ideas or suggestions, please let me know. I haven't worked with Interop between managed and unmanaged code very much. My experience up to this point has primarily been an entirely managed project or an entirely unmanaged project (and that only in college).

NOTES: Here are some resources I found while researching this:

[http://www.nedbatchelder.com/blog/20050318T070512.html]
[http://www.pinvoke.net/default.aspx/shell32/ShellExecuteEx.html]
[http://www.pinvoke.net/default.aspx/Constants/SW.html]
[http://msdn.microsoft.com/library/default.asp?url=/library/en-us/shellcc/platform/shell/reference/structures/shellexecuteinfo.asp]

Also, be sure to look at the ShellAPI.h header file!

posted on Friday, March 31, 2006 8:08:06 AM (Central Standard Time, UTC-06:00)  #    Comments [2]
 Wednesday, March 29, 2006

If Hollywood had its way with history, this might be what it would like.

It is basically the history of the world if every movie actually happened.

Nice.

(via Woot)

posted on Wednesday, March 29, 2006 8:10:03 AM (Central Standard Time, UTC-06:00)  #    Comments [0]
 Friday, March 24, 2006

Yesterday, after I had been at work for about an hour, Outlook started giving me some weird errors (something about cyclic redundancy checks). I googled the error and found a KB article that suggested that I try chkdsk. I tried that and it found some bad sectors on my drive. Afterwards, my computer booted back up and from then on... utter mayhem. Explorer would die with "Unknown hard errors" all over the place.

Below is a screenshot of my eventvwr after my disk was ghosted to a new, working drive. As you can see, the all-wise eventvwr knew there were problems before I did.

posted on Friday, March 24, 2006 5:09:06 PM (Central Standard Time, UTC-06:00)  #    Comments [0]
I've been using the System.Collections.Generic namespace an awful lot lately. I really like it, too. I use the List<T> collection all the time. It is so much better than inheriting from the CollectionBase to get a type-safe collection. I won't go into the reasons here, though. This post is about Predicates. If you have a List<T> collection, you'll notice it exposes a Find method that takes a Predicate as an argument. A Predicate is just a delegate that takes an object of type T and returns a boolean. When you call the Find method, it will call your Predicate for each object in its collection until your Predicate returns true. Looks like a nice, clean way to search collections, right?

Well, if you're using C# anyway.

Compare the following VB.NET code and C# code:

VB.NET :

    1 Module Module1

    2     Sub Main()

    3         Dim tests As New List(Of Test)

    4         tests.Add(New Test("test"))

    5         tests.Add(New Test("test2"))

    6         tests.Add(New Test("test3"))

    7 

    8         toSearchFor = "test2"

    9         Console.WriteLine(tests.Find(AddressOf FindTest).ID)

   10     End Sub

   11 

   12     Private toSearchFor As String = ""

   13     Private Function FindTest(ByVal val As Test) As Boolean

   14         Return val.ID = toSearchFor

   15     End Function

   16 

   17     Private Class Test

   18         Public ID As String

   19         Public Sub New(ByVal id As String)

   20             Me.ID = id

   21         End Sub

   22     End Class

   23 End Module


C# :

    1 using System;

    2 using System.Collections.Generic;

    3 using System.Text;

    4 

    5 namespace CSPredicateExample

    6 {

    7     class Program

    8     {

    9         static void Main(string[] args)

   10         {

   11             List<Test> tests = new List<Test>();

   12             tests.Add(new Test("test"));

   13             tests.Add(new Test("test2"));

   14             tests.Add(new Test("test3"));

   15 

   16             string toSearchFor = "test2";

   17             Console.WriteLine(tests.Find(delegate(Test val) { return val.ID == toSearchFor; }).ID);

   18         }

   19 

   20         class Test

   21         {

   22             public string ID;

   23             public Test(string id)

   24             {

   25                 this.ID = id;

   26             }

   27         }

   28     }

   29 }


I've bolded the important part. In case you missed it, it is the toSearchFor variable. The only way for a predicate to find a value is to compare it to another value; however, there is no way to pass this value to the predicate outside of an external variable. In C#, this isn't a problem because of closures. The anonymous delegate (my predicate) is a closure, which means it can access variables in the outside scope. VB.NET does not have this feature (yet!). Because of this limitation in VB.NET, you have to have a class-level variable or global variable to effectively use predicates so that your predicate has something to compare to! It seems to me that the lack of closures effectively cripples the use of predicates in VB.

Because of features like this, I am really looking forward to the next release of VB. Of course, with LINQ, will I even care about predicates then?

I would be very interested to know if anyone has any other suggestions on ways to effectively use the predicate model in VB.

UPDATE: Wow, go Paul Stovell! Instead of complaining like I did, Paul actually did something to get around this limitation in the current version of VB.NET and created an implementation of "Almost-anonymous" methods! His method also shows how to use the Widening overloaded operator in VB.NET, which I haven't seen much of. Cool!
posted on Friday, March 24, 2006 4:58:16 PM (Central Standard Time, UTC-06:00)  #    Comments [0]
 Wednesday, March 22, 2006
I've blogged about FileHelpers before. I like it a lot.

Since then, Marcos has added even more great features to it including support for .NET 2.0 Generics and a new Wizard application that really increases the speed in developing new records.

Marcos has an article up on CodeProject as well as a FileHelpers website with examples and a support forum.

Seriously, if you're still using String.Substring calls to parse out flat files, give the library a try.
posted on Wednesday, March 22, 2006 1:02:17 PM (Central Standard Time, UTC-06:00)  #    Comments [0]
At work, we're slowly moving from a classic ASP Intranet environment to a smart client environment. It has been very interesting watching (and being a part of) this movement. The typical intranet application is usually a form that consists of grabbing user input and doing something with it. Validating that user input can be a major headache. Typically, good applications would have both client-side (to improve usability and let users know about invalid data early on) and server-side (to ensure that nothing weird happened and to guarantee that the data is valid).

Where am I going with this? Well, I've seen more and more of my coworkers jumping at the chance to use masked textboxes. And you know why? I think it is because masked textboxes offer "free" validation. If you're unfamiliar with masked textboxes, you provide a mask (i.e. (999) 000-0000 for phone numbers) and the textbox will only accept input that matches the mask. It is basically a guarantee that the data from the textbox will be in the format you specify. If you only want 5 numbers, a dash, and 4 numbers (standard U.S. zip code), that's what you'll get. The problem is that it isn't particularly user friendly. There isn't any notification to the user when they type something invalid that it didn't take their input. It just sits there. It also lets them put their cursor in the middle of the mask, so they can start typing anywhere.

I really think that Jeff Atwood hit the nail on the head when he said that we should "we let the user enter the number however they like, and accept lots of formats" (see his post here). I think that the masked textbox idea could work if the mask it displays were gray and showed the user an example of what the input might look like; however, I don't think it should hinder a user's input. As soon as the user focuses, it could clear so they could type freely. Outlook has a similar feature in the search contact box at the top of the window (see image below).



I'd be curious if anyone has any really successful uses of masked textboxes. And I'm talking about cases where you know the user likes the functionality, not where you like it because it saved you a little bit of validation time :-)