调用方式是C++中使用纯虚函数,在Delphi中也就是纯虚类,他们有着相同的布局的虚方法表。每个Delphi的类都有一张VMT表,VMT中包含了一些基础信息、一些获得运行时信息的方法以及虚方法指针。因为布局相同,所以可以互相调用。
但是C++的类还是C++的类,Delphi类都继承于TObject,而C++没有这个概念。所以,获得了C++的类,不能去尝试调用TObject的方法。一般情况下都是将一些功能型模块封装出接口,导出给Delphi用。
将C++的类封装成DLL,并导出一个新建对象接口,Delphi层加载DLL后,调用该接口去创建C++类的对象,这样在Delphi层就可以直接使用这个对象。
Delphi XE8
Visual studio 2017
如下代码所示:
struct TEntityNode
{
...
void* key; //指向一块内存块
int lenKey; //这块内存块的size
...
};
demo是在以前的代码上修改的
//Interface.h
#pragma once
#ifndef INTERFACE_H
#define INTERFACE_H
#include "stdafx.h"
#define API_EXPORT __declspec(dllexport)
#pragma pack(push, 1)
struct TEntityNode
{
TEntityNode* xPrev;
TEntityNode* xNext;
TEntityNode* yPrev;
TEntityNode* yNext;
void* key;
int lenKey;
int x;
int y;
};
#pragma pack(pop)
#pragma pack(push, 1)
struct TAddNode
{
void* key;
int lenKey;
int x;
int y;
};
#pragma pack(pop)
//注意统一调用约定
typedef void (__stdcall *Fun_Print)(TEntityNode*);
struct TCallBackFuncRcd
{
Fun_Print print;
};
class TScene {
public:
virtual bool __stdcall Init() = 0;
virtual void __stdcall Free() = 0;
virtual void __stdcall registerCallBack(TCallBackFuncRcd rcd) = 0;
virtual TEntityNode* __stdcall Add(TAddNode* node) = 0;
virtual TEntityNode* __stdcall Get(void* key, int lenKey) = 0;
virtual bool __stdcall Leave(void* key, int lenKey) = 0;
virtual TEntityNode* __stdcall Move(void* key, int lenKey, int x, int y) = 0;
virtual void __stdcall PrintAll(bool isPrintX) = 0;
virtual void __stdcall PrintAOI(TEntityNode* node, int xArea, int yArea) = 0;
};
extern "C" API_EXPORT TScene* __stdcall NewScene();
#endif
extern "C" API_EXPORT TScene* __stdcall NewScene();
//Handler.h
class TSceneHandler : public TScene {
public:
virtual bool __stdcall Init();
virtual void __stdcall Free();
virtual void __stdcall registerCallBack(TCallBackFuncRcd rcd);
virtual TEntityNode* __stdcall Add(TAddNode* node);
virtual TEntityNode* __stdcall Get(void* key, int lenKey);
virtual bool __stdcall Leave(void* key, int lenKey);
virtual TEntityNode* __stdcall Move(void* key, int lenKey, int x, int y);
virtual void __stdcall PrintAll(bool isPrintX);
virtual void __stdcall PrintAOI(TEntityNode* node, int xArea, int yArea);
private:
void _add(TEntityNode* node);
private:
TEntityNode * head;
TEntityNode * tail;
Fun_Print fPrint;
};
typedef void (*Fun_Print)(TEntityNode*);
struct TCallBackFuncRcd
{
Fun_Print print;
};
void TSceneHandler::registerCallBack(TCallBackFuncRcd rcd)
{
fPrint = rcd.print;
}
这里我注册的是一个打印函数。
//Handler.cpp
TEntityNode* TSceneHandler::Add(TAddNode * node)
{
//这里将内容拷贝过来,以防在Delphi层被释放,进而引发内存访问异常的问题
TEntityNode* retNode = new TEntityNode();
retNode->lenKey = node->lenKey;
retNode->key = new char(node->lenKey);
memcpy(retNode->key, node->key, node->lenKey);
retNode->x = node->x;
retNode->y = node->y;
_add(retNode);
return retNode;
}
//Interface.cpp
#include "stdafx.h"
#include "Interface.h"
#include "handler.h"
API_EXPORT TScene* __stdcall NewScene() {
return new TSceneHandler();
}
直接返回新创建的对象
纯虚类定义如下
unit dll;
interface
type
PEntityNode = ^TEntityNode;
TEntityNode = packed record
xPrev : PEntityNode;
xNext : PEntityNode;
yPrev : PEntityNode;
yNext : PEntityNode;
Key : Pointer;
lenKey : Integer;
X : Integer;
Y : Integer;
end;
PAddNode = ^TAddNode;
TAddNode = packed record
Key : Pointer;
lenKey : Integer;
X : Integer;
Y : Integer;
end;
TCallBackFuncRcd = record
print: Pointer;
end;
type
TScene = class
public
function Init: Boolean; virtual; stdcall; abstract;
procedure Free; virtual; stdcall; abstract;
procedure registerCallBack(rcd: TCallBackFuncRcd);virtual; stdcall; abstract;
function Add(const node: PAddNode): PEntityNode; virtual; stdcall; abstract;
function Get(const key: Pointer; const lenKey: Integer): PEntityNode; virtual; stdcall; abstract;
function Leave(const key: Pointer; const lenKey: Integer): Boolean; virtual; stdcall; abstract;
function Move(const key: Pointer; const lenKey: Integer; const x, y: Integer): PEntityNode; virtual; stdcall; abstract;
procedure PrintAll(const isPrintX: Boolean);virtual; stdcall; abstract;
procedure PrintAOI(const node: PEntityNode; xArea, yArea: Integer); virtual; stdcall; abstract;
end;
implementation
end.
function NewScene(): TScene; __stdcall external 'Scene.dll';
调用NewScene方法就可以获得对象了
procedure TForm2.print(pNode: PEntityNode);
var
lvKey: string;
begin
if not Assigned(pNode) then
begin
mmo1.Lines.Add('Print-->节点不存在');
Exit;
end;
//这里除以了2是因为一个char占用两个字节
//且,内存长度的计算是用的ByteLength()方法,而不是Length()方法
SetString(lvKey, PChar(pNode.Key), pNode.lenKey div 2);
mmo1.Lines.Add(Format('%s - (%d, %d)', [lvKey, pNode.x, pNode.y]));
end;
procedure TForm2.FormCreate(Sender: TObject);
var
rcd: TCallBackFuncRcd;
begin
FScene := NewScene;
if not FScene.Init then
begin
mmo1.Lines.Add('初始化失败');
Exit;
end;
rcd.print := @GPrint;
FScene.registerCallBack(rcd);
end;
procedure TForm2.FormDestroy(Sender: TObject);
begin
FScene.Free;
end;
function TForm2.AddNode(const Key: string; const X, Y: Integer): PEntityNode;
var
addNode: PAddNode;
begin
New(addNode);
addNode.Key := PChar(Key);
//注意使用ByteLength(),Length()函数会少算一半长度
addNode.lenKey := ByteLength(Key);
addNode.X := X;
addNode.Y := Y;
Result := FScene.Add(addNode);
//C++层做了拷贝操作
Dispose(addNode);
end;
全部代码,我放在了我的资源里,欢迎下载
//download.csdn.net/download/I_can_/12007246
如有不足,请多指教