Click here to Skip to main content
Click here to Skip to main content

Using ACE with C++ CLI

, 6 Jan 2011
Rate this:
Please Sign up or sign in to vote.
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:

#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:

#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.

[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.

#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.

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:

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.

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.

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)

About the Author

Espen Harlinn
Architect Powel AS
Norway Norway
Chief Architect - Powel 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@powel.no

Comments and Discussions

 
GeneralMy vote of 5 PinmemberMichael Haephrati מיכאל האפרתי31-Oct-12 20:47 
GeneralRe: My vote of 5 PinmvpEspen Harlinn1-Nov-12 1:48 
GeneralMy vote of 5 PinmemberSimon Bang Terkildsen14-Oct-11 12:41 
GeneralRe: My vote of 5 PinmemberEspen Harlinn14-Oct-11 22:16 
GeneralMy vote of 5 PinmemberSAKryukov13-Oct-11 13:39 
GeneralRe: My vote of 5 PinmemberEspen Harlinn14-Oct-11 0:37 
Generallinker errors Pinmemberwsknprs26-Apr-11 8:37 
GeneralRe: linker errors PinmemberEspen Harlinn26-Apr-11 9:19 
GeneralRe: linker errors Pinmemberwsknprs26-Apr-11 9:39 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    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 | Mobile
Web04 | 2.8.140721.1 | Last Updated 7 Jan 2011
Article Copyright 2011 by Espen Harlinn
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid