Wednesday, January 24, 2007

DataGridView and unbounded mode

New DataGridView control in .NET 2.0 is a complex and very useful control. Grids are generally very useful for displaying large amount of data in a constrained screen space.

Like many other Windows Forms controls, DataGridView can operate in a data bound or unbounded mode. When unbound, client can manipulate rows and cells directly, while in data bound mode control operates according to a well-known Model-View paradigm, where changes to data (model) are automatically reflected by the control (view).

In my case, view did not map directly to the data I was trying to show in DataGridView, and so initially I opted for unbounded mode. I was trying to implement hierarchical views (which are unsupported by default in DataGridView), and also mix and match data types that appear in grid's rows. And so unbounded mode seemed like a good idea.

Not less than a week into implementation I have discovered that operating in this mode is insufficient for my needs. For one, I could not detect an event before a row is deleted, only after deletion took place. Since I was storing helper objects in the row's Tag property, I was not able to run special code on row deletions. In addition, because I was operating on DataGridView directly, it meant that my row-handler objects had to operate on the grid directly, which creates somewhat inter-dependent code (model that knows about view!).

The point of this post is that I switched back to data bound mode and never looked back (although it tooks some time to refactor existing code)! The key to making this work is to make an intermediary model, which models the rows in the grid. I made a class that inherits from BindingList and made it responsible for manipulating row-handler objects. Then DataGridView can be bound to that list, and all changes in the list are reflected in the grid.

Monday, December 04, 2006

Less MSIĆ©rables

Yeah, I thought it was a clever name too ... :) This is a little but very useful utility, with a great feature that allows to peek inside an MSI package and extract files out of it. Now, I found it useful at times when I needed to grab individual files out of an MSI without the need to install the whole product.

Get it here: http://blogs.pingpoet.com/overflow/archive/2005/11/16/14995.aspx

VS2005 debugger - unable to resolve a symbol

VS2005 is a lot better then its predecessor in guessing what exactly do you mean when typing an expression into Watch window (or the cool Immediate view - try it if you havent used it before!). It will correctly evaluate all the variable references, and will even let you execute methods and see their results (but watch out for side-effects, if method modifies some data).

Occasionally, however, it will complain that it cannot find the symbol you are referring to. This can be rather frustrating, but there are actually a few things to try to resolve this successfully:

1) If you are using namespaces, type the fully qualified name, starting with the top namespace, e.g. MyNamespace::SubNamespace::blah. Sometimes VS2005 gets confused with the "using namespace" directives - but to be fair, most of the time its pretty good at it. This works 99% of the time.

2) Some constructs actually do not have proper C++ syntax to get to them, like local struct/class definitions. Last resort is to get a mangled name from the map file, and use that - VS2005 understands it as well.

3) Finally, be creative - there are usually several ways to get to a certain variable or method. If all fails, you can quickly write a dummy method which you can call from debugger, but this is rarely necessary.

Vista UAC privelege elevation

No doubt everyone has already seen UAC in action, and the privilege elevation prompt - the one that grays out the whole screen and asks whether user wants to continue with the operation that requested such elevation.

Well, just be aware that legacy means for launching external processes within your application no longer work (well they do work, if new process does not require higher privileges). For example, CreateProcess will return a new error code ERROR_ELEVATION_REQUIRED, if the external process application is trying to launch requires higher privileges.

According to Microsoft, we must now use ShellExecuteEx (or ShellExecute), with lpVerb = "open". This will correctly prompt user with the new Vista elevation UI.

Here's a link to Vista compatibility team blog talking about this: http://blogs.msdn.com/vistacompatteam/archive/2006/10/02/Elevation-and-process-creation-APIs.aspx

Note:My comment about using lpVerb = "open" relates to the fact that "open" is the default verb and is normally used to launch .exe files. According to the blog, you can also use a "runas" verb, to force privilege elevation regardless of the .exe manifest, but I personally wouldn't do that unless it was absolutely necessary - we should let target process determine (via manifest) whether it needs special privileges or not.

C++ Name Mangling/Demangling

Before you say anything, yes I know, mangling is compiler specific and can change with each compiler version. But for purposes of debugging it is sometimes useful to decipher function signature from linker's outptut.

We already know that DBGHELP.DLL provides a function UnDecorateSymbolName. Just came across this page on the net, with links to various mangling/demangling resources and a comprehensive reverse engineering summary of Microsoft C++ compiler name mangling.

Hope this is useful to someone.

Swapping values without temporary variable

Just ran across it while browsing for something else, and I think it's pretty cool... in a useless kind of way! (Also I think I saw this once before, but can't remember when...) template <class T> inline void swap (T& x, T& y) { x = x ^ y; y = x ^ y; x = x ^ y; } Of course, it will only work with primitive types, for which operator^ is well defined!

Saturday, November 05, 2005

ASP.NET without JavaScript

It is possible, contrary to popular belief... asp.net without JavaScript

Saturday, October 15, 2005

Spring.NET - Application Framework

Check out the .NET version of the popular Spring framework. In short, Spring is a framework that allows your application to be highly configurable by using IoC (Inversion of control) principles, such as Dependency Injection. That is the heart of the framework. Framework also provides quite a few other goodies, such as ADO.NET helpers, threading utils, pooling. It is built to support Aspect-oriented programming, so most of the features require little changes to existing code. As of now, a preview of version 1.1 is available for download. Version 1.1 includes Spring.Web package, which is a set of features to simplify ASP.NET development by using Spring. It is really great, check it out! Here's a some of the features offered: master pages, bidirectional data binding, dynamic page navigation, a better way of writing web services.

Friday, October 07, 2005

XmlSerializer bug when "xsi:type" is used in the XML

There’s a subtle bug in the .NET Framework v1.1 that I have just uncovered. Firstly, a little background into the issue, which is related to .NET XML serialization.

Consider following XML (later assumed to be in a file “text.xml”):

<?xml version="1.0" encoding="utf-8" ?> <Test>  <Persons xmlns=”http://tempuri.org/” xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance”>   <Person xsi:type=”Male”>    <Name>Jeff</Name>    <FavouriteBeer>Monteith</FavouriteBeer>   </Person>   <Person xsi:type=”Female”>    <Name>Jessica</Name>    <FavouriteNailpolish>Revlon</FavouriteNailpolish>   </Person>  </Persons> </Test>

This would have been produced if you serialize the object of type Test, defined in the following code fragment:

[XmlIncludeAttribute(typeof(Male))] [XmlIncludeAttribute(typeof(Female))] [XmlTypeAttribute(Namespace=”http://tempuri.org/”)] public class Person {   public string Name; } [XmlTypeAttribute(Namespace=”http://tempuri.org/”)] public class Male : Person {   public string FavouriteBeer; } [XmlTypeAttribute(Namespace=”http://tempuri.org/”)] public class Female : Person {   public string FavouriteNailpolish; } [XmlTypeAttribute(Namespace=”http://tempuri.org/”)] [XmlRootAttribute(Namespace=”http://tempuri.org/”)] public class Test {   public Person[] Persons; }

The problem is that now you would not be able to deserialize the XML, if you write code similar to following:

XmlDocument doc = new XmlDocument(); doc.Load( “test.xml” ); XmlSerializer serializer = new XmlSerializer( typeof( Test ) ); Test test = (Test) serializer.Deserialize( new XmlNodeReader( doc ) );

And this is due to a bug in the XmlNodeReaderclass. I uncovered it only by stepping through the temporary serialization assembly generated by .NET framework. Without going into more detail, it is because LookupNamespace method does not return a canonical string from the reader’s NameTable. So the reference equality on the namespace inside the generated reader fails, and you get an exception similar to:

“The specified type was not recognized: name='Male', namespace='http://tempura.org/', at <Person xmlns='http://tempuri.org/'>.”

Fixing the problem is quite easy. All we have to do is write a class which extends from XmlNodeReader, and override the LookupNamespace method:

public class ProperXmlNodeReader : XmlNodeReader {   public ProperXmlNodeReader( XmlNode node ) : base( node )   {   }   public override string LookupNamespace(string prefix)   {     return NameTable.Add( base.LookupNamespace( prefix ) );   } }

Then you can use the ProperXmlNodeReader instead of the XmlNodeReader in the above example, and you should be able to deserialize the above XML with no problems.