C#方法的类型签名不是pinvoke兼容的

时间:2015-02-18 08:33:06

标签: c# interop dllimport

我想使用Omron V4KU的API,这样描述的文档: API Struct

原始c#代码:

    const string DllLocation = @"..\..\Libs\Omron\OMCR.dll";

    [DllImport(DllLocation)]
    public static extern LPCOMCR OMCR_OpenDevice(string lpcszDevice, LPCOMCR_OPTION lpcOption);

    public void Start()
    {
        var lpcOption = new LPCOMCR_OPTION();
        var result = OMCR_OpenDevice(null, lpcOption); // error method's type signature is not pinvoke compatible
    }

    [StructLayout(LayoutKind.Sequential)]
    public struct LPCOMCR
    {
        public string lpcszDevice;
        public IntPtr hDevice;
        public uint lpcDevice;
    }

    [StructLayout(LayoutKind.Sequential)]
    public struct LPCOMCR_OPTION
    {
        public uint dwReserved0;
        public uint dwReserved1;
        public uint dwReserved2;
        public uint dwReserved3;
    }

如果我在编写代码时遗漏或错误? 对不起,我的英语不好。谢谢你的帮助。

3 个答案:

答案 0 :(得分:3)

首先正确定义联合结构:

// OMCR_OPTION.COM
[StructLayout(LayoutKind.Sequential)]
public struct OmcrCom
{
    public IntPtr Reserved0;
    public uint BaudRate;
    public uint Reserved1;
    public uint Reserved2;
    public uint Reserved3;
    public IntPtr Reserved1;
    public IntPtr Reserved2;
}

// OMCR_OPTION.USB
[StructLayout(LayoutKind.Sequential)]
public struct OmcrUsb
{
    public uint Reserved0;
    public uint Reserved1;
    public uint Reserved2;
    public uint Reserved3;
}

// OMCR_OPTION (union of COM and USB)
[StructLayout(LayoutKind.Explicit)]
public struct OmcrOptions
{
    [FieldOffset(0)]
    public OmcrCom Com;

    [FieldOffset(0)]
    public OmcrUsb Usb;
}

// OMCR
[StructLayout(LayoutKind.Sequential)]
public struct OmcrDevice
{
    public string Device;
    public IntPtr DeviceHandle;
    public IntPtr DevicePointer;
}

[DllImport(dllName: DllLocation, EntryPoint = "OMCR_OpenDevice"]
public static extern IntPtr OmcrOpenDevice(string type, ref OmcrOptions options);

然后调用方法,例如:

var options = new OmcrOptions();
options.Com.BaudRate = 115200; // or whatever you need to set

var type = "COM"; // is this USB/COM? not sure

OmcrDevice device;

var devicePtr = OmcrOpenDevice(type, ref options);
if (devicePtr == IntPtr.Zero)
    device = (OmcrDevice)Marshal.PtrToStructure(devicePtr, typeof(OmcrDevice));

答案 1 :(得分:2)

嗯,首先,文档要求您将LPCOMCR_OPTION作为指针传递 - 您将其作为值传递。使用ref应该有所帮助。但是还有另一个问题,那就是返回值 - 再次,你试图把它解释为一个值,而文档说它是一个指针。但是,这比第一个错误要复杂得多 - 据我所知,您唯一的选择是使用C ++ / CLI互操作库,或期望IntPtr作为返回值。在任何情况下,您都需要通过这种方式处理正确的内存释放。

答案 2 :(得分:2)

你需要这样做:

[StructLayout(LayoutKind.Sequential)]
public struct OMCR
{
    [MarshalAs(UnmanagedType.LPStr)]
    public string lpcszDevice;
    public IntPtr hDevice;
    public IntPtr lpcDevice;
}

[StructLayout(LayoutKind.Sequential)]
public struct OMCR_OPTION
{
    public uint dwReserved0;
    public uint dwReserved1;
    public uint dwReserved2;
    public uint dwReserved3;
}

[DllImport(DllLocation, CallingConvention = CallingConvention.???,
    SetLastError = true)]
public static extern IntPtr OMCR_OpenDevice(string lpcszDevice, 
    ref OMCR_OPTION lpcOption);

您需要使用适当的调用约定替换CallingConvention.???。我们无法从问题中看出这是什么。您必须通过阅读头文件找到答案。

返回值是指向OMCR的指针。完成后,您需要抓住此指针并将其传递给OMCR_CloseDevice

要获得OMCR值,您可以执行以下操作:

OMCR_OPTION Option = new OMCR_OPTION(); // not sure how to initialize this
IntPtr DevicePtr = OMCR_OpenDevice(DeviceType, ref Option);
if (DevicePtr == IntPtr.Zero)
    throw new Win32Exception();
OMCR Device = (OMCR)Marshal.PtrToStructure(DevicePtr, typeof(OMCR));