One of the more annoying aspects of writing Windows applications using the .NET Framework is that eventually you brush up against the limitations in the APIs provided by the managed classes and end up having to use interop to talk to Win32 or COM-based APIs. This process typically involves exposing native code in a manner that makes them look like managed APIs when in fact they are not. When there is an error in this mapping it results in hard-to-track memory corruption errors. All of the fun of annoying C and C++ memory corruption errors in the all new, singing and dancing .NET Framework.

Most recently we were bitten by this in RSS Bandit and probably would never have tracked this problem down if not for a coincidence. As part of forward compatibility testing at Microsoft, a number of test teams run existing .NET applications on current builds of future versions of the .NET Framework. One of these test teams decided to use RSS Bandit as a test application. However it seemed they could never get RSS Bandit to start without the application crashing almost instantly. Interestingly, it crashed at different points in the code depending on whether one compiled and ran the application on the current build of the .NET Framework or just ran an executable compiled against an older version of the .NET Framework on the current build. Bugs were filed against folks on the CLR team and the problem was tracked down.

It turns out that our declaration of the STARTUPINFO struct obtained from PInvoke.NET was incorrect. Specifically the following fields which were declared as

 [MarshalAs(UnmanagedType.LPWStr)] public string  lpReserved;
 [MarshalAs(UnmanagedType.LPWStr)] public string  lpDesktop;
 [MarshalAs(UnmanagedType.LPWStr)] public string  lpTitle;

were declared incorrectly. We should have declared them as

public IntPtr lpReserved; 
public IntPtr lpDesktop; 
public IntPtr lpTitle;

The reason for not declaring them as strings is that the Interop marshaler, after having converted the string to a managed string, will release the native data using CoTaskMemFree. This is clearly not the right thing to do in this case so we need to declare the fields as IntPtrs and then manually marshal them to strings via the Marshal.PtrToStringUni() API.

The problems with errors that occur due to such memory corruption issues is that their results are unpredictable. Some users may never witness a crash, while others witness the crash when their machines are under memory pressure or in some cases it crashes right away. Of course, the crash is never in the same place twice. Not only do these problems waste lots of developer time trying to track them down they lalso lead to negative user experience with the target application.

Hopefully, when Longhorn ships and introduces WinFX this class of problem will become a thing of the past. In the meantime, I need to spend some time going over our code that does all the Win32 interop to ensure that there are no other such issues waiting to rear their head.


 

Sunday, June 6, 2004 9:23:59 AM (GMT Daylight Time, UTC+01:00)
I just spent Friday writing pInvoke stuff to swap user contexts. Between that, and the mess that's WMI things could be made a lot simplier. The framework still seems quite immature (I ran aginst lack of TimeZone support last week, having to call the J# libraries is just not right).

Having to wait for LongHorn and WinFX? That's just not right. There's no realy excuse for it when Whidbey will be there next year, and thus a new version of the framework arrives. Add in that ObjectSpaces will not be along until Longhorn either and I'm rather peeved that those of us who aren't going to aim their code at a beta install base are being left behind.
Thursday, June 10, 2004 10:51:40 PM (GMT Daylight Time, UTC+01:00)
An anomaly I have noticed in two of my .NET based RSS readers (Sharp and RSSBandit) They will both only run maximized. Any attempt to make them 'normal' sized fails. So if I click the middle system buton on the LHS of the taskbar, it will instantly minimize the app. Mazimizing it brings it back and functionaing normally. There are no desktop helper, add-ons or other utilities running.

RSSBandit and SharpReader are the only managed apps on my system that behave that way. The only thing in common I can figure out is that they are both managed and are RSS readers.

Any ideas?
Saturday, June 12, 2004 10:51:53 PM (GMT Daylight Time, UTC+01:00)
Out of curiosity do you know if the Adam Nathan's CLR Spy catches this particular problem?
Comments are closed.