![]() |
dll einbinden / Pointer Probleme
Hallo,
ich möchte eine dll, die mit c++ geschrieben wurde in meinem Delphi Programm nutzen. Die DLL habe ich wie folgt eingebunden:
Delphi-Quellcode:
Nun gibt es eine c++ Funktion (COM_TcpOpen) in dieser DLL, die folgende Übergabewerte erwartet:
function COM_TcpOpen(const m_hCom:Pointer; const ipAddress:Pchar; port:integer):string; stdcall; external 'HwCom.dll';
Code:
Jedoch habe ich Probleme beim Einbinden der Funktion (ich denke, es liegt an dem ersten Übergabewert). Und zwar bringt mir Delphi immer einen Lesefehler auf Adressbereich xyz (wobei xyz dem Wert des Pointers entspricht. Die Funktion erwartet eigentlich einen "leeren" Pointer, der durch die Funktion gefüllt werden soll.
COM_TcpOpen (COM_Handle * handle, const char * ipAddress, u16 port)
Der Quelltext meines Delphi Programms sieht zur Zeit wie folgt aus:
Delphi-Quellcode:
Hat vielleicht jemand einen Tipp für mich, woran es liegen kann, dass ich ständig Lesefehler bekomme? ich probiere nun schon seit Tagen rum und komme nicht wirklich weiter... Wäre super, wenn jemand helfen könnte. Ich komme eigentlich auch nicht aus der Delphi Ecke.
procedure TForm1.btnconnectClick(Sender: TObject);
var m_hCom: Pointer; ret:string; port:smallint; iparray:array[0..12] of char; ipAddress:PChar; begin m_hCom := NIL; port:= 1500; ipAddress:=iparray; ipAddress[0]:='1'; ipAddress[1]:='9'; ipAddress[2]:='2'; ipAddress[3]:='.'; ipAddress[4]:='1'; ipAddress[5]:='6'; ipAddress[6]:='8'; ipAddress[7]:='.'; ipAddress[8]:='1'; ipAddress[9]:='.'; ipAddress[10]:='1'; ipAddress[11]:='5'; ipAddress[12]:=#0; ret := COM_TcpOpen(m_hCom,ipAddress,port); end; |
AW: dll einbinden / Pointer Probleme
Hallo und Willkommen in der DP :dp:,
klappt es so?
Delphi-Quellcode:
Allerdings bin ich da auch kein Experte, geb ich zu.
function COM_TcpOpen(var m_hCom: THandle; ipAddress:Pchar; port:integer): PChar; stdcall; external 'HwCom.dll';
|
AW: dll einbinden / Pointer Probleme
COM_Handle wird doch bestimmt ein VAR-parameter sein. (vermutlich auch eher HANDLE/THandle, anstatt Pointer)
Und wie ist das Result deklariert? (im C-Code ist nix zu sehn) Wie sieht die Aufrufkonvention aus? (sicher daß es stdcall ist) Und welche Delphi-Version nutzt du? PChar ist aber so oder so keine sonderlich guter Idee. Ich würde vermuten, daß wohl eher PAnsiChar gemeint ist. |
AW: dll einbinden / Pointer Probleme
@DeddyH: Danke! Leider funktioniert es so auch nicht - ich hatte es auch schon mit THandle statt Pointer probiert - ohne Erfolg.
@himitsu: Mit THandle hatte ich es Anfangs auch probiert - leider brachte das aber kein Erfolg. In der DLL Doku steht folgendes: "COM_TcpOpen erwartet als handle-Parameter eine Variable vom Typ COM_Handle (z.B. COM_Handle m_hCom;). Diese Variable ist ein Zeiger auf das von der Funktion COM_TcpOpen erzeugte (Ethernet) Interface. Sprich dieser Pointer wird von COM_TcpOpen erst initialisiert(referenziert)." Deshalb die Idee, ein unreferenziertes Handle zu übergeben - aber anscheinend habe ich da etwas übersehen, denn es passiert nichts. Als Result ist folgendes deiniert:
Code:
Die Aufrufkonvention ist mir gänzlich unbekannt, da keinerlei Dokumentation für diese DLL mit Delphi existieren (und genau das ist mein Problem - denn ich tappe da ziemlich im dunkeln).
Returns:
COM_RETURN_OK Function executed successfully. COM_RETURN_Failed The function failed to create a new handle. Ob PChar so passt, ist auch fragwürdig. Ich habe nur die Information, dass für ipaddress ein nullteminierter String (const char* in c++) erwartet wird. Für Port wird ein unsigned short int erwartet. Ich benutze Delphi XE (15.0.xxx) |
AW: dll einbinden / Pointer Probleme
Würdest du uns bitte den kompletten Prototypen der Funktion in C/C++ geben, sowie den typedef für COM_Handle?
Ggf. laß lieber ein paar Zeilen rundherum mit dabei anstatt zuviel herauszuschnipseln. Ach ja, ein Link zu dem Header würde auch helfen wenn der alternativ vorhanden ist. Wenn du nur die DLL hast, wird das etwas schwieriger. Man bräuchte mindestens die DLL (klar) um mal in IDA nachzugucken, aber ne Garantie auf ein schnelles Resultat ist das nicht. Kann sein, kann aber auch nicht sein. Wenn du ein Programm hast welches diese DLL benutzt ist es auch sinnvoll dieses beizulegen. Kann man es irgendwo runterladen, gib halt den Link ;) |
AW: dll einbinden / Pointer Probleme
SHORT in C ist doch in Delphi ein Word/SmallInt? (ShortInt/Byte währe für einen Port eh zu klein)
Und ansonsten hat Assarbad ja noch genügend gesagt. :) |
AW: dll einbinden / Pointer Probleme
Zitat:
|
AW: dll einbinden / Pointer Probleme
Zitat:
|
AW: dll einbinden / Pointer Probleme
Und wo steht dort was von einem String/PChar?
Sieht eher nach einem HRESULT/Cardinal aus. Aber irgendwo wird ja COM_RETURN_OK ja deklariert sein. Und Integer = SmallInt. Wie sieht denn die genaue Fehlermeldung aus? Strg+C im Fehlerdialog drücken und dann Strg+V im Beitrageditor. Zitat:
Es wurde aber absichtlich nach der vollständigen Deklaration gefragt. |
AW: dll einbinden / Pointer Probleme
Zitat:
Ist das evtl. nur ein Wrapper für TCP/IP? Ich hab schon erlebt, dass manche versuchen eine DLL für die serielle Schnittstelle anzusteuern, obwohl man mit einer Delphi Komponente viel besser dran wäre. |
AW: dll einbinden / Pointer Probleme
Zitat:
![]() ![]() Meine Glaskugel hat auch Urlaub. Zitat:
|
AW: dll einbinden / Pointer Probleme
Wow, danke für die Beteiligung!
Konkret geht es um folgendes: Ich habe eine Hardware, die über Ethernet angesteuert werden soll. Der Hardwarehersteller hat dazu eine dll zur Verfügung gestellt, welche die Funktionen für Kommunikationsaufbau, Abbau und Datenübertragung enthält. Ich versuche nun eine Kommunikation mit dem Steuergerät herzustellen (Funktion COM_TcpOpen in der DLL). Die Funktion ist in der Onlinehilfe des Hardwareherstellers wie folgt dokumentiert:
Code:
Hier die Codeausschnitte aus dem c++ Beispielprogramm vom Hardwarehersteller:
EXPORTDLL COM_RETURN EBEL_API COM_TcpOpen ( COM_Handle * handle,
const char * ipAddress, u16 port ) Generates a new PC HW interface. To communicate with a hardware over Ethernet. Parameters: handle = Pointer to a handle representing the interface instance. Will be filled by this function. ipAddress = IP Address of the target. port = Port number used to communicate with the target. Returns: COM_RETURN_OK Function executed successfully. COM_RETURN_Failed The function failed to create a new handle. Typedef:
Code:
COM_Return Definition:
/// \brief Defines a handle to a PC->Hardware communication object.
typedef void* COM_Handle;
Code:
COM_TcpOpen Aufruf in C++:
/// \brief Return values used by the interface functions. This type provides information about an error. A zero value means no error occured.
typedef enum COM_RETURNtag { COM_RETURN_OK = 0, ///< Function executed successfully. COM_RETURN_Failed, ///< Function execution failed. COM_RETURN_InvalidHandle, ///< The handle parameter was NULL or not a matching PC HW interface handle. COM_RETURN_InvalidParameter, ///< One of the parameter was invalid. COM_RETURN_NullPointer, ///< One of the paramter was a NULL pointer but should point to a stucture or variable. COM_RETURN_Timeout, ///< The hardware was not responding or not reachable. COM_RETURN_NotSupported, ///< The command requested was not supported by the application on the hardware. COM_RETURN_AlreadyRunning, ///< The function / application is already running. COM_RETURN_Locked ///< The function can not be executed while the HW/SW/region is locked. } COM_RETURN;
Code:
Der komplette C++ Quellcode ist wohl leider zu groß, um ihn hier zu posten. Falls aber noch weitere Infos nötig sind, poste ich diese gerne.
//---------------------------------------------------------------------------
// Example of an implementation of a COM_TcpOpen call //--------------------------------------------------------------------------- void CHwComTestGuiDlg::OnBnClickedOpentcp() { CString str; UpdateData(); // Update the member variables with the values in the text fields. #ifdef BLUETOOTH_INTERFACE //Disable bluetooth "Open" and "Close" buttons CButton *tcpBTHOpenClose; tcpBTHOpenClose = (CButton*) GetDlgItem(IDC_CBUTTON_OPEN); tcpBTHOpenClose->EnableWindow(FALSE); tcpBTHOpenClose = (CButton*) GetDlgItem(IDC_CBUTTON_CLOSE); tcpBTHOpenClose->EnableWindow(FALSE); #endif COM_RETURN ret = COM_TcpOpen(&m_hCom,m_ipAddress.GetBuffer(),m_nPort); // Call the function PrintErrorInfos("COM_TcpOpen",ret); // Visualize the result } Der Entwickler der dll hat mir eben noch geschrieben, dass er sich mit Delphi leider nicht auskennt, aber er davon ausgeht, dass ich vergessen habe, die Zeigeradresse beim Funktionsaufruf mit anzugeben. Nun bin ich aber leider selber nicht der Delphi-Pro und wüsste auf Anhieb auch nicht, ob und wie ich die Adresse übergeben kann. |
AW: dll einbinden / Pointer Probleme
In Delphi sind ENUM standardmäßig so klein wie möglich.
In C sind sie standardmäßig (glaub ich) so groß wie ein Register. (früher Integer, aber weil irgendein Arsch meinte Integer/Cardinal einfriehren zu müssen NativeInt/NativeUInt) Also COM_Return entweder als NativeUInt oder als ENUM, aber mit MinimumEnumSize = RegisterSize. Die Strings als AnsiString/AnsiChar/PAnsiChar. COM_Handle als
Delphi-Quellcode:
.
var COM_Handle: THandle;
Tipp: Das iparray als AnsiString ... läßt sich dann leichter verwenden. :wink: Und siehst du ... gleich alle wichtigen Infos rausrücken und schon geht es schneller. |
AW: dll einbinden / Pointer Probleme
Mit THandle hatte ich es ja schon versucht, jedoch ohne Erfolg.
Der DLL Entwickler schrieb mir ja, dass man der Funktion die Zeigeradresse mit übergeben soll... nur wie macht man das in Delphi? Im Moment bekomme ich wieder die Fehlermeldung, dass das Lesen auf dem Speicherbereich x nicht möglich ist. |
AW: dll einbinden / Pointer Probleme
Delphi-Quellcode:
type PHandle = ^THandle;
var MyHandle;
Delphi-Quellcode:
(
var COM_Handle: THandle
Delphi-Quellcode:
) entspricht dem
MyHandle
Delphi-Quellcode:
(
COM_Handle: PHandle
Delphi-Quellcode:
).
@MyHandle
|
AW: dll einbinden / Pointer Probleme
Blöde Frage: Wo bringe ich die Befehle in meinem Code unter? Kommt hinter das "var MyHandle;" noch irgendwas? Delphi meckert da rum, dass es ein Komma oder Semikolon erwartet.
|
AW: dll einbinden / Pointer Probleme
So, der Verbindungsaufbau funktioniert nun endlich. Es lag an einem falschen Datentyp bei der IP Adresse. Dort habe ich nun einen Ansistring verwendet.
Nun stehe ich aber schon vor dem nächsten Problem. In der DLL gibt es eine Funktion, die folgende Struktur füllt und dann über einen Pointer ausgelesen werden soll: typedef struct COM_Version { u08 Major; u08 Minor; u08 Patch; u08 Build; } COM_Version; u08 steht dabei für unsigned char. Welchen Datentyp kann ich hier in Delphi verwenden, um diese Daten auszulesen? Ich denke, es muss in irgendeiner Weise ein Array verwendet werden, oder? Mit Datentyp char funktioniert es in Delphi leider nicht (Zugriffsverletzung). |
AW: dll einbinden / Pointer Probleme
Versuch einmal:
Delphi-Quellcode:
Ggf. musst Du die Felder in umgekehrter Reihenfolge deklarieren, kommt darauf an, wie sie befüllt werden.
type
TCOM_Version = packed record Major, Minor, Patch, Build: Byte; end; |
AW: dll einbinden / Pointer Probleme
Wie wäre es mit einem Array of Byte?
|
AW: dll einbinden / Pointer Probleme
ich habe die type Definition nun in Delphi so übernommen - aber es tat sich leider nichts. Immernoch Zugriffsverletzung.
Der Code sieht nun wie folgt aus (Typedeinition nicht mit inbegriffen):
Delphi-Quellcode:
Die public Variable Zeiger wurde schon von einer anderen Funktion (COM_TcpOpen) gefüllt.
function COM_GetVersionReq(var zeiger:Pointer; version:TCOM_Version): NativeUInt ; cdecl; external 'HwCom.dll';
procedure TForm1.btngetversionClick(Sender: TObject); var typevers: TCOM_Version; begin return := COM_GetVersionReq(zeiger, typevers); end; Typevers istd er Rückgabewert, den die Funktion liefern soll. Müsste ich hier evtl. wieder einen Pointer auf die Variable "typevers" setzen, um den Wert von der Funktion bekommen zu können? |
AW: dll einbinden / Pointer Probleme
Ich rate einmal ins Blaue:
Delphi-Quellcode:
return := COM_GetVersionReq(zeiger, @typevers);
|
AW: dll einbinden / Pointer Probleme
leider nicht. Immernoch "Zugriffsverletzung bei Adresse xyz. Schreiben von Adresse abc aufgetreten".
Hmm, Klingt fast danach, als wollte die Funktion was reinschreiben, wird aber durch irgend einen Grund daran gehindert, oder? |
AW: dll einbinden / Pointer Probleme
Wie sieht denn der Original-Aufruf aus?
|
AW: dll einbinden / Pointer Probleme
Der Originalaufruf sieht so aus:
Code:
Sieht in meinen Augen aber sehr ähnlich aus, wie mein "Delphi-Versuch". m_hCom ist das Handle, welches durch die COM_TcpOpen Funktion gefüllt wurde - äquivalent meinem Delphi Programm.
//---------------------------------------------------------------------------
// Example of an implementation of a COM_GetVersionReq call //--------------------------------------------------------------------------- void CHwComTestGuiDlg::OnBnClickedButtonGetversion() { COM_Version version; if (COM_RETURN_OK == PrintErrorInfos("COM_GetVersionReq",COM_GetVersionReq(m_hCom,&version))) { printf("COM_Version: %d.%d.%d.%d\r\n",version.Major,version.Minor,version.Patch,version.Build); } } |
AW: dll einbinden / Pointer Probleme
Nächster Versuch:
Delphi-Quellcode:
function COM_GetVersionReq(zeiger:Pointer; var version: TCOM_Version): NativeUInt ; cdecl; external 'HwCom.dll';
|
AW: dll einbinden / Pointer Probleme
Super, danke dir! Nun läuft die Funktion schon mal durch und liefert 0 zurück (also alles ok soweit). Jetzt kommt die Zugriffsverletzung erst, wenn ich über end; springe.
Wird jetzt wohl noch daran liegen, dass er versucht, die Werte in eine Variable mit falschem Datentyp zu schreiben. Ich werd mal ein bisschen durch probieren. |
AW: dll einbinden / Pointer Probleme
Hast du bei der anderen Funktion nicht "stdcall" als Aufrufkonvention angegeben?
Im Normalfall sind alle Funktionen einer DLL einheitlich. Es scheint mir zumindest fragwürdig warum es bei dieser Funktion dann plötzlich "cdecl" sein sollte. |
AW: dll einbinden / Pointer Probleme
Wird auch sehr wahrscheinlich STDCALL sein, da es beim beenden crashed, dort wo "end" an die Rücksprungadresse springt die durch doppeltes aufräumen (CDECL/STDCALL) nicht stimmt.
Hier mal ein Denkanstoß, wenn man rausfidnen will ob cdecl/stdcall, auch wenn man jetzt nicht direkt den Aufruf hat, kann man das am retn in der dll festmachen, wenn man weiß dass mind. 1 parameter vorhanden ist. ![]() |
AW: dll einbinden / Pointer Probleme
Die Aufrufkoncention war mir von vorn herein unbekannt, deshalb hatte ich zuerst damit rumprobiert (zuerst stadcall, dann cdecl - jedoch bei allen Funktionen gleich). Mit CDECL hatte der Verbindungsaufbau zum Steuergerät zunächst funktioniert, deshalb hatte ich es dabei belassen.
Ich habe es nun wieder alles auf stdcall umgestellt und was soll ich sagen...es funktioniert! Kurzum: Ihr seid der Wahnsinn! Danke für eure Geduld! Als Delphi Newbie ist der Einstieg leider etwas holprig. |
Alle Zeitangaben in WEZ +1. Es ist jetzt 17:41 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz