Click here to Skip to main content
12,693,244 members (31,704 online)
Click here to Skip to main content
Add your own
alternative version


44 bookmarked

C++/CLI Library classes for interop scenarios

, 20 Jun 2006 Ms-PL
Rate this:
Please Sign up or sign in to vote.
The article takes a brief look at some not so commonly used classes such as auto_handle, lock, and ptr.


Visual C++ 2005 comes with a bunch of helper classes that provide support for smart pointers, synchronization support, and COM wrappers. Most of them are very handy for interop scenarios, and this article will show examples on using these classes.

The auto_handle class

C++/CLI has syntactic support for deterministic disposal - and you can seemingly declare managed objects on the stack. Now, while this is extremely handy for most scenarios, sometimes, you end up with methods (mostly those in the BCL) that return handles to objects. This forces us to use the ^ syntax and to manually remember to call delete once the object is not required any more. The following code shows an example of one such method.

<PRE lang=mc++>void Demo1A() { StreamWriter^ sw; try { sw = File::CreateText("d:\\temp.txt"); sw->WriteLine("This is a line of text"); } finally { delete sw; } }

This is where the auto_handle class comes in handy. Add the following #include declaration to your code.

<PRE lang=mc++>#include <msclr\auto_handle.h>

Now, you can rewrite the previous method as follows.

<PRE lang=mc++>void Demo1B() { msclr::auto_handle<StreamWriter> sw = File::CreateText("d:\\temp.txt"); sw->WriteLine("This is a line of text"); }

The auto_handle class overloads the -> operator and returns the underlying handle. So we can call StreamWriter methods just as if we were using a StreamWriter object. And when the destructor is called, delete is called on the underlying handle. If you need to persist the StreamWriter beyond the present scope, you can free the handle from the auto_handle object by calling release on it, as shown below.

<PRE lang=mc++>sw.release();

Other operator overloads include those on =, !, and bool, so you can treat it like a pointer. And there's also a swap helper function that swaps handles between two auto_handle objects.

The gcroot and auto_gcroot classes

These two are probably quite well known and very commonly used, specially gcroot, since it existed in the old syntax too. But for the sake of completion, I include these here too. The gcroot template class wraps the BCL GCHandle class and allows us to declare and use a managed object as a member of a non-CLI class. The following code snippet shows a demonstration of the use of this class.

<PRE lang=mc++>class Demo2A { msclr::gcroot<StreamWriter^> m_sw; public: Demo2A() { m_sw = File::CreateText("d:\\temp.txt"); } ~Demo2A() { delete m_sw; } };

Notice how, I had to manually delete the StreamWriter object in the destructor. Using the auto_gcroot class, we can actually avoid having to do that on our own. Here's a modified class that uses auto_gcroot.

<PRE lang=mc++>class Demo2B { msclr::auto_gcroot<StreamWriter^> m_sw; public: Demo2B() { m_sw = File::CreateText("d:\\temp.txt"); } };

Well, now the destructor is gone. For most purposes, you should use the auto_gcroot class instead of the gcroot class, for obvious reasons. Remember to #include <msclr\gcroot.h> or <msclr\auto_gcroot.h> appropriately.

The _safe_bool class

_safe_bool is a value class that can be used in place of bool when providing an operator overload for bool. It prevents an implicit conversion to any integral type. Consider the following class.

<PRE lang=mc++>ref class Demo3A { public: operator bool() { return true; } };

Now the following code would compile fine, even when it may not have been intended to do so.

<PRE lang=mc++> Demo3A a; int y = a;

Here's how you would rewrite the class using a _safe_bool.

<PRE lang=mc++>ref class Demo3B { public: operator msclr::_detail_class::_safe_bool() { return msclr::_detail_class::_safe_true; } };

Now the following code will not compile.

<PRE lang=mc++> Demo3B a; int y = a;

You can also treat it like a bool, for most purposes.

<PRE lang=mc++> if(a == msclr::_detail_class::_safe_false) { }

Both auto_handle and auto_gcroot use _safe_bool for their bool operator overloads. You need to #include <msclr\safebool.h> to use this class.

The ptr template - a COM wrapper class

This class is quite handy when you need to use a COM object as a member of a CLI class. The following #include is needed for this class.

<PRE lang=mc++>#include <msclr\com\ptr.h>

The below code sample shows how to use the class.

<PRE lang=mc++>ref class ManLink { private: msclr::com::ptr<ILink> lnkptr; public: ManLink() { lnkptr.CreateInstance(__uuidof(Link)); // Create COM object } void Resolve() { lnkptr->ResolveLink(. . .); // Invoke COM method } };

The destructor will release the COM object (so you don't need to worry about it). There are several methods provided such as Attach which allows you to associate a COM pointer with a com::ptr object, Detach which makes the com::ptr object give up ownership of the COM object, and Release which releases the COM object. Note that Detach, increases the ref count before returning the interface pointer, and you are then responsible for releasing the object, once you are done using it.

The lock class

C# has the lock keyword which is internally implemented using the BCL Monitor class. C++/CLI does not have equivalent syntactic support, but the support library includes the lock class which (like the C# lock keyword) internally uses the Monitor class. You need to #include the following header file.

<PRE lang=mc++>#include <msclr\lock.h>

Now, here's a sample showing how the lock class can be used.

<PRE lang=mc++>ref class Demo4 { public: void DoSafeStuff() { msclr::lock lk(this); Console::WriteLine("Starting work on thread {0}", Thread::CurrentThread->ManagedThreadId); Thread::Sleep(300); // simulate complex task Console::WriteLine("Work ended on thread {0}", Thread::CurrentThread->ManagedThreadId); } };

The lock class also comes with methods such as is_locked which returns true if a lock is held, a release method that releases the lock, an acquire method that gets a lock (and throws an exception if the lock could not be obtained), and a try_acquire method which is similar except that it does not throw an exception (instead it returns a bool). The following code shows how an instance of the above class is used from multiple threads, and how try_acquire is used to wait until all the threads are done executing.

<PRE lang=mc++>int main(array<System::String ^> ^args) { Demo4 d; msclr::lock lk(%d,msclr::lock_later); // defers locking for(int i=0; i<5; i++,( gcnew Thread( gcnew ThreadStart(%d, &Demo4::DoSafeStuff)))->Start()); while(!lk.try_acquire(300)); Console::WriteLine("Exiting main"); return 0; }

I think it's fantastic that C++/CLI allows us to smoothly write library implementations where a language feature does not directly exist.

Mapping delegates to non-CLI class methods

There's a delegate_proxy_factory class declared in <msclr\event.h> that allows you to map an event handler to a non-CLI class's member function. If you've done Windows Forms - MFC interop, then you presumably already know how to do this. But it's very useful even outside MFC Forms interop scenarios, and is also trivial to implement. Here's some code that shows how to map the FileSystemWatcher class's Renamed event to a native class method (albeit with managed arguments).

<PRE lang=mc++>class Demo5 { msclr::auto_gcroot<FileSystemWatcher^> m_fsw; public: // Step (1) // Declare the delegate map where you map // native method to specific event handlers BEGIN_DELEGATE_MAP(Demo5) EVENT_DELEGATE_ENTRY(OnRenamed, Object^, RenamedEventArgs^) END_DELEGATE_MAP() Demo5() { m_fsw = gcnew FileSystemWatcher("d:\\tmp"); // Step (2) // Setup event handlers using MAKE_DELEGATE m_fsw->Renamed += MAKE_DELEGATE(RenamedEventHandler, OnRenamed); m_fsw->EnableRaisingEvents = true; } // Step (3) // Implement the event handler method void OnRenamed(Object^, RenamedEventArgs^ e) { Console::WriteLine("{0} -> {1}",e->OldName, e->Name); } };


Essentially, these support library classes, make up for missing syntactic support in C++/CLI. Why add compiler overhead, when library implementations are trivial and equally effective? As usual, feedback (both critical and otherwise) is welcome.


This article, along with any associated source code and files, is licensed under The Microsoft Public License (Ms-PL)


About the Author

Nish Nishant
United States United States
Nish Nishant is a Software Architect/Consultant based out of Columbus, Ohio. He has over 16 years of software industry experience in various roles including Lead Software Architect, Principal Software Engineer, and Product Manager. Nish is a recipient of the annual Microsoft Visual C++ MVP Award since 2002 (14 consecutive awards as of 2015).

Nish is an industry acknowledged expert in the Microsoft technology stack. He authored
C++/CLI in Action for Manning Publications in 2005, and had previously co-authored
Extending MFC Applications with the .NET Framework for Addison Wesley in 2003. In addition, he has over 140 published technology articles on and another 250+ blog articles on his
WordPress blog. Nish is vastly experienced in team management, mentoring teams, and directing all stages of software development.

Contact Nish : You can reach Nish on his google email id voidnish.

Website and Blog

You may also be interested in...


Comments and Discussions

GeneralC2061 when trying to pass managed type to native function using auto_gcroot Pin
alleyes17-Mar-10 10:30
memberalleyes17-Mar-10 10:30 
GeneralQuestion about managed/unmanaged code and /clr compilation Pin
El Bazza24-Sep-08 1:03
memberEl Bazza24-Sep-08 1:03 
Questioncom::ptr versus Atl's CComPtr, or comdef.h's _com_ptr Pin
oshah10-Jul-06 1:41
memberoshah10-Jul-06 1:41 
AnswerRe: com::ptr versus Atl's CComPtr, or comdef.h's _com_ptr Pin
Nishant Sivakumar12-Jul-06 3:22
staffNishant Sivakumar12-Jul-06 3:22 
GeneralRe: com::ptr versus Atl's CComPtr, or comdef.h's _com_ptr [modified] Pin
oshah13-Jul-06 11:04
memberoshah13-Jul-06 11:04 
Nishant Sivakumar wrote:
If you use the native classes, you'd have to then declare them as a pointer, and manage memory allocation/deallocation of that pointer.

That's is what I've been doing until now (I was interoping mostly with the native DirectX interfaces). Sure, the syntax is ugly, but at least I could freely mix .NET alongside COM. However, I do take your point about how complicated a pointer to smart pointer member pointer thingy can be (oh wait, that's too many pointers Big Grin | :-D ).

Nishant Sivakumar wrote:
If you try to Attach to a ptr already holding a COM object, it throws an InvalidOperationException.

Although slightly better than what ATL does (at least it throws an exception), I feel this limits the usefulness of com::ptr, particularly when you get to the complicated COM stuff (eg. iterating over a collection, using the MS Office COM interfaces).

So we'll have to decide on the lesser of two evils:
1. Use a com::ptr, taking extreme care when using code which could reassign the ptr.
2. Use a _com_ptr, which is more flexible and can handle reassignment, but is difficult to use inside a ref class.

-- modified at 16:05 Thursday 13th July, 2006
Hmm.. There might be an option 3:

3. Create our own com::ptr class. One which is reassignable, and can work well inside a ref class.
General[Message Removed] Pin
immetoz4-Oct-08 3:09
memberimmetoz4-Oct-08 3:09 
General[Message Deleted] Pin
Oliver_D28-Jun-06 6:37
memberOliver_D28-Jun-06 6:37 
GeneralRe: No 'delete' neccessary Pin
Nishant Sivakumar28-Jun-06 6:49
staffNishant Sivakumar28-Jun-06 6:49 
GeneralRe: No 'delete' neccessary Pin
Nemanja Trifunovic28-Jun-06 7:45
memberNemanja Trifunovic28-Jun-06 7:45 
GeneralRe: No 'delete' neccessary [modified] Pin
Oliver_D28-Jun-06 8:45
memberOliver_D28-Jun-06 8:45 
GeneralGreat Article Pin
Tomer Noy27-Jun-06 21:49
memberTomer Noy27-Jun-06 21:49 
GeneralRe: Great Article Pin
Nishant Sivakumar28-Jun-06 5:07
staffNishant Sivakumar28-Jun-06 5:07 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Terms of Use | Mobile
Web02 | 2.8.170118.1 | Last Updated 20 Jun 2006
Article Copyright 2006 by Nish Nishant
Everything else Copyright © CodeProject, 1999-2017
Layout: fixed | fluid