仅使用指针调用dll函数

时间:2016-10-06 06:58:40

标签: c# delphi dll delphi-xe2 openvr

我正在尝试使用delphi中的openVR dll。 但是,这个dll只输出了有限的功能,很多功能都停留在接口内。

因为有一些使用openVR的示例,所以我看看c version headerc# 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头如何加载库?我没有在那里找到相关的代码。

1 个答案:

答案 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作为函数表,我想知道是否会有一个更棘手的方法来破解虚方法表。