Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Programmieren allgemein (https://www.delphipraxis.net/40-programmieren-allgemein/)
-   -   Funktionspointerübergabe eines C-Programmes an Delphi-DLL (https://www.delphipraxis.net/64982-funktionspointeruebergabe-eines-c-programmes-delphi-dll.html)

Thomas233 10. Mär 2006 16:56


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:
//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
So, das ganze ist ein bissle kompliziert, ich hoffe aber das einer von euch vielleicht das Problem findet.

Wäre jedenfalls echt toll !

Vielen Dank im Vorraus,
Thomas

Flocke 10. Mär 2006 21:56

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".

Thomas233 11. Mär 2006 12:28

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:
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;
Ich bin mir nicht sicher ob ich alles richtig umgeändert habe, vor allem bei der Funktion "GetEventCallbFuncFromLists".

Muss ich im C-Programm auch etwas ändern ?

Vielen Dank erstmal für deine Hilfe !

Mit freundlichen Grüßen,
Thomas

Thomas233 29. Mär 2006 22:05

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:
http://www.delphipraxis.net/internal...ct.php?t=79372

Danke an alle fleissigen Helferlein (@Flocke) !


Alle Zeitangaben in WEZ +1. Es ist jetzt 02:57 Uhr.

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz