2016-10-06 2 views
1

delphi에서 openVR dll을 사용하려고합니다. 그러나이 dll은 제한된 기능 만 가져 왔으며 많은 기능이 인터페이스 안에 있습니다.포인터 만있는 dll 함수를 호출하십시오.

OpenVR을 사용하기위한 샘플이 있으므로 여기서는 c version headerc# version header을 살펴 봅니다.

C# 헤더에서 함수 테이블을 저장하기 위해 some struct (델파이의 인터페이스와 유사)을 사용하고 있음을 알았으며 an class (델파이의 구현 클래스와 유사 함) 그 구조체 안에는 클래스 안에 create 함수 마녀가 있습니다.이 모든 함수에 대한 포인터를 해킹하는 것처럼 보입니다.

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) 무엇을 C# 같은 짓을 델파이 수 있습니까? 그는 그냥 원시 포인터 (주소? 오프셋?)에 의해 이러한 함수를 호출하는 것처럼 나는 델파이 거래 dll에 대한 검색, 두 가지 방법 (정적 및 동적) 모두 함수 이름이 필요합니다.

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

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

(2) 어떻게 C 헤더가 라이브러리로드를했다입니까? 거기에 관련된 코드를 찾지 못했습니다.

+3

한 가지 : C#과 DLL 사이에 내용을 정리해야하기 때문에 좋은 평범한 C 헤더보다 번역하기가 조금 더 어렵습니다. C와 Delphi는 서로를 아주 잘 이해합니다. 따라서 C# 데모 대신 C 데모를 사용해보십시오. 그리고 네, 아마 포인터를 사용할 것입니다. –

+3

C# 마샬링을 복사하는 것이 유용하지 않습니다. 당신은 이해를 얻을 필요가 있습니다. 지름길이 없습니다. –

+1

OpenVR API는 C++ 추상 클래스 기반의 비 COM 인터페이스를 사용합니다. Delphi는 C++ 클래스를 사용하는 것을 지원하지 않으며 인터페이스 지원을 위해 다른 모델을 사용합니다. C# 코드는 시뮬레이션 된 vtable 포인터가 포함 된 일반 구조체를 마샬링하여 C++ 클래스의 메모리 레이아웃과 일치시켜이 문제를 해결합니다. C 사용자는 C++ 기반 COM 인터페이스를 사용할 때도 동일한 작업을 수행해야합니다. 델파이에서도 이와 비슷한 작업을해야 할 것입니다. C 코드 대신 C# 코드를 변환하는 것이이 상황에서 더 적합합니다. –

답변

1

Remy의 조언 덕분에 나는 그 해결책을 찾았다 고 생각합니다.

저는 C# 헤더를 델파이로 변환합니다. 이제 제대로 작동합니다.

예를 들어 VRSystem을 사용하겠습니다.

먼저 기본 enum, const, struct translate가 필요합니다.

enum 크기가 C 스타일 열거 형과 일치하도록하려면 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; 

그리고 우리는이 같은 인터페이스 안에있는 내부의 모든 기능에 위임 기능을 declear해야합니다.

_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; 

그래서 지금 우리가 직접이 방법에 의해, FNTable

내부의 기능을 가리 CVRSystem 내부의 함수를 호출하여이 기능을 사용할 수 있습니다, 우리는 함수 테이블로 구조체를 사용, 궁금가됩니다 가상 메소드 테이블을 해킹하는 것이 더 까다로운 방법 일 수 있습니다.

관련 문제