Thursday, July 02, 2009
Labels: dot NET general
Tuesday, May 19, 2009

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: dot NET general
Friday, April 24, 2009
Labels: dot NET general
Thursday, April 23, 2009
Labels: dot NET general
Monday, April 06, 2009
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: dot NET general
Wednesday, December 03, 2008

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: dot NET general
Sunday, September 21, 2008

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: dot NET general
Sunday, September 14, 2008
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: dot NET general
Monday, September 01, 2008
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: dot NET general
Thursday, August 28, 2008
Labels: dot NET general
Tuesday, August 26, 2008
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: dot NET general
Tuesday, July 29, 2008
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: dot NET general
Tuesday, May 27, 2008

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: dot NET general, Silverlight
Monday, May 19, 2008
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: dot NET general, Silverlight
Tuesday, May 06, 2008
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 =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).
from ia in XElement.Parse(e.Result).DescendantsAndSelf("ItemAttributes")
select ia.Element("Title").Value;
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()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:
{
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;
}
Dim res = _...and if you are wondering where the
From ia In XElement.Parse(e.Result)...<n:ItemAttributes> _
Select ia...<n:Title>.Value()
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: dot NET general, LINQ
Friday, February 29, 2008
For those of you that can't get a hard/physical copy, they have kindly made it available online for your reading pleasure.
Labels: dot NET general, ParallelComputing
Thursday, December 20, 2007
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)Note on the above:
{
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);
}
}
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: dot NET general, Mobile and Embedded
Tuesday, December 18, 2007
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: dot NET general
Monday, December 17, 2007

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: dot NET general
Sunday, December 16, 2007
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: dot NET general
Saturday, December 15, 2007
void button1_Click(System.Object sender, System.EventArgs e)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).
{
// 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;
}
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: dot NET general, UAC, Vista
Friday, December 14, 2007
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: dot NET general
Wednesday, December 12, 2007
Labels: dot NET general
Sunday, December 09, 2007
+ Parallel LINQ.
+ Parallel class and friends.
+ TaskManager, Task, Future and friends.
Labels: dot NET general
Friday, November 30, 2007
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: dot NET general, ParallelComputing
Thursday, November 29, 2007
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: dot NET general
Wednesday, November 28, 2007
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: dot NET general
Wednesday, October 03, 2007
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: dot NET general
Monday, October 01, 2007
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: dot NET general
Friday, September 21, 2007
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...where
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.");
}
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: dot NET general, ParallelComputing
Wednesday, May 16, 2007
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: dot NET general
Sunday, February 18, 2007
Sub MainIn 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.
myVariableName = 6
myVariableName = myVariableNmae + 1
Debug.WriteLine(myVariableName)
End Sub
Another bad thing you could do in VB6 still remains today and that is the ability to declare untyped variables, for example:
Sub MainEffectively, 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.
Dim myVariableName = 6
myVariableName = myVariableName + 1
myVariableName = "hello"
Debug.WriteLine(myVariableName)
'
Dim o
o = New Collection
o.FeelingLucky
End Sub
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: dot NET general
Monday, January 01, 2007
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: dot NET general, Links, Mobile and Embedded, Vista
Monday, December 11, 2006
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: dot NET general
Thursday, October 05, 2006
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: dot NET general
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: dot NET general
Wednesday, October 04, 2006
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: dot NET general
Thursday, September 28, 2006
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: dot NET general
Monday, July 03, 2006
"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()we write:
{
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;
}
void SomeMethod()...after extracting the following class:
{
using (BusyTaskRegion bt = new BusyTaskRegion(statusBar1, button1))
{
// do some real work here
}
}
class BusyTaskRegion : IDisposableAnother 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!).
{
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;
}
}
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: dot NET general
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();The using statement makes that cleaner, easier to remember and easier to enforce like this:
try
{
st.DoSomething();
}
finally
{
st.Dispose();
}
using (SomeType st = new SomeType())So, the easy way to describe the purpose of
{
st.DoSomething();
}
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: dot NET general
Sunday, November 13, 2005
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
Labels: dot NET general
Sunday, July 31, 2005
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 managed3. Just so you can see the IL for a C# version compiled under Visual Studio 2005 Beta 2, here is some code:
{
// 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
private ArrayList ar = new ArrayList();...and equivalent IL:
public void Box() {
ar.Add(5);
}
public void Unbox() {
int i = (int)ar[0];
}
.method public hidebysig instance void Box() cil managedBy 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
{
// 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
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: dot NET general
Monday, May 30, 2005
Dim b As Boolean 'b is already initialised to FalseIn 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()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 :-).
Dim i As Int32
i = GetANumber()
End Sub
Public Sub CsStyle()
Dim i As Int32 = 0
i = GetANumber()
End Sub
Here is the corresponding IL:
.method public instance void VBStyle() cil managedNeedless to say that the C# version closely reflects the first version (it is even better, since it uses a
{
// 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
call rather than a callvirt - but that is a different story...).Labels: dot NET general
Tuesday, May 10, 2005
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: dot NET general
Wednesday, March 16, 2005
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 EntryPointThe 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.
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
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()Add a Animal class module:
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 Mouse class module:
Public Sub Bite()
End Sub
Implements AnimalAdd a Shark class module:
Private Sub Animal_Bite()
MsgBox "Disease"
End Sub
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: dot NET general
Friday, March 04, 2005
"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, _And let's assume as part of a button click you are doing something like this:
ByVal e As System.EventArgs) Handles ListBox1.SelectedIndexChanged
MessageBox.Show(ListBox1.SelectedItem.ToString())
End Sub
Private Sub Button1_Click(ByVal sender As System.Object, _When you click the button you don't want to see a messagebox.
ByVal e As System.EventArgs) Handles Button1.Click
ListBox1.SelectedIndex = 0
End Sub
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 BooleanChange your button click event handler body to be like this:
mDontRun = TrueAnd add to the selectedindexchanged event handler the following as the first line:
ListBox1.SelectedIndex = 0
mDontRun = False
If mDontRun = True Then Return2) 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, _Simple really... and one more entry I can point to from the ng...
AddressOf ListBox1_SelectedIndexChanged
ListBox1.SelectedIndex = 0
AddHandler ListBox1.SelectedIndexChanged, _
AddressOf ListBox1_SelectedIndexChanged
Labels: dot NET general
Monday, February 28, 2005
"...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 Solution9. 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: dot NET general
Wednesday, February 16, 2005
Dim i As Int32Years 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...
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
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: dot NET general
Wednesday, January 12, 2005
[..] 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: dot NET general
Friday, December 03, 2004
Thursday, November 18, 2004
.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: dot NET general
Monday, November 15, 2004
Labels: dot NET general
Thursday, November 11, 2004
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).
// declarationsprivate 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 logicpublic 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 logicpublic 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 jobspublic void MoreInput(object someInput){
Console.WriteLine("More Input: " + someInput.ToString());
lock (mQue.SyncRoot){
mQue.Enqueue(someInput);}
mWaitEvent.Set();}
// process jobspublic void OnMyOwnThread(){
while (mStayAlive){if (mWaitEvent.WaitOne()){
mWaitEvent.Reset();while (mQue.Count > 0){ //Whether we do the looping depends
//on the specifics of DoWorkif (!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/inputif (queObj != null){
Console.WriteLine("Processing: " + queObj.ToString());
Thread.Sleep(300);//LONG PROCESSING
Console.WriteLine("Processed " + Environment.TickCount.ToString());
}
}
Labels: dot NET general
Friday, October 01, 2004
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: dot NET general
Thursday, September 30, 2004
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: dot NET general
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: dot NET general
Wednesday, September 29, 2004
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: dot NET general
Tuesday, September 28, 2004
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: dot NET general
Sunday, September 26, 2004
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: dot NET general
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: dot NET general
Monday, September 06, 2004
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: dot NET general
Thursday, August 19, 2004
.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: dot NET general
Sunday, August 15, 2004
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: dot NET general
Copyright © Daniel Moth


