Thursday, July 02, 2009

 

Tess has written a great post on debugging .NET dumps in Visual Studio 2010 (which also briefly touches on the Parallel Stacks window ;-)

Labels:


Tuesday, May 19, 2009

 

Last September (wow, time flies!) I blogged about a VS2008 issue described as: Not all AnonymousMethods are the same. My team fixed this, so let's revisit the equivalent code from that post, this time in VS2010. The screenshot tells the story:

Notice that anonymous methods now have a suffix? This tells you immediately that the 2 threads are not at the same method. The information becomes even clearer with a new debugging window we are introducing in VS2010 that I will describe in my next post: Parallel Stacks.

Labels:


Friday, April 24, 2009

 

Just came across (and thought I'd share) these resources for .NET 4 and C# 4 features on Bogdan's blog post.

Labels:


Thursday, April 23, 2009

 

Eric Eilebrecht (dev on CLR) is kicking off a blog post series on improvements to the CLR 4 ThreadPool. If you've used the .NET ThreadPool, you must read his first installment.

Labels:


Monday, April 06, 2009

 

When I created my Visual Studio C# demos for showing off Tasks versus Threads, I of course created the project in Release mode, but there were 2 additional things that I had to do.

One had little impact, but is important to remember: set the power plan on Windows to "High Performance". Otherwise CPU usage can be throttled by the OS, which is not what you want when you are demonstrating parallelism and 100% CPU usage ;-)

The other had a profound impact and had me puzzled for a bit: use Ctrl+F5 instead of F5. The difference in the time the threads scenario took was humongous. That is because the naïve threads demo creates around 1023 threads and it turns out creating threads under the debugger (F5 case, even in release mode) is measurably slower than not. I should have known that, but I didn't, so sharing it here in case you didn't either: when measuring perf, always use Ctrl+F5 in release mode.

For a lot more on the performance difference between running under the debugger and not, I recommend Joc's blog post: Why is my app so much slower under the debugger.

Labels:


Wednesday, December 03, 2008

 

It is Ctrl+K, Ctrl+I (just place your keyboard cursor on a variable and try it). You could have found this out on your own via the Tools->Options menu:

Unfortunately there isn't one for the datatip when debugging. Instead you can show the equivalent (and older) "Quick Watch" via Ctrl+Alt+Q or even better Shift+F9. If you really are determined to show the datatip via the keyboard(and I do mean if you really are fixated with that goal) there is a post here by Rob with a hack.

Labels:


Sunday, September 21, 2008

 

Each thread has a call stack (a list of stack frames, each representing a method call and the relevant state). When you break in the debugger, you can see it in the Call Stack window for the current thread, e.g. bottom right of this screenshot:


The current thread (aka active thread in some circles) is the thread that is currently selected in the Threads window, indicated by the yellow arrow icon (in the screenshot above, the "Main Thread"). By default the current thread is the one that hit the breakpoint (or, for example, the one on which the exception was thrown) which resulted in breaking in the debugger (all threads). You can switch the current thread via the ContextMenu on the Threads window (or by double clicking on a thread in the listview). When changing the current thread, the Call Stack window updates itself.

The Call Stack window indicates the top of stack (the latest stack frame) of the current thread with a yellow arrow icon (in the screenshot above, the “Program.B("hey")”). This is known as the active stack frame. When switching threads, obviously the active stack frame changes. When execution resumes (e.g. via F5), the execution continues from the active stack frame onwards (to be more specific, from the active stack frames of any/all of the threads). The active stack frame, by default, is also the current stack frame for that thread.

The current stack frame is the stack frame that drives the rest of the debugger toolwindows e.g. Locals, Autos, Watch and even the code editor. You can change the current stack frame by using the ContextMenu on the call stack window (or double clicking there). When changing the current stack frame to be something other than the active stack frame, it shows a green arrow. For example, in the following screenshot we double clicked in the Call Stack window on “Program.A("hey")”:


Obviously, if you change the current stack frame, when execution resumes it will still resume from the active stack frame(s). So, setting the current stack frame is purely a temporary action for inspecting the relevant data to that frame, e.g. in the Locals window.

On the screenshot above, notice the 3 icons shown in the margin of the code editor:
1. Yellow arrow: for the active stack frame of the current thread (in our example, of “Main Thread”).
2. Green arrow icon: if we have set the current stack frame to be something other than the top of stack (in our example, “Program.A”).
3. Red and blue cloth threads icon: the active stack frames of all other non-current threads (in our example, “moth”).

Quick Check: If you double click on the “moth” thread in the Threads window, what would the screenshot above look like in terms of icons in the code editor, threads window and call stack window? Picture it first and then check your answer by viewing this screenshot. Did you get it right?

Developers that have not used VS2008 in multithreaded programs, tend to forget the usefulness of the red and blue cloth threads icon. If you are one of those devs, watch my video for a refresher.

Let me ask another easy question: Why don’t we see this new icon anywhere else in the debugger toolwindows? The obvious answer to the question is that: no toolwindow shows active stack frames of non-current threads; hence the cloth threads icon does not appear anywhere.

The real issue here is that we only have a single Call Stack window that can only show stackframes for the current thread. Given that all threads are equal and “current” in real terms, Visual Studio’s notion of “current thread” as the only one we can focus on is limiting (to our productivity at least). In a following post I’ll explore an (imaginary?) solution ;-)

Labels:


Sunday, September 14, 2008

 

Whilst debugging code that uses multiple anonymous methods (or lambdas) from a single method combined with multiple Threads, an interesting issue surfaces with the stack frames that Visual Studio 2008 presents.

Can you spot the problem with the following screenshot (original code from this post)? Look at the Location column of the Threads window:

Are both of those Threads with the same location string (Program.Main.AnonymousMethod) at the same place in the code editor? Look at the code editor and the answer is no. The icons with the blue and red “cloth threads” in the gutter of the editor show the two locations: one is at t2.Wait and the other at the Console.WriteLine (you can verify this by hovering over the icons to see the tooltip with Thread info).

Bottom line: The Location column (and Stack Tip) of the Threads window (and the Call Stack window in fact) are not telling you the full truth. They are indicating that thread execution is in some anonymous method, but they are not distinguishing between different anonymous methods. It would be nice if they at least appended a number to the string: AnonymousMethod1 AnonymousMethod2, etc.

Aside: The real method name of the anonymous method in IL code starts with a chevron and is generally funky and it wouldn't add value to be displayed here. All we need is the ability to distinguish between different anonymous methods in the debugger tool windows, hence my suggestion above about suffixing them with a number. Do you have a better suggestion?

Labels:


Monday, September 01, 2008

 

Using the Make Object ID feature we were able to turn this screenshot into that screenshot.

Building on the Task.Current approach, I wanted to avoid having to expand the variable and instead wanted to get a quick glimpse of the properties of interest with just one glance. Then I remembered the DebuggerDisplayAttribute (part of the nice debugger visualizers wave introduced in VS2005).

The DebuggerDisplayAttribute overrides what you see for a Type in the expression windows, similar to what ToString does (except the attribute takes precedence). Hopefully the TPL team will add one to the Task class by RTM, so the previous screenshots can look something like this:

The way I accomplished that for now is by creating a new class library, referencing the Parallel Extensions library and pasting one line of code:
[assembly: System.Diagnostics.DebuggerDisplay(@"\{Id = {Id}, IsCompleted={IsCompleted}}", Target = typeof(System.Threading.Tasks.Task))]

Then I copied the output DLL to the Visualizers directory (%userprofile%\Documents\Visual Studio 2008\Visualizers). Get the DLL here for VS2008 and remember to do this for your own types so your users don't have to resort to writing their own ;-)

Labels:


Thursday, August 28, 2008

 

With the release of VS2008 the ability to debug into the framework source became possible (follow the link for my video on the topic). There is now a dedicated blog with instructions, links to forums and other relevant info, so visit it to learn more. They just announced the availability of sources for NetFx 3.5 SP1.

Labels:


Tuesday, August 26, 2008

 

I only learnt about this featurette very recently (from a reader's comment) and immediately found a use for it – read on.

If you tried to debug the code from this exercise (still no correct answers to the quiz!), you probably found out that the variable corresponding to the Task that you want to examine is usually out of scope. You can look at the Threads window and try and map the Thread to the Task but there is another way: add once to the Watch window the expression Task.Current. When breaking in the debugger, switch between the threads in the Threads window to see the active/current Task for that Thread in the Watch window.

The only problem is that we have to tediously expand the variable each time to determine its Id, since the default display when the expression is evaluated is not useful ("{System.Threading.Tasks.Task}").

This is where the C#-only debugger feature comes in: Make Object ID, accessible from the ContextMenu in the Watch window. Once you break in the debugger, Make Object ID for the Task.Current, then switch Threads and do the same for the other. Now you can distinguish between them easily due to the appended {1#}, {2#}, and you can add a Watch directly to the objects in memory:

This is a neat little feature and even more useful for other scenarios where there is a need to distinguish between 2 or more identical-looking objects in the debugger.

Labels:


Tuesday, July 29, 2008

 

Tip #1 – datatips on comments
One of the coolest debugger features introduced in VS2005 was DataTips (grey editable, navigable tooltips on steroids that also become transparent when you hold down the Ctrl key). Did you know that you can get data tips for commented code? At first this made me raise an eyebrow, but I can see how for some piece of code I may always need to inspect some other variables quickly and do not want to have to enter them in the watch window manually or navigate to the required area from existing variables that do exist in code. Here is a screenshot that shows this feature in action:

Notice how the datatip appears after highlighting a variable that is in a commented area of the editor (my highlight is set to yellow).

Tip #2 – save output window
In Visual Studio many times we need to transfer the text from the Output window to an actual txt file. Dunno about you, but I always selected all (Ctrl+A), copied (Ctrl+C) and then pasted (Ctrl+V) into a notepad instance that I always have running (Alt+TAB). It turns out that there is a direct way of saving that output to a file. Simply hit Ctrl+S (or invoke it from the menu item) once you've given focus to the Output window – nice!

What cool debugger features do you like in Visual Studio (or would like to see)?

Labels:


Tuesday, May 27, 2008

 

A cool class that was introduced in .NET Framework v2.0 is the BackgroundWorker. If you do any kind of UI development I encourage you to learn about this class (e.g. by following the links below), which makes it easy to execute long running operations on a separate thread, supporting cancellation, progress reporting and marshalling results back to the UI thread.


Back in 2004 I described what the class looks like (inc. links to MSDN) when I implemented it for the .NET Compact Framework v1.0/v2.0 (and for .NET Framework v1.1): BackgroundWorker. I also provided sample code to demonstrate the usage.

An added incentive to learn about it is that Silverlight 2 includes a fully interface-compatible version of BackgroundWorker. A good way to learn about it is by porting to Silverlight the desktop PI sample from my previous blog post and follow what the code does... have fun!

Labels: ,


Monday, May 19, 2008

 

Since you are reading my blog, chances are that you are a .NET developer. Do you realise that eXtensible Application Markup Language (XAML) is now part of .NET? Are you familiar with it? How would you describe XAML (pronounced "zammel") to someone that is not familiar with it if you only had 10-20 minutes? Below is my take.

Background
XAML was introduced as part of Windows Presentation Foundation (WPF) which was released in November 2006 as part of .NET Framework v3.0. In addition, XAML is at the core of Silverlight, v2 of which will be released this year. Whilst XAML itself is independent of those two technologies, I am a practical person so I associate XAML with those two presentation technologies (WPF for the Windows desktop and Silverlight for the cross-platform browser) and have no qualms in intermixing those terms in this blog post. The XAML that Silverlight 2 will support is a subset of the XAML that WPF supports but the core principles and most capabilities are the same.

XAML is an XML language for describing a hierarchy of objects and their properties; in our concrete examples, it describes a hierarchy of visual objects that make up a Graphical User Interface (GUI).

Relationship to managed code
An important fact about the XAML elements (more precisely the WPF/Silverlight graphical system and controls) is that they are fully composable. For example, the following screenshot shows some crazy XAML that places a TextBox inside a button as its content (and in the bottom right corner the result):

It is important to note that anything you can do with XAML, you can also do in code (C#, VB etc). For the previous example, the alternative code required is a single statement in the ctor:

Regardless of that important fact, it is our preference to use XAML for the (naturally) declarative part of describing a GUI. We then use code, of course, to programmatically react to user interaction with the GUI elements that were declared in XAML, i.e. we use code to capture the behaviour.

The obvious question that arises is how we connect the XAML bits to our managed code. In brief, the technique of partial classes ensures that the XAML bits and the managed code bits end up making a single class. XAML properties assign names to controls so we can reference them in the code-behind and, finally, XAML properties connect events in XAML to event method handlers in code. The following screenshot shows a GUI where clicking on the button, updates the time in the textbox.


Take a look at the combination of XAML and C# to achieve this.


Tool Support and the Designer-Developer Workflow
Visual Studio 2008 has a designer tool that allows you to type XAML (with full intellisense) and instantly see the results. For WPF projects it allows you to also drag and drop controls onto the surface and have the XAML generated for you. Have a look at this VS2008 screenshot of Silverlight designer.

For Silverlight 2, the VS2008 is just a read-only designer so you have to type things in the XAML pane or use an external tool to generate the XAML such as Expression Blend.

Expression Blend allows your designer friends to work on the same project/solution and more importantly on the same XAML that you, the developers, are working on.


Have a look at the screenshot of the exact same project you saw just now, but this time in Blend.

That is one of the reasons XAML is an XML-based language: XML is very toolable. Because of that we have a nice workflow between designer people in Blend and developer folk in VS2008, where there is no exchange of bitmaps or binaries but they are both truly working on the same asset: XAML files. The designer-developer interaction for WPF with XAML is described in this paper.

In my relevant demo, I use Blend to style the Button, add a storyboard for animating it and changing the background color to the LayoutRoot to a gradient color. You can see glimpses of that in both of the above screenshots of VS2008 and Blend, so revisit them paying attention to the XAML parts.

Concepts Worthy of Further Exploration (MSDN links)
If you are a seasoned .NET developer, you'll find that XAML/WPF/Silverlight introduce some new concepts. Below I list MSDN links to the top 5 areas I recommend you investigate – just follow the hyperlinks.

- The Layout System. Note that from the list of layout panels, Silverlight 2 only supports Canvas, StackPanel and Grid. Explore all 3 by changing the LayoutRoot type and dragging various controls on it. This is a good time to grok Attached Properties.

- Dependency Properties. These are important to understand because they enable the following 3 equally important areas:

- Animations (in my session I make a button fly around a bit when clicked).

- Databinding (in my session I bind the results of a WCF call to a list).

- Control Styling/Templating (in my session I change a button to look like a happy face)

Conclusion – XAML levels of competency
If you have been ignoring XAML so far, I don't think you can afford to do so any longer. IMHO there are 4 levels of XAML competency:

Level 100 – truly understand all of the above.

Level 200 – confidently read XAML (e.g. as spat out by VS2008 or Blend).

Level 300 – be able to type XAML yourself with an aim to create a structure of a bland GUI (setting basic properties and hooking events etc).

Level 400 – create styles, templates, animations and set gradient colours by hand.

Labels: ,


Tuesday, May 06, 2008

 

Recently I was playing with some LINQ to XML for a demo I was preparing and was having trouble retrieving the expected values from what was a very straightforward query.

Have a look at the XML file that looks like this (the results of programmatically calling this Amazon service).

Each Item element represents a book and I wanted to retrieve the Title. How would you form that query with LINQ to XML?

I went for the obvious:
  var res =
from ia in XElement.Parse(e.Result).DescendantsAndSelf("ItemAttributes")
select ia.Element("Title").Value;
When that did not produce the expected results I scratched my "tired" head at the time and pinged MikeT who came up with the correct way of doing this (you still have time to work it out on your own).

The clue (and at the same time further "excuse") is that all my previous experiments with LINQ to XML involved using my own demo XML files that never had namespaces inside so I forgot all about them (haven't paid the tax in a while). I find quite ugly what you have to do to incorporate namespaces in a LINQ to XML query, but there seems to be no nicer alternative to the following (thanks Mike):
void SomeMethod()
{
var res =
from ia in XElement.Parse(e.Result).DescendantsAndSelf(n("ItemAttributes"))
select ia.Element(n("Title")).Value;

// TODO use res
}

static XName n(string name)
{
return XNamespace.Get("http://webservices.amazon.com/AWSECommerceService/2005-10-05") + name;
}
I still didn't like this solution for the simple demo I wanted to use it for. So, I recalled VB's superior support for XML and I converted the project to VB and used the following instead which needs no extra method and is all round more elegant:
  Dim res = _
From ia In XElement.Parse(e.Result)...<n:ItemAttributes> _
Select ia...<n:Title>.Value()
...and if you are wondering where the n comes from, that is at the top of the VB file:
Imports <xmlns:n="http://webservices.amazon.com/AWSECommerceService/2005-10-05">
...another aspect of VB's beauty and another thing I had the opportunity to mention in my demo ;-)

Labels: ,


Friday, February 29, 2008

 

A while back I recorded some screencasts on this hot topic, and I see now that the popular VSJ developer magazine has published my article on Parallel Extensions to the .NET Framework.

For those of you that can't get a hard/physical copy, they have kindly made it available online for your reading pleasure.

Labels: ,


Thursday, December 20, 2007

 

When the Windows Mobile Managed APIs were introduced they made use of a new underlying Windows CE 5 feature (that WM 5.0 is based on): volatile registry keys (see dwOptions). Volatile keys are also available on normal/desktop/server Windows. In a nutshell, volatile registry keys do not survive an OS reboot so anything you write there is not persisted the next time you restart. The obvious question at this point is: Does the managed registry API support volatile keys? The answer is "no" for both the full .NET Framework and the .NET Compact Framework. Let's explore an UNSUPPORTED solution for both platforms.

On the surface without too much digging it appears that the native RegCreateKeyEx is wrapped by RegistryKey.CreateSubKey. So for the BCL team to add support for volatile keys to the managed API, one way would be to add a new overload to CreateSubKey that accepts our desire for volatileness and at the point it calls RegCreateKeyEx it passes in REG_OPTION_VOLATILE instead of 0 which is what the implementation does now (i.e. a change of one line of code).

But since we are not the BCL team and we cannot edit the library's code, we can create a helper static method to do that job for us. Maybe that method would live in the static Program class with a signature something like this:
public static RegistryKey CreateSubKey(this RegistryKey rk, string subkey, bool isVolatile)
{
if (!isVolatile)
{
return rk.CreateSubKey(subkey); // i.e. no change
}
else
{
// call our own method since we cannot change the framework's
return MothCreateVolatileSubKey(rk, subkey, RegistryKeyPermissionCheck.Default);
}
}
Note on the above:
1. I've made the method an extension method which means that we can call it in either of these two ways (the first being more natural):
RegistryKey rk1 = Registry.CurrentUser.CreateSubKey("my vol", true);

RegistryKey rk2 = Program.CreateSubKey(Registry.CurrentUser, "my vol", true);
2. As you can imagine the implementation of MothCreateVolatileSubKey is a simple duplication of the implementation of the existing framework method with 2 differences:
a) Where the framework's implementation passes 0 as the 4th argument to the native RegCreateKeyEx, we will pass REG_OPTION_VOLATILE.
b) Wherever the framework's implementation calls private/internal methods we will have to use reflection to access them (unless you fancy duplicating all of that too;)).

Yes, I know the above is very ugly, very unsupported and very much a hack. I have created a VS2008 solution with the above that you can use to test it out at your own risk. It contains two projects, one for NETCF to run on your Windows Mobile and one for the desktop.

It is quite possible that by running the code from the project your machine will be wiped clean and that your monitor will go up in flames after transferring all your money out of your bank account. You have been warned!

So, at your own risk, get the VS2008 projects here.

Labels: ,


Tuesday, December 18, 2007

 

At the same time as .NET Framework 3.5 we shipped Service Pack 1 for .NET Framework v2.0. There is a standalone update for v2.0 SP1 for Windows XP and Windows Server 2003 and it ships out of the box with Windows Server 2008. For Windows Vista, it is included with Vista SP1. Of course, Fx v3. 5 depends on v2.0 SP1 so the installer for v3.5 will also install v2.0 SP1 if it is not on the machine already.

So what is in Fx v2.0 Service Pack 1?

1. Tons of bug fixes. See the list here.

2. Performance Improvements.
+ NGEN boosts.

3. Some new public APIs:
+ New members on the GC class.
+ DateTimeOffset class (this has also propagated to many other APIs that in addition to DateTime now use this new type e.g. XmlConvert.ToDateTimeOffset()).
+ Addition of the ShieldIcon for drawing.
+ IME additions.
+ File Dialog Enhancements.

4. Internal changes:
+ Increase of ThreadPool limit.

Some devs are aiming at using VS2008 to target Fx v2.0. Please note that you are really targeting v2.0 SP1. I blogged a pointer before on potentially addressing this goal, but it is important to stress again that the supported framework for VS2008 is v2.0 SP1 and not v2.0 RTM.

By the way, at the same time, the .NET Framework v3.0 SP1 was also released. Everything I wrote in the first paragraph of this blog post for v2.0 SP1 applies to v3.0 SP1 too. The list of fixes for v3.0 SP1 is in this KB article.

Labels:


Monday, December 17, 2007

 

In Windows Forms, the OpenFileDialog and SaveFileDialog inherit from the abstract FileDialog class. If you work with these classes you should know that there have been a few additions in this area as highlighted by the following class diagram.


There are broadly 3 enhancements:

1. The OpenFileDialog has a new property (SafeFileName) that returns just the name and extension of the selected file without the path information. Because of that it is accessible to applications running with limited trust. Should the selected files be more than one, you can use the corresponding SafeFileNames property that returns an array of strings.

2. There is a new property for both Save- and OpenFileDialog that is only applicable on Windows Vista (it gets ignored on XP): AutoUpgradeEnabled. The default is true, and it means that the dialogs will have the Vista look and feel when run on Vista.

3. If you have not opted out from auto upgrading for Vista just discussed, then another property of the 2 dialogs may be useful: CustomPlaces (of type FileDialogCustomPlacesCollection). You can use this to add strings (or Known Folder GUIDs) that represent locations on your disc that are then easily accessible to the user of the dialog you are showing via the "Favorite Links" section.

To see the Vista dialog in action with custom places, watch my screencast.

Labels:


Sunday, December 16, 2007

 

It should be a known fact that Windows Forms controls support Input Method Editors out of the box, so you don't have to do anything special.

However, if you are writing your own control (e.g. UserControl) then with v2.0 of the Framework you may run into issues. This is a fairly niche scenario but if you are facing it then you should obtain hotfix 934197 that solves the issue by providing a property you can override in your control: CanEnableIme.

Also read the MSDN docs for the protected property.

Hopefully the details on the links above make it clear, but I also found this connect feedback item that makes it crystal clear with a repro. As per the MSFT response there, this property is now available in v2.0 Service Pack 1 on all controls. Maybe now that it is in an SP this angry guy here won't have such an issue distributing the fix...

Bonus IME topic: Also in v2.0 SP1, relevant to Chinese IMEs only, you will find a new member for the ImeMode enumeration for HalfShape: OnHalf.

Labels:


Saturday, December 15, 2007

 

Seasoned Windows Forms developers will be familiar with the System.Drawing.SystemIcons class that has a bunch of properties returning standard system icons. For example, if you throw on a form a picturebox and a button with its event handler the following code shows how you can take advantage of SystemIcons:
void button1_Click(System.Object sender, System.EventArgs e)
{
// use Error
pictureBox1.Image = Bitmap.FromHicon(SystemIcons.Error.Handle);

// use Warning
this.Icon = SystemIcons.Warning;

// use Information
int h = button1.ClientSize.Height / 2;
Icon ico = new Icon(SystemIcons.Information, h, h);
Bitmap bitmap1 = Bitmap.FromHicon(ico.Handle);
button1.Image = bitmap1;
button1.ImageAlign = ContentAlignment.MiddleLeft;
}
With Service Pack 1 of .NET Framework v2.0 we get a new member of that class: SystemIcons.Shield. So, if you are on Windows Vista and you are working with User Account Control, you may find it a useful icon to use (for example on a menu).

Below is a screenshot of what the code above looks like side by side, before clicking the button and after. The screenshot at the bottom is after replacing the 3 icons with shield:

Labels: , ,


Friday, December 14, 2007

 

Most .NET developers have at some point in their career called into a native library (whether it was C\C++ DLL part of the Windows OS or one of their own or one from a 3rd party is irrelevant). To call native functions form .NET you use the DLLImport attribute and even though it has various overloads, the main thing we do is point it to the native DLL name (the Declare statement in VB does the same thing although I use DllImport in VB projects as well).

The subtle point is that there is no convention for how we specify the name so, for example, all of the following are valid and will work at runtime:
    [DllImport("kernel32.dll")]
static extern ...;
[DllImport("kernel32")]
static extern ...;
[DllImport("Kernel32.DLL")]
static extern ...;
[DllImport("KERNEL32")]
static extern ...;
[DllImport("KeRnEl32.DlL")]
static extern ...;
Now, I know that there is no convention, but if you used the above this is what you would see in ILDASM (and indeed in reflector too):


You may think: "So what, isn't just one kernel32 loaded in my process at the end of the day?". Well, yes, but there is a slight performance penalty because the loader treats each separate string as a separate module!

Some of you are thinking that "for that performance reason alone" you should standardize on a convention e.g. always use lowercase and include the ".dll" extension... or something like that. Others are probably thinking that "the performance gains are negligible" for you to make a rule for this.

In my opinion (and it is my blog so don't be shocked that these are my opinions here!), you are both wrong and right at the same time. For me, this is an issue of hygiene. Once I learnt about this fact (many moons ago :-), I couldn't live with myself if in my assemblies I didn't define a standard for pinvoking. Nothing to do with performance – it just feels dirty to me not to use the same DLL name throughout my assembly. That's just the kind of person I am...

So I sighed when I discovered that System.Core.dll is the first and only assembly so far in v2.0/3.0/3.5 of the framework not to follow the "all lower case with .dll appended" convention, as viewing it through a disassembler proves :-(

Labels:


Wednesday, December 12, 2007

 

In this 4th video in my series on the ParallelFX, I explore what it is like to program against the lowest level API in the Task Parallel Library: the Task and TaskManager. Watch it or download it from here.

Labels:


Sunday, December 09, 2007

 

In my videos on Parallel FX, I showed some class diagrams. I thought that you may want to see those independently of the video. Click on the links below to open the respective class diagram png image (or "save as"):

+ Parallel LINQ.
+ Parallel class and friends.
+ TaskManager, Task, Future and friends.

Labels:


Friday, November 30, 2007

 

The Parallel Extensions to .NET Framework 3.5 is available! Download and play with the first ever public drop - the December CTP.

If you are then ready to dig into it, I have three 20' screencasts (plus more cooking):
1. Tour of the Samples. A tour of what gets installed to get you started.
2. Declarative data parallelism. This is about PLINQ.
3. Imperative data parallelism. This is about the static Parallel class.

After watching the above, visit the relevant MSDN dev centre. For any questions please use the dedicated online forums. For feedback please use the connect site. If you want to congratulate or blame the product team, visit their blog.

Labels: ,


Thursday, November 29, 2007

 

If you watched my videos here, please note the following clarifications:

First, in all videos I am using the old internal sort-of-a codename "PFX". This is no longer used internally or externally. Instead just refer to it as Parallel Extensions.

Second, in the PLINQ video, when I very briefly mention what pipelining does, my description is outdated; for an up to date description of pipelining please see this. Also in the same video I do not make it clear that the ForAll option will *not* allow you to preserve ordering.

Third, in the Parallel video, where I use return sum and imply that it is the same as return 0, I am obviously wrong: The issue is that it’s possible for the first thread to complete so fast that the second thread doesn’t have any work to process. The first thread will store its partial result back into the total sum, but since the thread local selector delegate has captured that total sum variable, the second thread will be initializing its partial sum with the total sum that already includes the first sum’s partial. Thus, you could end up counting values twice so you should use return 0 instead. In the same video, if you really wanted to simulate break, in the parallel version you would have to add a return statement after the ps.Stop() statement that I used.

Labels:


Wednesday, November 28, 2007

 

I was in Joe's session at Tech Ed when he mentioned in passing (almost as a throwaway comment) that there are some changes in the System.Threading.ThreadPool in v3.5. I guessed that what he really meant was changes in v2.0 Service Pack 1 for the ThreadPool class (which I confirmed myself by testing it on my machine). It goes to show you that you cannot rely on API surfacing to discover all the changes in SP1 and somebody should come up with a master list... Anyway, you are probably more interested in what the change is, right?

Apparently, the ThreadPool now defaults to having a max of 250 threads instead of 25. I found this ironic because I recall that the NETCF ThreadPool had 256 in v1.0 and changed to 25 to match the desktop behaviour in v2.0 and I wondered if they caught this change in NETCF v3.5 so they can be in sync again. Seems not :-)

Regardless, remember that starting with v2.0 you can change the max yourself not just through hosting APIs but through the managed SetMaxThreads method. In fact, to validate all of the above, I used the counterpart method, GetMaxThreads that you can try yourself:
  int a, b;
ThreadPool.GetMaxThreads(out a, out b);
MessageBox.Show(a.ToString());
:-)

Labels:


Wednesday, October 03, 2007

 

Huge announcement today: Microsoft is releasing the source code for parts of the .NET Framework (inc. BCL, WinForms, WPF, ASP.NET) under the Ms-RL license which effectively, by my interpretation, means that you can read but you cannot copy or modify.

The cool bit is not that you can just read the framework code in your favourite text editor once you download and accept the license; no, the real goodness is that when you debug your applications with Visual Studio 2008 you will have the option to debug right down into the Framework code (with an autodownload feature from an MSDN server)! Are you still debating the move to VS2008? ;-)

For more details read ScottGu's blog post or listen to ScottHa's podcast or watch ch9 interview with the man that made it happen.

Labels:


Monday, October 01, 2007

 

I have no reservations in describing the move from Visual Studio 2005 to Visual Studio 2008 as a "no-brainer upgrade". The latter is a superset of the former and given framework multi-targeting and the layered approach of Framework 3.0 and 3.5, it makes perfect sense to move your development environment over and, when you are ready to change your deployment, seamlessly take advantage of a new .NET Framework 3.x

But how about those people still using VS.NET 2003 (shocking I know :) who wish to take advantage of the VS2008 enhancements and move closer to our latest platform? That's a different kettle of fish. The issue there is that: you are on a different CLR version (1.1) which has some breaking changes compared to the CLR 2.0 (which is used by Fx 2.0/3.0/3.5). You are also on a different framework version (1.1) which has some breaking changes compared to Framework v2.0 (which is also an essential part of Fx 3.0/3.5). There is no reason for you to go to VS2005 as an intermediate step, so by all means go from the IDE of 2003 to 2008, but be prepared to face all the issues people faced when they moved from Fx 1.x to Fx 2.0.

I thought I'd resurface below some links to documents that help people move from v1.x to v2.0, the first two being the most important ones IMO:
- Design time Breaking Changes in .NET Framework 2.0
- Runtime Breaking Changes in .NET Framework 2.0
- Microsoft .NET Framework 1.1 and 2.0 Compatibility
- Compatibility Testing Scenarios

Also note that if you search you'll find plenty of issues in particular for web projects since the project model fundamentally changed from VS.NET 2003 to VS2005. It was later amended via separate downloads for VS2005 but since you are moving to VS2008 you don't have to worry about that (both web site projects and web application projects are included out of the box with VS2008). So, just one extra link for you pre-ASP.NET v2.0 devs:
- Feature changes in ASP.NET 2.0

A much older blog post on the same topic may also be of use to you.

Labels:


Friday, September 21, 2007

 

Angelos found an interesting article via the UK MSDN Flash. If you did as well, check out more about that on the author's blog (one more reason to be sorry PDC was cancelled).

Anyway...

In a not so unrelated area, on a list that I am a member of, a question came up about affinitising a managed thread to a specific CPU. Jeffrey Richter came to the rescue by pointing out the System.Diagnostics.ProcessThread and its ProcessorAffinity property but then the harder question came along of how to associate that class with the System.Threading.Thread class. Below is the answer in C# from Mr Richter again:
      // Call this passing in 0
public static ProcessThread GetProcessThreadFromWin32ThreadId(Int32 threadId) {
if (threadId == 0) threadId = ThreadUtility.GetCurrentWin32ThreadId();
foreach (Process process in Process.GetProcesses()) {
foreach (ProcessThread processThread in process.Threads) {
if (processThread.Id == threadId) return processThread;
}
}
throw new InvalidOperationException("No thread matching specified thread Id was found.");
}
...where ThreadUtility is a class containing at least:
      [DllImport("Kernel32", EntryPoint = "GetCurrentThreadId", ExactSpelling = true)]
public static extern Int32 GetCurrentWin32ThreadId();

The code (and much more) is part the Power Threading Library which is available on the Wintellect site.

Labels: ,


Wednesday, May 16, 2007

 

One of the things you will hear/see a lot in Orcas talks/articles is that the CLR remains at the same version: v2.0.50727. What is meant by that is that a "service pack type" upgrade will be made which is guaranteed not to break any existing code: just bug fixes and maybe some tiny enhancements that can have no negative side effects and in most cases have to be explicitly taken advantage of from newly written code.

So, on your system navigate to your %windir%/Microsoft.NET/Framework/v2.0.50727 directory. Pick any of the DLLs starting with "mscor", e.g. mscorjit.dll, and look at its full version information. Note that the presence of Fx v3.0 has no effect on the scenarios below or to this post as a whole.
1. If you have installed NetFx v2.0 on XP or lower, the revision will be 42 i.e. full version is v2.0.50727.42
2. If you have installed Orcas Beta 1 on your machine the revision is actually 1318.
3. If you are on Vista (which comes with NetFx 2.0 by default) and have *not* installed Orcas, then your revision is 312 (that's right, it is "the same version" as RTM)

So there isn't much point to this post, other than to highlight/reinforce that when we say it is the same version, we do not count the Revision part – just the Major.Minor.Build parts.

Labels:


Sunday, February 18, 2007

 

In VB you are always advised to declare all your variables since due to its heritage, VB allowed you not to declare a variable type, which is bad thing:
Sub Main
myVariableName = 6
myVariableName = myVariableNmae + 1

Debug.WriteLine(myVariableName)
End Sub
In the code above you were expecting myVariableName to be 7 when actually it is 1, the reason being that you misspelled your variable. Because you don't have to declare the variable, a new one was created for you when you misspelled it and of course it starts with a value of zero. Crazy world! Luckily, in VB6 and before, you could specify Option Explicit and that would not allow you to use variables without declaring them... phew. In .NET land with VB 7.0 by default Option Explicit On is specified for all projects but if people want to be stupid they can turn it off.

Another bad thing you could do in VB6 still remains today and that is the ability to declare untyped variables, for example:
Sub Main
Dim myVariableName = 6
myVariableName = myVariableName + 1
myVariableName = "hello"
Debug.WriteLine(myVariableName)
'
Dim o
o = New Collection
o.FeelingLucky
End Sub
Effectively, myVariableName is a Variant (or Object in .NET land) which means it can take any value you want and you never get a compile time error, instead you get a logical error. Similarly for variable o where the compiler cannot tell you that FeelingLucky is not a method of the Collection class so you get a runtime error/exception. So how can you escape this crazy world? A new option in VB 7.0 and beyond is Option Strict. Unfortunately, to this very day, you have to manually turn this option On yourself - it is not the default. If you haven't already, do it now for all your projects. You will prevent logical errors at runtime, runtime exceptions *and* you will make your code faster since method calls will be early bound rather than late bound.

Now, there are some niche scenarios where Option Strict Off may be convenient, namely when doing COM Interop with old automation models that are constructed in a certain way or if you have large codebase that already works and you do not want to touch it (hence you do not want to deal with the compile time errors that you will get when you turn option Strict On). The point here is that you can turn this option on/off at the file level. So I suggest that you turn it On at the project level and turn it off for the files that you think could do without the compile time checking.

Before I close this blog post, note that C# does not have either of these options which basically can be seen as that they are both On and you cannot turn them Off. While Option Explicit is useless, the convenience of doing easy late binding in VB with Option Strict Off can be cool. In c#, you have to do explicit late binding using reflection (which is what the VB compiler does for you in the VB case).

For much more on this topic use your favourite search engine i.e. like this or like that.

Labels:


Monday, January 01, 2007

 

Exactly two years ago on New Year's day, I wrote the Best of "The Moth" 2004 blog enrty where I picked my favorite blog entries out of 96 posts. Exactly one year ago I had to choose from 151 posts to find the ones I thought were the best in terms of content and the result was the Best of "The Moth" 2005.

The year of 2006 I made 142 blog entries and below are a select few. Happy New Year!

01. I didn't have a chance to play with it as much as I wanted to, but with very little public info available, this blog served it well: .NET Micro Framework, its product sheet and other NETMF links.

02. Recognising an idiom of the using statement.

03. A cute desktop feature implemented for the Windows Mobile/WinCE platform in a reusable NETCF control: TextBox cue banner.

04. A picture is worth a 100 words and a video is... a whole bunch of pictures! Check mine out following the instructions here for my nuggets.

05. A comprehensive collection of links for Windows Workflow Foundation (WF).

06. I collected the links to my 9 blog posts on sharing assets between desktop and mobile platforms in one place. Follow the numbered links.

07. The most controversial feature of Windows Vista is something every developer must understand: User Account Control.

08. One of Vista's features is becoming my obsession and that is SideShow. My series of SideShow gadgets blog posts will continue in 2007 and so far you can read parts one, two, three, four and five.

09. I spent 6 months last year focusing almost entirely on Vista developer features that are new and that are *not* part of NetFx3. I have catalogued my blogging & screencasting efforts in a large collection of links to content that supports my speaking engagements on Vista. IMO this blog post alone could have been the best of "The Moth" this year:
Vista-only features for the managed developer.
Stay tuned in 2007 via one of the subscribe options on the left :-)

Labels: , , ,


Monday, December 11, 2006

 

A few months ago when I was looking at what new Vista native APIs to play with from managed code, I was advised internally not to touch anything that is loaded in arbitrary processes. The short answer was that this has versioning implications.

Let's drill into it. If you write a shell extension of any sort with managed code, you have introduced a dependency onto the version of the CLR that you are using. The classic example is to think of all the managed applications on a computer that open a file dialog. Every time they do that, your .NET shell extension code gets injected into their process and bad things can happen (not just to the shell) but more importantly to those applications *IF* the version used in your managed extension, is not the same as the version used by that application. So the real root of this issue is the fact that each process can only load one version of the CLR combined with the fact that a version of the CLR can side by side on the same machine with other versions of the CLRs.

It sounds like we are pretty serious about this advice. An article written in 2004 demonstrating how to write namespace extensions with managed code was edited this June 2006 to include the following warning in red at the top of the article:
[ Editor's Update - 6/23/2006: Because shell extensions are loaded into arbitrary processes and because managed code built against one version of the runtime may not run in a process running an earlier version of the runtime, Microsoft recommends against writing managed shell extensions and does not consider them a supported scenario.]

Now at this point, some of you will have arguments and workarounds of how to avoid this limitation. I doubt they haven’t been raised already, but if you think you have something new to offer, go contribute to this extremely interesting discussion on the msdn forums (inc. contributions from Raymond Chen).

Labels:


Thursday, October 05, 2006

 

The problem
When I was trying to call the WerRegisterFile API as described previously, I run into an interesting situation: Calling the API without specifying any CharSet should have attempted first the WerRegisterFile. If I specify CharSet.Auto, it should first attempt WerRegisterFileW and if it cannot find that then go back to try WerRegisterFile. Either way, you would have thought that this would succeed or blow. As it turns out, leaving the CharSet off, silently fails (no exception, return value is 0, Marshal.GetLastWin32Error is 0 etc) but specifying CharSet.Auto works as expected! For the record, CharSet.Unicode behaves like CharSet.Auto and CharSet.Ansi fails like when we omit altogether CharSet from the DllImport declaration.

Download a repro VS2005 project here (obviously requires Vista).


Solution
Looking at kernel32.dll (which exports this function) shows that there is only one entry for the API (screenshot of dumpbin). This seems to be a pattern with Vista, according to my colleague MikeT.

Well it seems that after a series of chats with Mike, he updated his post with useful thoughts. Read his 4th thought in the updated section and come back... I’ll wait...

[...time passes...]

So to prove the thought, I looked at another Vista API that takes strings: RegisterApplicationRestart. It too has no trailing A or W (screenshot). So calling this API without CharSet also gives no errors, but the string you get passed back to the application at the command line is definitely not the one I passed to it (something Chinese-looking on my system when I gave it something English).

That rests the case. I should have realised earlier that CharSet is not just about finding the correct entry point but also about how the string will be marshalled.

As an excuse I should state that, having mostly coded for WinCE, I think I have been spoilt since that is all Unicode and I can’t remember using CharSet with any of NETCF pinvokes and they all worked fine :)

Final thoughts
1. Whoever thought the default of CharSet should be Ansi has a lot to answer for. Note that it is a C# decision as the CLR defaults to Auto!
2. I wonder if the Vista change (that threw me off track) is going to bite others or if it just muppets like me that fell for it :S
3. Why is WerRegiserFile in kernel32.dll when all the other WER APIs are in wer.dll?!
4. WerRegisterFile should be giving some indication to the developer that it failed. At the end of the day, you give it a path (string), it thinks it is a different string (path), so it cannot find the file and then it silently fails! WTF?
5. I detest silent failures. Make an explosion next time. A big loud one or a quiet one, but not a silent one. Silent ones are the worst!

Labels:


 

This post just serves as a background URL that I can link to from my next post later :)

We all know that to call unmanaged code from managed code you have to pinvoke (i.e. use the DllImport attribute). One of the enumerations that becomes relevant when calling native methods that accept strings is CharSet.

It is also relevant for native structures with strings but I am explicitly ignoring that in this post. I am also ignoring the CharSet.None enumeration as it means the same as CharSet.Ansi and is there for C++ legacy reasons, I think.

CharSet is useful so you can instruct the runtime to invoke the "A" version of an API or the "W" version (Ansi or Unicode) e.g. MessageBoxA or MessageBoxW. If you select CharSet.Ansi the CLR attempts to invoke an entry point with an appended "A" if the entry point specified by the signature doesn't exist. If you select Auto, then on modern OSs it will default to Unicode. This means the CLR will attempt to invoke an entry point with an appended "W" before attempting to invoke the entry point specified by the signature. If you miss the CharSet from your DllImport declaration, the default is Ansi with the behaviour described above.

Labels:


Wednesday, October 04, 2006

 

In my Vista sessions I focus on accessing native APIs form managed code. A few times now people ask me if there is an API browser of some sort... you know, like the API Text Viewer from the VB6 times... I found this replacement on the web but haven’t personally tried it. Frankly, I don’t know of a Microsoft one so if there is a replacement hiding somewhere and you know about it please share a pointer!

So the alternative I offer is... the alternative I have always offered! The title gives it away: pinvoke.net
If you read my older entry then you’ll know where to go to get the interop book.

There is also a Visual Studio 2005 add-in for the pinvoke wiki site, but I haven’t personally tried it. Get it from gotdotnet.

I plan to update the wiki with Vista API definitions at some point (the power API I mentioned previously is already there). I’ve added this to my TODO list (item # 88345602), but if you feel you’d like to take on the task, please go for it (Vista dllimports all over my blog entries since May this year)!

Labels:


Thursday, September 28, 2006

 

I've talked about the new button style in Vista before: CommandLink (and Vista uses this everywhere).

While looking on the web for something irrelevant, I came accross an old post by Geoff Appleby that offers a custom implementation of CommandLink for XP. Check it out!

Labels:


Monday, July 03, 2006

 

Previously we described the using statement. After showing a quick code example and describing the intent of the construct, we proceeded to a more pragmatic description of what it does which I repeat here:
"The using statement accepts as an argument an object that implements IDisposable; it defines a coding block where the ctor of the said object is called at the start and the Dispose method is called in the end."

Taking the definition above, a design pattern is formed (or to be more precise in this case, an idiom):

Sometimes you have a piece of code that has to be enclosed between two code blocks A and B. Code blocks A and B are repeated in multiple places in your project(s). When you recognise that, you can extract a new class with a ctor containing code block A and the Dispose method containing code block B. Replace all client side occurrences with a using block passing in the newly extracted class.

As an example, instead of:
void SomeMethod()
{
Cursor.Current = Cursors.WaitCursor;
statusBar1.Text = "Busy...";
button1.Enabled = false;

// do some real work here

button1.Enabled = true;
statusBar1.Text = "Ready";
Cursor.Current = Cursors.Default;
}
we write:
void SomeMethod()
{
using (BusyTaskRegion bt = new BusyTaskRegion(statusBar1, button1))
{
// do some real work here
}
}
...after extracting the following class:
class BusyTaskRegion : IDisposable
{
private Control _c1;
private Control _c2;

public BusyTaskRegion(Control c1, Control c2)
{
this._c1 = c1;
this._c2 = c2;
Cursor.Current = Cursors.WaitCursor;
c1.Text = "Busy...";
c2.Enabled = false;
}

public void Dispose()
{
this._c1.Enabled = true;
this._c1.Text = "Ready";
Cursor.Current = Cursors.Default;
}
}
Another example would be measuring performance of some code (i.e. extract the timer setup and tear down into a class and then use it via using). I was trying to find the pattern formally documented online but I couldn't. However, I did find examples of its usage here, here and here (much better than my fictitious example above!).

When I first saw this (at a previous project for some impersonation code), it felt wrong on two levels. First, it felt like using was being misused in scenarios that it wasn't originally intended for (e.g. when people read the client side code they have to take an extra mental step to digest that no memory management stuff takes place). Second, it felt wrong to define classes that have just a constructor and a Dispose method with nothing else in-between.

What do you think?

Labels:


 

The using statement has been in C# for ever and was newly added to VB8 as well (Using). I hope everybody is familiar with it by now (not to be confused with the using directive typically appearing at the top of code files - Imports in VB). If I asked you to tell me about the using statement, I bet that most of you would use a code example , maybe something like the following.

Given a class like this:
class SomeType : IDisposable{
public SomeType(){
// do some ctor stuff
}

public void DoSomething(){
// do some useful stuff
}

public void Dispose(){
// clean up unmanaged resources
}
}
We know that the client code should use it like this:
SomeType st = new SomeType();
try
{
st.DoSomething();
}
finally
{
st.Dispose();
}
The using statement makes that cleaner, easier to remember and easier to enforce like this:
using (SomeType st = new SomeType())
{
st.DoSomething();
}
So, the easy way to describe the purpose of using (without a code example) is this:
The using statement offers an elegant way of ensuring that the developer does not forget to call Dispose on an object that (directly or indirectly) holds unmanaged resources. (My links to msdn at the top pretty much say the same thing)

Effectively, we all associate the using statement (or at least I always did) with not leaking. However, if we look at the using statement not from an intent point of view but instead from a practical point of view, we would probably come up with this:
The using statement accepts as an argument an object that implements IDisposable; it defines a coding block where the ctor of the said object is called at the start and the Dispose method is called in the end.

Next, we'll see how to take that last statement further to describe a design pattern.

Labels:


Sunday, November 13, 2005

 

We are all familiar with the Type class of the framework and how useful it is in many scenarios. To obtain the Type of a type we can call GetType() on the instance, the static Type.GetType passing in the full name, or use C#'s typeOf operator (or GetType operator in VB).

We are also familiar with Generics (supported on NETCF as well).

At first there isn't much relation between the two. There are some cases, though, when you design an API (that depends on a type to be passed to it) where either of the two can satisfy your goal: A generic class or a class with a constructor accepting a Type. So in that case, which approach should you choose and why?

1. Blah<T>{...} //type declaration
2. Blah(Type t); //ctor

Just to be ultra-clear, the calling code for each occasion looks something like this:
1. new Blah<SomeType>();
2. new Blah(typeOf(SomeType));

Just FYI, and don't allow this to affect your thoughts, the indigo (or WCF if you prefer) team chose the 1st approach originally and then, after Beta 1, changed to the second. I am referring, of course, to the ServiceHost class. Why did they do that?

Since this blog doesn't have comments, reply on your own blog (or if you don't have one, feel free to email me your reply).

UPDATE:
1) .NET design guidelines guru provides comments.
2) Ayende describes his preferences
3) Apparently, there is no mystery on the Indigo change:
"The ServiceHost just needs to know the type of the object being hosted - none of the methods or properties were accepting or returning the so the generic mechanism wasn't really being using per se."

Labels:


Sunday, July 31, 2005

 

If I am interviewing you for a dotnet position and I ask you about boxing I expect you to be able to quickly describe what it is, why one should care and give me a quick example. If I see you struggle, I'll help you by asking "If I add an integer to an ArrayList, does boxing occur?". If you hesitate answering that then... [this really happened recently when I interviewed someone for a senior .NET position].

So it was with pleasure that I saw a post on boxing this week. If you are struggling with the concept go read Raymond Lewallen's Boxing and Unboxing for Beginners.

I don't really have anything to add to that post other than a couple of comments on the Intermediate Language:
1. Note the IL instruction box. That is where boxing gets its name (should be obvious but thought I'd spell it out :-)
2. Raymond's example uses VB and unfortunately has Option Strict Off. If it had Option Strict On, you'd see that when you retrieve the result you have to cast it to the integer
i.e. b = DirectCast(a(0), Int32)

If you make that modification, then you see the other magic IL instruction: unbox (rather than the *really* ugly VB-compiler-injected-statement:
[Microsoft.VisualBasic]Microsoft.VisualBasic.CompilerServices.IntegerType::FromObject(object)).

Here is the IL with that small modification for VB in VS.NET 2003 (note that it is compiled in Release mode so we get cleaner IL):
.method public instance void  Method1() cil managed
{
// Code size 39 (0x27)
.maxstack 2
.locals init (class [mscorlib]System.Collections.ArrayList V_0,
int32 V_1)
IL_0000: newobj instance void [mscorlib]System.Collections.ArrayList::.ctor()
IL_0005: stloc.0
IL_0006: ldloc.0
IL_0007: ldc.i4.s 10
IL_0009: box [mscorlib]System.Int32
IL_000e: callvirt instance int32 [mscorlib]System.Collections.ArrayList::Add(object)
IL_0013: pop
IL_0014: ldloc.0
IL_0015: ldc.i4.0
IL_0016: callvirt instance object [mscorlib]System.Collections.ArrayList::get_Item(int32)
IL_001b: unbox [mscorlib]System.Int32
IL_0020: ldobj [mscorlib]System.Int32
IL_0025: stloc.1
IL_0026: ret
} // end of method Form1::Method1
3. Just so you can see the IL for a C# version compiled under Visual Studio 2005 Beta 2, here is some code:
private ArrayList ar = new ArrayList();
public void Box() {
ar.Add(5);
}
public void Unbox() {
int i = (int)ar[0];
}
...and equivalent IL:
.method public hidebysig instance void  Box() cil managed
{
// Code size 19 (0x13)
.maxstack 8
IL_0000: ldarg.0
IL_0001: ldfld class [mscorlib]System.Collections.ArrayList BoxUnbox.Form1::ar
IL_0006: ldc.i4.5
IL_0007: box [mscorlib]System.Int32
IL_000c: callvirt instance int32 [mscorlib]System.Collections.ArrayList::Add(object)
IL_0011: pop
IL_0012: ret
} // end of method Form1::Box

.method public hidebysig instance void Unbox() cil managed
{
// Code size 19 (0x13)
.maxstack 8
IL_0000: ldarg.0
IL_0001: ldfld class [mscorlib]System.Collections.ArrayList BoxUnbox.Form1::ar
IL_0006: ldc.i4.0
IL_0007: callvirt instance object [mscorlib]System.Collections.ArrayList::get_Item(int32)
IL_000c: unbox.any [mscorlib]System.Int32
IL_0011: pop
IL_0012: ret
} // end of method Form1::Unbox
By the way, a great follow up to the above is to show how Generics eliminate the need for boxing in such a scenario pointing out that
a) No boxing/unboxing penalty takes place
b) No cast is required
c) Compiler prevents anyone adding objects of other types to our List

Labels:


Monday, May 30, 2005

 

As you know, in VB variables do not need to be initialised, as they always get the default value for the variable type in question, e.g.
Dim b As Boolean 'b is already initialised to False

In C-based languages (inc. C#) this does not apply; you must initialise the variable before you use it, e.g.
bool b = false;

The above is the reason we cannot have ByOut in VB (only ByVal and ByRef) whereas C# has both ref and out (ByVal is implied by omission).

I have seen VB code that follows the C-style and there are two common reasons for doing so; one is to be explicit and the other is because of a C-based upbringing. The question is what IL will the VB compiler generate, faced with code that differs only by explicit assignment (we know it is pretty crap at optimising the simplest of scenarios, so we don't go in with our hopes high).

Given these two methods (and assuming a private method GetNumber):
    Public Sub VBStyle()
Dim i As Int32
i = GetANumber()
End Sub

Public Sub CsStyle()
Dim i As Int32 = 0
i = GetANumber()
End Sub
I can tell you that the VB compiler generates slower code for the second scenario (I have to say if you have a bottleneck in your project, cases like this will not be it, but it is still good to know :-).

Here is the corresponding IL:
.method public instance void  VBStyle() cil managed
{
// Code size 8 (0x8)
.maxstack 1
.locals init ([0] int32 i)
IL_0000: ldarg.0
IL_0001: callvirt instance int32 VBWinApp.Class3::GetANumber()
IL_0006: stloc.0
IL_0007: ret
} // end of method Class3::VBStyle

.method public instance void CsStyle() cil managed
{
// Code size 10 (0xa)
.maxstack 1
.locals init ([0] int32 i)
IL_0000: ldc.i4.0
IL_0001: stloc.0
IL_0002: ldarg.0
IL_0003: callvirt instance int32 VBWinApp.Class3::GetANumber()
IL_0008: stloc.0
IL_0009: ret
} // end of method Class3::CsStyle
Needless to say that the C# version closely reflects the first version (it is even better, since it uses a call rather than a callvirt - but that is a different story...).

Labels:


Tuesday, May 10, 2005

 

Can you think about the amount of information that is part of your knowledge and account for it in terms of where you found out and how you consider it as common knowledge? Well, it turns out there is some stuff in my head that I thought everyone knew but it is not true. So I might as well capture it here on my blog.

What does mscorlib stand for? Stop reading! Don’t look for the answer, just try and work out the answer. What does the main dll of .the NET Framework stand for? What was the codename or first candidate name if you like, for C#? Well here are my answers (this is just my understanding which I cannot track back to a reference!):

C# and the design of this new .NET language ws COOL! More importantly, mscorlib has 3 parts to its name: ms cor lib.
ms: Magnificent Software (ok, it is Microsoft :-)
lib: as you expect this means library
cor: Before .NET was chosen as the name, this new platform was a successor to COM so it was codenamed COM 3.0 and then the name chosen was… Common Object Runtime (cor) and that is where mscorlib derives its name from (and that stuck regardless of the fact that .NET was the final name)!

So, now you know ;-) And if you knew already now you have something to point to!

Labels:


Wednesday, March 16, 2005

 

On his blog, as part of a useful OOP series, Raymond Lewallen defines polymorphism. He merges 3 concepts in one post. We've had the discussion on the topic previously, but I don't think we reached total agreement. In my opinion, to say that there is such a thing as "true" polymorphism and to claim that it applies only when inheritance is involved, is plain wrong.

If you are reading that blog entry to understand polymorphism, please read my (complementary) take on the topic below.

First I would ignore overloading. This has nothing to do with polymorphism and I would not bring it up in any discussions on the topic. Just for info, overloading is the ability to define two or more methods on the same class with the same name but different argument lists. Nothing more, nothing less.

Second, do not directly associate polymorphism with inheritance (as you can probably tell this is my pet peeve :-). Polymorphism directly depends on subtyping. Unfortunately, many people confuse subtyping with implementation inheritance. Inheritance is *a* way to achieve subtyping, but not the only one (another is interface implementation). If you ask the question in reverse: Is inheritance the same as polymorphism? The answer is no. Inheritance offers a way to achieve subtyping *and* a way to reuse code.

So if someone asks you to explain polymorphism with a VB.NET example using inheritance, you can do something simple like this:
Public Class EntryPoint
Shared Sub Main()
Dim m As New Mouse
Dim s As New Shark
DoSomethingWith(m)
DoSomethingWith(s)
End Sub

' Client code
Public Shared Sub DoSomethingWith(ByVal a As Animal)
a.Bite()
End Sub
End Class

Public MustInherit Class Animal
Public MustOverride Sub Bite()
End Class

Public Class Mouse
Inherits Animal

Public Overrides Sub Bite()
MsgBox("Disease")
End Sub
End Class

Public Class Shark
Inherits Animal

Public Overrides Sub Bite()
MsgBox("ouch!")
End Sub
End Class
The client code uses the type Animal. It does not know what objects it will be given (i.e. instances of what class) but the fact that they support the programmatic interface of the Animal type is enough for it to use them: polymorphism in action.

If someone asks you to explain polymorphism with a VB6 example, you can do something like this:
In a Standard EXE project, change the startup Object in project properties to Sub Main.

Add a module1 with this code:
Sub Main()
Dim m As New Mouse
Dim s As New Shark
DoSomethingWith m
DoSomethingWith s
End Sub

' Client code
Sub DoSomethingWith(ByVal a As Animal)
a.Bite
End Sub
Add a Animal class module:

Public Sub Bite()
End Sub
Add a Mouse class module:
Implements Animal
Private Sub Animal_Bite()
MsgBox "Disease"
End Sub
Add a Shark class module:
Implements Animal
Private Sub Animal_Bite()
MsgBox "ouch!"
End Sub

That's it. Polymorphism in VB6: nothing fake or incomplete about it.

Naturally you can mix many concepts in your designs including polymorphism, inheritance and overloading etc. If you want to see a design combining these topics, then Raymond's post has a nice VB.NET example.

Labels:


Friday, March 04, 2005

 

Here is another question that appears in various guises.
"Event X from control Y gets fired twice" or "I want to stop this event from firing while I am waiting for Z"

For example assume that you do stuff in the event handler of the selectedindexchanged event of a list; you now need to select an item in a list programmatically but do not want to run your event handling in that case (only when it is done by the user). Here is a simple example:

Given a form with a listbox and a button let's assume your event handler looks something like this:
Private Sub ListBox1_SelectedIndexChanged(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles ListBox1.SelectedIndexChanged
MessageBox.Show(ListBox1.SelectedItem.ToString())
End Sub
And let's assume as part of a button click you are doing something like this:
Private Sub Button1_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles Button1.Click
ListBox1.SelectedIndex = 0
End Sub
When you click the button you don't want to see a messagebox.

As you'd expect the solution is simple:
1) Use a boolean flag and check it in your event before processing
or
2) Dynamically remove the event handler

1) Define a boolean in your form code like this:
Private mDontRun As Boolean
Change your button click event handler body to be like this:
mDontRun = True
ListBox1.SelectedIndex = 0
mDontRun = False
And add to the selectedindexchanged event handler the following as the first line:
If mDontRun = True Then Return
2) The alternative is not to declare a boolean, not to change the selectedindexchanged event handler and simply change the button click method body like this:
RemoveHandler ListBox1.SelectedIndexChanged, _
AddressOf ListBox1_SelectedIndexChanged
ListBox1.SelectedIndex = 0
AddHandler ListBox1.SelectedIndexChanged, _
AddressOf ListBox1_SelectedIndexChanged
Simple really... and one more entry I can point to from the ng...

Labels:


Monday, February 28, 2005

 

It is amazing how many requests in the newsgroups are something like
"...I have this C# code I need to translate to VB..."
Occasionally we get requests for translating VB to C# and the same principle applies.

If you really need to translate the code, *please* learn how to at least read the other language: it will make you a better .NET developer, guaranteed. There are many sites that list the differences and there are many converters for VB-to-C# or for C#-to-VB or both.

However, if you just picked up a C# file and you need to use it from your VB project you can do just that by adding it to a dll first. Given that the advice leads to more "how to" questions (believe me it does!), here are the steps needed to achieve just that:

1. Create New C# Smart Device project (not for Full Fx)
2. From the wizard select the target and then Class Library. Choose a suitable name and location.
3. Delete the default file Class1.cs
4. Project->Add Existing Item (from the menu)
5. Navigate to the folder where you have saved/downloaded your C# file. Open the file (which makes a copy to the project's directory) or Link to it (which allows you to use it in the project but only keeps one copy on disc)
6. Double-click in solution explorer to view the file. Note the namespace declaration at the top (e.g. namespace OpenNETCF.IO). Optionally change it to the name of your project.
7. Repeat steps 5-6 for any other files
8. Build->Rebuild Solution
9. You now have a dll in the bin\Debug directory under the project you just created

From your exe/application project select from the menu Project->Add Reference and browse to the dll; Select it and OK.

Labels:


Wednesday, February 16, 2005

 

Dim i As Int32
Dim k As Int32 = mCol.Count
For i = 0 To mCol.Count - 1
Me.MethodThat_May_ResultInRemovalFromCol()

If k > mCol.Count Then
i -= 1
k = mCol.Count
End If
If k <= i + 1 Then
Exit For
End If
Next i
Years ago I upgraded some nasty VB6 code that, amongst other things, used the Collection class. The VB.NET Collection object allows removals from it while iterating. If you upgrade it to ArrayList, though, (apart from making changes to reflect the 0 index base), you soon find that ArrayList forbids removing items while iterating. At the time I came up with the above smelly hack. Due to recent refactorings the design/code has been modified, so I am capturing the hack here for posterity...

PS I upgraded Collection to ArrayList for performance reasons
PS2 Locking the collection is irrelevant here
PS3 I am aware of Synchronized - I don't like it
PS4 The real solution is not to remove while iterating; it is bad design.

Labels:


Wednesday, January 12, 2005

 

This is a repost. The content appeared orginaly here, but I thought it deserved a post on its own rather than being at the bottom of an off (the main) topic entry.

[..] a demo I saw Don Box deliver at Tech Ed 2001 (in VB6) and TechEd 2004 (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
Dim crh As CorRuntimeHost

Dim ad As AppDomain
Dim oh As ObjectHandle
Dim o As Object
Stop

5. Run->Start. The IDE breaks so you are in the debugger. View->Immediate Window
6. In the Immediate Window, type the following (line by line hitting return, don't just copy/paste)
Set crh = New CorRuntimeHost

crh.Start
crh.CurrentDomain ad
Set oh = ad.CreateInstance("mscorlib", "System.Collections.Stack")
Set o = oh.Unwrap
o.Push "Rocks"
o.Push "NET "
o.Push "."
MsgBox o.Pop & o.Pop & o.Pop

That's it! You've just used a .NET Stack class in VB6 by hosting the runtime.

Labels:


Friday, December 03, 2004

 

Top 10 Things to be thankful for in .NET

Check out number 9

Labels:


Thursday, November 18, 2004

 

Maximizing .NET Performance

.NET Framework Tour from a Performance Perspective - 4stars

There are no other books on .NET Performance so, when this one fell in my hands, it put a smile on my face (sad, I know). When I got to the end, I was not disappointed. Around 250 well-written pages over 15 chapters and, as you'd expect, you can delve into it in random order, making it a good reference book. Even so, I read it cover to cover. The first two chapters lay the ground; the last chapter provides generic advice on troubleshooting and the 12 chapters in-between focus on specific .NET areas: a framework tour from a performance perspective. Naturally, a subject of this nature assumes the reader has some .NET experience and targets the Intermediate/Advanced level.

Don't expect material on GUI (Windows.Forms), Database (ADO.NET) and Web (ASP.NET); rather a discussion on elements that every application is built on (Type design/implementation, Strings/Text/RegEx, Collections, Language Specifics, GC & Object Lifetime, Exceptions, Security, Threading, IO/Serialisation, PInvoke, CLR). I challenge you to find a chapter that does not teach you at least one thing you were unaware of before. We have to sum it up with the great technical phrase: "It is all great stuff".

There are no axioms presented, and readers expecting a "cookbook" will be disappointed. Every claim is backed up with a reference to a testcase and even then, only after we have delved under the covers to see *why* something is slow or *how* a change makes something faster. By taking this approach, the reader should be able to repeat the investigation/tests for newer/other versions of the framework. So, having just mentioned how there is a cross-reference to specific testcases, I have hinted at what is one of the best contributions of this book: A .NET Benchmark Test Harness. This is described in the appendix of the book and the code/binaries can be obtained from the publisher's site.

Now how about something like this for the Compact Framework?

Labels:


Monday, November 15, 2004

 

Almost two years ago I was asking why VB adds extra IL lines in try catch situations compared to C#. I got an unsatisfactory answer. Now, someone that seems to agree with my sentiments blogs about it. Cool!

Labels:


Thursday, November 11, 2004

 

Sometimes we write code that uses polling. A brief example of that is some method/routine that runs on a timer (e.g. every 5 seconds), reads new entries from a file/database and performs some operation based on the input - and repeates this cycle until we stop the timer.

Although there are valid scenarios for taking the approach described above, there are others where it is a sub-optimal solution. For example, if you need to know as soon as there is a new entry to process, then there is no point waiting for your timer's tick; conversly, if there are no new items to process then there is no point running the function. A similar (equally not good) alternative is instead of running a timer to make the thread sleep for a while.

So in those case where the 2 aforementioned similar solutions are not the best, what is the correct way? Use a thread! The following code shows you an example of how. Note that I use this technique with the Compact Framework so, for example, we need the extra boolean to tell the thread to kill itself/exit since the CF 1.0 threads are missing many properties that could help (e.g. IsBackground, Abort etc).

        // declarations
        private Thread mSendNextThread;            // worker thread
        private bool mStayAlive;    // for controlling the thread termination
        private Queue mQue;                        // buffer of jobs
        private ManualResetEvent mWaitEvent;// signal the thread to wake up
 
        // Initialisation logic
        public void Start(){
            Console.WriteLine("*********");
            Console.WriteLine("Start");
            mQue = new Queue();
            mWaitEvent = new ManualResetEvent(false);
            mStayAlive = true;
            mSendNextThread = new Thread(new ThreadStart(OnMyOwnThread));
            mSendNextThread.Start();
        }
 
        // Tear down logic
        public void Stop(){
            Console.WriteLine("Stop request");
            lock (mQue.SyncRoot){
                mQue.Clear();
 
                // kill the thread
                mWaitEvent.Reset();
                Thread.Sleep(10);
                mStayAlive = false;
                mWaitEvent.Set();
                Thread.Sleep(10);
                mSendNextThread = null;
            }
            Console.WriteLine("Stopped");
        }
 
        // queue more jobs
        public void MoreInput(object someInput){
            Console.WriteLine("More Input: " + someInput.ToString());
            lock (mQue.SyncRoot){
                mQue.Enqueue(someInput);
            }
 
            mWaitEvent.Set();
        }
 
        // process jobs
        public void OnMyOwnThread(){
            while (mStayAlive){
                if (mWaitEvent.WaitOne()){
 
                    mWaitEvent.Reset();
                    while (mQue.Count > 0){    //Whether we do the looping depends
                                            //on the specifics of DoWork
                        if (!mStayAlive){
                            break;
                        }
 
                        this.DoWork2();
                        mWaitEvent.Reset();
                    }
                }
            }
            Console.WriteLine("Thread exiting");
        }
 
        private void DoWork2(){
            object queObj = null;
            lock (mQue.SyncRoot){
                if (mQue.Count > 0){
                    queObj = mQue.Dequeue();
                }
            }
 
            // do some long processing with this job/input
            if (queObj != null){
                Console.WriteLine("Processing: " + queObj.ToString());
                Thread.Sleep(300);//LONG PROCESSING
                Console.WriteLine("Processed " + Environment.TickCount.ToString());
            }
        }

Labels:


Friday, October 01, 2004

 

It should be a well known fact by now that, when in need to updade controls created on the GUI thread, you must use Control.Invoke (call the thread-safe static Invoke method on any control, e.g. the Form). It should be but, judging at how often this comes up in the newsgroups, it's not.

The issue and solution are the same for both full and compact frameworks; the difference is that, although the desktop seems to be forgiving (sometimes updating from non-GUI thread works), the CF certainly isn't: every time you try it, the result is an application that is hung/frozen/locked up. If you see this on your device, start looking for the said problem.

Of course, like almost every other area of the CF, Control.Invoke support is limited. It is limited in 3 areas:

1. You cannot pass any delegate you want to Invoke; rather, you can only use the EventHandler. So, if you were hoping on using the efficient MethodInvoker or one of your own, forget about it.

2. Invoke cannot be used to pass arguments. So, you can marshal control from a thread to the GUI thread, but you cannot pass any parameters in the same call.

3. BeginInvoke is not supported. So, you can only do it synchronously (your non-GUI thread does not return until the Invoked method itself completes).

A solution to the 2nd limitation is to write code like this:

Private mDataQue As New Queue
Private mUpdateDel As New EventHandler(AddressOf UpdateBox)

' This method runs on a non-GUI thread e.g. Threading.Timer
Friend Sub OnNonGuiThread(ByVal o As Object)
' if you have more than one argument
' create an object or structure
' that holds the data you want to pass to the GUI thread
SyncLock mDataQue.SyncRoot
mDataQue.Enqueue(o)
End SyncLock

' assuming all this code is in a form
Me.Invoke(mUpdateDel)
End Sub

' This method runs on GUI thread
Private Sub UpdateBox(ByVal sender As Object, ByVal e As EventArgs)
Dim o As Object
SyncLock mDataQue.SyncRoot
If mDataQue.Count > 0 Then
o = mDataQue.Dequeue()
End If
End SyncLock

' TODO use o
' cast o to your object/structure and
' use it to update the GUI
End Sub


The 3rd limitation can be overome simply by using the threadpool. Extend the previous solution with:

' NOW, *this* is the method that runs on non-GUI thread
' e.g. Threading.Timer
' The original method is now just a helper
Public Sub OnNonGuiThread2(ByVal o As Object)
ThreadPool.QueueUserWorkItem(AddressOf OnNonGuiThread,o)
End Sub


We look at what Whidbey brings to the table next time.

Labels:


Thursday, September 30, 2004

 

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.

Labels:


 

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.

Labels:


Wednesday, September 29, 2004

 

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 we saw how C# is catching up with VB previously.

Here (in random order) is what VB is getting tomorrow, which C# already has today
1. unsigned types
2. using statement
3. custom events
4. operator overloading
5. continue statement
6. XML documentation comments
7. pre- post-build steps
8. static methods only accessible on class - not instance
9. hooking into control events from the props window
10. TryCast

Naturally they both get some of the top features of .NET 2.0
11. Generics
12. nullable types
13. accessor accessibility
14. advantage of code snippet technology


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.

C# devs don't want My, but they sure are screaming about EnC.

Labels:


Tuesday, September 28, 2004

 

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

5. Declare namespaces in code. So, delete the "root namespace" from Project->Properties->General

6. Use Return X instead of FunctionName = X, PropertyGetname = X, Exit Sub/Function/Property

7. Use overloading instead of optionals.

8. In conditions, instead of stringA = stringB, use String.Equals(stringA, stringB).

9. Don't use modules. If you need the functionality they offer, just use Static (Shared)Classes.

10. Use DllImport, not Declare

11. Understand WithEvents and Handles and what they generate for you in IL. Use the alternative AddHandler/RemoveHandler where appropriate.

12. Understand CType, DirectCast and Convert.ToXxx methods and use them instead of CInt/CXxx, unless you really need the extra functionality the latter provide.

13. When exposing .NET classes to COM, don't use the ComClassAttribute

14. Don't use Microsoft.VisualBasic.Compatibility (this is different to the Microsoft.VisualBasic.dll)

15. Consider very carefully which namespaces you need imported globally (Project->Properties->Imports).

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].

18. When doing release builds, check the "Remove Integer Overflow Checks" (and the other one)

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.

As always, rules are there for the breaking :-)

Labels:


Sunday, September 26, 2004

 

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:

Namespaces, assemblies
Properties
Reference types vs ValueTypes (boxing/unboxing)
String
Attributes
Exception Handling
Delegates and Events
Threading
GC (and the dispose pattern)
Reflection [+ you must know how to use ILDASM or some other decompiler]
Versioning and deployment

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).

[1] more on language choice in the coming days

Labels:


 

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).

Labels:


Monday, September 06, 2004

 

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).

Another answer is PInvoke. In other words, use the traditional Win32 APIs in the .NET app. There are a number of good MSDN pages on the subject including:
1. Serial Communications in Win32
2. Programming Serial Connection on WinCE

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.

Labels:


Thursday, August 19, 2004

 

Read the first two parts here and here.

.NET 2.0 fixes the problem with exceptions being swallowed on background threads (based on the VS2005 Beta 1).

When global exception handling is not present, unhandled exceptions on background threads will result in the app either exiting or JIT debug window appearing (based on the reg entry mentioned previously - on my VS2005 Beta 1 installation, the registry entry has the decimal value of 10 so there are clearly more options added in this area; but sorry, I just don't know more about them).

When global exception handling is present, the same rules as today apply, except we also get to see the JIT debugging window before our catch code runs(!). I guess this is for helping us on our dev machines, since by changing the reg entry to 1 the JIT debugging dialog does not appear (phew :-)

UPDATE: The CF 2.0 story is better with the November CTP compared to the Beta 1 story below.

With the CF 2.0, there is still no support for Application.ThreadException or AppDomain.UnhandledException, but the story gets better with try..catch around the main entry point. Basically the bug has been fixed, so the app will not freeze in the Control.Invoke scenario. To recap, if you try..catch the Appliccation.Run then you have two scenarios with CF 2.0:
1. Exceptions on the GUI thread are caught [just as in CF 1.0]
2. Exceptions in other threads (including the Control.Invoke scenario) are caught, BUT before your catch code runs the built-in dialog still appears!

This is the same behaviour with the full Framework (when we use global exception handling) with one major difference. On the desktop we can change the registry setting to override that behaviour - with the CF there is no way that I know of to suppress the built-in dialog :-( Let's hope this situation changes by release time...

Labels:


Sunday, August 15, 2004

 

We should be trapping possible exceptions in various places with the try..catch mechanism, but all software contains bugs and so will your code; in that scenario you still want to catch the exception (log it, present custom GUI to user, etc). To do this on the full Framework 1.1 we use a try..catch around the entry point (typically Application.Run), hook into System.Windows.Forms.Application.ThreadException (for GUI thread exceptions) and hook into AppDomain.CurrentDomain.UnhandledException for other thread exceptions. We need to perform all 3 actions.

There is a good article on the subject in June's edition of MSDN Magazine on the above, go read it.

To finish the desktop story, check out the registry entry described here. Note that, if there is no global error handler mechanism, any exceptions on background threads are swallowed if not explicitly caught. This means the application does not exit or put up a JIT debugging window, it just continues running in whatever state it is in!

Next time we'll look at how things are different with the Compact Framework.

Labels:


Copyright © Daniel Moth