我的任务是维护遗留的非托管 C++ 系统。我无权访问整个系统的源代码,但我确实有一些扩展 dll 的源代码,当它们包含在与核心系统相同的目录中时,将加载它们而不是内置的默认值。
我过去曾使用这些扩展进行小的更改,没有出现问题。然而,我现在的问题是我被要求彻底检查一个具有大量额外功能的扩展 dll。在 C# 中创建这个额外的功能将明显更快(开发时间)并且更易于维护(我们的团队主要由 C# 开发人员组成)。
扩展dll 只有两个被核心系统调用的函数。这两个函数采用bool
、int
、uint
、RECT
、Point
、 CString
和返回空值
。它们接受的一些参数是 const
。
我真的很想找到一种可靠的方法将这些扩展函数桥接到 C# (.NET 4)。到目前为止,我已经投入大量精力研究 COM Visible、Regasm、c++ 混合模式和互操作包装库。在这项研究中,我还在概念验证项目上浪费了大量时间,到目前为止,我还没有一个有效的“桥梁”。
启动和运行它最轻松的方法是什么?
我在这个项目上承受的压力比平时大得多 - 我现在真的开始使用 C#,并假设我会以某种方式让它工作。
非常感谢帮助和反馈。
这是 .h 和 .def 文件:
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
最佳答案
几年前我研究过这个主题:我想使用本地代码中的 log4net 和 Npgsql 库,即使使用我们的/clr 键也能编译。
Paul DiLascia 在他的两篇精彩文章中描述了这项技术背后的主要思想:
Managed Code in Visual Studio 2005 Use Our ManWrap Library to Get the Best of .NET in Native C++ Code
例如,这里有一些使用 native 代码中的 log4net 库的代码片段(此代码驻留在简单的非托管 dll 中,但您应该使用/clr 编译它,但使用/clr 关键代码编译并不是必需的从 native 代码使用此 dll):
// 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_);
}
将此代码编译为 native dll,然后将此 dll 添加到您的 native 项目,向该项目添加如下内容:
#pragma once
#pragma comment(lib, "Log4NetWrapper")
extern "C"
{
_declspec(dllimport) void ReportDebugMessage(char* msg);
}
并使用 ReportDebugMessage 从 native 代码访问托管代码。
关于c# - 从非托管 C++ 调用托管 C# 函数(没有返回值)的无痛方式?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3845022/