Willkommen auf myCSharp.de! Anmelden | kostenlos registrieren
 | Suche | FAQ

Hauptmenü
myCSharp.de
» Startseite
» Forum
» Suche
» Regeln
» Wie poste ich richtig?

Mitglieder
» Liste / Suche
» Wer ist online?

Ressourcen
» FAQ
» Artikel
» C#-Snippets
» Jobbörse
» Microsoft Docs

Team
» Kontakt
» Cookies
» Spenden
» Datenschutz
» Impressum

Wie aus einem unmanaged Bereich eines Array of Structs in Array in managed Bereich kopieren?
mifi261
myCSharp.de - Member



Dabei seit:
Beiträge: 3

Themenstarter:

Wie aus einem unmanaged Bereich eines Array of Structs in Array in managed Bereich kopieren?

beantworten | zitieren | melden

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:


		[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++:


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?
private Nachricht | Beiträge des Benutzers
Spook
myCSharp.de - Member



Dabei seit:
Beiträge: 233
Herkunft: Esslingen a.N.

beantworten | zitieren | melden

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:


        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++

        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
private Nachricht | Beiträge des Benutzers
mifi261
myCSharp.de - Member



Dabei seit:
Beiträge: 3

Themenstarter:

beantworten | zitieren | melden

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.
private Nachricht | Beiträge des Benutzers
mifi261
myCSharp.de - Member



Dabei seit:
Beiträge: 3

Themenstarter:

beantworten | zitieren | melden

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

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


        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
             }
         } 
private Nachricht | Beiträge des Benutzers
chilic
myCSharp.de - Experte



Dabei seit:
Beiträge: 2111

beantworten | zitieren | melden

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 zu. Dann weist du etwas ganz anderes an innere 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.
private Nachricht | Beiträge des Benutzers
Spook
myCSharp.de - Member



Dabei seit:
Beiträge: 233
Herkunft: Esslingen a.N.

beantworten | zitieren | melden

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


IntPtr pAeusere;
getData(pAeusere);

Alleine das kann schon nicht kompilieren.


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.
private Nachricht | Beiträge des Benutzers