myCSharp.de - DIE C# und .NET Community
Willkommen auf myCSharp.de! Anmelden | kostenlos registrieren
 
 | Suche | FAQ

» Hauptmenü
myCSharp.de
» Startseite
» Forum
» FAQ
» Artikel
» C#-Snippets
» Jobbörse
» Suche
» Regeln
» Wie poste ich richtig?
» Forum-FAQ

Mitglieder
» Liste / Suche
» Wer ist wo online?

Ressourcen
» openbook: Visual C#
» openbook: OO
» Microsoft Docs

Team
» Kontakt
» Übersicht
» Wir über uns

» myCSharp.de Diskussionsforum
Du befindest Dich hier: Community-Index » Diskussionsforum » Entwicklung » Basistechnologien und allgemeine .NET-Klassen » Marshalling Array od Struct
Letzter Beitrag | Erster ungelesener Beitrag Druckvorschau | Thema zu Favoriten hinzufügen

Antwort erstellen
Zum Ende der Seite springen  

Marshalling Array od Struct

 
Autor
Beitrag « Vorheriges Thema | Nächstes Thema »
mifi261 mifi261 ist männlich
myCSharp.de-Mitglied

Dabei seit: 01.07.2020
Beiträge: 3


mifi261 ist offline

Marshalling Array od Struct

Beitrag: beantworten | zitieren | editieren | melden/löschen       | Top

Hallo zusammen,

ich möchte in C# eine Funktion aus einer C++ DLL aufrufen. Diese Funktion liefert mir einen Pointer auf Äußere Struktur zurück. Diese Äußere Struktur enthält wiederum ein Array bzw. Pointer auf eine Innere Struktur.

Meine Frage ist nun, wie kann ich die Daten des Array of Structs aus dem Unmanaged Bereich in ein Array of Struct in den Managed Bereich kopieren.
Folgend ist die Realisierung der Strukturen, sowie der Realisierte Aufruf der C++ Funktion und ein Lösungsvorschlag zum kopieren der Daten:

C#-Code:
        [StructLayout(LayoutKind.Sequential)]
        private struct Innere
        {
            public IntPtr data;
            public int size;
            //Weitere Felder
        }

        [StructLayout(LayoutKind.Sequential)]
        rivate struct Aeusere
        {
            public Int32 iValue1;
            public Int32 iValue2;
            public double dValue;
        };

        [DllImport(DLLPfad, CallingConvention = CallingConvention.Cdecl)]
        private static extern void getData(IntPtr Data);

        main()
        {
            IntPtr pAeusere;

            getData(pAeusere);

            Aeusere aeusere = (Aeusere) Marshal.PtrToStructure(pAeusere, typeof(emxArray));

            // Bisheriger Versuch Daten zu kopieren
            Innere[] innere = new Innere[aeusere.size];
            for (int i = 0; i < aeusere.size; i++)
            {
                IntPtr pElement = new IntPtr(aeusere.data.ToInt32() + Marshal.SizeOf(typeof(Innere)) * i);
                Innere element =  (Innere) Marshal.PtrToStructure(pElement, typeof(Innere)); // Geht (Element enthält richtige Daten)
                innere[i] = element;   // Hier tritt Exception auf
            }
        }

Strukturen und Funktion in C++:

Code:
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
struct Innere
{
  int iValue1;
  int iValue2;
  double dValue;
};

struct aeusere
{
  Innere *data;
  int size;
  // Weitere Felder
};

DLL_EXPORT void getData(Aeusere* pAeusere)
{
	//Allokiere Speicherplatz für aeusere und Befülle aeusere
}

Beim bisherigen Versuch kann ich Problemlos die Außere Struktur auf meine C# Variable kopieren. Ebenso kann ich die Daten der Inneren Struktur auf meine Variable element kopieren.
(Im Überwachungsfenster beim Debuging werden mir die richtigen Werte innerhalb der Variablen element angezeigt.)

Erst bei der Zuweisung der Element Variable an das Array (innere) (im Code markiert) tritt eine mit folgendem Wortlaut Exception auf:
"Der Objektverweis wurde nicht auf eine Objektinstanz festgelegt."

Ich verstehe jedoch nicht wieso die Variable element nicht zugewiesen werden kann? Im Überwachungsfenster ist sie ja schließlich befüllt und nicht "null".
Hatte jemand schon ein solches Problem oder kann jemand einen Fehler in meinem Programm feststellen?
Neuer Beitrag Gestern, 15:10 Beiträge des Benutzers | zu Buddylist hinzufügen
Spook Spook ist männlich
myCSharp.de-Mitglied

Dabei seit: 28.10.2008
Beiträge: 210
Entwicklungsumgebung: VS2019
Herkunft: Esslingen a.N.


Spook ist offline

Beitrag: beantworten | zitieren | editieren | melden/löschen       | Top

Hallo mifi261,

die Definitionen der structs im C# entspricht nicht denen aus dem C++ Code.

Zitat:
IntPtr pElement = new IntPtr(aeusere.data.ToInt32() + Marshal.SizeOf(typeof(Innere)) * i);

Einen Pointer nach Int32 umzuwandeln ist keine gute Idee. Sollte dein Programm unter 64Bit laufen wirst du eine Exception bekommen. Verwende stattdessen besser den  + Operator von IntPtr.

Zitat:
Aeusere aeusere = (Aeusere) Marshal.PtrToStructure(pAeusere, typeof(emxArray));

Wo ist emxArray definiert? Mir scheint hier, dass dies a) nicht kompiliert und b) zusammengewürfelte Teile sind.

Wenn du ein Array of structs übertragen willst, kannst du dies sehr viel einfacher machen indem du im C# direkt ein Array deiner Struct als Parameter angibst. Im C++ kopierst du dann einfach die Daten via memcpy in das Array.
Da du das Array natürlich im C# vorallokieren musst, und in C++ keine Länge da ist würde ich einen weiteren in/out Parameter für die Array-Länge anlegen:

C#-Code:
        struct Innere
        {
            int iValue1;
            int iValue2;
            double dValue;
        };

        [DllImport(DLLPfad, CallingConvention = CallingConvention.Cdecl)]
        private static extern void GetData(Innere[] data, ref int size);

                int size = 0;
                Innere[] data = null;
                GetData(data, ref size); // Länge abrufen
                data = new Innere[size]; // Array allokieren
                GetData(data, ref size); // Werte direkt ins Array schreiben

C++

Code:
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
        DLL_EXPORT void GetData(Innere* array, int& size)
        {
            if (array == nullptr)
            {
                size = ...;//
            }
            else
            {
                memcpy(array, ..., sizeof(Innere) * size);
            }
        }

Damit kannst du dir die äußere Struct sparen und die Daten werden direkt kopiert also auch kein Marshalling nötig.


Grüße
spooky
Neuer Beitrag Gestern, 16:01 E-Mail | Beiträge des Benutzers | zu Buddylist hinzufügen
mifi261 mifi261 ist männlich
myCSharp.de-Mitglied

Dabei seit: 01.07.2020
Beiträge: 3

Themenstarter Thema begonnen von mifi261

mifi261 ist offline

Beitrag: beantworten | zitieren | editieren | melden/löschen       | Top

Danke für deine Antwort, bei mir im Programm haben die Strukturen und Variablen andere Namen. Beim kopieren habe ich wohl vergessen alle zu ändern, daher sollte "emxArray" eigentlich "Aeusere" heißen.

Leider kann ich im C++ Code nichts ändern, dieser ist fest vorgegeben.
Neuer Beitrag Gestern, 16:09 Beiträge des Benutzers | zu Buddylist hinzufügen
mifi261 mifi261 ist männlich
myCSharp.de-Mitglied

Dabei seit: 01.07.2020
Beiträge: 3

Themenstarter Thema begonnen von mifi261

mifi261 ist offline

Beitrag: beantworten | zitieren | editieren | melden/löschen       | Top

Habe meinen Fehler selbst gefunden, war ein Anfänger Fehler. Hatte vergessen den Speicher im Managed Bereich zu Allokieren. traurig

Habe nun "innere[i] = new Innere();" in der For-Schleife eingefügt jetzt klappt alles wie gewünscht.

C#-Code:
        main()
         {
             IntPtr pAeusere;

             getData(pAeusere);

             Aeusere aeusere = (Aeusere) Marshal.PtrToStructure(pAeusere, typeof(emxArray));

             // Bisheriger Versuch Daten zu kopieren
             Innere[] innere = new Innere[aeusere.size];
             for (int i = 0; i < aeusere.size; i++)
             {
                 IntPtr pElement = new IntPtr(aeusere.data.ToInt32() + Marshal.SizeOf(typeof(Innere)) * i);
                 Innere element =  (Innere) Marshal.PtrToStructure(pElement, typeof(Innere)); // Geht (Element enthält richtige Daten)
                 innere[i] = new Innere();  // Hier war der Fehler
                 innere[i] = element;   // Hier tritt Exception auf
             }
         }
Neuer Beitrag Heute, 07:38 Beiträge des Benutzers | zu Buddylist hinzufügen
chilic
myCSharp.de-Poweruser/ Experte

Dabei seit: 12.02.2010
Beiträge: 2.037


chilic ist offline

Beitrag: beantworten | zitieren | editieren | melden/löschen       | Top

Ich glaube nicht dass deine Lösung wirklich das Problem behoben hat.
Du erstellst zuerst ein neues Objekt (new Innere) und weist das an innere[i] zu. Dann weist du etwas ganz anderes an innere[i] zu. Das ist als wenn du schreibst
i = 4;
i = 5;

Die Zuweisung von 4 ist überflüssig, da die 4 gleich von der 5 überschrieben wird. In deinem Fall erstellst du ein Objekt (new Innere() ) ohne es zu verwenden.
Neuer Beitrag Heute, 08:19 E-Mail | Beiträge des Benutzers | zu Buddylist hinzufügen
Spook Spook ist männlich
myCSharp.de-Mitglied

Dabei seit: 28.10.2008
Beiträge: 210
Entwicklungsumgebung: VS2019
Herkunft: Esslingen a.N.


Spook ist offline

Beitrag: beantworten | zitieren | editieren | melden/löschen       | Top

Das Problem ist, dass der Code hier vermutlich extrem ausgedünnt und dabei noch diverse Fehler enthält:

C#-Code:
IntPtr pAeusere;
getData(pAeusere);

Alleine das kann schon nicht kompilieren.

C#-Code:
Aeusere aeusere = (Aeusere) Marshal.PtrToStructure(pAeusere, typeof(emxArray));

Das wird zur Laufzeit krachen, außer Aeusere ist ein Alias für emxArray.

Was du machen möchtest ist relativ simpel zu lösen. Aber bitte zeige uns den richtigen Code und nicht etwas völlig verfälschtes.
Neuer Beitrag Heute, 12:34 E-Mail | Beiträge des Benutzers | zu Buddylist hinzufügen
Baumstruktur | Brettstruktur       | Top 
myCSharp.de | Forum
Antwort erstellen


© Copyright 2003-2020 myCSharp.de-Team | Impressum | Datenschutz | Alle Rechte vorbehalten. | Dieses Portal verwendet zum korrekten Betrieb Cookies. 02.07.2020 21:42