无法封送“返回值”:托管/非托管类型组合无效
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 char
是byte
,所以不用byte[]
或IntPtr
你只需要使用byte
。我会在几秒钟内编辑它。以上是关于无法封送“返回值”:托管/非托管类型组合无效的主要内容,如果未能解决你的问题,请参考以下文章
在 C# 中使用非托管 C++ 代码对所有双精度类型返回 0
C#调用C DLL笔记,提示:无法在 DLL“xxx.dll”中找到名为“xxxx”的入口点