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

  • »
  • Community
  • |
  • Diskussionsforum
Marshalling im Struct?
Te-Ha
myCSharp.de - Member



Dabei seit:
Beiträge: 8

Themenstarter:

Marshalling im Struct?

beantworten | zitieren | melden

Hallo,

ich habe folgendes Problem:

Ich möchte in C# einen Messverstärker ansteuern, dessen Code nur in C++ vorliegt. Über einen DLLImport habe ich auch schon die meisten Funktionen und Structs importieren können und das funktioniert auch alles gut.

Ein Import funktioniert allerdings nicht:


[DllImport("gUSBamp.DLL")]
private static extern bool GT_SetDAC(IntPtr hDevice, DAC AnalogOut);

"DAC" ist hierbei ein Struct, der im Original so aussieht:


typedef struct DAC
{
	BYTE WaveShape;
	WORD Amplitude;
	WORD Frequency;
	WORD Offset;
}

Mein Struct, den ich mir für den Import definiert habe, ist folgender:


public struct DAC
{
    public int Amplitude, Frequency, Offset;
    public byte WaveShape;
}

Während der Laufzeit bekomme ich nun die Fehlermeldung:
"Ein Aufruf an die PInvoke-Funktion "BCITestApplication!BCITestApplication.Amplifier::GT_SetDAC" hat das Gleichgewicht des Stapels gestört. Wahrscheinlich stimmt die verwaltete PInvoke-Signatur nicht mit der nicht verwalteten Zielsignatur überein."

Ich vermute, dass dieser Fehler daher rührt, dass die beiden Structs nicht exakt gleich aussehen.

Wie kann ich dieses Problem lösen? Kann ich das über Marshalling lösen? Und wenn ja, wie?

Danke für die Antworten!

Viele Grüße
Thorsten
private Nachricht | Beiträge des Benutzers
nils
myCSharp.de - Experte



Dabei seit:
Beiträge: 750
Herkunft: Nähe von Kassel

beantworten | zitieren | melden

hallo Te-Ha,
Zitat
Ich vermute, dass dieser Fehler daher rührt, dass die beiden Structs nicht exakt gleich aussehen.
warum sehen die denn unterschiedlich aus ? hat das irgendwelche gründe??
wenn nein, dann mach sie doch "gleich" und guck ob der fehler immer noch auftritt.





nils
?( wer suchet, der findet auch! :]
private Nachricht | Beiträge des Benutzers
Borg
myCSharp.de - Member



Dabei seit:
Beiträge: 1.529
Herkunft: Berlin, Germany

beantworten | zitieren | melden

Ich vermute eher, dass die Funktion den Struct nicht wirklich auf den Stapel packt (unüblich), sondern nur die Referenz. Also musst du ihn auch per Referenz übergeben.

[StructLayout(LayoutKind.Sequential, Pack = 1)]
private struct DAC
{
    byte WaveShape;
    UInt16 Amplitude;
    UInt16 Frequency;
    UInt16 Offset;
}

[DllImport("gUSBamp.DLL")]
private static extern bool GT_SetDAC(IntPtr hDevice, ref DAC AnalogOut);

Falls es so auch nicht geht, kannst du es ja doch wieder ohne ref probieren.
private Nachricht | Beiträge des Benutzers
Te-Ha
myCSharp.de - Member



Dabei seit:
Beiträge: 8

Themenstarter:

beantworten | zitieren | melden

Zitat
Original von nils
hallo Te-Ha,
Zitat
Ich vermute, dass dieser Fehler daher rührt, dass die beiden Structs nicht exakt gleich aussehen.
warum sehen die denn unterschiedlich aus ? hat das irgendwelche gründe??
wenn nein, dann mach sie doch "gleich" und guck ob der fehler immer noch auftritt.

Das würde ich ja gerne, aber der "Unterschied" ist im Variablentyp "word" (vermute ich). Ich habe das im übrigen auch schon mit "Int16" versucht, aber es hat nicht funktioniert.

Kann natürlich sein, dass ich da gänzlich falsch liege, aber das wäre für mich die Erklärung. Und daher suche ich nach einer Möglichkeit, "int" oder auch "Int16" in den Typ "word" zu casten.

Oder befinde ich mich auf dem Holzweg?
private Nachricht | Beiträge des Benutzers
nils
myCSharp.de - Experte



Dabei seit:
Beiträge: 750
Herkunft: Nähe von Kassel

beantworten | zitieren | melden

Zitat
aber der "Unterschied" ist im Variablentyp "word" (vermute ich).

für mich ist der Unterschied eher die Reihenfolge deiner Elemente.


//edit: Borg hat schon eine (mögliche) Lösung gepostet.




nils
?( wer suchet, der findet auch! :]
private Nachricht | Beiträge des Benutzers
Te-Ha
myCSharp.de - Member



Dabei seit:
Beiträge: 8

Themenstarter:

beantworten | zitieren | melden

Hi,

also das mit dem "ref" hat zu genau demselben Fehler geführt.

Der Fehler konnte durch ein Ersetzen von "int" nach "UInt16" (sowas simples ist ja fast schon peinlich!) behoben werden. Die Reihenfolge im Struct hatte dabei allerdings keine Auswirkung.

Interessanterweise hatte die Reihenfolge im Struct jedoch eine Auswirkung auf den Rückgabewert der Funktion. So lieferte sie bei der einen Reihenfolge ein "false" und bei der anderen ein "true" zurück.

Das finde ich wiederum lustig. Da muss ich mal weitersehen, woran das denn jetzt liegen könnte.

Danke aber für die schnelle Hilfe!
private Nachricht | Beiträge des Benutzers
nils
myCSharp.de - Experte



Dabei seit:
Beiträge: 750
Herkunft: Nähe von Kassel

beantworten | zitieren | melden

Zitat
Interessanterweise hatte die Reihenfolge im Struct jedoch eine Auswirkung auf den Rückgabewert der Funktion. So lieferte sie bei der einen Reihenfolge ein "false" und bei der anderen ein "true" zurück.

und bei welcher reihenfolge gibt die funktion das für dich "richtige" ergebniss zurück?
bei eingehaltener oder bei anderer Reihenfolge?




nils
?( wer suchet, der findet auch! :]
private Nachricht | Beiträge des Benutzers
Te-Ha
myCSharp.de - Member



Dabei seit:
Beiträge: 8

Themenstarter:

beantworten | zitieren | melden

Zitat
Original von nils
und bei welcher reihenfolge gibt die funktion das für dich "richtige" ergebniss zurück?
bei eingehaltener oder bei anderer Reihenfolge?

Bei eingehaltener Reihenfolge wird das "richtige" Ergebnis zurückgeliefert. Ich hätte nicht gedacht, dass die Reihenfolge in einem Struct so extrem wichtig ist... Man lernt halt immer dazu.
private Nachricht | Beiträge des Benutzers
Borg
myCSharp.de - Member



Dabei seit:
Beiträge: 1.529
Herkunft: Berlin, Germany

beantworten | zitieren | melden

Ist doch logisch. Die Funktion erwartet immer die angegebene Reihenfolge. Änderst du diese, liest die Funktion sinnlose Daten. So könnte beispielsweise eine Frequenz von 60kHz verlangt werden. Kein Wunder, dass das false zurückkommt.
private Nachricht | Beiträge des Benutzers
Te-Ha
myCSharp.de - Member



Dabei seit:
Beiträge: 8

Themenstarter:

beantworten | zitieren | melden

Stimmt. Damit wird ja die Reihenfolge im Speicher angegeben.

Oh man... Man kann auch mit einem Brett vorm Kopf herumlaufen. Ich brauche das Wochenende!
private Nachricht | Beiträge des Benutzers
Te-Ha
myCSharp.de - Member



Dabei seit:
Beiträge: 8

Themenstarter:

beantworten | zitieren | melden

Das bringt mich doch gleich zu der Frage, wie das mit Arrays im Struct aussieht?

Beispiel:

Struct in der Unmanaged DLL:


typedef struct SCALE
{
	float factor[16];
	float offset[16];
} *PSCALE;

Struct bei mir:


public struct SCALE
{
    public SCALE(int Dummy)
    {
        factor = new float[16];
        offset = new float[16];
    }
    public float[] factor;
    public float[] offset;
}

Ist in diesem Fall die Speicherbelegung in beiden Fällen gleich?

Mein nächstes Problem ist nämlich:

Die Methode in der Unmanaged DLL benötigt als Übergabeparameter einen Pointer von SCALE:


GT_Calibrate(HANDLE hDevice,PSCALE Scaling);

Das löse ich über einen Referenzparameter:


[DllImport("gUSBamp.DLL")]
public static extern bool GT_Calibrate(IntPtr hDevice, ref SCALE Scaling);

Das hat mit einem Struct, das keine Arrays beinhaltet auch wunderbar funktioniert.

In diesem hier beschriebenen Fall bekomme ich aber die Fehlermeldung, dass in den geschützten Speicher geschrieben wird, was natürlich zu einem Abbruch führt.

Kann das daran liegen, dass ausserhalb der Array-Grenzen geschrieben werden soll, was ich natürlich nicht möchte?
Oder wird vielleicht durch meinen definierten Konstruktor ein falscher Startpunkt zum Schreiben ausgewählt?
Dieser Beitrag wurde 1 mal editiert, zum letzten Mal von Te-Ha am .
private Nachricht | Beiträge des Benutzers
marsgk
myCSharp.de - Member



Dabei seit:
Beiträge: 1.439
Herkunft: Linz, Austria

beantworten | zitieren | melden

Probier mal


[StructLayout(LayoutKind.Sequential)]
public struct SCALE {
    [MarshalAs(UnmanagedType.ByValArray, SizeConst=16)] 
    public float[] factor;
    [MarshalAs(UnmanagedType.ByValArray, SizeConst=16)] 
    public float[] offset;
}
private Nachricht | Beiträge des Benutzers
Te-Ha
myCSharp.de - Member



Dabei seit:
Beiträge: 8

Themenstarter:

beantworten | zitieren | melden

Danke marsgk!

Dein Tipp war mir wirklich sehr hilfreich. Dadurch wurde der Fehler eliminiert. Super!

Was ist der Grund, warum meine Variante nicht funktioniert hat?
private Nachricht | Beiträge des Benutzers
marsgk
myCSharp.de - Member



Dabei seit:
Beiträge: 1.439
Herkunft: Linz, Austria

beantworten | zitieren | melden

Weil bei deiner Variante factor und offset nur Zeiger auf ein Array sind. Bei meiner hingegen wird der Speicherplatz für das Array direkt im strukt reserviert.
private Nachricht | Beiträge des Benutzers
Te-Ha
myCSharp.de - Member



Dabei seit:
Beiträge: 8

Themenstarter:

beantworten | zitieren | melden

OK, Danke!
private Nachricht | Beiträge des Benutzers