如何将指针参数从C#传递到C ++ .dll中的函数 [英] How to pass pointer arguments from C# to a function in C++ .dll

查看:225
本文介绍了如何将指针参数从C#传递到C ++ .dll中的函数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

你好,
在将参数从托管代码传递到非托管代码时,我遇到了一些问题.我有一个C ++ dll,我想从C#项目(VS2010)中调用它的几个功能. C ++ dll不是本机程序集或COM组件.所以我正在使用DllImport-P \ Invoke.

C ++函数详细信息

Hello,
I am facing some issues in passing arguments from managed code to unmanaged code. I am having a C++ dll and i want to call few functions of it from a C# project (VS2010). C++ dll is not a native assembly or COM component. So i am using DllImport - P\Invoke.

C++ function details

typedef unsigned long UINT32;
typedef UNIT32 ABC_RESULT; // the return code from a ABC function
typedef UINT32 ABC_HOBJECT; // basic object handle
typedef ABC_HOBJECT ABC_HCONTEXT; // context object handle

ABC_RESULT Abc_Context_Create(
ABC_HCONTEXT* phContext  // out
);


phContext-接收创建的上下文对象的句柄.

C#签名-


phContext - Receives the handle to the created context object.

C# signature -

public class Abc1api
{
[DllImport("Abc1.dll")]
public static extern UInt32 Abc_Context_Create(UIntPtr phContext);
}


我称呼它如下-


And i am calling it as below -

UInt32 result = 0;
UIntPtr hContext = new UIntPtr(sizeof(UInt32));
result = Abc1api.Abc_Context_Create(hContext);



我能够构建项目,但是在运行时出现错误-
调用PInvoke函数"ABCTool!ABCTool.Abc1api :: Abc_Context_Create"已使堆栈不平衡.这可能是因为托管PInvoke签名与非托管目标签名不匹配.检查PInvoke签名的调用约定和参数是否与目标非托管签名匹配.

我尝试了IntPtr hContext而不是UIntPtr,但是结果是相同的.

所以我修改了C#签名,如下所述-



I am able to build the project but while running i am getting below error -
A call to PInvoke function ''ABCTool!ABCTool.Abc1api::Abc_Context_Create'' has unbalanced the stack. This is likely because the managed PInvoke signature does not match the unmanaged target signature. Check that the calling convention and parameters of the PInvoke signature match the target unmanaged signature.

I tried IntPtr hContext instead of UIntPtr but result is same.

So I modified C# signature as mentioned below -

public class Abc1api
{
[DllImport("Abc1.dll")]
[return: MarshalAs(UnmanagedType.U4)]
public static extern UInt32 Abc_Context_Create([MarshalAs(UnmanagedType.U4), Out()] IntPtr phContext);
}



我称它为-



And I am calling it as below -

UInt32 result = 0;
IntPtr hContext = new IntPtr(sizeof(UInt32));
result = Abc1api.Abc_Context_Create(hContext);


当我运行它时,错误是-无法编组参数#1":无效的托管/非托管类型组合(Int/UInt必须与SysInt或SysUInt配对).

我尝试了UIntPtr,但结果相同.还尝试使用元帅(即
)分配IntPtr hContext IntPtr hContext = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(UInt32)));但出现与上述相同的错误.

我找不到此错误的原因.任何人都可以帮助我定义C#签名以及如何传递参数,以便可以从非托管代码中获取所需的hContext并使用它吗?

谢谢
Satish.


When i run it, the error is - Cannot marshal ''parameter #1'': Invalid managed/unmanaged type combination (Int/UInt must be paired with SysInt or SysUInt).

I tried UIntPtr but same result. Also tried allocating IntPtr hContext using Marshal i.e.
IntPtr hContext = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(UInt32))); but getting same error as above.

I could not find out the reason of this error. Can any one help me in defining C# signature and how can I pass the arguments so that I can get the required hContext from unmanaged code and use it?

Thank you,
Satish.

推荐答案

既然您了解C ++的用法,为什么不使用C ++/CLI混合模式解决问题呢?在本文中,我演示了将ACE与C ++ CLI一起使用 [
Since you know your way around C++, why not solve the issue using mixed mode C++/CLI? In this article I demonstrate using ACE with C++ CLI[^], where ACE is a regular native C++ library compiled into a DLL. One of the nice things is that you can forget about c++ name mangling, it''s all taken care of for you.

I guess this is an easier solution :) - Expose the functionality of your c++ library as CLI - call native dll from cli code.

Regards
Espen Harlinn


首先,您需要使用__declspec(dllexport)导出该函数,以使其显示在DLL的导出函数中(还有其他可用的方法,例如.def文件)

C ++会在导出函数名称时对其进行修改",以导出参数的类型并返回类型.为避免这种情况,需要在extern "C" {}块中定义导出的函数,该块无需进行任何处理就可以将它们导出为C函数.

要检查名称是否乱码,请使用诸如
DependencyWalker [
Firstly, you need to export the function with __declspec(dllexport) for it to show up in the DLL''s exported functions (there are also other methods avaliable for this such as a .def file)

C++ will "mangle" function names when it exports them in order to export the type of arguments and return type. To avoid this, the exported functions need to be defined inside a extern "C" {} block which exports them as a C function without this mangling.

To check if the names are mangled get a program such as DependancyWalker[^] and open the C++ DLL in it.
What you are looking for is over the right hand side in the middle which shows the exported functions.
You need to cehck to see if the function names contain return and parameter types or have jumbled up names.

typedef unsigned long UINT32;
typedef UNIT32 ABC_RESULT; // the return code from a ABC function
typedef UINT32 ABC_HOBJECT; // basic object handle
typedef ABC_HOBJECT ABC_HCONTEXT; // context object handle

extern "C" {
	__declspec(dllexport) ABC_RESULT Abc_Context_Create(ABC_HCONTEXT * phContext) {
		//The code, you may need to call another function from here if you are wanting to do something only valid in C++
	}
}


// int or uint
typedef unsigned long UINT32;
// int or uint
typedef UNIT32 ABC_RESULT; // the return code from a ABC function
// int or uint
typedef UINT32 ABC_HOBJECT; // basic object handle
// int or uint
typedef ABC_HOBJECT ABC_HCONTEXT; // context object handle
// returns int or uint and passes out a pointer (reference) to a int or uint that is the context
ABC_RESULT Abc_Context_Create(ABC_HCONTEXT* phContext  // out);


因此,我要声明:


Therefore I would declare it:

public class Abc1api
{
    [DllImport("Abc1.dll")]
    public static extern UInt32 Abc_Context_Create(out UInt32 hContext);
}




or

[DllImport("Abc1.dll")]
public static extern Int32 Abc_Context_Create(out Int32 hContext);



希望这会有所帮助!



Hope this helps!


这篇关于如何将指针参数从C#传递到C ++ .dll中的函数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆