Ich bin gerade dabei ein in C++ geschriebenes Terminalprogramm-Tool in C# zu portieren. Dabei soll eine Funktion von einer unverwalteten DLL aufgerufen werden.
Der alte Aufruf (mit C++) sieht so aus:
CLUINT32 numPorts;
clGetNumPorts(&numPorts);
Die Funktion hat den Prototype: INT32 __stdcall clGetNumPorts (UINT32* numPorts)
Jetzt habe ich das in C# folgendermaßen umgesetzt:
[DllImport("clallserial.dll", EntryPoint="clGetNumPorts")]
public extern static unsafe int clGetNumPorts(
uint* numPorts); // für Anzahl der Ports
mit dem Aufruf:
uint numPorts;
clGetNumPorts(&numPorts);
Leider funktionert es so nicht. Bei dem Aufruf bleibt das Programm hängen.
Meine Frage: Was mache ich falsch? Muß ich noch ein 'MarshalAs' verwenden oder muß ich ein DLLImport Attribut angeben?
Kann ich überhaupt einen Zeigerparameter beim Aufruf verwenden? Oder was muß ich dabei beachten.
Ich vermute mal, dass "numPorts" ein [out]-Parameter ist, dass heisst der Wird wird in dieser Variablen zurückgegeben, ist das so?
Dann müsste nämlich numPorts nach dem Aufruf die Anzahl der gefunden Ports enthalten. Du hast das ganze aber als normalen In-Parameter definiert.
Ausserdem brauchst du bei dieser Deklaration kein unsafe Schlüsselwort benutzen.
Es sollte auch so gehen.
Seit der Erkenntnis, dass der Mensch eine Nachricht ist, erweist sich seine körperliche Existenzform als überflüssig.
Ja numPorts soll wird wieder zurückgegeben werden. Ich werde es gleich am Montag, wenn ich wieder in der Arbeit bin, ausprobieren. Danke für die Hilfe.
Ich habe es jetzt wie folgt abgeändert:
[DllImport("clallserial.dll")]
public extern static unsafe int clGetNumPorts(
out uint* numPorts); // für Anzahl der Ports
mit dem Aufruf:
clGetNumPorts(out &numPorts);
Ich bekomme die Fehlermeldung vom Compiler:
Fehler CS1510: Ein ref- oder out-Argument muss eine zuweisbare Variable sein.
Irgendwas mache ich falsch, ich weis nur nicht was???
Was habe ich falsch verstanden? Hat jemand evtl. eine Art Beispiel?
Was ich auch noch nicht so ganz versehe warum Du [out] in eckigen Klammern geschrieben hast?
[DllImport("clallserial.dll")]
public extern static unsafe int clGetNumPorts(
out uint numPorts); // kein pointer
uint numPorts = 0;
clGetNumPorts(out numPorts);
So sollte es aussehen
Danke! Jetzt kann ich es kompilieren. Allerdings bleibt das Programm wieder beim Aufruf von:
clGetNumPorts(out numPorts);
hängen...
...irgendwelche Ideen??
nimm statt OUT mal REF
2 Tips hab ich noch, dann ist auch bei mir empty:
zu 1. habe ich probiert, war aber unverändert
zu 2. müßte eigentlich schon UINT32 sein, steht zumindest so in der Doku
Leider kann ich innerhalb der unmanaged DLL anscheinend auch nicht debuggen, sonst würde ich dem schon auf die Spur kommen. Oder gibt es doch eine Möglichkeit zu debuggen?? Fehlermeldung kriege ich auch keine, bleibt einfach hängen.
oder
[DllImport("clallserial.dll", EntryPoint="clGetNumPorts")]
public extern static int clGetNumPorts(out UInt32 numPorts); // für Anzahl der Ports
Statt auf, kannst Du auch, wie es DaSchroeter schon vorgeschlagen hat auch ref mal ausprobieren.
Heisst der EntryPoint auch wirklich clGetNumPorts?
Was sagt der DependencyWalker?
und noch was ganz wichtiges: Sind die DLLNamen vielleicht dekoriert?
Du brauchst auf jeden Fall genau den Namen den der Dependency-Walker für Dich betreffs der Funktion ausspuckt, sonst wird es nicht funktionieren.
Ansonsten, wenn das nichts hilft, lad mal die DLL hier hoch, wenn es keine Eigenentwicklung sein sollte (sonst darfst Du die ja nicht rausgeben)
Seit der Erkenntnis, dass der Mensch eine Nachricht ist, erweist sich seine körperliche Existenzform als überflüssig.
Hier kommt die DLL gezippt....
Das mit dem dekorieren habe ich nicht ganz kapiert
thfu: Die DLL ist nicht bzw. die Funktionsnamen sind nicht dekoriert.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;
namespace WindowsApplication3
{
public partial class Form1 : Form
{
[DllImport("clallserial.dll", EntryPoint="clGetNumPorts")]
public extern static int clGetNumPorts(uint numPorts); // für Anzahl der Ports
public Form1()
{
InitializeComponent();
int n1 = clGetNumPorts(10);
}
}
}
Dieser Code liefert bei mir als Ergebnis: -10010, wenn ich zuvor die DLL ins bin/debug Verzeichnis des entsprechenden dazu erstellten Projekt kopiert habe.
Bleibt der bei Dir auch hängen?
In welcher Sprache wurde die clseriadll erstellt?
Seit der Erkenntnis, dass der Mensch eine Nachricht ist, erweist sich seine körperliche Existenzform als überflüssig.
Hallo!
Leider kann ich innerhalb der unmanaged DLL anscheinend auch nicht debuggen, sonst würde ich dem schon auf die Spur kommen. Oder gibt es doch eine Möglichkeit zu debuggen??
Du kannst eigentlich ganz gut sogar aus dem managed Bereich in den unmanaged Bereich debuggen. Dabei muss man folgendes beachten, vorausgesetzt, dass die unmanaged Dll von Dir stammt:
Gruß, DaMoe
Tach noch einmal!
Nur eine kurze Frage. Sind denn bei Dir die Funktionen korrekt in der Dll bspw. per
extern "C"
{
int _declspec(dllexport) Add(int a, int b);
}
exportiert?
Gruß, DaMoe
@DaMoe80:
(zu extern "C"...) Das weis ich nicht. Ich habe leider den Quellcode nicht. Derjenige der es evtl. haben bzw. wissen würde, ist gerade im Urlaub. Vielleicht liegt hier das Problem.
Debuggen kann ich dann wohl ohne DLL-Quellcode auch nicht richtig, aber jetzt weis ich schon mal wie es gehen würde.
@dr4g0n76:
Du hast natürlich auch nicht die entsprechende Hardware (Kamera & Framegrabber) um was auszulesen, aber mein Programm bleibt auch beim Aufruf der externen Methode hängen. Ohne C#, d.h. mit C++, hat es funkioniert.
Ist das mit dem 'nicht dekoriert' ein Vorteil oder ein Nachteil?
hallo thfu,
Ist das mit dem 'nicht dekoriert' ein Vorteil oder ein Nachteil?
also:
Ich habe es überprüft, die Funktionen sind nicht dekoriert (hab ich mit dem DependencyWalker gesehen).
Dekoration heisst, dass der Compiler best. Zeichen reinmacht, um die Parametergröße in Bytes zu bestimmen und ähnliches. Das heisst der Funktionsname würde dann z.B.
@@??clGetSerial@@
heissen.
Dann würdest Du aber von DllImport eine Exception bekommen ("DLLEntryPoint not found" oder so ähnlich)
Du hast natürlich auch nicht die entsprechende Hardware (Kamera & Framegrabber) um was auszulesen, aber mein Programm bleibt auch beim Aufruf der externen Methode hängen. Ohne C#, d.h. mit C++, hat es funkioniert.
Hast Du das ganze schon mal exakt mit meinem oberen Code-Ausschnitt probiert!?!?
Sonst hat es keinen Sinn hier weiterzudiskussieren.
Seit der Erkenntnis, dass der Mensch eine Nachricht ist, erweist sich seine körperliche Existenzform als überflüssig.
Ich habe es jetzt wie folgt abgeändert und jetzt bleibt es nicht mehr hängen.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;
namespace WindowsApplication1
{
public partial class Form1 : Form
{
[DllImport("clallserial.dll", EntryPoint = "clGetNumPorts")]
public extern static int clGetNumPorts(out uint numPorts); // für Anzahl der Ports
public Form1()
{
uint numPorts = 10;
InitializeComponent();
int n1 = clGetNumPorts(out numPorts);
}
}
}
Ich weis blos noch nicht was der Unterschied ist. Irgendwas muß jetzt anders sein als zu meinem Consolenprogramm. Ich weis aber nicht was.
Ich habe den Unterschied jetzt herausgefunden.
Meine Methode main sieht jetzt so aus:
[STAThread] // Das ist neu
static void Main()
Der Unterschied war das [STAThread]
Danke an alle die mit geholfen haben!!!