C # P / Invoke struktur problem

stemmer
6

Jeg prøver å skrive et C # P / Invoke wrapper for en C API (opprinnelig Win dll), og generelt dette fungerer fint. Det eneste unntaket er en spesifikk metode som tar en struct som en parameter i den C-kode. Funksjonen startes uten unntak, men det returnerer false indikerer at noe sviktet i utførelsen.

I API-topptekstfilen de involverte metode og structs er definert som følger:

#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*/);

Jeg har gjort et forsøk på å skape en C # P / Invoke wrapper ved hjelp av følgende kode:

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);

Så prøver jeg å påkalle EncodeMagstripe metoden ved hjelp av følgende C # kode:

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());
}

Dette forårsaker en ApplicationException å bli kastet, og feilkoden er 801 som i henhold til dokumentasjons betyr Data inneholder for mange tegn for det valgte spor 2 format.. Men det valgte sporet format bør tillate opptil 39 tegn (Jeg har også prøvd kortere strenger).

Jeg mistenker at problemet occurrs grunn av noe jeg gjorde galt i MSTrackData definisjon, men jeg kan ikke se hva dette kan være. Er det noen som har noen forslag?

Publisert på 17/03/2009 klokken 15:25
kilden bruker
På andre språk...                            


4 svar

stemmer
5

Alle svarene som er gitt så langt har litt av svaret, men er ufullstendig. Du trenger MarshalAs - ByValArray samt den nye, dine MSTrackDatas allerede referanser slik at du ikke trenger å sende dem av dommeren, og du må sjekke hva kaller konvensjonen ICEAPI representerer, hvis det er STDCALL trenger du ikke å endre noe, men hvis det er cdecl du må legge til CallingConvention til DllImport attributt. Også, må du kanskje legge til en MarshalAs attributt til bool returverdi å sikre at det blir formidlet som 4 byte WinAPI stil bool. Her er erklærer du vil (sannsynligvis) behov:

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);
Svarte 20/03/2009 kl. 18:15
kilden bruker

stemmer
2

Jeg vil definere byte array ikke med nye, men det brukes følgende kode i stedet for å initialisere riktig størrelse:

[MarshalAs (UnmanagedType.byValTSt, SizeConst = 256)] offentlig lesetilgang byte [] TrackData;

Jeg har brukt dette med hell på char arrays i fortiden.

Svarte 17/03/2009 kl. 15:35
kilden bruker

stemmer
1

Ser for meg ut som problemet er at du sender en referanse som referanse. Da MSTrackDataer en klasse (dvs. referanse type), passerer den ved referanse er som passerer en peker-til-pekeren.

Endre klarte prototype til:

public static extern bool EncodeMagstripe(IntPtr hDC,
                    MSTrackData pTrack1,
                    MSTrackData pTrack2,
                    MSTrackData pTrack3,
                    MSTrackData reserved);

Se MSDN-artikkelen om bestått strukturer .

Svarte 17/03/2009 kl. 17:05
kilden bruker

stemmer
0

Jeg hadde nesten nøyaktig det samme problemet - men med ReadMagstripe. Og løsningen gitt her for EncodeMagstripe fungerte ikke for ReadMagstripe! Jeg tror grunnen til det ikke fungerte var at ReadMagstripe må returnere data i TRACKDATA struktur / klasse, mens EncodeMagstripe bare passerer data til dll og data i TRACKDATA trenger ikke å endres. Her er gjennomføringen som til slutt fungerte for meg - både med EncodeMagstripe og ReadMagstripe:

    public const int MAX_ICE_MS_TRACK_LENGTH = 256;
    [StructLayout(LayoutKind.Sequential)]
    public struct TRACKDATA
    {  
        public UInt32 nLength;
        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
        public string szTrackData;
    }


    [DllImport("ICE_API.dll", EntryPoint="_ReadMagstripe@20", CharSet=CharSet.Auto, 
        CallingConvention=CallingConvention.Winapi, SetLastError=true)]
    [return: MarshalAs(UnmanagedType.Bool)]
    public static extern bool ReadMagstripe(int hdc, ref TRACKDATA ptrack1, ref TRACKDATA ptrack2,
         ref TRACKDATA ptrack3, ref TRACKDATA reserved);

    [DllImport("ICE_API.dll", EntryPoint="_EncodeMagstripe@20", CharSet=CharSet.Auto,
        CallingConvention = CallingConvention.Winapi, SetLastError=true)]
    public static extern bool EncodeMagstripe(int hdc, [In] ref TRACKDATA ptrack1, [In] ref TRACKDATA ptrack2,
        [In] ref TRACKDATA ptrack3, [In] ref TRACKDATA reserved);


/*
        ....
*/


    private void EncodeMagstripe()
    {
        ICE_API.TRACKDATA track1Data = new ICE_API.TRACKDATA();
        ICE_API.TRACKDATA track2Data = new ICE_API.TRACKDATA();
        ICE_API.TRACKDATA track3Data = new ICE_API.TRACKDATA();
        ICE_API.TRACKDATA reserved = new ICE_API.TRACKDATA();

        //if read magstripe
        bool bRes = ICE_API.ReadMagstripe(printer.Hdc, ref track1Data, ref track2Data,
            ref track3Data, ref reserved);

        //encode magstripe
        if (bRes)
        {
            track2Data.szTrackData = "1234567890";
            track2Data.nLength = 10;

            bRes = ICE_API.EncodeMagstripe(printer.Hdc, ref track1Data, ref track2Data, ref track3Data, ref reserved);
        }
    }
Svarte 31/07/2009 kl. 03:55
kilden bruker

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more