本文介绍了C#的P / Invoke结构问题的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图写一个C#的P / Invoke的C API封装(本机运DLL),通常这是工作的罚款。唯一的例外是需要一个结构作为C代码参数的具体方法。该函数被调用,没有任何异常,但它返回假,指示一些在执行失败

I am trying to write a C# P/Invoke wrapper for a C API (a native Win dll), and generally this is working fine. The only exception is a specific method which takes a struct as a parameter in the C code. The function is invoked without any exceptions, but it returns false indicating that something failed in the execution.

在API头文件所涉及的方法和结构的定义如下:

In the API header file the involved method and structs are defined as follows:

#define MAX_ICE_MS_TRACK_LENGTH  256
typedef struct tagTRACKDATA
{
    UINT nLength;
    BYTE TrackData[MAX_ICE_MS_TRACK_LENGTH];
} TRACKDATA, FAR* LPTRACKDATA;
typedef const LPTRACKDATA LPCTRACKDATA;

BOOL ICEAPI EncodeMagstripe(HDC /*hDC*/,
		     LPCTRACKDATA /*pTrack1*/,
		     LPCTRACKDATA /*pTrack2*/,
		     LPCTRACKDATA /*pTrack3*/,
		     LPCTRACKDATA /*reserved*/);



我曾试图创建一个C#P /使用下面的代码调用包装>

I have made an attempt to create a C# P/Invoke wrapper using the following code:

public const int MAX_ICE_MS_TRACK_LENGTH = 256;

[StructLayout(LayoutKind.Sequential)]
public class MSTrackData {
    public UInt32 nLength;
    public readonly Byte[] TrackData = new byte[MAX_ICE_MS_TRACK_LENGTH];
}

[DllImport("ICE_API.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern bool EncodeMagstripe(IntPtr hDC,
                    [In]ref MSTrackData pTrack1,
                    [In]ref MSTrackData pTrack2,
                    [In]ref MSTrackData pTrack3,
                    [In]ref MSTrackData reserved);



然后我尝试使用下面的C#代码来调用EncodeMagstripe方式:

Then I try to invoke the EncodeMagstripe method using the following C# code:

CardApi.MSTrackData trackNull = null;
CardApi.MSTrackData track2 = new CardApi.TrackData();
byte[] trackBytes = Encoding.ASCII.GetBytes(";0123456789?");
track2.nLength = (uint)trackBytes.Length;
Buffer.BlockCopy(trackBytes, 0, track2.TrackData, 0, trackBytes.Length);

if (!CardApi.EncodeMagstripe(hDC, ref trackNull, ref track2, ref trackNull, ref trackNull)) {
    throw new ApplicationException("EncodeMagstripe failed", Marshal.GetLastWin32Error());
}

这会导致ApplicationException的抛出,并根据该错误代码是801该文件是指数据包括选定轨道2格式字符太多。然而,选择的曲目格式应允许最多39个字符(我也曾尝试更短的字符串)。

This causes an ApplicationException to be thrown, and the error code is 801 which according to the documentation means "Data includes too many characters for the selected Track 2 format.". However the selected track format should allow up to 39 characters (I have also tried shorter strings).

我怀疑问题occurrs由于我做的事错在MSTrackData定义,但我看不出这是什么可能。有没有人有什么建议?

I suspect the problem occurrs due to something I did wrong in the MSTrackData definition, but I cannot see what this may be. Does anyone have any suggestions?

推荐答案

给出迄今为止有一点的答案,但不完整的所有答案。您需要的MarshalAs - ByValArray以及新的,你MSTrackDatas已经引用,所以你不需要通过裁判通过他们,你必须检查什么调用约定ICEAPI表示,如果是STDCALL你不需要改变什么,但如果是的cdecl您需要将CallingConvention添加到您的DllImport属性。此外,您可能需要一个的MarshalAs属性添加到您的布尔返回值,以确保它被封送4字节WINAPI风格布尔。以下是声明,你会(可能)需要:

All the answers given so far have a bit of the answer but are incomplete. You need the MarshalAs - ByValArray as well as the new, your MSTrackDatas are already references so you do not need to pass them by ref and you must check what calling convention ICEAPI represents, if it is StdCall you don't need to change anything but if it is cdecl you will need to add the CallingConvention to your DllImport attribute. Also, you may need to add a MarshalAs attribute to your bool return value to make sure it is marshaled as 4 byte WinApi style bool. Here are the declares you'll (probably) need:

public const int MAX_ICE_MS_TRACK_LENGTH = 256;

[StructLayout(LayoutKind.Sequential)]
public class MSTrackData {
    public UInt32 nLength;
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 256)]
    public Byte[] TrackData = new byte[MAX_ICE_MS_TRACK_LENGTH];
}

[DllImport("ICE_API.dll", CharSet = CharSet.Auto, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool EncodeMagstripe(IntPtr hDC,
                [In] MSTrackData pTrack1,
                [In] MSTrackData pTrack2,
                [In] MSTrackData pTrack3,
                [In] MSTrackData reserved);

这篇关于C#的P / Invoke结构问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-20 01:10