我知道我可以将其用于技术工作,但我想实施最清晰的解决方案。情况如下:
我有一个托管库,它包装了一个非托管C风格的库。我正在包装的C风格的库函数执行一些涉及字符串列表的处理。库的客户端代码可以提供委托,这样在列表处理期间,如果遇到“无效”场景,库可以通过此委托回调客户端并允许他们选择要使用的策略(抛出异常,替换无效的字符等。)
我理想的是,所有托管C ++都在一个函数中隔离,然后能够调用一个单独的函数,该函数只接受非托管参数,以便所有本机C ++和非托管代码都被隔离在那里一点。为这个非托管代码提供回调机制被证明是我的关键点。
#pragma managed
public delegate string InvalidStringFilter(int lineNumber, string text);
...
public IList<Result> DoListProcessing(IList<string> listToProcess, InvalidStringFilter filter)
{
// Managed code goes here, translate parameters etc.
}
#pragma unmanaged
// This should be the only function that actually touches the C-library directly
std::vector<NativeResult> ProcessList(std::vector<char*> list, ?? callback);
在这个片段中,我想保留ProcessList中的所有C库访问,但在处理过程中,它需要进行回调,并且这个回调是以InvalidStringFilter委托的形式提供的,该委托是从我托管图书馆的一些客户。
答案 0 :(得分:2)
如果声明正确,.NET可以将委托自动转换为指向函数的指针。有两个警告
http://www.codeproject.com/KB/mcpp/FuncPtrDelegate.aspx?display=Print
答案 1 :(得分:2)
如果我正确理解问题,您需要在C ++ / CLI程序集中声明一个非托管回调函数,该函数充当C库和托管代理之间的桥梁。
#pragma managed
public delegate string InvalidStringFilter(int lineNumber, string text);
...
static InvalidStringFilter sFilter;
public IList<Result> DoListProcessing(IList<string> listToProcess, InvalidStringFilter filter)
{
// Managed code goes here, translate parameters etc.
SFilter = filter;
}
#pragma unmanaged
void StringCallback(???)
{
sFilter(????);
}
// This should be the only function that actually touches the C-library directly
std::vector<NativeResult> ProcessList(std::vector<char*> list, StringCallback);
如上所述,此代码显然不是线程安全的。如果你需要线程安全,那么需要一些其他的机制来在回调中查找正确的托管委托,可以是ThreadStatic,也可能是回调被传递给你可以使用的用户提供的变量。
答案 2 :(得分:0)
你想做这样的事情:
typedef void (__stdcall *w_InvalidStringFilter) (int lineNumber, string message);
GCHandle handle = GCHandle::Alloc(InvalidStringFilter);
w_InvalidStringFilter callback =
static_cast<w_InvalidStringFilter>(
Marshal::GetFunctionPointerForDelegate(InvalidStringFilter).ToPointer()
);
std::vector<NativeResult> res = ProcessList(list, callback);