Here are the reasons that VB6 devs move to C# and not to VB.NET. The following assumes you have read my previous post.

1. Some R&D departments do have a split of C++ and VB6 developers: the closer_to_the_metal crowd and the RAD crowd. .NET has something for both of these groups, so it is a good opportunity to unify the development teams. When doing that, why not standardize on a single language. As much as we know the answer, you will not get a typical C person to read/iterate VB code.

2. VB6 was almost forced upon them in the first place, so moving to C# is salvation. This is no joke, I know people in this category. Look at the pre-NET era. If you are going to do COM, VB is the easiest choice. If you are moving from Java to an MSFT environment, VB is easier than C++. If you program in C and only occasionally need to knock up a simple GUI, VB is a good choice. Today, moving to C# makes sense.

3. There is a rumour that VB.NET is so different to VB6, that learning C# is just as hard/easy so why not. Truth or not, this is a quoted reason.

4. C# devs earn more than VB.NET devs.

5. There is a stigma associated with VB devs in some circles. MSFT refers to the typical VB developer as "Mort". Some people don't want to be Mort so they switch to C#.

6. C# is a new cool language - the latest kid on the block. Why not add another skill to the resume/CV.

7. C# is the native .NET language. What leads to this claim is the fact that the framework libraries are written in C#. This is no surprise, as the devs that wrote them were previously coding in C++. Nevertheless, it does seem that C# gets the new .NET features first in the development cycle, and then other languages (inc. VB) decide whether they will adopt them or not.

So, after all of the above, if you are a VB6 dev still undecided, remember this: VB.NET is not a second class citizen and assuming you can do it the .NET way then go for it. My advice is that you try a bit of C# as well. I hope that we all build a simple small app when trying out a new language and we don't just dive into a contract. Well, build that small app in both languages and see which suits you best.

Just for a laugh, allow me a quick counter attack on the reasons above:
1. If you have existing VB6 projects, the easiest upgrade path is to VB.NET
2. Same as 1. Applies to VB6 code fragments, not just projects
3. No difference is greater than case sensitivity. In any case, VB2005 makes the transition even easier.
4. This may only be true because most of C# devs have a C++ background, and that background is worth more than the VB6 one; learning C# will not change your background.
5. Bill Gates loves Mort.
6. C# is a standardized language. Innovation is easier with a proprietary language such as VB.
7. So VB gets only features that are of real value, and not of academic interest.

If you want to know how popular this question is, just search Google for VB vs. C#.

No flames please, this is just my view, if you disagree write about it in your own blog. I have given my real answer here.

Clearly, if you are a C++ person you'll go for C# (or stick with C++), mix the languages for existing apps and start new ones in C#. If you are a Java person you'll go for J# (or C#); I'd say go with C#, the syntax is so similar, why not develop in one of the top two managed languages. If you are a VB person you'll go for VB.NET or C#.

So the latter case deserves more attention. First let's filter out a couple of categories. If you just hate semicolons, curly braces etc then obviously you go with VB.NET; the dilemma does not apply. Remember, however, that you must be able to read C#. A lot of the opensource code, samples etc is in C# and it will hinder your career not even being able to read the language at least. Also, if you have not yet grasped Object-Orientation, VB.NET will make the transition easier than what C# would. If you are in any of these two categories that's great but don't stick with VB6, make the move to the .NET platform.

Now, why do VB6 developers (not belonging to the two aforementioned categories) move to C# (and it is a fact that some do). I give my answer to that question next time.

There will always be the language zealots on both camps that will try to prove how VB is better than C#, or the other way round. Trust me: the differences are insignificant when it comes to choosing between one and the other, and this becomes even truer with Whidbey. If ever you really need a feature that only the other language offers, then just write a dll in that language and use it from your main project (or a .NET module if you want to take it that far). One day, hopefully, we'll be able to mix languages in the same C#/VB project (much like VC++2005 allows you to).

So will both camps be happy now? Don't be silly :-)
VB devs don't seem to really care about some new C#-only features (Static classes, iterators, anonymous methods, code definition window, OTB) but they want refactoring.

Although everybody concedes that language choice is a matter of taste on the .NET platform, we still encounter phrases such as "VB encourages bad programming style" or "VB is not clean" or "VB performs worst" and other similar comments on the same theme, which derive from VB.NET carrying baggage from the VB6 days.

There is bad .NET code running around, but it boils down to who writes the code and not what language it is written in. The truth is that it is easier to write smelly code in VB.NET than in C#. To that extent I have a set of rules that I follow when coding in VB and, rather than trying to pull them out of my head every time I get asked, I thought I'd post this so I have something to point to from now on.

So, in no particular order, this is how I do VB in .NET style:

1. Always turn on Option Strict, Option Explicit

2. Use Try..Catch instead of On Error Goto/Resume Next/Err.Xxxx

3. Use AndAlso, OrElse instead of And, Or. Write your conditions so they do not need to use And, Or for logical comparisons.

4. Use shifting (<<>>) instead of multiplying/dividing when appropriate

16. Remove the Microsoft.VisualBasic import from Project->Properties->Imports. This will force you to specifically add it when you need it in each file. At that point consider using the framework's functionality instead (or at least find out what the equivalent is)

17. In the MS.VB namespace, do not use the Strings, DateAndTime, FileSystem, VBMath, Collection [browse the library in Object Browser to see what's in them, find the framework's equivalent].

Of course, some times your project is small or you just need to get the job done as fast as possible. Smelly vs Clean code is not in the picture, performance is irrelevant or dominated by other factors such as network roundtrips and, in any case, the app's life-expectancy is very short. In those cases, you may find VB's flexibility helping you get results faster. I've never had a project like that, but thought I'd mention it.

If you are new to the .NET platform, regardless of your background (C++, Java, VB etc) it is important to understand that "it's the runtime stupid" (written/posted in 2002, a couple of months after .NET was RTM)

The point is to forget about the language. Language selection is a matter of upbringing and syntax choice. What is important is the framework. So when starting out, choose any language[1] and then search the web/books/magazines/newsgroups/whatever for topics on the following list:

Links are not provided for the above topics by design. Go discover them yourself, and only then start writing .NET software that is intended to leave your PC and run on somebody else's. Also note that, by design, there is no mention on WinForms, WebForms, Data access, remoting, COM Interop or platform invoke. One or more of these topics will have to be explored while writing a .NET app but all of the topics on my first list must be understood in order to write any professional .NET app.

Another important point is to know your tool. After knocking up your first hello world app in VS, just seat back and take a tour of the IDE e.g. explore every menu and find out what the menu items do. In particular open all windows from the View and Debug menus and examine them. Go to Tools->Options and check out all of the options available (this is a good way to discover the IDE).

One of the major gripes I have with C# today is its inferior intellisense. [Before you tell me that has nothing to do with the language, rather it's an IDE thing, let's get things straight: I use VS for development and not Notepad; when talking about any language I always refer to the collective experience of the language plus the MSFT tools that come with it]. Back to my point: C# intellisense sucks compared to what VB has to offer. If you disagree with this, you simply have not used both environments long enough (didn't leave enough room for argument there did I ;-).

VS2005 rectifies this, and writing C# code is now a hugely improved experience. Intellisense pops up not only type declarations, but language keywords such as public, void etc; formatting of code is also better. The areas where VB's intellisense is still better, are covered by expansions, e.g. typing forr generates a reverse for loop section.

I was going to go into a full blown description of expansions and how to create your own etc, but before posting I did a search and found that someone had already done that here.

The point I am making is that in VS2005:

C# Intellisense + Expansions = VB's intellisense

While talking about Whidbey C# improvements already in VB today, C# gets nop instructions in IL so you can enter a breakpoint wherever you like (the funny thing is that some bigots used to mock VB for having this feature) and adding event handlers does not require explicit creation of a delegate (already supported in VB with AddressOf).

Today I presented a feedback session from July's Tech Ed in Amsterdam. At Tech Ed, I mainly followed the Whidbey sessions. My employer sends me to these events on the basis that, upon return, the knowledge is shared with the rest of the group and it does in fact form part of my review. What is great about these debriefings is that in order to prepare the material (slides, demos etc), I get to revisit not just the sessions that I attended at the conference, but also research everything relevant to VS2005 and .NET 2.0. My audience consisted of C++, VB6, C# and VB.NET devs plus managerial types. In case you are in a similar situation (feeding back or just presenting on the same topic), here is the outline I followed.

PART A. 25 introductory slides summarising the various MSFT product roadmaps. This consisted of material straight out of the Tech Ed keynote. As you can imagine, I lost all managerial persons after this.

PART B. 100 slides (plus tons of demos). More on this further below.

PART C. 25 slides on SO/SOA (Helland sessions) and Longhorn. [and the Compact Framework; I am the only CF dev, hence just squeezed in a few slides near the end]

So the main part is the second one (PART B) and the list of its contents follow. I give you some URLs where there is useful info for coalescing into slides and demos. My material came mostly from the Tech Ed DVD and I don't think it is available online anywhere.

As usual, I showed the TechEd intro clip. Basically a 2-3 minute MTV-style video including scenes from the party and generally showing what "hard work" attendees have at these events :-) If you ask me, I think MS should make these clips widelly available as they form good advertising for the conference. By the way, special thanks to Tim for sorting out some issues I had with the conference DVDs. It is individuals like him that help MSFT's image of a company that cares about the customer.

You know that many have not made the move to managed code yet. Inevitably, the question of which language is best (which should we choose etc) comes up. This has been done to death, but the subject never ceases to come up. I think, against my better judgement, I will blog about C# and VB soon.

Finally, I leave you with a demo I saw Don Box deliver at Tech Ed 2001 (in VB6) and this year (in Word Macro). So, in case you aren't aware of it, here is some VB6 code that always gets a nice reaction:

1. New VB6 "Standard EXE"
2. Project->References. Add:
Common Language Runtime Execuion Engine (mscoree)
Common Language Runtime Library (mscorlib)
3. Double-click on the form to get the Form_Load method (event handler)
4. Type in there the following 5 lines of code and Run->Start

If you are playing with VS2005 you must be familiar with the MSDN product feedback center. Anybody can basically make suggestions for enhancements and also report bugs (it goes without saying that the two are not the same thing)

When I first met it, I thought this was a great idea and immediately starting using it for bug reports and suggestions. Now I am not so sure. The cynic in me has started to believe that the feedback center is there to gather our input for the next version of .NET (i.e. not Whidbey but Orcas). I do hope that is not the case and I will keep using it. I reserve final judgment for when the product ships.

The reason I have started having doubts is the number of suggestions that get 'postponed', 'resolved as won't fix' etc. Just randomly browse through the suggestions made and note how many are actually taken on board. Browsing through bug reports reveals that actually MSFT have already caught most of the bugs that we report. The few additional ones that have slipped their net seem to get attention (unlike the suggestions we file).

If you know of any suggestions that have made it into the product do let me know. Naturally suggestions that they had already decided to make don't count (usually these are stated as "Thank you for your suggestion this is how it works in our current builds").

Here is the list of suggestions I was tracking that are postponed [1,2,3,4,5,6] and here are the outstanding ones [1,2,3,4]. Not to mention the 10 postponed suggestions on the Class Designer (detailed in a previous entry)

As I said, my bug reports have all been addressed except for one which is resolved as won't fix; still fighting it.

When talking about .NET code running on both CE platforms (against CF) and the PC (full FX), usually what follows is a discussion on sharing the same binaries. This is possible and we looked at retargetable previously. My prefered approach is to share code instead. Two projects, two outputs, same set of code files. Before talking about the advantages of this approach, let's briefly summarise the process.

Basically we create two projects, one for the full FX and one for the CF. In the full FX project we add a conditional compilation constant; I name it FULL_FRAME, but obviously it can be whatever you fancy. Then we share the same code files between the two projects. This can be done by creating the file in one project and then adding a link to it from the other or even better, place the projects in the same directory and include the code files in both projects. Either way you are working on the same file, not a copy. I rename the output of the CF assembly by appending a CF to it before the extension, but obviously the namespaces etc inside are the same. Build both projects and you get two outputs (make sure one does not overwrite the other). Now, whenever you need to add some desktop-only functionality, you just surround the code with FULL_FRAME e.g.

If any of the above is unclear, drop me a comment (it is also described here). I maintain a fairly large set of dlls between the two platforms (the desktop side uses remoting and COM interop which are non-existent on the CF) and it works great.

The advantages of this approach are obvious. You can enhance the desktop assembly with full FX specific features and vice-versa for the CF assembly. In fact, even when there is no business case for it, I do this for every CF dll I write. By running your CF code on the desktop you can debug using features not available when debugging on the device/emulator, such as "Set Next Statement" and full tracing support; there are a whole bunch of profilers (none for CF) you can use, e.g. for examining allocation patterns of your code; modelling tools that don't work with CF projects can be used to design or reverse engineer your code; same goes for unit testing tools and so on and so forth: I hope you get the point. Through simple, short tasks you can get great benefits and it amazes me how very few devs use this technique.

When discussing retargetable, I offered my opinion on why it didn't make sense for EXEs. With the shared code approach I create an EXE project per platform, but no code sharing takes place; they just reference the corresponding dlls. This is one of the reasons I make my EXE assemblies very thin, typically containing only Forms. The difficulty is that the forms designer is very different between the two project types (in terms of auto generated code). Trying to share the form code would effectively mean not using the designer at all. However, with VS2005 and partial classes the story might get better. I'll be looking at having different designer code files while sharing the partial form class which contains the event handlers and other methods. You can imagine how the form can be designed (and properties of its controls set) in such a way as to fit in both platforms, while the real logic is the same. Too excited about this now, I must go play with it!

If you create a new Windows Application project in VS2005 you'll notice that viewing the code for the Form1 class shows very little. All the designer generated code is missing. If you then "Show All Files" in the solution explorer, you can see under the Form1.cs file a Form1.Designer.cs file which upon viewing reveals the designer generated code in yet another Form1 class. If you build the project and look into the assembly with ILDASM, you notice exactly one Form1 class and no indication about this split. The clue to the whole mystery is the keyword "partial" before each class declaration (in fact VB allows one class not to be declared as partial so you'll only see "Partial" in the Form1.Designer.vb file).

So this is a tool thing. You can split a class over multiple files in the same project, as long as you declare them as partial. With forms, note that adding event handler methods or any other methods that you write, appear in the main code file.

To complete the story of how the solution explorer links the two in the manner that it does, we simply look at the .csproj/vbproj file in Notepad or your favorite XML editor. Under the ItemGroup tag you find something like this:

It is the DependentUpon tag that makes a file appear under another in VS. It is being put to very good use with Partial classes.

So here is a money making thought (and you don't even have to turn adsense on). Write a tool/addin that will create these entries. MSFT is not offering anything in the IDE apart for forms, so it is down to tedious manual work at the moment. If I were using it, I'd wish for a menu item when I right click on a code file that offers: "Add Partial". So if I used it on a SomeClass.cs, it would ask me for a name XXX and then create a partial class SomeClass.XXX.cs under SomeClass.cs. The greatest use of this tool would be for upgrading existing projects. When upgrading, VS2005 does not split Form classes, so you have to do all the work manually if you want to fit in with the new environment. Oh, and if you need Beta testers, count me in :-)

One of the FAQs on the CF newsgroup is about running assemblies on both desktop and CE device. The answer is that on a CE device you cannot run assemblies built against the desktop/full framework. The reverse is possible, due to the System.Reflection.AssemblyNameFlags enumeration and specifically its Retargetable value. Basically, almost all of the CF assemblies are retargetable to the desktop v1.1 assemblies, which means that your CF app will run on the desktop against the full framework. There is a caveat, which is obvious once you understand the previous sentence:

* You must only use functionality that is common on both platforms *

At first this may sound superfluous, given that the CF is a subset of the full framework, but a closer look reveals functionality specific to the CF in the Microsoft.WindowsCE namespace (such as MessageWindow and InputPanel), the infrared classes and of course the SQL stuff is different. In addition, no real CF 1.0 application survives without pinvoking, so you'll have to detect what platform you are on (System.Environment.OSVersion.Platform) in order to call the right dllimport (i.e. not pointing to coredll.dll). So, break these rules and look forward to TypeLoadExceptions and the like; follow them and you are good to go...for class libraries projects (dlls).

Do expect to encounter differences in functionality. On the desktop your app is running against a different implementation of the .NET library. Although interface-compatible and in most cases functionality compatible, there are differences due to bugs or design decisions based on platform applicability.

For GUI apps (exes), I don't think there is much point in attempting the above. Technically it will work (just run your exe from the build folder) and it also makes a nice demo for your boss, but how will a WinForms app look good on two platforms that are so different to each other? The difference in screen size should put the argument to rest but, in addition, the user input is typically very different too (keyboard vs soft input panel, mouse vs stylus), not to mention non-resizable windows etc.

It is worth mentioning that VS2005 with CF 2.0 makes this approach even easier. All the same issues apply, but there is help for debugging this scenario. When you choose Debug->Run, you are presented with a Deploy window that includes a bunch of emulators (so far the same as VS2003) but also includes the 'My Computer' option! Choosing this actually runs your app on the desktop, providing you with the same experience you'd have if it were a normal Windows app.

To sum it up, my attitude towards the "retargetable" approach is not to use it. I prefer the alternative of sharing the same code base between desktop and CF apps and I use that successfully everyday. More on that approach next time.

Today I got yet another email account (you would have thought 5 were enough but I enjoy reading the same spam over and over again) courtesy of Neil. The difference with this one (apart from its Beta status) is the 1GB storage! So, if you are too shy to use the comments facility (I know it doesn’t show up in aggregators), you can now email me about anything. It's on the sidebar under Links: Email Me. You can't miss it :-)

If you have .NET apps talking to each other on the same machine today, chances are you are using remoting. Furthermore, you are probably using binary over tcp and have dealt with the idiosyncrancies of handling events over remoting.

So what is new with .NET 2.0 for this scenario? Well, there is now an Ipc namespace, and using it offers performance improvements over the TCP one. To use it you need to change your config files (and of course you are using config files and not setting up the channel programmatically :-).

Assuming your server.exe.config file looks like this, you simply have to change it to look like this:

The changes may seem obvious (isn't everything once you know it:-), but I would not have figured the above out if it wasn't for Manish G, whose help was invaluable.

Another improvement with .NET 2.0 – well with the IDE really – is the ability to add references to EXE assemblies, not just DLLs. You can do this today via the command line, but with VS2005 you can do it in the IDE as well. This brings us closer to the ActiveX EXE days (out-of-proc COM) where there were only two files. So you can now merge (if that is what your design wishes) SomDllName.dll into the Server.exe and offer the SomeNamespace.SomeClass from it directly.

7. For simple data sharing, it is easy for an app to write data to predefined regisrty entries and signal a named event; at that point the other side can read from the registry. It looks something like this:

8. Directly sharing memory is not advisable but we can do it. The logic is identical to case 7 with named events but instead of writing/reading from registry, we access memory directly. It looks something like this:

// SERVER
// As in previous example but instead of writing to registry
// do the following in cmdWrite_Click
IntPtr memHwnd=ObtainHandleToSharedMemory();
if (memHwnd.ToInt32() !=0 ){
SharedMemory sm=new SharedMemory(true);
Marshal.StructureToPtr(sm,memHwnd,false);
}

1. Sockets are accessible to .NET apps via the System.Net.Sockets namespace. You could use a TcpListener (on 127.0.0.1 and some port you fancy) and a TcpClient or even get down to the Socket class which the other two aggregate. The msdn links given are good and as always search the web and newsgroup.

2. CF code for memory mapped files can be found here and an example of their use here

3. Passing windows messages between apps requires a windows handle of course. CF has the Microsoft.WindowsCE.Forms namespace not available on the desktop that includes the MessageWindow class. [This class was necessary to overcome the CF's limitation of not being able to pass delegates to pinvoke and hence achieve windows callbacks - this limitation is no longer in CF 2.0]. Learn about the MessageWindow here, here, here and here.

5. Pinvoking MSMQ is not easy (apparently, I haven't tried it myself) and I am aware of no sample code for that. CF 2.0 will support it via the System.Messaging namespace. For further details and a bunch of links on this subject check out theseblogentrieshere.

6. COM interop is not supported in CF. A commercial offer is available. CF 2.0 will have some support for COM Interop but I don't know if out-of-proc servers will be supported. If you know drop me a note.

This week Kenny Kerr started an Introduction to MSILCheck out parts 1, 2, 3, 4[if you are interested in MSIL, there is the good “Partition III CIL.doc” on your dev machine – on mine its under: C:\Program Files\Microsoft Visual Studio .NET 2003\SDK\v1.1\Tool Developers Guide\docs]

If you are confused about the various different GCs (Server, Workstation, Concurrent) check out this entry by Chris Lyon as well as this one.

The .NET Framework has survived until now without offering a class for serial comms in its otherwise rich class library. I guess MS thought that rs232 was becoming obsolete - or I don't know what. The fact is that, especially on CE devices, rs232 is part of everyday life. The upshot is that .NET 2.0 comes with a SerialPort class.

So can you use your COMM ports today?

In VB6 one would use the MSComm control, which did a great job. You could still use that in your .NET apps (by hosting the ActiveX control on a Form - assuming the license for the control exists) just be aware of various threading scenarios. In particular, things become tricky if you are using the control in a remoted server (all threads are MTA and not STA as required, so it's pretty much a dead end situation - I ran into this a while back).

The first rs232 code to appear for .net is here. This leads us to a 3rd solution, which is to use an existing library. Apart from commercial packages and a number of user samples, there is a very good article with code on the MSDN mag; so you could use that!

Now, if you are working with the Compact Framework, you have to be mindful of a few facts. WinCE does not support overlapped io. Even the non-overlapped io is implemented differently on the PC than on CE (e.g. Read/WriteFile do not block on CE). Finally, the threading support of the CF is not as rich as that of the full framework. What does all this mean? Well, basically rs232 libraries designed for the desktop/full framework will not just work on CE devices with the CF.

So what is the solution?

You can use a different library depending on which platform you are targeting, e.g. download a free assembly for the CF here. Alternatively, the shared source repository for CF has C# code that works on both platforms!

Finally, I recommend looking at the interfaces of the System.IO.Ports.SerialPort in Whidbey, so that when you upgrade your code it is easy to switch one implementation out for the other. I have put an example here.

If you are not aware of the MyEvents functionality that VB2005 offers, check out a screenshot and short description here.

The question is how to get the same support in C#. Well it all becomes pretty straightforward if you understand how MyEvents and the new startup model work in VB. I provided an exploration here.

So, armed with that knowledge, in a new C# Windows Application do the following:
1. Add a reference to Microsoft.VisualBasic.dll
2. Replace all the code in Program.cs with the 35 lines of code given below
3. Form1.cs. This is the main form (you could put a button that throws an exception)
4. Add a form Form2.cs. This is the splash screen, no code needed.
5. Build in release mode and run from explorer.

With VS2005, VB gets the My feature. Part of the package is a new startup model and MyEvents.

If you look in a VB project properties, you will find a (unchecked by default) checkbox "Startup with custom Sub Main". Below it there are more "Windows Application Properties", including choosing a Splash screen. There is also a button "View Code" which takes you to the partial MyApplication class - you can also go there by showing all files in the solution explorer and navigating to the MyEvents.vb file under My Project. By using the dropdown you can hook into various events e.g. Startup, UnhandledException etc. So how does this work?

Well the first thing to note is that, if you check the "Startup with custom Sub Main" (and provide your own Sub Main OR use the implicit one of a Form1), then none of the events will be caught, so obviously the two are intertwined. Second, if you use the Class Designer to drag the MyApplication class on a diagram and then display the full hierarchy, you will find that it inherits from WindowsFormsApplicationBase (WFAB), which in turn inherits from ApplicationBase. All of these are in the System.Windows.Forms namespace but are defined in the Microsoft.VisualBasic.dll

To continue the exploration, we build a simple VB WindowsApplication in Release mode and place a Trace.Assert(False, “stack") in its Form.Load event handler. After running the app, we see the stack trace in a msgbox that uncovers the startup call path. Usually we'd expect to see our Sub Main function followed by Application.Run and then a whole bunch of other methods (not of interest right now) ending up in Form1_Load. Instead, we notice that the call stack starts with:
MyApplication.Main -> WFAB.Run -> WFAB.DoApplicationModel -> WFAB.OnRun -> Application.Main etc.

And those methods are where the magic is.

OnRun does the following:
-sets the MainForm to be your main form (via OnCreateMainForm)
-hides the splash screen
-sets up the NetworkAvailabilityChanged event
-calls Application.Run

So how does all this affect the startup performance of VB apps compared to C#? I don't have that answer, but if you go and look in the methods above, you will find a whole bunch of other objects getting created (relative to thread safety, security etc). Also take into account the call path for the creation of MyApplication, e.g. it is in the WFAB.ctor that the StartupNextInstance event gets hooked.

Finally, a separate note on the UnhandledException event: This is setup in DoApplicationModel by hooking into the Application.ThreadException event. DoApplicationModel can also raise the UnhandledException event as a result of an exception occurring around (effectively) Application.Run. We know that there are 3 actions one must take to catch all unhandled exceptions, instead here we see only two! So it is obvious that the AppDomain.UnhandledException has to be separatelly subscribed to by the developer (for catching thread exceptions other than the GUI). I think this is a gotcha and the VB team should also hook into it so that when we catch the UnhandledException in MyEvents.vb we really are catching all unhandled exceptions.

Next time we'll look at the possibility of using this approach (including catching the events) from C#.