无法封送“返回值”:托管/非托管类型组合无效

Posted

技术标签:

【中文标题】无法封送“返回值”:托管/非托管类型组合无效【英文标题】:Cannot marshal 'return value': Invalid managed/unmanaged type combination 【发布时间】:2017-07-24 14:53:12 【问题描述】:

我在非托管库中有这个函数,我想在 C# 中调用它:

unsigned char __stdcall InitDev(unsigned char comport, long BaudRate)

这是在 C# 中

[System.Security.SuppressUnmanagedCodeSecurity]
[DllImport("*.dll", CallingConvention = CallingConvention.Cdecl,CharSet =CharSet.Auto)]
public static extern byte[] InitDev(byte[] comport, [Out]long BaudRate);

但是当我在 C# 中调用此函数时,出现以下错误

“无法封送'返回值':托管/非托管类型组合无效。”

string COM = "COM3";
byte[] ptr = new byte[1];
try

    ptr = InitDev(Encoding.ASCII.GetBytes(COM), 9600);

catch (Exception ex)

    MessageBox.Show(ex.Message);

如果提供一些指导,我是新手,我将能够解决此问题

【问题讨论】:

这个函数几乎不可能在 C 程序中可靠地调用,当你从 C# 中执行它时,它永远不会变得更好。你不知道数组中有多少元素,也不知道如何释放它。您必须与此代码的程序员交谈以了解该指针的含义。只要你这样做,让他解决它。波特率参数是一个 int。 【参考方案1】:

假设您的本地呼叫类似于unsigned char* InitDef(unsigned char*, long long &baudRate),那么您可能希望使用IntPtr 代替您的unsigned char*。但首先,由于它是托管/非托管混合,您应该为输入和输出分配 byte[] 缓冲区:

byte[] pInBuffer = Encoding.ASCII.GetBytes("COM3");
// allocate unmanaged memory
IntPtr inputBuffer = Marshal.AllocHGlobal(pInBuffer.Length * sizeof(byte));
Marshal.Copy(pInBuffer, 0, inputBuffer, pInBuffer.Length);

// now your inputBuffer contains a native pointer to the `unsigned char*`
// and since your function returns a new pointer to some `unsigned char*`
// just retrieve it to IntPtr
IntPtr result = InitDev(inputBuffer, 9600);

// free your allocated memory
Marshal.FreeHGlobal(inputBuffer);

在这个阶段,您的result 包含从InitDev 返回的值。


InitDev函数的新定义

[System.Security.SuppressUnmanagedCodeSecurity]
[DllImport("*.dll", CallingConvention = CallingConvention.Cdecl,CharSet =CharSet.Auto)]
public static extern IntPtr InitDev(IntPtr comport, [Out] long BaudRate);

所有必要的电话,你可以在这个msdn page找到


编辑: 由于您的本机通话如下所示:extern unsigned char __stdcall InitDev(unsigned char comport,long BaudRate); 我猜第一个参数只是"COMn" 的最后一位(索引),因为unsigned char 的最低可能值为 0,而 COM 的最低索引可以为 0。

尝试使用这个 sn-p :

[System.Security.SuppressUnmanagedCodeSecurity]
[DllImport("*.dll", CallingConvention = CallingConvention.Cdecl,CharSet =CharSet.Auto)]
public static extern byte InitDev(byte comport, long BaudRate);

然后这样称呼它:

byte comIdx = 3;
byte result = InitDev(comIdx, 9600);
// byte should yield correct result now

【讨论】:

附加信息:对 PInvoke 函数 'WindowsFormsApplication1!WindowsFormsApplication1.Form1::InitDev' 的调用使堆栈失衡。这可能是因为托管 PInvoke 签名与非托管目标签名不匹配。检查 PInvoke 签名的调用约定和参数是否与目标非托管签名匹配。 你能准确地发布 InitDev 的定义在原生 .h 文件中的样子吗? 我已经拿到了这个设备的SDK,它有这个头文件,但是没有以适当的方式解释......让我给你看 extern unsigned char __stdcall InitDev(unsigned char comport,long BaudRate); C# 中的unsigned charbyte,所以不用byte[]IntPtr 你只需要使用byte。我会在几秒钟内编辑它。

以上是关于无法封送“返回值”:托管/非托管类型组合无效的主要内容,如果未能解决你的问题,请参考以下文章

封送包含 char* 成员的非托管结构

在 C# 中使用非托管 C++ 代码对所有双精度类型返回 0

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

C#调用C DLL笔记,提示:无法在 DLL“xxx.dll”中找到名为“xxxx”的入口点

C#调用C DLL笔记,提示:无法在 DLL“xxx.dll”中找到名为“xxxx”的入口点

C#调用C DLL笔记,提示:无法在 DLL“xxx.dll”中找到名为“xxxx”的入口点