处理非托管代码中的托管代理

时间:2008-10-03 19:33:49

标签: .net c++ callback managed-c++

我知道我可以将其用于技术工作,但我想实施最清晰的解决方案。情况如下:

我有一个托管库,它包装了一个非托管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委托的形式提供的,该委托是从我托管图书馆的一些客户。

3 个答案:

答案 0 :(得分:2)

如果声明正确,.NET可以将委托自动转换为指向函数的指针。有两个警告

  1. 必须构建C函数STDCALL
  2. 指向函数的指针不计为对象的引用,因此您必须安排引用以保留基础对象不是垃圾收集
  3. 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);