PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : DLL-Import: Pointer-to-Pointer in C# ?


Jesus
2006-09-27, 16:17:52
Hallo,

ich versuche grad verzweifelt einen DLL zu importieren deren Funktion einen Pointer auf einen Pointer auf eine Struktur erwartet.

Die Struktur hab ich schon recht gut abgebildet in C# und einfache Pointer gehen auch problemlos, aber wie mach ich einen P2P in C#?

Das ist die Originalfunktion (C DLL):

int Receive1 ( portHandle Handle, event **ppEvent)

SgtTynis
2006-09-27, 16:25:23
Wuerde jetzt mal aus der holen geschossen sagen du musst die Struktur als class schreiben und als ref handeln.

[DllImport(".....")]
static extern int Receive1(IntPtr handle, ref MyEventClass ppEvent)

Jesus
2006-09-27, 20:07:11
Wuerde jetzt mal aus der holen geschossen sagen du musst die Struktur als class schreiben und als ref handeln.

[DllImport(".....")]
static extern int Receive1(IntPtr handle, ref MyEventClass ppEvent)

Macht das einen Unterschied ob "struct" oder "class"? So wie oben mach ichs schon, nur eben als "struct"...

Gast
2006-09-27, 22:21:23
Macht das einen Unterschied ob "struct" oder "class"? So wie oben mach ichs schon, nur eben als "struct"...

In C#:
struct -> Wertetyp
class -> Referenztyp

SgtTynis
2006-09-28, 08:33:02
Macht das einen Unterschied ob "struct" oder "class"? So wie oben mach ichs schon, nur eben als "struct"...

Ja, macht einen Unterschied. Eine Uebergabe eines Klassentypes ist implizit schon eine Referenz die mittels ref Schluesselwort zu deinem gewuenschten Pointer Pointer wird. Bei einer Struktur in .NET geht das nicht.

Jesus
2006-09-28, 11:58:38
So hab den struct jetzt als class definiert, klappt aber immer noch net, krieg immer :

A call to PInvoke function 'DTS1!DTS1.XDriver::Receive1' has unbalanced the stack. This is likely because the managed PInvoke signature does not match the unmanaged target signature. Check that the calling convention and parameters of the PInvoke signature match the target unmanaged signature.

Die Klasse sieht so aus:

[StructLayout(LayoutKind.Sequential)]
public class Vevent{
public byte tag;
public byte Index;
public byte transId;
public byte portHandle;
public int timestamp;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 14)]
public byte[] tagData;
} // 22 bytes

SgtTynis
2006-09-28, 16:06:55
Probier mal:
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public class Vevent
{
public byte tag;
public byte Index;
public byte transId;
public byte portHandle;
public int timestamp;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 14)]
public byte[] tagData;
} // 22 bytes

Gast
2006-09-28, 17:26:12
Selbes Ergebnis :(

Kabelsalat
2006-09-28, 18:03:36
Da es auch nicht hilft Event als Klasse zu definieren und diese mittels ref Schlüsselwort zu übergeben, solltest du erneut eine Struktur verwenden. Auch das Pack=1 müsstest du weglassen können.

... anbieten kann ich leider auch nur eine sehr unkomfortable Lösung (wahrscheinlich geht es einfacher, wenn man nur wüsste wie):


[DllImport(...)]
private static extern int Release1(IntPtr handle, [In] ref IntPtr event);

public static int Release1(IntPtr handle, Event event)
{
IntPtr eventPointer = Marshal.AllocHGlobal(Marshal.SizeOf(event));
Marshal.StructureToPtr(event, eventPointer, true);

int result = Release1(handle, ref eventPointer);

Marshal.FreeHGlobal(eventPointer);
return result;
}


Getestet ist das nicht, sollte aber funktionieren...

Jesus
2006-09-29, 08:56:16
Klappt leider auch net, bekomme immer noch dieselbe Fehlermeldung :(

Kabelsalat
2006-09-29, 13:30:37
Wie instantierst du das DllImport-Attribut?

Jesus
2006-09-29, 13:40:11
Wie instantierst du das DllImport-Attribut?

Hab schon viel versucht, aktuell so:

[DllImport("xdriver.dll", EntryPoint = "Receive1")]
private static extern int Receive1(long portHandle, [In,Out] ref IntPtr ev);

(habs auch schon nur mit [In] versucht...

Kabelsalat
2006-09-29, 14:04:18
Nur als kleiner Hinweis: ref entspricht [In, Out]. Lediglich wenn du auf In beschränken willst, wird das Attribut wirklich benötigt. Für out gibt es auch ein entsprechendes Schlüsselwort.

... wozu gehört diese xdriver.dll? Sicher, das die Methodensignatur "int Receive1 ( portHandle Handle, event **ppEvent)" korrekt ist?

Könntest du noch die Deklaration der Methode und der Struktur aus der Header-Datei posten? Evtl. bringt dich auch ein automatischer Konverter wie der P/Invoke Wizard weiter: http://www.paulyao.com/resources/tools/pinvoke.asp . In der Trial Version musst du die generierte Signatur allerdings abtippen (laut HP, verwendet habe ich das Tool noch nie; bisher hat es noch immer von Hand geklappt).

Gast
2006-09-29, 16:06:40
Nur als kleiner Hinweis: ref entspricht [In, Out]. Lediglich wenn du auf In beschränken willst, wird das Attribut wirklich benötigt. Für out gibt es auch ein entsprechendes Schlüsselwort.

... wozu gehört diese xdriver.dll? Sicher, das die Methodensignatur "int Receive1 ( portHandle Handle, event **ppEvent)" korrekt ist?

Könntest du noch die Deklaration der Methode und der Struktur aus der Header-Datei posten? Evtl. bringt dich auch ein automatischer Konverter wie der P/Invoke Wizard weiter: http://www.paulyao.com/resources/tools/pinvoke.asp . In der Trial Version musst du die generierte Signatur allerdings abtippen (laut HP, verwendet habe ich das Tool noch nie; bisher hat es noch immer von Hand geklappt).

Jep die C Methode sieht genau so aus wie du beschrieben hast.

Die Struktur so:

// event type definition
struct s_event {
eventTag tag; // 1
unsigned char Index; // 1
unsigned char transId; // 1
unsigned char portHandle; // 1
unsigned long timeStamp; // 4
union s_tag_data
tagData; // 14 Bytes
}; // 22 Bytes

typedef struct s_event V_EVENT, Vevent, *PVevent;


(eventTag = unsigned char)

SgtTynis
2006-09-29, 17:57:16
Bin mir jetzt nicht ganz sicher, aber es kann gut sein das man trotz das man [MarshalAs(UnmanagedType.ByValArray, SizeConst = 14)] verwendet, das Array mit new initalisieren muss, damit es im fuer den Aufruf gueltig uebergeben werden kann.

Kabelsalat
2006-09-29, 18:10:59
Ich würde ebenfalls sagen, dass sich an dieser Stelle das Problem verbirgt. Wie ist denn eigentlich s_tag_data definiert?

Jesus
2006-09-29, 20:21:57
Bin mir jetzt nicht ganz sicher, aber es kann gut sein das man trotz das man [MarshalAs(UnmanagedType.ByValArray, SizeConst = 14)] verwendet, das Array mit new initalisieren muss, damit es im fuer den Aufruf gueltig uebergeben werden kann.

Danke, werd ich am Mittwoch probieren, erstmal langes Wochenende :)

s_tag_data ist ne union aus 2 structs, eine 3 und eine 14 bytes lang (in C).

Jesus
2006-10-04, 08:49:53
...geht auch net :(

Kabelsalat
2006-10-04, 13:42:17
Langsam wird es mysteriös...

Hast du VS2005 Prof oder besser? Falls ja, verwende doch mal C++ / CLI um die Methode aufzurufen. Du kannst damit wie von C++ gewohnt verfahren und der Compiler kümmert sich dann automatisch um das P-Invoke. Danach kannst du mit Reflector einen Blick auf den tatsächlich erstellten Code werfen.