Reputation: 11003
I have been tasked with maintaining a legacy unmanaged c++ system. I do not have access to the source of the entire system but I do have the source to a number of extension dlls that, when included in the same directory as the core system, will be loaded instead of the built in defaults.
I have used the extensions in the past for small changes without problems. My issue now, however, is that I'm being asked to overhaul one of the extension dlls with a substantial amount of extra functionality. Creating this extra functionality in C# is going to be significantly faster (time-to-develop) and more maintainable (our team is primarily composed of C# devs).
The extension dll only has two functions that get called by the core system. The two functions take a bool
, int
, uint
, RECT
, Point
, CString
and return void
. Some of the parameters they accept are const
.
I'm really keen to find a solid way to bridge these extension functions to C# (.NET 4). So far I've put considerable effort into researching COM Visible, Regasm, c++ mixed mode and interop wrapping libraries. I've also lost a considerable amount of time on proof of concept projects during this research and so far I do not have a working 'bridge'.
What is the most pain free method to get this up and running?
I'm under considerably more pressure on this project than normal - I'm literally starting the C# now and assuming I will get this working somehow.
Really appreciate help and feedback.
Here is the .h and .def files:
modeldll.h
#ifndef INC_MODELDLL_H
#define INC_MODELDLL_H
#ifdef MODELDLL_EXPORTS
#define MODELDLL_API __declspec(dllexport)
#else
#define MODELDLL_API __declspec(dllimport)
#endif
typedef int (*model_updatemodel_t)(const bool update_model, const HWND hwnd, const RECT rect, const POINT next_point, const CString title);
MODELDLL_API int UpdateModel(const bool update_model, const HWND hwnd, const RECT rect, const POINT next_point, const CString title);
typedef int (*model_updatemodelpoint_t)(const bool update_model, const HWND hwnd, const RECT rect, UINT update, const POINT next_point);
MODELDLL_API int UpdateModelPoint(const bool update_model, const HWND hwnd, const RECT rect, UINT update, const POINT next_point);
typedef void (*model_process_message_t)(const char *message, const void *param);
MODELDLL_API void ProcessMessage(const char *message, const void *param);
#endif // INC_MODELDLL_H
modeldll.def:
LIBRARY model.dll
EXPORTS
ProcessMessage @1
UpdateModel @2
UpdateModelPoint @3
Upvotes: 3
Views: 459
Reputation: 11657
I've investigated this topic couple of years ago: I want to use log4net and Npgsql libraries from native code that compiles even withour /clr key.
The main idea behind this technique described by Paul DiLascia in his two remarkable articles:
Managed Code in Visual Studio 2005 Use Our ManWrap Library to Get the Best of .NET in Native C++ Code
For example, here some code snippets that uses log4net library from native code (this code resides in simple non-managed dll, but you should compile this with /clr, but it's not nessary to compile with /clr key code that would use this dll from native code):
// Log4NetWrapper.h
#pragma once
using namespace System;
//facade for log4net library (you may create something like this too)
ref class Log4NetWrapper
{
public:
//I intentionally remove additional methods, because
//I'm trying to show the main principle
static void ReportDebugMessage(char* msg);
private:
static property log4net::ILog^ Logger
{
log4net::ILog^ get();
}
static Object^ syncObject_ = gcnew Object();
static String^ loggerName_ = "";
};
//C-interface that could be accessed from native code
extern "C"
{
_declspec(dllexport) void ReportDebugMessage(char* msg)
{
Log4NetWrapper::ReportDebugMessage(msg);
}
}
// This is the main DLL file.
#include "stdafx.h"
#include "Log4NetWrapper.h"
void Log4NetWrapper::ReportDebugMessage(char* msg)
{
String^ data = gcnew String(msg);
Logger->Debug(data);
}
log4net::ILog^ Log4NetWrapper::Logger::get()
{
if ( loggerName_ == nullptr )
return log4net::LogManager::GetLogger("");
return log4net::LogManager::GetLogger(loggerName_);
}
Compile this code as native dll, than add this dll to your native project, add something like this to that project:
#pragma once
#pragma comment(lib, "Log4NetWrapper")
extern "C"
{
_declspec(dllimport) void ReportDebugMessage(char* msg);
}
And use ReportDebugMessage to access managed code from native code.
Upvotes: 1
Reputation: 2834
As Preet suggested, this can be done using a Managed C++ wrapper that will do the bridging you need.
This article explains the entire process: http://www.codeproject.com/KB/mcpp/unmanaged_to_managed.aspx
I've actually done these sort of things quite a lot several years ago, and all direction work pretty well - C# calling C++ code, C++ code calling C# (via a Managed C++ proxy) and C# passing delegate to a C++ code treating them as function pointers and calling them. I've had some example projects for this, I'll try and find them.
Upvotes: 1
Reputation: 65506
Without further information there's not much to go on but I would suggest that you have the following.
Extension Dll (unmanaged code) -> Managed C++ (wrapper) -> C# dll
The first jump is explained in this example:
http://www.codeproject.com/KB/mcpp/cpptomancpp.aspx
You can then load the c# assembly from the managed c++ fairly easily using
using namespace YourNameSpace; // the namespace of the c# routines
In time you may be able to merge the first two.
Upvotes: 1