January 2008 - Posts

Is C++/CLI a Second Class Language with Microsoft?

The post frequency on the Visual C++ team blog is reasonably high. Some posts deal with new features that were added to VC++ 2008.

But, is Visual C++ a second-class citizen in the Visual Studio product group?  Recently the Visual Studio 2008 Product Comparison was released (don't ask me why it wasn't released at the same time as the products...).  In the product comparisons VC++ Express has an inordinate number of features that only it doesn't have.  When you look at the Visual C++ 2008 Express Edition product sites, it seems pretty clear that it's geared towards native-only software development.  Despite this the product comparison shows VC++ Express has Managed Debugging, Mixed-Mode Debugging and Compiler Support for any CPU (which details "...compile your managed application...").  But, VC++ 2008 Express is the only edition that doesn't support adding reference to WCF services ("Service Reference"), Code Snipped Manager, Code Snippets, Rename Refactoring, Text File (you can't create a plain text file with VC++ 2008 Express?), and one of two editions that doesn't include support for XML File (create a blank XML file), and SQL Server 2005 Compact Edition.  As well, only VC++ 2008 doesn't include managed-only features like Object Browser, Object Relational Designer, and SQLMetal (the last two deal with .NET-only LINQ-to-SQL.

C++ has stagnated as a language for quite some time, but Visual C++ 2008 includes new language features like C++0x and TR1 that help evolve the language for the parallel future.  But, despite assurances that native development is still a focus at Microsoft, there is the appearance that VC++ just isn't getting the same resources as the other editions.  Makes you wonder how much longer will Microsoft keep it in the Visual Studio family...

"Object is currently in use elsewhere" error.

I was debugging what I thought was a strange exception the other day.  The exception was an InvalidOperationException and the message was "Object is currently in use elsewhere".  Unless you're familiar with this exception, it really doesn't offer much as to why the exception is occurring.  There seems to be several stale threads on the Web about this issue, so I'd thought I'd post about it.

As it turns out it had to do with some code that was PInvoking some native graphics functions and the interaction with the WinForm that was hosting the drawing surface was to blame.

What's really happening with "Object is currently in use elsewhere" is that GDI+ is complaining that the device context (DC) that it is trying to use is already "in use".  With WinForms, this generally means there is a recursive Graphics.GetHdc occurring.  GetHdc must match a ReleaseHdc before any other GetHdc.  Recursive means you have something like GetHdc->GetHdc->ReleaseHdc->ReleaseHdc, instead of GetHdc->ReleaseHdc->GetHdc->ReleaseHdc.  Another possibility is that there is a missing call to ReleaseHdc. (i.e. GetHdc->GetHdc->ReleaseHdc)

Now, in my case there was some seemingly innocuous code like this:

    SafeNativeMethods.DrawSomeStuff(e.Graphics.GetHdc(), parameters);

    e.Graphics.DrawString(text, this.Font, Brushes.Black, point);

...no matching ReleaseHdc(), before the DrawString call.

The fix turned out to be really simple:

    try

    {

        SafeNativeMethods.DrawSomeStuff(e.Graphics.GetHdc(), parameters);

    }

    finally

    {

        e.Graphics.ReleaseHdc();

    }

    e.Graphics.DrawString(text, this.Font, Brushes.Black, point);

You can also encounter this exception if you're drawing to a form from multiple threads.  You'll likely also be encountering a cross-threading exception as well.  The solution in this case is to not use multiple threads when accessing a form, including drawing.

Formatting/parsing for a specific culture redux

In recent blog post I detailed how creating a culture via the CultureInfo constructor could actually create a user-overridden culture--which could be completely different than the culture that you've requested by name.  Fortunately there's a way of overriding the user override (apologies for overloading "override") by supplying the boolean value "false" in a CultureInfo overload.

As Greg Beech commented, there's another method to create a culture--System.Globalization.CultureInfo.CreateSpecificCulture.  This sounds like it does exactly what you might expect and creates a "specific" culture.  Unfortunately, this method too violates the principle of least astonishment and creates a culture that uses the user-overridden values when the culture name matches that of the user's current culture.

CreateSpecificCulture does not, as far as I can tell, have an overload/alternative to you allow to to force a "specific" culture, so the problem is much worse with CreateSpecificCulture.  I've gone ahead and logged a bug for it on Connect: https://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=321241

In case you're wondering why this is more serious, consider the following following block of code that formats a date value as text:

    System.Globalization.CultureInfo ci;

    String text;

    ci = System.Globalization.CultureInfo.CreateSpecificCulture("en-us");

    text = String.Format(ci, "{0:d}", DateTime.Now);

And that text is transmitted to another application (or another session of the same application, e.g. serialization), potentially in another locale, to be parsed with the following block of code:

    System.Globalization.CultureInfo ci;

    ci = System.Globalization.CultureInfo.CreateSpecificCulture("en-us");

    String text = ReadRecord();

    DateTime now = DateTime.Parse(text, ci);

If either (or) the user's current culture is set to "English (United States)" and they've overridden the currency format the short date (say from "M/d/yyyy" to "d/M/yyyy") will randomly result in the wrong date.