如何使用非托管 C/C++ 结构和函数

Posted

技术标签:

【中文标题】如何使用非托管 C/C++ 结构和函数【英文标题】:How to use unmanaged C/C++ structs and functions 【发布时间】:2015-08-22 03:55:33 【问题描述】:

我的任务是找出一种方法(如果可能的话)将用 C/C++(更多是 C,然后是 C++)编写的商业程序的低级处理部分转换为托管库,以便与更新后的库一起使用C# 中的程序。我拥有 Visual C++ 6.0 中的完整源代码以及 DLL 和静态库。

一个必须的要求是不要修改任何 C/C++ 代码 - 只是以某种方式围绕它创建一个包装器。我相信我会尝试创建一个托管的 C++ DLL。在许多函数中广泛使用结构和结构指针。

考虑一下来自 C/C++ 头文件的类似内容:

typedef struct 
   union 
       char *char_p;
       void *void_p;
   
   int a;
   void *rsvd[16];
  sample_struct;

int sample_func(sample_struct *struct_p, double x);
int sample_func(sample_struct *struct_p, double x, double y);

如何将其包装到 CLR 包装器中?

非常感谢任何反馈。我什至对不同的方法持开放态度。

谢谢。

【问题讨论】:

CLR 环境有一种称为平台调用的机制,它在大多数情况下只允许您直接调用本机代码。 mono-project.com/docs/advanced/pinvoke 这里有什么问题?你还没有确定行动计划。 C++/CLI 调用现有的 DLL? C++/CLI 重新编译源码? P/invoke 现有的 DLL?会是什么。 研究完,我打算重新编译C++/CLI源码。 【参考方案1】:

您可以先创建一个包装器 ref 结构: 因为托管C++没有联合,所以使用cp_valid作为标志(cp或vp有效)。

ref struct wrapper_st 
    String^ cp;
    IntPtr^ vp;
    bool cp_valid;
    int a;
    array<IntPtr^>^ rsvd;
;

其次,创建包装函数

int wrapper_func(wrapper_st ^st, double x)

    sample_struct t;
    char *pp = (char*)Marshal::StringToHGlobalAnsi(st->cp).ToPointer();
    if (st->cp_valid)
        t.char_p = pp;
    else
        t.void_p = st->vp->ToPointer();
    t.a = st->a;

    // must ensure st->rsvd is not null, and length is 16!!!
    for (int i = 0; i < 16; ++i)
    
        t.rsvd[i] = st->rsvd[i]->ToPointer();
    
    int ret = sample_func(&t, x);
    Marshal::FreeHGlobal(IntPtr(pp));
    return ret;

那么,你可以在c#中使用包装函数

【讨论】:

如何包装一个简单的 int 指针?本质上,将 int ^ 转换为 int 。示例 C 函数:带包装函数的 Add(int a, int b, int sum):Add_wrapper(int a, int b, int ^sum)。 我认为这个解决方案的一个问题是非托管函数可能会修改结构成员的值,比如“t.a”。这没有反映在可能重要的 wrapper_st 上 您可以使用 pin_ptr 包装一个 int 指针。 pin_ptr pa = &t.a; int *native_pointer = pa;见link

以上是关于如何使用非托管 C/C++ 结构和函数的主要内容,如果未能解决你的问题,请参考以下文章

如何从非托管 C++ 代码获取结构化列表值到 C#?

通过 DllImport 调用非托管函数时堆损坏

调用非托管代码时,CLR 如何封送仅包含单个字段的结构?

如何使用 std::vector 作为 C# 的参数调用非托管 C++ 函数?

C#/C++ 回调类(非函数)互操作 - 如何?

dllimport如何在非托管dll中获取哪个应用程序调用了函数