C# P/Invoke-Struktur problem
Ich bin beim schreiben einer C# P/Invoke-wrapper für eine API in C (eine native Win-dll), und in der Regel gut funktioniert. Die einzige Ausnahme ist eine spezielle Methode, die eine struct als parameter in C-code. Die Funktion wird aufgerufen, ohne Ausnahmen, aber es gibt Sie false zurück, der anzeigt, dass etwas versagt in der Ausführung.
In der API-header-Datei der beteiligten Verfahren und Strukturen sind wie folgt definiert:
#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*/);
Habe ich den Versuch gemacht, zum erstellen einer C# P/Invoke-wrapper verwenden Sie den folgenden 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);
Dann versuche ich zu rufen Sie das EncodeMagstripe-Methode unter Verwendung der folgenden 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());
}
Dadurch wird eine ApplicationException geworfen werden, und der Fehler code 801, die laut Dokumentation bedeutet "Daten enthält zu viele Zeichen für den ausgewählten Track 2-format.". Jedoch ist der ausgewählte track-format soll es erlauben, bis zu 39 Zeichen (ich habe auch versucht, kürzere strings).
Ich vermute, dass das problem Auftritt wegen etwas, was ich falsch gemacht habe in der MSTrackData definition, aber ich kann nicht sehen, was dieses sein kann. Hat jemand irgendwelche Vorschläge?
Du musst angemeldet sein, um einen Kommentar abzugeben.
Alle Antworten gegeben, so weit ein bisschen die Antwort, aber sind unvollständig. Benötigen Sie das MarshalAs - byvalarray-Attribut als auch die neue, Ihr MSTrackDatas sind schon Referenzen, so dass Sie nicht brauchen, um passieren Sie von ref und Sie müssen prüfen, welche Aufrufkonvention ICEAPI darstellt, wenn es StdCall Sie brauchen nicht, etwas zu ändern, aber wenn es cdecl, müssen Sie die CallingConvention auf deine DllImport-Attribut. Sie können auch hinzufügen müssen, um eine MarshalAs-Attribut auf Ihre bool-Wert zurückgeben, um sicherzustellen, dass es gemarshallt wird als 4 byte WinApi Stil bool. Hier sind die erklärt werden Sie (vermutlich) brauchen:
Ich würde definieren Sie das BYTE-array nicht mit neuen, sondern stattdessen den folgenden code verwenden initialisieren Sie die richtige Größe:
Habe ich dieses erfolgreich auf char-arrays in der Vergangenheit.
Sieht für mich wie das problem ist, dass Sie vorbei sind eine Referenz durch Referenz. Da
MSTrackData
ist eine Klasse (d.h. den Typ der Referenz), übergabe per Referenz ist wie an einem Zeiger-auf-Zeiger.Ändern Sie Ihr verwalteten Prototyp:
Finden Sie im MSDN-Artikel über übergabe von Strukturen.
Hatte ich fast genau das gleiche problem - aber mit ReadMagstripe. Und die Lösung hier für EncodeMagstripe nicht funktioniert ReadMagstripe! Ich denke, der Grund warum es nicht funktioniert hat, war, dass ReadMagstripe hat, um die Daten in die TRACKDATA Struktur/Klasse, während EncodeMagstripe übergibt nur Daten an die dll und Daten in TRACKDATA nicht geändert werden müssen. Hier ist die Umsetzung, die schließlich für mich gearbeitet - sowohl mit EncodeMagstripe und ReadMagstripe: