Magazine > Issues > 2004 > December >  C++ Q&A: Deleting Managed Objects, Wrapping a L...
New information has been added to this article since publication.
Refer to the Editor's Update below.

C++ Q&A
Deleting Managed Objects, Wrapping a Library, and More
Paul DiLascia

Code download available at: CQA0412.exe (235 KB)
Browse the Code Online

Q In managed C++, can you tell me if it is safe to destroy a managed object using operator delete?
Q In managed C++, can you tell me if it is safe to destroy a managed object using operator delete?
Bernie Sanders

A Yes, you can delete managed objects in managed C++, as long as you understand that all delete does is call the object's destructor, which must be explicitly defined. Calling delete does not free the object's storage. Only the garbage collector can do that. Figure 1 shows a simple program that defines a managed class with a destructor that displays a message when it runs. TESTDTOR allocates two instances of ManagedClass. It explicitly deletes the first instance but not the second. If you run TESTDTOR, you'll get results something like this:
Begin main
  ManagedClass(04A712D4)::ctor
  ManagedClass(04A712D4)::dtor
  ManagedClass(04A712E0)::ctor
End main
  ManagedClass(04A712E0)::dtor
A Yes, you can delete managed objects in managed C++, as long as you understand that all delete does is call the object's destructor, which must be explicitly defined. Calling delete does not free the object's storage. Only the garbage collector can do that. Figure 1 shows a simple program that defines a managed class with a destructor that displays a message when it runs. TESTDTOR allocates two instances of ManagedClass. It explicitly deletes the first instance but not the second. If you run TESTDTOR, you'll get results something like this:
Begin main
  ManagedClass(04A712D4)::ctor
  ManagedClass(04A712D4)::dtor
  ManagedClass(04A712E0)::ctor
End main
  ManagedClass(04A712E0)::dtor
////////////////////////////////////////////////////////////////
// MSDN Magazine — December 2004
// If this code works, it was written by Paul DiLascia.
// If not, I don't know who wrote it.
// Compiles with Visual Studio .NET 2003 on Windows XP. Tab size=3.
//
// This program illustrates what happens when you delete a managed object 
// in Managed C++: the compiler calls the object's dtor.
//
// To compile: cl /clr testdtor.cpp

#include <stdio.h>
#using <mscorlib.dll>

using namespace System;

//////////////////
// Managed class WITH dtor.
//
public __gc class ManagedClass {
public:
   ManagedClass() {
      printf(" ManagedClass(%p)::ctor\n", this);
   }
   ~ManagedClass() {
      printf(" ManagedClass(%p)::dtor\n", this);
   }
};

//////////////////
// Managed class WITHOUT dtor
//
public __gc class ManagedClassNoDtor {
public:
   ManagedClassNoDtor() {
      printf(" ManagedClassNoDtor(%p)::ctor\n", this);
   }
};

void main()
{
   printf("Begin main\n");

   ManagedClass *pmc = new ManagedClass();   // create instance
   delete pmc;                               // "destroy" (force-call 
                                             // dtor)
   pmc = new ManagedClass();                 // create another
// delete pmc;                               // don't destroy 
                                             // (cleaned up when pgm 
                                             // terminates)

   ManagedClassNoDtor *pmcnd = new ManagedClassNoDtor();
// delete pmcnd; // ERROR!: can't delete instance of class with no dtor!

   printf("End main\n");
}
This shows that the first object's destructor executes immediately when the delete statement executes; whereas the second object (at 04A712E0) isn't destroyed until after control leaves main and the system termination code invokes the garbage collector to free outstanding objects.
Figure 2 testdtor Highlights 
Whenever you're unsure about what happens in the .NET environment, you can always write some code, compile it, and inspect the Microsoft® intermediate language (MSIL) generated. As Figure 2 shows, defining a destructor causes the compiler to generate two methods: a Finalize method that contains your implementation (in this case, the call to printf), and the __dtor method that calls System.GC::SuppressFinalize, then Finalize. When you delete an object, the compiler generates a call to this special __dtor method. If you compile TESTDTOR with /FAs to generate an assembly listing with source code, you'll see that the delete statement compiles in the following manner:
; delete pmc;
ldloc.0  ; _pmc$
call ??1ManagedClass@@$$FQ$AAM@XZ
The strangely cryptic symbol is just the mangled name for the destructor (__dtor) function.
Seasoned C++ programmers may scratch their heads and wonder if calling delete doesn't free the object, what's the point of calling it? Good question. The only reason to call delete would be to reclaim any unmanaged resources your class uses. For example, if your object opens files or creates a database connection, you can write a destructor that closes its resources and then use delete to invoke it when you're done using the object. Alas, a better way to free resources in managed classes is by implementing the Dispose pattern, IDisposable and—if you're writing in managed C++—an auto_dispose pattern to call it. (For further information see "Tips and Tricks to Bolster Your Managed C++ Code in Visual Studio .NET" by Tomas Restrepo in the February 2002 MSDN®Magazine).
If you implement the dispose pattern, other consumers of .NET can use it. If you do your cleanup in the destructor, other languages have no way to explicitly call your cleanup code. There's no delete operator in C# or Visual Basic®.
So the upshot is that you can call delete to invoke your destructor, but it's probably not a good idea to put cleanup code in the destructor. Better to implement IDisposable, which all citizens can use. Note, though, that this behavior changes in Visual C++® 2005. For more information, see Andy Rich's discussion of deterministic finalization at Deterministic Finalization IV - Benefits, part II as well as the current C++/CLI Language Specification Standard.

Q I have an unmanaged function returning a linked list that has char* strings in it:
struct blah {
   int a, b;
   char *a, *b;
   struct blah *next;
};
struct blah *getmystruct();
Because getmystruct() allocates memory, I need to call freemystruct(struct blah *b) when I'm finished with it. I'm trying to make a wrapper that will convert it to a collection of managed types, but I'm not sure how to deal with all these pointers as they need to be freed. Could you offer any insight?
Q I have an unmanaged function returning a linked list that has char* strings in it:
struct blah {
   int a, b;
   char *a, *b;
   struct blah *next;
};
struct blah *getmystruct();
Because getmystruct() allocates memory, I need to call freemystruct(struct blah *b) when I'm finished with it. I'm trying to make a wrapper that will convert it to a collection of managed types, but I'm not sure how to deal with all these pointers as they need to be freed. Could you offer any insight?
Cory Nelson

[ Editor's Update - 1/11/2005: The ListWrap sample as published had a memory leak because ListWrap.cpp failed to delete nn->str when deleting the node. This has been corrected by calling FreeList instead of deleting the node manually.] The third module is a C# test program which calls the wrapper to show how it works. You can download the full source for ListLib.cpp and the C# test program from the MSDN Magazine Web site.
////////////////////////////////////////////////////////////////
// MSDN Magazine — December 2004
// If this code works, it was written by Paul DiLascia.
// If not, I don't know who wrote it.
// Compiles with Visual Studio .NET 2003 on Windows XP. Tab size=3.
//
#using <mscorlib.dll>
#include "ListLib.h"

using namespace System;
using namespace System::Collections;

// Handy definition for human readability.
#define MANAGED __gc

namespace ListWrap {

//////////////////
// Managed wrapper for NativeNode mirrors definition.
//
public MANAGED class ManagedNode 
{
public:
   int a, b;      // same as NativeNode::a, NativeNode::b
   String* str;   // managed String, not char*

   // static
   static ArrayList* CreateList(int nelt) {
      NativeNode* nnlist = AllocateList(nelt);
      ArrayList*  ar = new ArrayList(); // create managed array list
 
      // Copy each NativeNode to managed ManagedNode
      for (NativeNode* nn=nnlist; nn; nn=nn->next) {
         ManagedNode* mn = new ManagedNode();
         mn->a = nn->a;
         mn->b = nn->b;
         mn->str = nn->str; // it just works!
         ar->Add(mn);       // append to list
      }
      FreeList(nnlist); // free the whole list
      return ar;        // ..and return managed copy
   }
};

}
ListLib.cpp implements two native functions, AllocateList and FreeList, which allocate and free a list of NativeNode structs:
// from ListLib.h
struct NativeNode {
   int a, b;
   TCHAR *str;
   struct NativeNode *next;
};
The wrapper class ManagedNode in ListWrap.cpp mimics the definition of NativeNode with a couple of minor differences: the native char* is replaced with a managed String and there's no next pointer since I'll use ArrayList to implement the list structure. In code, it looks like this:
// managed equivalent of NativeNode
public __gc class ManagedNode {
public:
   int a, b;
   String* str;
};
With ManagedNode defined, the next step is to write some code that converts NativeNodes to ManagedNodes. But before you run to the keyboard, stop a moment to consider what the converter function should look like and what arguments and return value it should have. One way is to write a function that takes a native list of NativeNodes and returns a managed list of ManagedNodes, possibly destroying the native list in the process. .NET client applications would call the ListLib DLL (or your getmystruct) directly to obtain the native list as an IntPtr, then pass this IntPtr to the conversion function, as shown here:
// call DLL directly through interop
IntPtr nativeList = AllocateList(7); 
// call wrapper to convert
ArrayList amanagedList = ListWrap.Convert(nativeList);
The client would be responsible for calling the DLL to free the native list in most cases, or perhaps the Convert function would do it automatically.
A different approach is to hide the DLL completely by wrapping the native function AllocateList in a wrapper that allocates the list, converts it, and frees the original native list before returning the managed list as an ArrayList. Which way is better? The advantage of the first strategy is that you only have to write a single conversion function which can be used anywhere you have a native list. The second approach requires wrapping each function that creates a list. It's a little more work if you have several functions that create lists, but it has the advantage of completely hiding all the native stuff from .NET clients. There's no need for clients to deal with IntPtrs or even import the DLL; ListWrap hides everything. This is the approach I'll take and the one I encourage you to use in your own apps. It takes more effort to fully wrap your library, but the result is more reliable and fully encapsulated.
With ManagedNode in hand, all that remains is to wrap AllocateList. The procedure is very straightforward. First, call AllocateList to allocate the native list; and then create an empty ArrayList. Next copy all the NativeNodes to ManagedNodes and add them to the managed list, deleting them as you go. Figure 3 shows the full details. One of the beauties of managed C++ is that all the code looks simple and neat, even when you're dealing with mixed objects. Copying the native char* to a managed String is just a simple assignment, as shown in the following line:
mn->str = nn->str; // String = char*: it just works!
There is no need to call a conversion function; the compiler knows what to do. CreateList deletes the native nodes as it goes. This is more storage-efficient than deleting them at the end.
By converting the entire list to managed objects (instead of exporting it with interop and StructLayout), you let managed clients live in a managed world. When in Rome, do as the Romans do! After all, one of the main reasons some programmers choose .NET is automatic garbage collection. If you export your list directly with interop, you'll have to export FreeList too, and make programmers using other .NET-based languages remember to call it.
In general, if you're exporting to the managed world, it's best to convert as much of your data as possible to managed objects. Otherwise what's the point? Your clients may as well write in C++. Of course, this rule doesn't always apply. Sometimes it's better to export structures directly and require that clients free them—for example, if copying entails an unacceptable performance or memory hit. You have to use judgment in deciding whether to go managed or native.

Q I'm using the Managed Extension for C++ to wrap an existing C++ library so that .NET-based languages can access it. In managed C++, I can write
String* s = new String();
s = _T("Hello, world");
but how can I convert a managed String back to a native TCHAR*?
Q I'm using the Managed Extension for C++ to wrap an existing C++ library so that .NET-based languages can access it. In managed C++, I can write
String* s = new String();
s = _T("Hello, world");
but how can I convert a managed String back to a native TCHAR*?
Matthew Brady

A It's easy, once you know the magic voodoo. You have to call PtrToStringChars and pin the result. In code, it looks like this:
String __gc* s = S"Hello";
const wchar_t __pin* p = PtrToStringChars(s);
Don't forget to __pin the pointer returned from PtrToStringChars. Pinning is required because PtrToStringChars returns a managed (__gc) pointer to the first character of the String object in managed memory, and the garbage collector can move managed memory any time it pleases, unless you explicitly __pin it. In general, you must use __pin any time you pass a __gc pointer to a native (unmanaged) function.
A It's easy, once you know the magic voodoo. You have to call PtrToStringChars and pin the result. In code, it looks like this:
String __gc* s = S"Hello";
const wchar_t __pin* p = PtrToStringChars(s);
Don't forget to __pin the pointer returned from PtrToStringChars. Pinning is required because PtrToStringChars returns a managed (__gc) pointer to the first character of the String object in managed memory, and the garbage collector can move managed memory any time it pleases, unless you explicitly __pin it. In general, you must use __pin any time you pass a __gc pointer to a native (unmanaged) function.
Figure 4 shows a short program that converts a managed String to both wide-character and ANSI strings. To convert to ANSI, use your favorite conversion function, such as wcstombs or the ATL W2A macro. If you're using MFC CStrings, you don't have to do anything since CString has assignment operators for both char* and wchar_t:
// both will work
CString s1 = "hello, world";
CString s2 = L"Hello, world";
////////////////////////////////////////////////////////////////
// MSDN Magazine — December 2004
// If this code works, it was written by Paul DiLascia.
// If not, I don't know who wrote it.
// Compiles with Visual Studio .NET 2003 on Windows XP. Tab size=3.
//
#include < stdio.h >
#include < stdlib.h >
#include < vcclr.h >
#using < mscorlib.dll >
using namespace System;

//////////////////
// Shows how to convert managed String to char* or wchar_t
//
int main()
{
   // A managed string
   String* s = S"Hello, world";

   // Convert to wide char
   const wchar_t __pin* p = PtrToStringChars(s);
   printf("%S\n", (wchar_t*)p);
   
   // Convert to char:
   size_t len = wcstombs(NULL, p, 0)+1; // calculate required length..
   if (len == 0) return -1;
   char* buf = (char*)malloc(len);      // ..allocate new string and..
   wcstombs(buf, p, len);               // ..convert
   printf("%s\n", buf);
   return 0;
}

Q I want to change the background color of tab control for my app from gray to white. I tried to make a derived class from CTabCtrl and use all functionalities, but without success. Can you help me?
Q I want to change the background color of tab control for my app from gray to white. I tried to make a derived class from CTabCtrl and use all functionalities, but without success. Can you help me?
Mayur Patel

A Changing the color of the tabs in your tab control is fairly easy, but giving property sheets a full color makeover requires quite a bit of work and isn't for the fainthearted. For the tabs, the basic idea is to make the control an owner-draw control and then handle WM_DRAWITEM. If you're using MFC, you can override the virtual function DrawItem.
A Changing the color of the tabs in your tab control is fairly easy, but giving property sheets a full color makeover requires quite a bit of work and isn't for the fainthearted. For the tabs, the basic idea is to make the control an owner-draw control and then handle WM_DRAWITEM. If you're using MFC, you can override the virtual function DrawItem.
In the March 1998 issue of Microsoft Systems Journal, I showed how to implement a tab control class, CTabCtrlWithDisable, that supports disabling the tabs. As part of disabling the tabs, CTabCtrlWithDisable changes the tab text color to light gray when the tab is disabled. This month, I borrowed some code from CTabCtrlWithDisable to implement a new class, CColorTablCtrl, that lets you change the color of the tabs (see Figure 5).
////////////////////////////////////////////////////////////////
// MSDN Magazine — December 2004
// If this code works, it was written by Paul DiLascia.
// If not, I don't know who wrote it.
// Compiles with Visual Studio .NET 2003 on Windows XP. Tab size=3.
//
// CColorTabCtrl implements a CTabCtrl with colored tabs.

#include "StdAfx.h"
#include "ColorTab.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

IMPLEMENT_DYNAMIC(CColorTabCtrl, CTabCtrl)
BEGIN_MESSAGE_MAP(CColorTabCtrl, CTabCtrl)
END_MESSAGE_MAP()

CColorTabCtrl::CColorTabCtrl()
{
   m_clrBackground = GetSysColor(COLOR_3DFACE);
   m_clrForeground = GetSysColor(COLOR_BTNTEXT);
}

CColorTabCtrl::~CColorTabCtrl()
{
}

//////////////////
// Set bg/gf colors
//
void CColorTabCtrl::SetColors(COLORREF bg, COLORREF fg)
{
   m_clrBackground = bg;
   m_clrForeground = fg;
}

//////////////////
// Subclass the tab control: also make owner-draw
// 
CColorTabCtrl::SubclassDlgItem(UINT nID, CWnd* pParent)
{
   if (!CTabCtrl::SubclassDlgItem(nID, pParent))
      return FALSE;
   ModifyStyle(0, TCS_OWNERDRAWFIXED);
   return TRUE;
}

//////////////////
// Draw the tab: use bg/fg colors.
//
void CColorTabCtrl::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)
{
   DRAWITEMSTRUCT& ds = *lpDrawItemStruct;
   
   int iItem = ds.itemID;

   // Get tab item info
   char text[128];
   TCITEM tci;
   tci.mask = TCIF_TEXT;
   tci.pszText = text;
   tci.cchTextMax = sizeof(text);
   GetItem(iItem, &tci);

   // use draw item DC
   CDC dc;
   dc.Attach(ds.hDC);

   // calculate text rectangle and color
   CRect rc = ds.rcItem;
   rc += CPoint(1,4);                   // ?? by trial and error

   dc.FillSolidRect(rc, m_clrBackground);
   dc.SetBkColor(m_clrBackground);
   dc.SetTextColor(m_clrForeground);
   dc.DrawText(text, &rc, DT_CENTER|DT_VCENTER);

   dc.Detach();
}

IMPLEMENT_DYNAMIC(CColorPropertyPage, CPropertyPage)
BEGIN_MESSAGE_MAP(CColorPropertyPage, CPropertyPage)
   ON_WM_ERASEBKGND()
END_MESSAGE_MAP()

CColorPropertyPage::CColorPropertyPage(UINT nID, COLORREF bg) : CPropertyPage(nID)
{
   SetBGColor(bg);
}

CColorPropertyPage::~CColorPropertyPage()
{

}

void CColorPropertyPage::SetBGColor(COLORREF bg)
{
   m_clrBackground = bg;
}

//////////////////
// Handle WM_ERASEBKGND: fill bg with bg color
//
BOOL CColorPropertyPage::OnEraseBkgnd(CDC* pDC)
{
   CRect rc;
   GetClientRect(&rc);
   pDC->FillSolidRect(rc, m_clrBackground);
   return TRUE;
}
To use CColorTablCtrl, create an instance in your property sheet:
class CMyPropSheet : public CPropertySheet {
protected:
   CColorTabCtrl m_tabCtrl;
};
You have to subclass the tab control in your property sheet's OnInitDialog handler (so MFC will use it), then set the foreground and background colors to whatever you like:
// in CMyPropSheet::OnInitDialog()
HWND hWndTab = (HWND)SendMessage(PSM_GETTABCONTROL);
m_tabCtrl.SubclassDlgItem(::GetDlgCtrlID(hWndTab), this);
m_tabCtrl.SetColor(WHITE, RED);
Here WHITE and RED are standard COLORREF values, namely RGB(255, 255, 255) and RGB(255,0,0). Once you've instantiated and initialized your CColorTabCtrl, the color tab control does the rest (see Figure 6).
Figure 6 The Color Tab Control 
CColorTabCtrl has an override for SubclassDlgItem that calls ModifyStyle to change the style to TCS_OWNERDRAWFIXED. A better place to do this would be in PreSubclassWindow because that's called whether the control is subclassed or created with CreateWindow (but I had to shrink the code to fit in the magazine, so I took a shortcut). Note that SubclassDlgItem is a simple override, not a virtual function. To set the colors, SetColor saves the colors passed in two member variables, m_clrBackground and m_clrForeground.
Once the style is set to owner-draw, Windows® sends WM_DRAWITEM messages whenever it's time to paint the tabs. MFC traps this message and calls the tab control's virtual DrawItem function, which CColorTabCtrl implements by painting the text with the new colors:
// in CColorTabCtrl::DrawItem
dc.FillSolidRect(rc, m_clrBackground);
dc.SetBkColor(m_clrBackground);
dc.SetTextColor(m_clrForeground);
dc.DrawText(...);
This is all quite straightforward, so see the source code for details. Since you probably don't want to change the tab color without changing the page color as well, I also implemented a CColorPropertyPage that lets you change the background color of the property page to match, as shown in Figure 6. For property sheets, the easiest way to change the background color is by handling WM_ERASEBKGND:
BOOL CColorPropertyPage::OnEraseBkgnd(CDC* pDC)
{
   CRect rc;
   GetClientRect(&rc);
   pDC->FillSolidRect(rc, m_clrBackground);
   return TRUE;
}
If you try this at home, you'll discover various annoying problems. First, if you change the page color, all the controls have the wrong background color, so you have to fix them too. For that you have to handle WM_CTLCOLOR and WM_ERASEBKGND. The details appear in my MSJ column from way back in May 1997.
Another problem is that the tab control still draws the edges and rounded corners of the tabs using the system 3D colors. Sigh. To fix that, there's nothing to do but handle WM_PAINT and take over the entire paint operation yourself. This includes drawing the tab offset from the others when it's selected, so it appears in the foreground. By this point, you're starting to reinvent the tab control. As every programmer using Windows knows, changing control colors is a royal pain in the brain, and once you start down this path it seems there's no end to the work that must be done. Pretty soon the standard colors will look better than they did at first, or else you'll wonder why you don't switch to using the .NET Framework where changing colors is as simple as writing:
ctl.BackColor = Color.Aquamarine;
Happy programming!

Send your questions and comments for Paul to  cppqa@microsoft.com.


Paul DiLascia is a freelance writer, consultant, and Web/UI designer-at-large. He is the author of Windows++: Writing Reusable Windows Code in C++ (Addison-Wesley, 1992). Paul can be reached at www.dilascia.com.

Page view tracker