【问题标题】:passing structure reference from a c# code to call a c++ DLL function that accept structure reference in its prototype从 c# 代码传递结构引用以调用在其原型中接受结构引用的 c++ DLL 函数
【发布时间】:2011-07-21 02:54:22
【问题描述】:

我在 c++ DLL 中有一个具有以下原型的函数

int function(RefPar &params);

如何使用“DLLImport”从 c# 程序调用此函数。

当我像下面这样尝试时,AccessViolationException 在 Visual Studio 2008 中运行时发生..

[DllImport("VistaGMMDLL.dll", EntryPoint = "function"]
unsafe static extern int function(ref RefPar params);

并称为..

int ret=function(ref params);

注意:RefPar结构有很多 无符号整数值和 1 个枚举 作为其成员的价值。

请任何人帮助我正确调用该函数..

【问题讨论】:

  • 我对编组为本机代码的经验很少,但您可能需要将其作为IntPtr 传递。您还必须非常小心如何在 C# 和 C++ 中定义结构,因为两种语言之间的结构布局/打包完全不同。
  • 我正在使用 [StructLayout(LayoutKind.Sequential)] 进行布局打包。
  • 我认为您可能还需要在 C++ 中使用一些特殊关键字来确保(可移植地)特定的对象布局。

标签: c# c++ dll reference parameter-passing


【解决方案1】:

这样试试:

[StructLayout(LayoutKind.Sequential)]
public struct RefPar
{
    UInt32 uint1;
    UInt32 unti2;
    ....
} 


[DllImport("VistaGMMDLL.dll", EntryPoint = "function"]
unsafe static extern int function(IntPtr params);

//calling

//fill the refParStructure
//create the IntPtr  

refParStruct rs = new RefPar();

IntPtr refparPtr = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(refPar)));


Marshal.StructureToPtr(refParStruct, refparPtr,false);
ret=function(refParPtr);

如果您需要更多详细信息,请告诉我

【讨论】:

  • 嗨.. 感谢您的回复.. 我是 c# 的新手.. 我确实是你说的。以这种方式创建了一个 IntPtr。 IntPtr refptr=new IntPtr(); Marshal.StructureToPtr(refparstruct,refptr, true); refptr 即将出现 ArgumentNullException,请告诉我是否必须以不同的方式初始化 IntPtr??
  • 您好,您必须使用 refptr=Marshal.AllocHGlobal(Marshal.SizeOf(size)); 分配指针;
【解决方案2】:

另一个非常简单的调用这个函数的方法是:

Create a c++ dll warapper that link your original dll and contains this function

//c++ code

function2(uint param1, uint param2.....)
{
  RefPar refpar;

  refpar.param1=param1

  refpar.param2=param2

  function(&refpar)

}



in this way you have just to import (in C#) the dll wrapper function in this way


[DllImport("wrapperdll.dll", EntryPoint = "function2"]
static extern int function2(Uint32 param1,Uint32 param2....);


that is very simple to call.


Regards

【讨论】:

    【解决方案3】:

    我突然想到了几件事。首先,我不明白为什么需要使用 unsafe。其次,你可能有一个调用约定不匹配,C++ 中的 cdecl 和 C# 中的 stdcall。

    我会这样做:

    C++

    struct RESOURCE_PARAMETERS{
        unsigned int uSurfaceHeight;
        unsigned int uSurfaceDepth;
        unsigned int uSurfaceWidth;
        unsigned int uMSAAHeight;
        unsigned int uMSAAWidth;
        unsigned int uArraySize;
        unsigned int uNumSamples;
        unsigned int uMaxLod;
        unsigned int uBpp;
        unsigned int uprefFlag;
        unsigned int uusageFlag;
        RESOURCE_TYPE_REC ResourceType;
        int ResourceFormat;
        int iBuildNumber;
    };
    
    int function(RefPar &parameters)
    {
    }
    

    C#

    [StructLayout(LayoutKind.Sequential)]
    public struct RESOURCE_PARAMETERS
    {
        uint uSurfaceHeight;
        uint uSurfaceDepth;
        uint uSurfaceWidth;
        uint uMSAAHeight;
        uint uMSAAWidth;
        uint uArraySize;
        uint uNumSamples;
        uint uMaxLod;
        uint uBpp;
        uint uprefFlag;
        uint uusageFlag;
        [MarshalAs(UnmanagedType.U4)]
        ResourceType ResourceType;
        int ResourceFormat;
        int iBuildNumber;
    } 
    
    [DllImport("VistaGMMDLL.dll", CallingConvention = CallingConvention.Cdecl)]
    static extern int function(ref RESOURCE_PARAMETERS parameters);
    
    RESOURCE_PARAMETERS parameters = new RESOURCE_PARAMETERS();
    int result = function(ref parameters);
    

    我不确定枚举在 C++ 大小上的大小。这就是为什么我在 C# 代码中放置了一个明确的 MarshalAs。如果它只是一个字节,则使用 UnmanagedType.U1 代替。我相信你明白了。

    如果您的 C++ 函数将其参数视为输入/输出参数,则在 C# 端使用 ref 是正确的。如果它实际上是一个 out 参数,则将代码更改为:

    [DllImport("VistaGMMDLL.dll", CallingConvention = CallingConvention.Cdecl)]
    static extern int function(out RESOURCE_PARAMETERS parameters);
    
    RESOURCE_PARAMETERS parameters;
    int result = function(out parameters);
    

    【讨论】:

    • 嗨..我添加了调用约定.Cdecl。我的结构在 C++ DLL 中, struct RESOURCE_PARAMETERS{ unsigned int uSurfaceHeight;无符号 int uSurfaceDepth;无符号整数 uSurfaceWidth;无符号整数 uMSAAHeight;无符号整数 uMSAAWidth;无符号整数 uArraySize;无符号整数 uNumSamples;无符号整数 uMaxLod;无符号整数 uBpp;无符号整数 uprefFlag;无符号整数 uusageFlag; RESOURCE_TYPE_REC 资源类型;诠释资源格式; int iBuildNumber; } 其中 RESOURCE_TYPE_REC 是一个枚举
    • 在 c# 中的结构是在 c# [StructLayout(LayoutKind.Sequential)]struct ResourceParameters {public UInt32 uSurfaceHeight;公共 UInt32 uSurfaceDepth;公共 UInt32 uSurfaceWidth;公共 UInt32 uMSAAHeight;公共 UInt32 uMSAAWidth;公共 UInt32 uArraySize;公共 UInt32 uNumSamples;公共 UInt32 uMaxLod;公共 UInt32 uBpp;公共 UInt32 uprefFlag;公共 UInt32 使用标志;公共资源类型记录资源类型;公共 Int32 资源格式;公共 Int32 iBuildNumber; } 在这 ResourceTypeRec 也是一个枚举
    • 我也要给枚举结构吗??
    猜你喜欢
    • 2015-02-10
    • 1970-01-01
    • 1970-01-01
    • 2013-05-12
    • 2011-02-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多