Archive for ‘.NET / C#’

March 2, 2012

C# Inconveniences for C++ Programmers: RAII and Cloning Objects

As a mostly C++ guy, I have admired a lot of C# features and libraries that are simply not available in C++. As I am working a little bit more with C#, I however start to cherish the features that we take for granted in C++, but are not available in C#.

One of them is RAII, which automates cleaning up (with deterministic destructor) and is exception friendly. C# does not have deterministic destructor but relies on garbage collector. The closest match in C# is the using statement, but it is not exact. For example, a common exception safe approach in C++ is “create-and-swap”. In the “create” phase, RAII makes sure everything is cleaned up if anything goes wrong. If all is going fine, then the “swap” phase just steals the guts of the painstakingly created object, which does not throw exceptions. In C#, if you put the object in using statement, it will be disposed of when going out of scope in the case of exceptions. The problem is that you cannot steal it when that object is in a desired state near the end of the using scope. You can let your own object reference point to the real object. However, you cannot assign to the object reference in using statement (it is read-only), for example, a null, to trick it. It stubbornly calls Dispose() on that real object when leaving the scope, and all your work evaporates.

The other one is object cloning. In C++, often you rely on the compiler generated assignment operator function as long as your contained objects follow the same rule, and you automatically have object cloning. In C#, assigning to an object merely replaces the object reference (just like C++ pointer assignment). Cloning is not free in coding! You have to write code to do that in most cases. Due to the fact that the class member is often object reference to real object too, cloning can be shallow or deep at each level, which you may not have control or there is no established convention when you use classes from other parties. There is no easy and simple approach to clone C# objects. See C# Object Clone Wars and Cloning objects in C# for more information.

I do not know Java, but I think Java should have similar problems, given the similarities of C# and Java.

September 22, 2011

Passing Arrays Between an ActiveX and a .NET Application

We can quickly create an ActiveX control using Visual Studio 2010’s MFC Active Control project wizard, and let a .NET e.g., C# application talk to it. It is trivial to pass fundamental types and strings across the boundary.

However, sometimes, more complex data must go through that boundary. One specific case is that when some binary data has to be passed, for example, pixels of an image. A natural choice would be a SAFEARRAY, for example, of bytes (VT_UI1). Unlike in a hand written COM server, where you can freely add IDL methods that take SAFEARRAY parameters (see an earlier post), when we add a method/property to the ActiveX using the wizard, the data types that can appear in the IDL are quite limited, and SAFEARRAY is not among them.

If we check carefully the available parameter types, there are not too many sensible choices:

image

BYTE* or BSTR* seems promising, but trying that turns out that AxImp.exe maps them to ref byte or ref string. If not impossible, at least a lot of hacking would be required to smuggle an array of bytes under the cover.

Enters VARIANT. VARIANT is the type that can house very different things, in particular a SAFEARRAY. In this example, I will show how to let a .NET application to obtain an array of bytes, representing pixels of an image, from an ActiveX.

Add a method using Add Method Wizard to the MFC ActiveX, let the parameter to be of type VARIANT*. The generated IDL should look like this:

   [id(1)] void GetImage(VARIANT* pixels);

And modify the generated C++ function implementation to be:

void COcx1Ctrl::GetImage(VARIANT* pixels)
{
    AFX_MANAGE_STATE(AfxGetStaticModuleState());

    // TODO: Add your dispatch handler code here
    COleSafeArray sa;
    sa.CreateOneDim(VT_UI1, 100);
    unsigned char* pData = NULL;
    sa.AccessData((void**)&pData);
    for(int i=0; i<100; ++i)
        pData[i] = (unsigned char)i;
    sa.UnaccessData();

    *pixels = sa.Detach();

}

This would fill the VARIANT with an array of 100 bytes. I use COleSafeArray helper class in MFC to create a SAFEARRAY VARIANT, because it is quite cumbersome to do the same work using direct API functions.

After adding the COM reference of ActiveX to the C# application, the C# code to get the pixel data is like this:

    object data = null;
    axocx11.GetImage(ref data);
    byte[] pixels = (byte[])data;
    // now access the array
    pixels[0] = 10;

As we can see, VARIANT* is mapped to ref object. Then object is casted to its run-time type byte[]. That’s it.

Note 1: Pre-allocating in C# does not work, because it does not know that the byte[] hidden in object should be converted to a SAFEARRAY in VARIANT:

    byte[] pixels = new byte[100];
    object data = (object)pixels;
    axocx11.GetImage(ref data);  // run-time exception: System.Runtime.InteropServices.COMException

Note 2: Do not try to use VARIANT as return value of a method in IDL. For SAFEARRAY, the C# side would throw a run-time exception when it tries to create an object from what the ActiveX returns.

September 22, 2011

Building Visual Studio 2010 Setup Project: “ERROR: Unable to update the dependencies of the project”

All other projects in the solution build fine, but the Setup project spits: “ERROR: Unable to update the dependencies of the project”. Nothing has been changed in the solution when it was completely building okay.

Searching on the Internet shows that this is a common problem with Visual Studio, dated back to Visual Studio 2005. This Microsoft Connect entry, Building setup project in devenv.com command line fails, works in IDE, despite the title, is most relevant. Click “Workarounds”, people have found 7 (as of today) workarounds. Some other workarounds do not work for me; for example, emptying Hierarchy and File sections, really removes the data files that I put in file system in the Setup project, which is not acceptable.

For my specific situation, the workaround is:

  • Remove the Setup project from solution;
  • Rebuild the solution (in Release configuration);
  • Add back the Setup project to solution;
  • Rebuild the Setup project (in Release configuration).

Viola! The Setup project now builds. This is definitely a bug in Visual Studio that should not happen.

June 21, 2011

Use C++/CLI to bridge .NET with C++: Convert Managed String

C++/CLI

First of all, C++/CLI is a .NET language. You can write (managed) classes and assemblies, and they can be used by other .NET languages, C#, VB.NET etc, or in the opposite direction.

Second, C++/CLI has a close relationship with C++. C++/CLI is a different language than C++, instead, it is more like a superset of C++. In C++/CLI, you can mix unmanaged C++ with managed C++.

I guess writing a new assembly with C++/CLI may not be very favorable, given the complexity of C++ and hence C++/CLI. However, C++/CLI provides a prime opportunity to wrap up legacy C++ code as .NET assemblies, and therefore to be shared with the .NET world.

You can certainly wrap up unmanaged work into ActiveX/COM controls, but COM is so complex and there are many places that can go wrong, and the types can go through the COM interface is often limited to Automation compatible types. For example, often you can not pass by a class object, but you will have to use a generic IDispatch interface, which is inconvenient.

The other approach is to use P/Invoke for unmanaged C DLLs. Again, you have to wrap your type-rich C++ library into flat pure C DLLs. All classes are gone.

With C++/CLI, you have a lot of control on how the C++ class library is exposed to .NET. There is still the bridging code, but it works at a much finer level if you want, and restrictions are minimal.

Example

To create a C++/CLI class library, in your Visual Studio 2010, choose File | New | Project… | Visual C++ | CLR | Class Library. The created project, TestCppCli, is similar to a regular C++ project, but /clr option is added, and references to a few system assemblies are added to the project.

In this example, I will show how to pass a .NET string to an unmanaged function call. This example is an adaptation of How to convert from System::String* to Char* in Visual C++ at Microsoft Support. Note that other fundamental types, such as int, float etc., are quite effortless. Also, passing back a .NET string is relatively easy, because it is a managed object created in managed heap.

This is the header file with inline functions (the cpp file is empty):

  1 // TestCppCli.h
  2 #pragma once
  3 
  4 #include <afx.h>            // CString
  5 #include <vcclr.h>          // PtrToStringChars
  6 #include <msclr/marshal.h>  // marshal_as, marshal_context
  7 #include <windows.h>        // MessageBox
  8 
  9 namespace TestCppCli {
 10     public ref class Foo
 11     {
 12     public:
 13         void MessageBox0(System::String^ s)
 14         {   // Not recommened.
 15             // 1. exception-unsafe. If you have to use it, use a smart pointer (shared_ptr, auto_ptr etc) to wrap it.
 16             // 2. concrete character type. Need to use template such that it's character type agnostic to client.
 17             char* ss = (char*)(void*)System::Runtime::InteropServices::Marshal::StringToHGlobalAnsi(s);
 18             ::MessageBoxA(0, ss, "Title", 0);
 19             System::Runtime::InteropServices::Marshal::FreeHGlobal(System::IntPtr(ss));
 20         }
 21 
 22         void MessageBox1(System::String^ s)
 23         {
 24             CString ss(s);  // requires MFC; agnostic to client's Unicode/non-Unicode setting.
 25             // wide string obtained using efficient PtrToStringChars; a copy (Unicode) or convertion (Ansi) is then made.
 26             ::MessageBox(0, ss, _T("Title"), 0);
 27         }
 28 
 29         void MessageBox2(System::String^ s)
 30         {
 31             pin_ptr<const wchar_t> ss = PtrToStringChars(s); // requires <vcclr.h>; only wide string; efficient
 32             ::MessageBoxW(0, ss, L"Title", 0);
 33         }
 34 
 35         void MessageBox3(System::String^ s)
 36         {	// requires <msclr/marshal.h> for marshal_as/marshal_context
 37             // context can live in an outer scope and be shared.
 38             msclr::interop::marshal_context^ context = gcnew msclr::interop::marshal_context();	
 39             LPCTSTR ss = context->marshal_as<LPCTSTR>(s);// ss in context until context is destroyed. agnostic to Unicode/non-Unicode
 40             ::MessageBox(0, ss, _T("Title"), 0);
 41             delete context;
 42         }	// Marshal::StringToHGlobalUni or Marshal::StringToHGlobalAnsi used in implementation, so always a cost there.
 43     };
 44 } 

As pointed out in the comment of MessageBox0, using StringToHGlobalAnsi directly is not exception safe, because FreeHGlobal may not be called if exception happens. This is an attempt to wrap them:

  1 template<class Char_>
  2 class NativeConstString
  3 {
  4 // this is how you use it.
  5 public:
  6     NativeConstString(System::String^ s);
  7     ~NativeConstString() { System::Runtime::InteropServices::Marshal::FreeHGlobal(System::IntPtr(p_)); }
  8     operator const Char_* () { return p_; }
  9 
 10 // no copy or assignment
 11 private:
 12     NativeConstString(const NativeConstString&);
 13     NativeConstString& operator = (const NativeConstString&);
 14 
 15 private:
 16     Char_* p_;
 17 };
 18 
 19 template<> NativeConstString<char>::NativeConstString(System::String^ s)
 20     : p_( (char*)(void*)System::Runtime::InteropServices::Marshal::StringToHGlobalAnsi(s) )
 21     {}
 22 
 23 template<> NativeConstString<wchar_t>::NativeConstString(System::String^ s)
 24     : p_( (wchar_t*)(void*)System::Runtime::InteropServices::Marshal::StringToHGlobalUni(s) )
 25     {}
 26 
 27 /*
 28 template<>
 29 class NativeConstString<wchar_t>
 30 {
 31 public:
 32     NativeConstString(System::String^ s) 
 33         : p_( PtrToStringChars(s) )
 34         {}	// better than System::Runtime::InteropServices::Marshal::StringToHGlobalUni ?
 35     ~NativeConstString() {}
 36     operator const wchar_t* () { return p_; }
 37 private:
 38     pin_ptr<const wchar_t> p_;	// !!FAIL. pin_ptr cannot be used a member of class; it must be a stack variable.
 39 };
 40 */

And here is a usage example of NativeConstString:

  1     void MessageBox4(System::String^ s)
  2     {
  3         NativeConstString<TCHAR> ss(s);
  4         ::MessageBox(0, ss, _T("Title"), 0);
  5     }

Summary

This is a table to compare different approaches to convert a managed System::String to a unmanaged const C/C++ string:

Approach Requires Char Support for Client Pros & Cons Implementation
StringToHGlobalAnsi

StringToHGlobalUni
System::Runtime::

InteropServices::Marshal
explicit concrete types: char or wchar_t new copy created; exception unsafe in cleanup Make a copy of managed string in unmanaged heap
CString MFC/ATL String TCHAR (agnostic to project setting); or explicit char/wchar_t new copy created; auto cleanup PtrToStringChars (little cost), then make a copy (wchar_t) or convert to ansi (char)
PtrToStringChars #include <vcclr.h> wchar_t only efficient string pinning; auto cleanup Pin managed string until pin_ptr destructs.
marshal_as #include <msclr/marshal.h> LPCTSTR(agnostic to project setting); or explicit char/wchar_t new copy created; one-time context setup and teardown; new copy cannot be freed before context is destroyed; StringToHGlobalXXXX. New copies are created and added in a context (container)
NativeConstString System::Runtime::

InteropServices::Marshal
TCHAR (agnostic to project setting); or explicit char/wchar_t new copy created; auto cleanup smart pointer around StringToHGlobalXXXX

References:

Chapters 22, 23, 24, Pro Visual C++_CLI and the .NET 3.5 Platform

Chapters 8, 9, Expert C++/CLI

How to convert from System::String* to Char* in Visual C++

Sample: Mixing Unmanaged C++, C++/CLI, and C# code at Junfeng Zhang’s Windows Programming Notes

How do I mix C# and C++ code in a single assembly? at Junfeng Zhang’s Windows Programming Notes

MSDN: How to: Convert Between Various String Types

May 21, 2011

Graph Plotting in .NET and WPF

Windows Forms

ZedGraph is a well-known free class library, user control, and web control for drawing 2D Line, Bar, and Pie Charts in .NET. The Code Project also houses a simple C# library for graph plotting specialized on ECG signals.

WPF

WPF controls are very different from Windows Forms controls. Even though you can wrap up your Windows Forms charting control and put it in a WPF window, the interoperation is not native and natural, for example, in binding and others. Nevertheless, Rongchaua’s blog shows an example of using ZedGraph in WPF.

The Code Project has a WPF Chart Control from John Stewien, hosted also at SourceForge Swordfish Charts. It has not been updated in past 2 years.

DynamicDataDisplay is a charting library of WPF controls for dynamic data visualization, developed by Microsoft Research and freely available at CodePlex. This is very powerful graph plotting library with binding support etc, and drawing 2D plots is very convenient (think of Matlab). In MSDN Magazine there was an article Generating Graphs with WPF employing DynamicDataDisplay.

At last, if you are looking for anything not shipped with WPF in your Visual Studio, try your luck at official WPF CodePlex site first.

May 19, 2011

ADO.NET Entity Framework Code First

Code First is a new Entity Data Model (EDM) design approach in ADO.NET Entity Framework in Version 4.1, in addition to Database First and Model First. ADO.NET Entity Framework is built on top of ADO.NET. For more background of Entity Framework, check this.

In Entity Framework, the data has three aspects: physical persistence in a database (or an XML file), logical and conceptual model (often described in specialized XML, CSDL/MSL/SSDL), and client accessible .NET classes (code). With Database First, the designer creates the database schema first, then Visual Studio EDM Wizard would read the database structure and generate the data model XML descriptions and the .NET classes. In the Model First approach, the designer uses Visual Studio EDM Designer to create the data model (stored in 3 CSDL/MSL/SSDL files), then it creates both database schema and .NET classes from them.

The Code First approach starts from .NET code, and it infers data model out of the code and creates database schema. This is especially convenient if you are a programmer and more familiar with code than with EDM or database.

The ADO.NET Team Blog has a very good Walkthrough for Entity Framework 4.1 Code First. If you check the sample project, you can find that Code First does not generate the CSDL/MSL/SSDL files. When you first run the application, it will create the database structure. See Database.SetInitializer for strategy of whether to recreate the whole database when your EDM classes in code change. Data Annotations or Code First Fluent API can be used in defining how your .NET classes map to database.

A more comprehensive article, Code First in the ADO.NET Entity Framework 4.1, can be found in May 2011 Issue of MSDN Magazine.

April 14, 2011

Spin, Up-Down, NumericUpDown, DecimalUpDown, DoubleUpDown, or IntegerUpDown

A spin box, or up-down, looks like this:

image

Depending on what development tool you use, you get different levels of support on Windows.

Visual C++

In C/C++, the spin button control is the two buttons with up and down arrows. The edit box, attached to the left of the spin button normally, is called a companion control, or buddy window. In fact, the companion control does not have to be an edit control. The spin button is like a reduced scroll bar, which has a loose integration with the target control.

In Visual C++, you can add the Spin Control from Toolbox to a dialog. In MFC, the spin control is backed by the CSpinButtonCtrl class. Here is an example of it.

.NET

While Visual C++ provides the flexibility of using the spin control with different types of companion controls, it also makes the whole thing unnecessarily complex, especially when what you need is just an edit box with the spin button to represent a numeric value. I’d say this is 90% of the case.

In .NET, Microsoft provides much better support for this scenario with the NumericUpDown control (System.Windows.Forms.NumericUpDown). In a Windows Forms applications, such as in Visual C# or Visual Basic, you can use the control under Common Controls in Toolbox. The type of the numeric value is decimal, which means you can use the control to represent also integer and real numbers (with some care).

WPF

WPF is however different. Up to Visual Studio 2010, Microsoft does not ship built-in NumericUpDown control with WPF.

There have been some user made controls for WPF, for example, Numeric Spinner Control in phoenix-control-library, Kevin Moore’s NumericUpDown in his WPF Bag-o-Tricks, and Numeric up/down textbox from Clifford Nelson.

But my recommendation is with Extended WPF Toolkit. It used to supply NumericUpDown that is similar to .NET NumericUpDown. The latest version now provides three different controls: DecimalUpDown, DoubleUpDown, and IntegerUpDown.

April 11, 2011

JSON.NET

[memo]

Faster serialization of data than XML (and still human readable), JSON, has a very good library support in .NET 4, JSON.NET, available at NuGet Gallery.

http://www.hanselman.com/blog/NuGetPackageOfTheWeek4DeserializingJSONWithJsonNET.aspx

Tags: , ,
April 11, 2011

Microsoft PDC videos

[memo]

Channel 9: PDC videos (PDC 2010, PDC 2009, PDC 2008).

Tags:
April 6, 2011

Project Properties of Visual Studio Deployment (Installer)

Details in MSDN: Deployment Properties.

Variables/Macros:

    • Author: It will show up as Contact when you click support information of the installed program in Add or Remove Programs.
    • Manufacturer: It will show up as Publisher when you click support information of the installed program in Add or Remove Programs.
    • ProductName: It will be the software name in Add or Remove Programs. It will also be the caption of installer window.
    • Title: Title is only put in the msi file as Title property of in Summary page of Properties. It does not affect the installed system.

Application Folder: Where the application will be installed in the target PC’s file system.

    • DefaultLocation = [ProgramFilesFolder][Manufacturer]\[ProductName]
    • If your ProductName includes Manufacturer, you may want to modify DefaultLocation.

User’s Programs Menu: The folders/subfolders and shortcuts appearing in Start | All Programs.

    • You cannot use variables/macros here such as [Manufacturer]. You have to use the actual folder or shortcut name.
    • Remember to give the shortcut an icon, usually from the same executable, e.g., a project output.
Follow

Get every new post delivered to your Inbox.

Join 35 other followers