![]() |
Funktionspointerübergabe eines C-Programmes an Delphi-DLL
Hi,
ich habe ein ganz spezielles Problem an dem sowohl C++ sowie Delphi (und d.h. auch teilweise die WinApi) beteiligt ist. Zuerst einmal die Problemstellung: Von einem C-Programm aus rufe ich eine von mir mit Delphi erstellte Dll auf. Das funktioniert soweit ganz gut, aber in der Dll gibt es eine Funktion die auf ein Ereignis reagieren soll und dann dieses Ereignis an eine Funktion im C-Programm weitergeben soll (Callback). Das ganze mache ich derzeit so das ich der Dll über eine Funktion einen Funktionspointer übergebe welche die Dll dann im Ernstfall aufrufen soll (im C-Programm). Leider klappt das nicht da ich so immer eine Zugriffsverletzung kriege. Ich denke mal das Problem ist die Übergabe des Funktionspointers, kann aber natürlich auch woanders liegen (es lässt sich ja leider nicht so einfach debuggen). Zur Veranschaulichung hier die wichtigsten Ausschnitte beider Codes (bei dem ganzen handelt es sich übrigens um eine teilweise Auslagerung der VCL in eine Dll):
Delphi-Quellcode:
//Delphi Code
//DLL //... //Konstanten const VCLA_CLOSE=$aa; const VCLA_CLICK=$ab; const VCLA_DBLCLICK=$ac; const VCLA_CHANGE=$ad; //Globale Deklarationen var Controls:TObjectList; //Alle VCL-Controls var ControlsAliases:TStringlist; //Hier werden die Namen der Controls gespeichert (zur Zuordnung von Ids) var ctrlsEventCallbackFunc:TList; //Pointer auf die Callback-Funktionen var EventHandlerInst:TVCLAdaptEventHandler; //Event-Handler, mit den Methoden in dieser Klasse werden die Callback-Funktionen aufgerufen type StandardEventCallback=procedure(_ctrlname:PChar;action:integer;_value:PChar); stdcall; //Das ist die Deklaration der Callback-Funktion im C-Programm type pStandardEventCallback=^StandardEventCallback; function SetCallback(_ctrlname:PChar;var _callbfunc:pStandardEventCallback):integer; stdcall; export; //Hiermit wird so eine Callbackfunktion "registriert" var tmpid:integer; begin Result:=0; if (ControlsAliases<>nil) and (ctrlsEventCallbackFunc<>nil) then begin tmpid:=ctrlsEventCallbackFunc.Add(_callbfunc); //Pointer auf die Callback-Funktion im C-Programm wird in die zugehörige-Liste eingetragen ControlsAliases.Add(_ctrlname); //Der Name des zugehörigen Controls wird ebenfalls gespeichert end else Result:=-1; end; function GetEventCallbFuncFromLists(_ctrlname:PChar):pStandardEventCallback; //Findet heraus ob eine Callback-Funktion zum angegebenen Control existiert und liefert den Pointer auf die Callback-Funktion zurück var tmpid:integer; begin if (ControlsAliases<>nil) and (ctrlsEventCallbackFunc<>nil) then begin tmpid:=ControlsAliases.IndexOf(_ctrlname); Sucht die Id in der Callback-Pointer-Liste heraus (anhand des Control-Namens) if tmpid>-1 then Result:=ctrlsEventCallbackFunc[tmpid]; end else Result:=nil; end; procedure TVCLAdaptEventHandler.CloseEventHandler(_sender:TObject;var _action:TCloseAction); var tmpCallbFunc:pStandardEventCallback; //Diese Funktion springt bei Bedarf in die Callback-Funktion im C-Programm begin tmpCallbFunc:=GetEventCallbFuncFromLists(PChar(TControl(_sender).Name)); //s.o. if tmpCallbFunc<>nil then //Wenn Callback-Funktion gefunden tmpCallbFunc^(PChar(TControl(_sender).Name),VCLA_CLOSE,PChar(nil)); //Aufruf der Callback-Funktion im C-Programm, ich glaube HIER kommt es zum Fehler! end; //...
Code:
So, das ganze ist ein bissle kompliziert, ich hoffe aber das einer von euch vielleicht das Problem findet.
//C++ Code
//Hauptprogramm (Win32) //Folgendes steht in einer Header //... #define VCLA_CLOSE 0xaa; #define VCLA_CLICK 0xab; #define VCLA_DBLCLICK 0xac; #define VCLA_CHANGE 0xad; typedef int (__stdcall *VCLADAPTSetCallback)(char*,void*); //Die SetCallback Methode in der Dll VCLA_SetCallback = (VCLADAPTSetCallback)GetProcAddress(h_VCLA_DLL,"SetCallback"); //Nachdem die Dll geladen wurde wird die SetCallback-Methode ebenfalls geladen (ist nicht NULL !!) //... //In Haupt-Cpp-Datei void __stdcall CALLBACK AppCall(char* _ctrlname,int _action,char* _val) //Dies ist so eine Callback-Funktion die aus der Dll heraus aufgerufen werden sollte { //... PostQuitMessage(0); } int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow) { MSG wmsg; //... VCLA_SetCallback(test,AppCall); while(GetMessage(&wmsg,NULL,0,0)) { TranslateMessage(&wmsg); DispatchMessage(&wmsg); } return wmsg.wParam; //return 0; } //ENDE Wäre jedenfalls echt toll ! Vielen Dank im Vorraus, Thomas |
Re: Funktionspointerübergabe eines C-Programmes an Delphi-DL
Ich rate jetzt mal ins Blaue, da ich mein Delphi nicht mehr offen habe: "StandardEventCallback" ist selbst schon ein Funktionszeiger, "pStandardEventCallback" wäre ein Zeiger auf einen solchen Zeiger. Von C aus übergibst du aber einen einfachen Zeiger. Mit "tmpCallbFunc^" rufst du daher nicht die Prozedur auf sondern versuchst von der Prozeduradresse selbst einen Prozedurzeiger zu lesen.
Benutze also "StandardEventCallback" statt "pStandardEventCallback" und ändere dann an den Stellen mit Compilerfehlern den Zugriff von "x <> nil" auf "Assigned(x)" oder "@x <> nil". |
Re: Funktionspointerübergabe eines C-Programmes an Delphi-DL
Hi,
ich glaube du könntest Recht haben (hab schon irgendwo mal so etwas gesehen) aber entweder der Fehler liegt woanders oder ich krieg das nicht hin. Hier die geänderten Funktionen:
Delphi-Quellcode:
Ich bin mir nicht sicher ob ich alles richtig umgeändert habe, vor allem bei der Funktion "GetEventCallbFuncFromLists".
function SetCallback(_ctrlname:PChar;var _callbfunc:StandardEventCallback):integer; stdcall; export;
var tmpid:integer; begin Result:=0; if (ControlsAliases<>nil) and (ctrlsEventCallbackFunc<>nil) then begin tmpid:=ctrlsEventCallbackFunc.Add(@_callbfunc); ControlsAliases.Add(_ctrlname); end else Result:=-1; end; function GetEventCallbFuncFromLists(_ctrlname:PChar):StandardEventCallback; var tmpid:integer; begin if (ControlsAliases<>nil) and (ctrlsEventCallbackFunc<>nil) then begin tmpid:=ControlsAliases.IndexOf(_ctrlname); if tmpid>-1 then Result:=ctrlsEventCallbackFunc[tmpid]; end else Result:=nil; end; procedure TVCLAdaptEventHandler.CloseEventHandler(_sender:TObject;var _action:TCloseAction); var tmpCallbFunc:StandardEventCallback; begin tmpCallbFunc:=GetEventCallbFuncFromLists(PChar(TControl(_sender).Name)); if Assigned(tmpCallbFunc) then tmpCallbFunc(PChar(TControl(_sender).Name),VCLA_CLOSE,PChar(nil)); end; Muss ich im C-Programm auch etwas ändern ? Vielen Dank erstmal für deine Hilfe ! Mit freundlichen Grüßen, Thomas |
Re: Funktionspointerübergabe eines C-Programmes an Delphi-DL
So, das Problem wurde inzwischen gelöst, war eine ganz gemeiner Logikfehler irgendwo anders.
However, wie so oft entstand inzwischen ein neues Problem, bei dem ich nicht weiter weiss: ![]() Danke an alle fleissigen Helferlein (@Flocke) ! |
Alle Zeitangaben in WEZ +1. Es ist jetzt 10:24 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 by Thomas Breitkreuz