2016-10-06 10 views
1

delphiからopenVR dllを使用しようとしています。 しかし、このDLLは限られた機能を輸出しているだけで、多くの機能はインターフェースの中にとどまっています。ポインタのみでdll関数を呼び出す

openVRを使用するためのサンプルがあるので、c version headerc# version headerを見てください。

私はC#ヘッダーでは、関数テーブルを格納するためにsome struct(デルファイのインターフェイスのような)を使用しており、an class(デルファイの実装クラスのような)その構造体、クラス内には、作成機能があります。魔法使いは、これらすべての関数へのポインタをハックするようです。

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つです。

だから私の問題は、次のとおりです。

(1)C#は何をするかのような何かをしたデルファイことができますか?私はdllでdllを扱っていましたが、2つの方法(静的と動的)では関数名が必要です。

function someFunction(a : integer) :integer; stdcall; external ’someDll.dll’; 

dllHandle := LoadLibrary(’someDll.dll’); 
@someFunction := GetProcAddress(dllHandle,'someFunction'); 

(2)cヘッダーはどのようにライブラリの読み込みを行ったのですか?そこに関連するコードは見つかりませんでした。

+3

1つの事:C#とDLLの間で整理されなければならないことがあるため、素敵なプレーンなCヘッダーよりも翻訳するのが少し難しいです。 CとDelphiはお互いをよく理解しています。だから、C#のデモを使うのではなく、Cのデモを試してみてください。もちろん、それはおそらくポインタを使用します。 –

+3

C#のマーシャリングをコピーするのは便利ではありません。あなたは理解を得る必要があります。ショートカットはありません。 –

+1

OpenVR APIは、C++抽象クラスに基づく非COMインターフェイスを使用しています。 Delphiは消費するC++クラスをサポートしていないため、インタフェースサポートに異なるモデルを使用しています。 C#コードは、C++クラスのメモリレイアウトに合わせてシミュレートされたvtableポインタを含むプレーンな構造体を整列化することで、この問題を回避します。 Cユーザーは、C++ベースのCOMインターフェイスを使用する場合にも同じことを行う必要があります。 Delphiでも同様のことを行う必要があります。そのため、Cコードの代わりにC#コードを変換すると、この状況ではより意味があります。 –

答えて

1

レミーのアドバイスのおかげで、私はそれを解決する方法を考え出しました。

私はC#ヘッダをdelphiに変換していますが、今は正常に動作します。

例としてVRSystemを使用します。

まず、いくつかの基本的なenum、const、struct translateが必要です。

enumサイズがCスタイルのenumに一致するようにZ4タグが必要です。

{$Z4} 
ETrackingResult = (
    ETrackingResult_Uninitialized = 1, 
    ETrackingResult_Calibrating_InProgress = 100, 
    ETrackingResult_Calibrating_OutOfRange = 101, 
    ETrackingResult_Running_OK = 200, 
    ETrackingResult_Running_OutOfRange = 201 
); 

の構造体には、完全に一致するレコードです。

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; 

を必要とし、最終的にクラスが構造体を保持し、ANを与えることによって、この構造体を初期化しますそれへのポインタ。

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; 

ので、今私たちが直接ちなみにFNTable

内部の機能を指してCVRSystem内部関数を呼び出すことで、これらの機能を使用することができ、我々は関数テーブルとして構造体を使用し、私は疑問があるかどう仮想メソッドテーブルをハックするのは難しい方法です。

関連する問題