Laden...

[gelöst] DllImport einer C Dll: Aufgerufene Funktion hängt

Erstellt von Jochen1980 vor 10 Jahren Letzter Beitrag vor 10 Jahren 5.519 Views
J
Jochen1980 Themenstarter:in
111 Beiträge seit 2006
vor 10 Jahren
[gelöst] DllImport einer C Dll: Aufgerufene Funktion hängt

Hallo!

ich habe hier eine C-DLL auf die ich zugreifen möchte und komme einfach nicht weiter. Leider konnte ich über die Forensuche nichts passendes finden, vielleicht kann mir jemand von euch freundlicherweise weiter helfen?!

Die C-Methode ist in der Header Datei folgendermaßen definiert:


long __stdcall ApintUsb(unsigned long ProductNumber, 
	unsigned long ChannelNumber, char Function[], double In1, double In2, 
	double In3, double In4, double In5, double In6, short int *Out1, 
	short int *Out2, short int *Out3, short int *Out4, short int *Out5, 
	short int *Out6, unsigned short int Array[], long *len);

Ich importiere folgendermaßen:


  [DllImport("ap_int_usb.dll")]
    public extern static long ApintUsb(ulong ProductNumer, ulong ChannelNumber, string Function, double In1, double In2, double In3, double In4,
      double In5, double In6, IntPtr Out1, IntPtr Out2, IntPtr Out3, IntPtr Out4, IntPtr Out5, IntPtr Out6, IntPtr Array, IntPtr Length);

Wenn ich nun versuche, die Methode "ApintUsb" aufzurufen, so bleibt mein Programm beim Methodenaufruf hängen und ich bekomme keine Antwort mehr. Ich gehe mal davon aus, dass ich bei DllImport einen Fehler gemacht habe. Gibt es andere Lösungsansätze für die ganzen C-Pointer?

Ich habe auch ein Beispielprojekt in C. Hier wird die Dll folgendermaßen aufgerufen:


int main(int argc, char **argv)
{
        Function Myfunction;
	HINSTANCE ID = LoadLibrary(TEXT("D:\\_TEMP\\ap_int_usb.dll"));

	
	/* Get DLL function "ApintUsb" */
	Myfunction = (Function)GetProcAddress(ID,"ApintUsb");
	
	
	/* Init USB Link */
	Return_Code = Myfunction(1,0,"Init usb",0,0,0,0,0,0,0,0,0,0,0,0,NULL,0);
}
[CODE]

Hat jemand einen Lösungsansatz für mich? Dank schonmal für Eure Hilfe!
S
248 Beiträge seit 2008
vor 10 Jahren

Hallo Jochen1980,

als ersten Schritt solltest du die verwendeten Datentypen überprüfen.
In Calling Win32 DLLs in C# with P/Invoke ist eine allgemeine Einführung in das Thema PInvoke.

Unten findest du auch eine Tabelle welcher C/C++ Datentyp zu welchem C# Datentyp passt.

Grüße

spooky

J
Jochen1980 Themenstarter:in
111 Beiträge seit 2006
vor 10 Jahren

Demzufolge müsste der DllImport so aussehen:


[DllImport("ap_int_usb.dll")]
    public extern static long ApintUsb(UInt32 ProductNumer, 
      UInt32 ChannelNumber, sbyte[] Function, double In1, double In2,
      double In3, double In4, double In5, double In6, ref Int16 Out1, ref Int16 Out2, ref Int16 Out3, ref Int16 Out4, ref Int16 Out5, 
      ref Int16 Out6, UInt16[] myArray, ref Int32 Length);

Dennoch bleibt die Anwendung beim Aufruf der Methode "ApintUsb" hängen?!? Was kann es sonst noch sein? ggf. stimmt was mit dem Pointern bzw. dem "ref" nicht?!?

C
5 Beiträge seit 2010
vor 10 Jahren

Hallo Jochen1980,

versuche es doch mal der CallingConvetion und wie in deinem letzten Post die Funktionsbekantgabe alle pointer mit "ref" und
Arrays z.B mit "[MarshalAs(UnmanagedType.LPArray)]" zu versehen.

Hier ein Beispiel:

 [DllImport("ap_int_usb.dll", CallingConvention = CallingConvention.Cdecl)]
 public extern static long TestFunction([MarshalAs(UnmanagedType.LPArray)] UInt16[] myArray, ref Int16 Out1);

Gruß

J
Jochen1980 Themenstarter:in
111 Beiträge seit 2006
vor 10 Jahren

Hallo C#EDDY,

danke für den Tip, klappt leider dennoch nicht:


    [DllImport("ap_int_usb.dll", CallingConvention = System.Runtime.InteropServices.CallingConvention.Cdecl)]
    public extern static long ApintUsb(UInt32 ProductNumer,
      UInt32 ChannelNumber, sbyte[] Function, double In1, double In2,
      double In3, double In4, double In5, double In6, ref Int16 Out1, ref Int16 Out2, ref Int16 Out3, ref Int16 Out4, ref Int16 Out5,
      ref Int16 Out6, UInt16[] myArray, ref Int32 Length);

Anwendung bleibt "hängen".

S
248 Beiträge seit 2008
vor 10 Jahren

Hallo Jochen,

wenn es mit dem von dir im Startpost posteten C-Code funktioniert ohne zu hängen, dann versuche folgendene Definition:


        [DllImport("ap_int_usb.dll", CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Ansi)]
        public extern static uint ApintUsb(
            uint ProductNumer,
            uint ChannelNumber,
            string Function,
            double In1, double In2, double In3, double In4, double In5, double In6,
            IntPtr Out1, IntPtr Out2, IntPtr Out3, IntPtr Out4, IntPtr Out5, IntPtr Out6,
            IntPtr myArray, IntPtr Length);

Und mit folgendem Aufruf:

ApintUsb(1, 0, "Init usb", 0, 0, 0, 0, 0, 0, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero);

Dies entspricht 1 zu 1 dem, was du in C gemacht hast.
Wenn es dann immernoch "hängt", dann liegt es nicht am Aufruf, sondern an deiner DLL.

49.485 Beiträge seit 2005
vor 10 Jahren

Hallo Spook,

hast du wirklich geprüft, ob die Anwendung in der C-Funktion hängt, z.B. durch eine Testausgabe davor und danach?

Was sagt die Dokumentation der C-Funktion? Stellt sie bestimmte Anforderungen an den Aufrufer bzw. die Umgebung (z.B. den Thread, in dem sie läuft)?

Hast du versucht die C-Funktion aus einem C-Programm heraus aufzurufen? Hängt sie dann auch?

herbivore

J
Jochen1980 Themenstarter:in
111 Beiträge seit 2006
vor 10 Jahren

So, jetzt wird es ganz seltsam:
MIt dieser Deklaration bekomme ich das ganze unter Windows XP und Visual Studio 2008 zum laufen, aber nicht unter Windows 7. Dort bekomme ich immer den Fehler: > Fehlermeldung:

Es wurde versucht im geschützten Speicher zu lesen...

Wie gesagt, unter XP funktioniert es nun, nicht aber unter Win7???


 [DllImport("C:\\Program Files\\dll c call herkules\\ap_int_usb.dll", CallingConvention = System.Runtime.InteropServices.CallingConvention.Cdecl)]
    public extern static long ApintUsb(int ProductNumer,
    int ChannelNumber, StringBuilder Function, double In1, double In2,
    double In3, double In4, double In5, double In6, ref Int16 Out1, ref Int16 Out2, ref Int16 Out3, ref Int16 Out4, ref Int16 Out5,
    ref Int16 Out6, ref UInt16[] myArray, ref int Length);

2.298 Beiträge seit 2010
vor 10 Jahren

Nur so ne Idee. Hast du das Programm unter Windows 7 mal direkt als Administrator ausgeführt (Kontextmenü "als Administrator ausführen")?

Wissen ist nicht alles. Man muss es auch anwenden können.

PS Fritz!Box API - TR-064 Schnittstelle | PS EventLogManager |

S
248 Beiträge seit 2008
vor 10 Jahren

long __stdcall ApintUsb
CallingConvention = System.Runtime.InteropServices.CallingConvention.Cdecl
Absicht?

J
Jochen1980 Themenstarter:in
111 Beiträge seit 2006
vor 10 Jahren

@Spook: ich hab die DLL in zwei unterschiedlichen Versionen, zuerst habe ich es mit dem __stdcall versucht, jetzt mit dem __cdecl. Richtig ist:


long __cdecl ApintUsb(unsigned long ProductNumber, 
	unsigned long ChannelNumber, char Function[], double In1, double In2, 
	double In3, double In4, double In5, double In6, short int *Out1, 
	short int *Out2, short int *Out3, short int *Out4, short int *Out5, 
	short int *Out6, unsigned short int Array[], long *len);

Noch zur Ergänzung der Windows 7 Fehlermeldung: Bevor der Fehler mit dem geschützten Speicher auftritt kommt die Meldung:

Fehlermeldung:
Der Assistent für verwaltetes Debugging "LoaderLock" hat ein Problem in "C:\Program Files\dll c call herkules\Jochen\bin\Debug\USPC_Test.exe" festgestellt.
Weitere Informationen finden Sie unter: Die DLL "C:\Program Files\National Instruments\Shared\LabVIEW Run-Time\7.0\DNCompInfo.dll" unternimmt einen Versuch, innerhalb der Sperre für den OS-Loader eine verwaltete Ausführung durchzuführen.

@inflames2k: Kann man beim Debugging in VS einstellen, dass das Programm als Admin ausgeführt werden soll?

1.346 Beiträge seit 2008
vor 10 Jahren

Du kannst Visual Studio als Admin starten. Dann wird deine Anwendung automatisch als Admin gestartet.

LG pdelvo

J
Jochen1980 Themenstarter:in
111 Beiträge seit 2006
vor 10 Jahren

Ok, danke für den Hinweis. Leider bleibt das Verhalten auch als Admin gleich.

W
872 Beiträge seit 2005
vor 10 Jahren

Vielleicht mischst Du unter Windows 7 eine 32bit Dll mit einem 64 bit OS?

J
Jochen1980 Themenstarter:in
111 Beiträge seit 2006
vor 10 Jahren

@weismat: Ne, leider nicht. Die Dll gibt es nur für 32bit OS.
Vielleicht noch wichtig als Zusatzinfo: Es handelt sich um eine mit LabVIEW geschriebene DLL eines Zulieferanten. Aber wie gesagt, im C - Beispiel Code läuft die Anwendung. In C wird die Dll so eingebunden:


typedef long (*Function)(unsigned long, unsigned long, char [], double, double, 
	double, double, double, double, short int *, 
	short int *, short int *, short int *, short int *, 
	short int *, unsigned short int [], long *);

W
872 Beiträge seit 2005
vor 10 Jahren

Eine 32bit Dll kann auch unter Windows 7 - 64 bit laufen.
Nur .NET Applikationen müssen unter 64 Bit explizit auf 32 Bit eingestellt werden (entweder innerhalb des Projekts oder mittles corflags).

J
Jochen1980 Themenstarter:in
111 Beiträge seit 2006
vor 10 Jahren

Beide Systeme sind 32bit Prof., sowohl XP als auch Windows 7. Der Unterschied kann ja nur mit dem Windows 7 zu tun haben, die Frage ist nur wie bekommt man den Fehler weg?

T
2 Beiträge seit 2013
vor 10 Jahren

Hallo Jochen,

wie erfolgt denn die Arrayinitialisierung auf der C# Seite?
Üblicherweise kommt diese Meldung, wenn das Array nicht bzw. nicht groß genug initialisiert ist.
Unter XP wurde das noch nicht ganz so eng gehandhabt, da konnte es sogar auftreten, dass im Debug alles lief und im Release (optimierter Code) Exceptions flogen.
Hoffe es hilft...

MFG,
Trusti

C
5 Beiträge seit 2010
vor 10 Jahren

Hallo Jochen,

hast du das mit dem

[MarshalAs(UnmanagedType.LPArray)]

vor deinem Array schon versucht?

[DllImport("C:\\Program Files\\dll c call herkules\\ap_int_usb.dll", CallingConvention = System.Runtime.InteropServices.CallingConvention.Cdecl)]
    public extern static long ApintUsb(int ProductNumer,
    int ChannelNumber, StringBuilder Function, double In1, double In2,
    double In3, double In4, double In5, double In6, ref Int16 Out1, ref Int16 Out2, ref Int16 Out3, ref Int16 Out4, ref Int16 Out5,
    ref Int16 Out6, [MarshalAs(UnmanagedType.LPArray)] UInt16[] myArray, ref int Length);
J
Jochen1980 Themenstarter:in
111 Beiträge seit 2006
vor 10 Jahren

Habe das Problem nun folgendermaßen lösen können:

1. Windows DEP deaktivieren: bcdedit /set {current} nx AlwaysOff
2. Restart Computer
3. Handle LoaderLock: Error with LoaderLock Managed Debugging Assistant (MDA) when Calling a DLL

Seitdem funktioniert das C# Projekt unter Windows 7 genauso wie unter Windows XP.

Hinweis von herbivore vor 10 Jahren

Vielen Dank, dass du deine selbst gefundene Lösung veröffentlicht hast.