我正在尝试使用delphi中的openVR dll。 但是,这个dll只输出了有限的功能,很多功能都停留在接口内。
因为有一些使用openVR的示例,所以我看看c version header和c# version header来看看他们是如何做到的。
我从c标题中得不到充分的知识,而在c#标题中,我注意到他们正在使用some struct(如delphi中的界面)来存储函数表,并且an class(就像delphi中的实现类一样,对于那个结构,在类中有一个创建函数,它似乎是黑客指向所有这些函数的指针。
IVRSystem FnTable;
internal CVRSystem(IntPtr pInterface)
{
FnTable = (IVRSystem)Marshal.PtrToStructure(pInterface, typeof(IVRSystem));
}
pInterface
指针在一个包含一组实现类的大类中给出。
public CVRSystem VRSystem()
{
CheckClear();
if (m_pVRSystem == null)
{
var eError = EVRInitError.None;
var pInterface = OpenVRInterop.GetGenericInterface(FnTable_Prefix+IVRSystem_Version, ref eError);
if (pInterface != IntPtr.Zero && eError == EVRInitError.None)
m_pVRSystem = new CVRSystem(pInterface);
}
return m_pVRSystem;
}
其中OpenVRInterop.GetGenericInterface
是dll导出的函数之一。
所以我的问题是:
(1)delphi可以像C#那样做吗?看起来他只是通过原始指针调用这些函数(地址?偏移?)我搜索了delphi处理dll,只有两种方式(静态和动态)都需要函数名称。
function someFunction(a : integer) :integer; stdcall; external ’someDll.dll’;
dllHandle := LoadLibrary(’someDll.dll’);
@someFunction := GetProcAddress(dllHandle,'someFunction');
(2)c头如何加载库?我没有在那里找到相关的代码。
答案 0 :(得分:1)
感谢Remy的建议,我想我已经找到了解决方案。
我将C#标题翻译成delphi,现在工作正常。
我将以VRSystem为例。
首先,我们需要一些基本的枚举,const,struct translate。
枚举确实需要一个Z4标签来使大小与c样式枚举匹配。
{$Z4}
ETrackingResult = (
ETrackingResult_Uninitialized = 1,
ETrackingResult_Calibrating_InProgress = 100,
ETrackingResult_Calibrating_OutOfRange = 101,
ETrackingResult_Running_OK = 200,
ETrackingResult_Running_OutOfRange = 201
);
对于struct,记录是完美的匹配。
TrackedDevicePose_t = record
mDeviceToAbsoluteTracking : HmdMatrix34_t;
vVelocity : HmdVector3_t;
vAngularVelocity : HmdVector3_t;
eTrackingResult : ETrackingResult;
bPoseIsValid : boolean;
bDeviceIsConnected : boolean;
end;
然后我们需要为接口内部的每个函数解析委托函数,如下所示。
_GetRecommendedRenderTargetSize = procedure(var pnWidth : uint32; var pnHeight : uint32); stdcall;
_GetProjectionMatrix = function(eEye : EVREye; fNearZ : single; fFarZ : single; eProjType : EGraphicsAPIConvention) : HmdMatrix44_t; stdcall;
...
_AcknowledgeQuit_UserPrompt = procedure(); stdcall;
和一个结构来保存它们,但这次我们需要一个完美的大小匹配,所以我们需要打包记录
PIVRSystem = ^IVRSystem;
IVRSystem = packed record
GetRecommendedRenderTargetSize : _GetRecommendedRenderTargetSize;
GetProjectionMatrix : _GetProjectionMatrix;
....
AcknowledgeQuit_UserPrompt : _AcknowledgeQuit_UserPrompt;
end;
最后一个类保存结构,并通过给它指向它来初始化这个结构。
CVRSystem = class
FnTable : PIVRSystem;
Constructor Create(FNPointer : IntPtr);
procedure GetRecommendedRenderTargetSize(var pnWidth : uint32; var pnHeight : uint32);
function GetProjectionMatrix(eEye : EVREye; fNearZ : single; fFarZ : single; eProjType : EGraphicsAPIConvention) : HmdMatrix44_t;
...
procedure AcknowledgeQuit_UserPrompt();
end;
现在我们可以通过调用CVRSystem
中的函数来使用这些函数,该函数直接指向FNTable
通过这种方式,我们使用struct作为函数表,我想知道是否会有一个更棘手的方法来破解虚方法表。