У меня есть dll для управления сетью, написанная на C ++ с функциями-обертками на C, которая требует процедуры из прилагаемого приложения Delphi для отправки данных по сети.
Я передаю указатель на функцию в C ++ dll, чтобы он мог вызывать процедуру в приложении delphi.
Вот то, что я думал, что будет работать, но привел к EAV в DLL:
unit NetMgrWrapper;
interface
uses System.Classes;
type
TNetMgrSendData =
procedure ( AUID, ASize: Integer; ABuffer: Pointer ) of object;
TNetMgr = class ( TObject )
private
fNetworkManager : Pointer;
public
constructor Create ( const AOnSendData: TNetMgrSendData );
destructor Destroy; override;
end;
implementation
const
DLL_NAME = 'NetMgr.dll';
function CreateNetMgr ( APtrToSendData: Pointer ): Pointer; cdecl; external DLL_NAME;
procedure FreeNetMgr ( ANetMgr: Pointer ); cdecl; external DLL_NAME;
constructor TNetMgr.Create ( const AOnSendData: TNetMgrSendData );
begin
fNetworkManager := CreateNetMgr ( @AOnSendData );
end;
destructor TNetMgr.Destroy;
begin
FreeNetMgr ( fNetworkManager );
end;
end.
#include "cbase.h"#include "buffer.h"#include "INatMgr.h"
class NetMgr : public INetManager
{
private:
void (*ExternalSendData) (int, int, void *);
public
NetMgr ( void (*PtrToSendData) (int,int,void *) )
{
ExternalSendData = PtrToSendData;
}
virtual void SendData ( int uid, const CBuffer &payload )
{
CBuffer Packet;
Packet = payload;
Packet.ResetPtr ();
ExternalSendNATData ( uid, Packet.LengthBuffer(), Packet.Ptr() );
}
}
DLL_EXPORT NetMgr CreateNetMgr ( void(*APtrToSendData)(int,int,void *) )
{
return new NetMgr ( APtrToSendData );
}
DLL_EXPORT void FreeNetMgr ( NetMgr *pNetMgr )
{
delete pNetMgr;
}
Функция C ++ получает указатель на функцию типа
void(*APtrToSendData)(int,int,void *)
Но ваш код Delphi передает это:
procedure ( AUID, AType, ASize: Integer; ABuffer: Pointer ) of object;
Это просто не совместимо. Процедурный тип Delphi имеет дополнительный параметр, использует register
Соглашение о вызовах и является методом объекта.
Вы должны объявить TNetMgrSendData
следующее:
TNetMgrSendData = procedure(uid, len: Integer; buffer: Pointer); cdecl;
Ты усложняешь себе жизнь, когда заявляешь CreateNetMgr
получить нетипизированный указатель. Было бы намного лучше объявить это так:
function CreateNetMgr(APtrToSendData: TNetMgrSendData): Pointer; cdecl;
external DLL_NAME;
Тогда вы также можете воздержаться от использования @
оператор, когда вы звоните.
Других решений пока нет …