C++ Dll - struct-array in C#



  • Kanns nicht einfach sein dass einfach der Inhalt deiner structs Falsch ist sodass die Funktion nix damit anfangen kann!?

    AGBDSC123 schrieb:

    Könnte es sein, dass der Pointer AVPtable auf mehrere (Anzahl = sCount_VPWaveList) structs vom Typ (nennt man das in C++ so) AppVPEntry zeigt?

    Ja klar, was denn sonst? AVPtable zeigt auf das erste Element eines Arrays aus AppVPEntries. Daher sollte MarshallAs(UnmanagedType.LPArray) eigentlich genau richtig sein. Der erste Parameter der Funktion gibt halt die Anzahl der Elemente an. Ich dachte das wäre aus dem C/C++ Beispielcode da oben offensichtlich. Lass dich davon

    Skubidus schrieb:

    Der "*****" in diesem Zusammenhang bedeutet, dass die Funktion einen (!!) Zeiger auf ein struct AppVPEntry erwartet und keinen Array von structs dieses Typs.

    nicht verwirren, das ist natürlich Blödsinn...



  • Ja klar, was denn sonst? AVPtable zeigt auf das erste Element eines Arrays aus AppVPEntries. Daher sollte MarshallAs(UnmanagedType.LPArray) eigentlich genau richtig sein. Der erste Parameter der Funktion gibt halt die Anzahl der Elemente an. Ich dachte das wäre aus dem C/C++ Beispielcode da oben offensichtlich.

    OK deine Aussage überzeugt mich, dass ich das dann doch richtig verstanden habe, dass es sich hierbei auch wirklich um ein struct-array handelt (da es immer schwer ist, an mehreren Baustellen gleichzeitig zu suchen). Jetzt kann ich eben meine Fehlersuche eingrenzen, auch dadurch, da mir in C# nichts anderes zur Verfügung steht, um dieses C++ struct Objekt darzustellen, als ein struct-array in C#. Ich werde mir in Ruhe nochmal die Werte ansehen.

    Mein struct-array in C# sieht jetzt so aus:

    public struct AppVPEntry
    {
        [MarshalAs(UnmanagedType.I4)] public int Num;
        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)] public string WavFile;
        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)] public string WavOut;
        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)] public string CompName;
        [MarshalAs(UnmanagedType.U8)] public ulong Size; 
        [MarshalAs(UnmanagedType.I4)] public int SRCode; 
        [MarshalAs(UnmanagedType.I4)] public int CompType;
        [MarshalAs(UnmanagedType.I1)] public byte MessageType;
        [MarshalAs(UnmanagedType.U8)] public ulong VPBeginAddress;
    }
    

    Der Dll-Import in C# sieht so aus:

    [DllImport(@"C:\Test.dll")]
        public static extern void CreateDownloadFile(
        [MarshalAs(UnmanagedType.I4)] int NumOfVP,
        [MarshalAs(UnmanagedType.LPArray)] ref AppVPEntry[] AppVPE
    

    );

    Die Deklaration des struct-arrays in C# sieht so aus:

    AppVPEntry[] AppVPEArray = new AppVPEntry[Binliste.Length];
                for (int i = 0; i < Binliste.Length; i++)
                {
                    AppVPEArray[i].Num = i;
                    AppVPEArray[i].WavFile = Wavpfad + Wavliste[i];
                    AppVPEArray[i].WavOut = Binpfad + Binliste[i]; 
                    AppVPEArray[i].CompName = "C"; 
                    AppVPEArray[i].Size = Sizeliste[i];
                    AppVPEArray[i].SRCode = 3;
                    AppVPEArray[i].CompType = 5;
                    //AppVPEArray[i].MessageType = 205; 
                    //AppVPEArray[i].VPBeginAddress = 0;
                }
    

    Der Methodenaufruf in C# sieht dann so aus:

    Wrapper.CreateDownloadFile(Binliste.Length, ref AppVPEArray);
    

    Ich suche mal die Werte nach fehlern ab, vielen Dank für deine Anteilnahme.



  • Mach das ref weg und gib deinem struct ein [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]. Nur zur Sicherheit: Ist MAX_FILENAME_LEN wirklich 256? MAX_PATH unter Windows wär nämlich 260. Wenns dann noch Probleme gibt dann liegts evtl. daran dass die C++ dll ein anderes struct Packing verwendet. Hast du Zugriff auf den Code der dll? Mit was für einem Compiler wurde die dll erstellt? Ist long dort wirklich ein 64bit Wert? Auf MSVC wärs nämlich 32bit...



  • Mach das ref weg

    Ich probiere jeden Schritt einmal mit und einmal ohne ref, um auszuschließen, dass es nicht daran liegt.

    gib deinem struct ein [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]

    Ja genau so habe ich das, habs aus Versehen nicht mitkopiert.

    Hast du Zugriff auf den Code der dll?

    Nein, es liegt nichts vor, bis auf eine unkommentierte, magere Headerdatei. Desweiteren liegt eine Demoanwendung in C++ vor, die diese DLL verwendet. Daher habe ich auch die C++ Codeausschnitte die ich gepostet habe.

    Nur zur Sicherheit: Ist MAX_FILENAME_LEN wirklich 256? MAX_PATH unter Windows wär nämlich 260

    Die 256 habe ich aus der besagten C++ Demoanwendung, die die DLL verwendet, werde das aber überprüfen.

    Ist long dort wirklich ein 64bit Wert? Auf MSVC wärs nämlich 32bit

    Ich meine so hätte ich das gelesen, werde das aber überprüfen.

    Vielen Dank für deine Hilfe und die Hinweise. Ich melde mich wenn es etwas neues gibt.



  • Nur zur Sicherheit: Ist MAX_FILENAME_LEN wirklich 256? MAX_PATH unter Windows wär nämlich 260

    Ich habe das nachgeprüft: Bei Pfadangaben von Ordnern wird in der besagten Demoanwendung eine Länge von 260 verwendet, bei Pfadangaben samt Dateiname und Endung wird in der besagten Demoanwendung eine Länge von 256 verwendet.

    Ist long dort wirklich ein 64bit Wert? Auf MSVC wärs nämlich 32bit

    Das ist korrekt, nur muss man in diesem Fall beim Marshallen in C# 64bit nehmen, da sonst eine TypeLoadException geworfen wird.

    So als kleiner Nachtrag.



  • AGBDSC123 schrieb:

    Ist long dort wirklich ein 64bit Wert? Auf MSVC wärs nämlich 32bit

    Das ist korrekt, nur muss man in diesem Fall beim Marshallen in C# 64bit nehmen, da sonst eine TypeLoadException geworfen wird.

    Die TypeLoadException bekommst du sicher nur wenn du versuchst einen C# ulong als U4 zu marshallen, was natürlich Schwachsinn ist. long ist auf Windows normalerweise immer 32bit, außer die dll wurde mit einem Compiler gebaut der das anders macht (z.B. gcc). Du kannst da nicht einfach einen 64bit Wert reinstecken wenn die dll einen 32bit Wert erwartet sonst passen die struct Layouts ja überhaupt nicht zusammen!? Nimm stattdessen int:

    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)] 
    public struct AppVPEntry 
    { 
        public Int32 Num; 
        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)] 
        public string WavFile; 
        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
        public string WavOut; 
        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
        public string CompName; 
        public UInt32 Size; 
        public Int32 SRCode; 
        public Int32 CompType; 
        public Byte MessageType; 
        public UInt32 VPBeginAddress; 
    }
    


  • Alles klar, ich verstehe. Dann wende ich die neuen Erkenntnisse auch auf alle anderen Deklarationen an, die nicht so deklariert waren. ich melde mich dann heute Abend/morgen wieder, hab bald Feierabend.
    Danke dot, dass du mir hilfst.



  • Hallo ihr beiden,

    genau das (bzgl. "long" und 32-bit) hatte ich doch schon in meinem Beitrag geschrieben 😉

    Ich gehe jetzt davon aus, daß es mit dieser Umstellung dann laufen wird...



  • Dickes Danke euch beiden, es funktioniert tatsächlich. Oh man ich Holzkopf, wie Th69 mich bereits darauf hingewiesen hatte, lag es wirklich nur daran. Oh man oh man da hätte ich mir einiges an Fehlersuche ersparen können. Ich hatte bei anderen structs, die ich für andere Methodenaufrufe verwendet hatte, auch die 64bit Variablen benutzt, und dort funktionierte es komischerweise. Deshalb hatte ich den Hinweisen nicht soviel Beachtung geschenkt, weil man ja denkt "woanders funktioniert das, dann wird das sicherlich richtig sein". Dennoch ein Happy End, und ich habe reichlich dazugelernt. Habe natürlich die meine anderen Variablen entsprechend geändert, jetzt tauchen auch die gelegentlichen AccessViolationExceptions nicht mehr auf 🙂

    Mein nächstes Bier trink ich auf euch 😉



  • Hallo
    Eine Frage wie hast du den in C++ die dll Exportiert?
    Kannst du die Zeile mal hier rein schreiben?





  • Die DLL stammt nicht von mir, sie war schon vorhanden.


Anmelden zum Antworten