如何通过C++;结构到C#DLL?

如何通过C++;结构到C#DLL?,c#,c++,struct,pinvoke,marshalling,C#,C++,Struct,Pinvoke,Marshalling,我下面有一个类似的C#DLL。我想在C++ Builder中使用这个C语言DLL。 但是我不知道C结构和C++结构编组: using RGiesecke.DllExport; using System; using System.Collections.Generic; using System.Runtime.InteropServices; using System.Text; namespace TestLibrary { [ComVisible(true)] [Str

我下面有一个类似的C#DLL。我想在C++ Builder中使用这个C语言DLL。

但是我不知道C结构和C++结构编组:

using RGiesecke.DllExport;
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Text;

namespace TestLibrary
{

    [ComVisible(true)]
    [StructLayout(LayoutKind.Sequential, Pack = 1)]
    public struct MyStruct
    {
        public int X;
        public int Y;
    }


    public class Class1
    {
        [DllExport("DoSomething", CallingConvention = CallingConvention.StdCall)]
        public static int DoSomething(int x, int y, ref MyStruct myStruct)
        {
            myStruct.X = 50;
            myStruct.Y = 75;
            return x + y;
        }

    }
}
我想从C++ Builder下面传递“MyStult”参数,如

void __fastcall TForm1::FormCreate(TObject *Sender)
{
  struct MyStruct
  {
    int X;
    int Y;
   };

  int (__stdcall *DoSomething)(int,int,MyStruct);


  HINSTANCE dllHandle = NULL;
  dllHandle = LoadLibrary( edtdllPath->Text.c_str());
  if(dllHandle == NULL) return;
  int status = -1;

  try
  {
    DoSomething =(int (__stdcall *)(int,int,MyStruct)) GetProcAddress(dllHandle, "DoSomething");
  }
  catch(Exception &Err)
  {
    ShowMessage(Err.Message);
  }

  if(DoSomething != NULL)
  {
    try
    {
      MyStruct myStruct;
      status = DoSomething(5,5,myStruct);
      String strStatus = status;

      ShowMessage(strStatus);
      ShowMessage(myStruct.X);
      ShowMessage(myStruct.Y);
    }
    catch(EAccessViolation &err)
    {
     ShowMessage(err.Message);
    }
  }

}
调试代码时,myStruct.X和myStruct.Y的值是错误的


我的错在哪里?

您没有将结构作为指向c的指针传递,但在c中,您告诉它将是一个指针(
ref
)。

您没有将结构作为指向c的指针传递,但在c中,您告诉它将是一个指针(
ref
)。

c项目声明结构参数如下:

ref MyStruct myStruct
int status = DoSomething(5,5,&myStruct);
作为指向结构的指针封送。在C++中,这意味着

MyStruct*
因此,将函数指针变量的声明更改为:

int (__stdcall *DoSomething)(int,int,MyStruct*);
并在强制转换时使用相同的类型:

DoSomething =(int (__stdcall *)(int,int,MyStruct*)) GetProcAddress(dllHandle, "DoSomething");
请注意,这里使用typedef可以更好地避免重复。还要注意,
GetProcAddress
不会引发异常。它通过返回
NULL
来表示错误。您没有正确检查错误

调用函数时,传递结构的地址:

status = DoSomething(5,5,&myStruct);
声明
status
并将其初始化为-1,但随后覆盖该值也有点毫无意义。更惯用的做法是这样声明和初始化它:

ref MyStruct myStruct
int status = DoSomething(5,5,&myStruct);
C#项目声明struct参数如下:

ref MyStruct myStruct
int status = DoSomething(5,5,&myStruct);
作为指向结构的指针封送。在C++中,这意味着

MyStruct*
因此,将函数指针变量的声明更改为:

int (__stdcall *DoSomething)(int,int,MyStruct*);
并在强制转换时使用相同的类型:

DoSomething =(int (__stdcall *)(int,int,MyStruct*)) GetProcAddress(dllHandle, "DoSomething");
请注意,这里使用typedef可以更好地避免重复。还要注意,
GetProcAddress
不会引发异常。它通过返回
NULL
来表示错误。您没有正确检查错误

调用函数时,传递结构的地址:

status = DoSomething(5,5,&myStruct);
声明
status
并将其初始化为-1,但随后覆盖该值也有点毫无意义。更惯用的做法是这样声明和初始化它:

ref MyStruct myStruct
int status = DoSomething(5,5,&myStruct);


绳子是个大问题。您不能使用
ref-StringBuilder
,我认为您也不能使用
StringBuilder
。到目前为止,最简单的解决方案是使用
UnmanagedType.BStr
和COM
BStr
。你确实需要做一点备份,并且比目前更了解基础知识。谢谢大家的关注@DavidHeffernan。我已经检查了StringBuilder参数,它正在工作。不起作用只有myStruct参数。不,字符串生成器不能起作用。问问自己,谁将释放内存?首先。还有更多的问题。你弄错了。谢谢@DavidHeffernan-ur-guruI,你给X添加了这样的地址。结构MyStruct{int*X;double*Y;};我得到的“myStruct.X”值如下所示。ShowMessage(*myStruct.X);但是*myStruct.X的值是错误的。字符串是一个大问题。您不能使用
ref-StringBuilder
,我认为您也不能使用
StringBuilder
。到目前为止,最简单的解决方案是使用
UnmanagedType.BStr
和COM
BStr
。你确实需要做一点备份,并且比目前更了解基础知识。谢谢大家的关注@DavidHeffernan。我已经检查了StringBuilder参数,它正在工作。不起作用只有myStruct参数。不,字符串生成器不能起作用。问问自己,谁将释放内存?首先。还有更多的问题。你弄错了。谢谢@DavidHeffernan-ur-guruI,你给X添加了这样的地址。结构MyStruct{int*X;double*Y;};我得到的“myStruct.X”值如下所示。ShowMessage(*myStruct.X);但是*myStruct.X的值是错误的。我得到的错误是行状态=DoSomething(5,5,&myStruct);[C++错误]Unit1.cpp(63):E2034无法将“MyStruct**”转换为“MyStruct*”,但当我删除该命令时&已编译字符。谢谢你所做的一切@david这是因为你改变了问题中的代码。您声明了
MyStruct*MyStruct
,这是一个错误。当我向struct中添加两个以上的字段时,会引发EAccessViolation异常。问题的根源是什么?如何调试此问题?------------------------------------调试器异常通知-----------------Project 1.exe引发异常类EAccessViolation,消息为“地址CCD处的访问冲突”。读取地址“CCD”。进程已停止。使用步骤或运行继续。----------------------------好的帮助-----------------你说得对。我只添加了int Z命名的字段。结构MyStruct{intx;双Y;intz;};这只是代码的一半。C代码也很重要。出于某种原因,打包了C++结构,而不是C++结构。不建议使用包装。这会导致数据不一致。为什么决定打包?我得到一个错误,行状态=DoSomething(5,5,&myStruct);[C++错误]Unit1.cpp(63):E2034无法将“MyStruct**”转换为“MyStruct*”,但当我删除该命令时&已编译字符。谢谢你所做的一切@david这是因为你改变了问题中的代码。您声明了
MyStruct*MyStruct
,这是一个错误。当我向struct中添加两个以上的字段时,会引发EAccessViolation异常。问题的根源是什么?如何调试此问题?------------------------------------调试器异常通知-----------------Project 1.exe引发异常类EAccessViolation,消息为“地址CCD处的访问冲突”。读取地址“CCD”。进程已停止。使用步骤或运行继续。----------------------------好的帮助-----------------你说得对。我只添加了int Z命名的字段。结构MyStruct{intx;双Y;intz;};这只是代码的一半。C代码也很重要。出于某种原因,您打包了C#struct,但没有打包