Click here to Skip to main content
15,867,890 members
Articles / Programming Languages / C++/CLI

Using ACE with C++ CLI

Rate me:
Please Sign up or sign in to vote.
4.94/5 (8 votes)
6 Jan 2011CPOL2 min read 42.6K   353   12   10
Demonstrates how easy it is to combine ACE and .NET using C++ CLI mixed mode

Introduction

This article demonstrates something I should have tested years ago. I've been wondering about the power and limitations of the Microsoft C++ CLI for years, nearly always choosing C# for my .NET development needs.

What if it is possible to combine a powerful C++ Framework like ACE with .NET Microsoft C++ CLI and mixed mode programming? Turns out it works quite well.

The simple purpose of this program will be to execute code in a native thread, and return a result to the calling managed code.

Prerequisites

Compile ACE as described by the included documentation. I'll assume you know how to set up the include and library paths for the project, and how to set up a mixed mode C++ CLI project.

Follow this link to download ACE.

Coding

What really surprised me was how easy it was – it probably shouldn’t, but it did.

First, we create a Visual C++ Windows Forms Application.

We are going to pull in a few header files from ACE, so open stdafx.h and add the following:

C++
#ifndef STRICT
#define STRICT
#endif

#pragma managed(push,off)
#include <sdkddkver.h />

#include "ace/Log_Msg.h"
#include "ace/Svc_Handler.h"
#include "ace/Method_Request.h"
#include "ace/Activation_Queue.h"
#include "ace/Future.h"
#include <vector>
#include <string>

#pragma managed(pop)

#pragma managed(push,off) and #pragma managed(pop) turns off and on managed code compilation respectively, enabling unmanaged code compilation.

In ACEDotNetDemo.cpp which contains our C++ CLI main method, we add the following just before our main method:

C++
#pragma managed(push,off)
#ifndef _DEBUG
#pragma comment(lib,"ace")
#else
#pragma comment(lib,"aced")
#endif
#pragma managed(pop)

This lets the linker know that we want to link against "ace.lib" or "aced.lib" in release or debug builds respectively.

The main method is fairly standard, we only call ACE::init() and ACE::fini() to initialize and finalize the framework.

C++
[STAThreadAttribute]
int main(array<:string> ^args)
{
 int result = ACE::init();
 if(result >= 0)
 {
  // Enabling Windows XP visual effects before any controls are created
  Application::EnableVisualStyles();
  Application::SetCompatibleTextRenderingDefault(false); 

  // Create the main window and run it
  Application::Run(gcnew MainForm());

  ACE::fini();

  }
  return result;
}

In ACEDotNetDemoTask.hpp, we declare a very simple class ACEDotNetDemoTask derived from ACE_Task_Base. This is our thread implementation, and the svc method is executed in another thread.

C++
#pragma once

#pragma managed(push,off)

typedef ACE_Future<int> IntFuture;

class ACEDotNetDemoTask : 
 public ACE_Task_Base
{
 ACE_Activation_Queue 
   activation_queue_;

public:
  ACEDotNetDemoTask(void);
  ~ACEDotNetDemoTask(void);

  virtual int svc (void);
  int enqueue (ACE_Method_Request *request);

  IntFuture call_exit();
};

typedef ACE_Singleton<ACEDotNetDemoTask, ACE_Null_Mutex> 
    ACEDOTNETDEMOTASK;

class ExitMethodRequest : 
 public ACE_Method_Request
 {
  IntFuture result_;
public:
 ExitMethodRequest(IntFuture& result)
  : result_(result)
 {
 ACE_TRACE ("ExitMethodRequest::ExitMethodRequest");
 }

 ~ExitMethodRequest( )
 {
  ACE_TRACE ("ExitMethodRequest::~ExitMethodRequest");
 }

 // Sets the value of the IntFuture to -1, and
 // returns -1 causing the svc method to exit.
 virtual int call (void)
 {
  ACE_TRACE ("ExitMethodRequest::call");
  int result = -1;
  result_.set(result);
  return result;
 }
};

#pragma managed(pop)

We use ACE_Singleton to declare a singleton, ACEDOTNETDEMOTASK, for our ACEDotNetDemoTask.

ACEDotNetDemoTask.cpp contains the implementation of ACEDotNetDemoTask.

The svc method dequeues method requests from the activation queue, and calls the call method of the dequeued request until the call method returns -1, quite similar to a standard windows message loop.

C++
int ACEDotNetDemoTask::svc (void)
{
 ACE_TRACE ("ACEDotNetDemoTask::svc");

 while (1)
 {
  auto_ptr<ace_method_request /> 
    request (this->activation_queue_.dequeue ());

  if (request->call () == -1)
  {
    break;
  }
 }
 return 0;
}

The enqueue method enqueues request into the activation queue, for servicing by the svc method:

C++
int ACEDotNetDemoTask::enqueue (ACE_Method_Request *request)
{
 ACE_TRACE ("ACEDotNetDemoTask::enqueue");
  return this->activation_queue_.enqueue (request);
}

call_exit enqueues an ExitMethodRequest to the activation queue, and returns an IntFuture that allows the caller to get the result from the unmanaged thread.

C++
IntFuture ACEDotNetDemoTask::call_exit()
{
 ACE_TRACE ("ACEDotNetDemoTask::call_exit");
 IntFuture result;

 ExitMethodRequest *request = new ExitMethodRequest(result);
 enqueue(request);

 return result;
}

#pragma managed(pop)

That takes care of our unmanaged thread implementation based on ACE_Task_Base.

Interacting with the unmanaged thread from managed C++ CLI code is as you can see really, really simple.

C++
protected:
 virtual void OnShown(EventArgs^ e) override 
 {
  System::Windows::Forms::Form::OnShown(e);
  // Start unmanaged thread
  ACEDOTNETDEMOTASK::instance()->activate();
 }

 virtual void OnFormClosing(FormClosingEventArgs^ e) override 
 {
  // Call unmanaged thread, and tell it to exit
  IntFuture futureResult = ACEDOTNETDEMOTASK::instance()->call_exit();

  // and get the result
  int result = 0;
  futureResult.get(result);
  
  // Wait for the unmanaged thread to exit
  ACEDOTNETDEMOTASK::instance()->wait();

  System::Windows::Forms::MessageBox::Show(
      String::Format(L"Exit Result:{0}",result),
              L"Call Exit");

  System::Windows::Forms::Form::OnFormClosing(e);
 }

Concluding Remarks

No doubt, many of you already know that integrating managed and unmanaged code using mixed mode C++ CLI works amazingly well. But I guess there are many like me who thought this a tantalizing, even probable, idea – but just never got around to verifying it.

What I’ve implemented is a simple active object in unmanaged code; and interacted with it successfully from managed code.

So in the hope that some of you may find it useful, I wrote this little article demonstrating that it actually works very well.

History

  • 6th of January, 2011 - Initial posting

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Architect Sea Surveillance AS
Norway Norway
Chief Architect - Sea Surveillance AS.

Specializing in integrated operations and high performance computing solutions.

I’ve been fooling around with computers since the early eighties, I’ve even done work on CP/M and MP/M.

Wrote my first “real” program on a BBC micro model B based on a series in a magazine at that time. It was fun and I got hooked on this thing called programming ...

A few Highlights:

  • High performance application server development
  • Model Driven Architecture and Code generators
  • Real-Time Distributed Solutions
  • C, C++, C#, Java, TSQL, PL/SQL, Delphi, ActionScript, Perl, Rexx
  • Microsoft SQL Server, Oracle RDBMS, IBM DB2, PostGreSQL
  • AMQP, Apache qpid, RabbitMQ, Microsoft Message Queuing, IBM WebSphereMQ, Oracle TuxidoMQ
  • Oracle WebLogic, IBM WebSphere
  • Corba, COM, DCE, WCF
  • AspenTech InfoPlus.21(IP21), OsiSoft PI


More information about what I do for a living can be found at: harlinn.com or LinkedIn

You can contact me at espen@harlinn.no

Comments and Discussions

 
GeneralMy vote of 5 Pin
Michael Haephrati31-Oct-12 20:47
professionalMichael Haephrati31-Oct-12 20:47 
GeneralRe: My vote of 5 Pin
Espen Harlinn1-Nov-12 1:48
professionalEspen Harlinn1-Nov-12 1:48 
GeneralMy vote of 5 Pin
Simon Bang Terkildsen14-Oct-11 12:41
Simon Bang Terkildsen14-Oct-11 12:41 
GeneralRe: My vote of 5 Pin
Espen Harlinn14-Oct-11 22:16
professionalEspen Harlinn14-Oct-11 22:16 
GeneralMy vote of 5 Pin
Sergey Alexandrovich Kryukov13-Oct-11 13:39
mvaSergey Alexandrovich Kryukov13-Oct-11 13:39 
GeneralRe: My vote of 5 Pin
Espen Harlinn14-Oct-11 0:37
professionalEspen Harlinn14-Oct-11 0:37 
Generallinker errors Pin
wsknprs26-Apr-11 8:37
wsknprs26-Apr-11 8:37 
GeneralRe: linker errors Pin
Espen Harlinn26-Apr-11 9:19
professionalEspen Harlinn26-Apr-11 9:19 
GeneralRe: linker errors Pin
wsknprs26-Apr-11 9:39
wsknprs26-Apr-11 9:39 
GeneralRe: linker errors Pin
Member 107544906-Apr-15 5:21
Member 107544906-Apr-15 5:21 

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.