2011-06-27 30 views
7

OK, więc próbuję zrobić nakładkę na dodatkowe przyciski w grze Direct X.Hak D3D9 - Nakładka z Direct3D9

znalazłem C++ próbki, który zostanie nałożony dość ładnie tutaj: http://www.gamedev.net/topic/359794-c-direct3d-hooking-sample/

więc zacząłem go przekonwertować do Delphi. Z niektórymi logami widzę, że uruchamia hook na poprawnym procesie i poprawnie podpina Direct3DCreate9().

Następna strona TMyDirect3D9 została utworzona pomyślnie. Ale proces się kończy.

Moje wykształcone przypuszczenie (w oparciu o niektóre debugowanie w Ollydbg), że kiedy zwracam MyDirect3D9 z powrotem do oryginalnego procesu za pośrednictwem hooked Direct3DCreate9() i próbuje wywołać jedną z funkcji klasy (interfejs), to się nie powiedzie.

Kod następuje. Jeśli mogę podać inne informacje, które mogą mi pomóc.

główna DLL:

library LeagueUtilityBox; 

{$R *.res} 

{$DEFINE DEBUG} 

uses 
    Windows, 
    APIHijack in 'APIHijack.pas', 
    Direct3D9 in '..\DirectX 9.0\Direct3D9.pas', 
    uSharedMem in '..\Misc\uSharedMem.pas', 
    MyDirect3D9 in 'MyDirect3D9.pas', 
    MyDirect3DDevice9 in 'MyDirect3DDevice9.pas', 
    {$IFDEF DEBUG} 
    SysUtils, 
    uLog in '..\Misc\uLog.pas', 
    {$ENDIF} 
    uMisc in 'uMisc.pas'; 

var 
    SharedMem : TSharedMem; 
    D3DHook: SDLLHook; 
    hHook : DWORD; 
    MyDirect3D9 : TMyDirect3D9; 

function GetTargetProcess: String; 
const 
    KeyBase : DWORD = HKEY_CURRENT_USER; 
    KeyLocation : String = 'Software\LeagueUtilityBox'; 
var 
    RegKey : HKEY; 
    TargetProcess : Array[0..511] Of Char; 
    Count : DWORD; 
begin 
    Result := ''; 
    If RegOpenKeyEx(KeyBase, PChar(KeyLocation), 0, KEY_QUERY_VALUE, RegKey) = ERROR_SUCCESS Then 
    begin 
    Count := 512; 
    If RegQueryValueEx(RegKey, nil, nil, nil, @TargetProcess[0], @Count) = ERROR_SUCCESS Then 
     begin 
     Result := String(TargetProcess); 
    end; 
    end; 
end; 

type 
    TDirect3DCreate9 = function(SDKVersion: LongWord): Pointer; stdcall; 

function MyDirect3DCreate9(SDKVersion: LongWord): Pointer; stdcall; 
var 
    OldFunc : TDirect3DCreate9; 
    D3D : PIDirect3D9; 
begin 
    {$IFDEF DEBUG} 
    WriteToLog('C:\LeagueUtilityBox.log', 'MyDirect3DCreate9 called'); 
    {$ENDIF} 
    Result := nil; 
    OldFunc := TDirect3DCreate9(D3DHook.Functions[0].OrigFn); 
    D3D := OldFunc(SDKVersion); 
    If D3D <> nil Then 
    begin 
    {$IFDEF DEBUG} 
    WriteToLog('C:\LeagueUtilityBox.log', 'D3D created: 0x' + IntToHex(DWORD(Pointer(D3D)), 8)); 
    {$ENDIF} 
    New(MyDirect3D9); 
    MyDirect3D9 := TMyDirect3D9.Create(D3D); 
    {$IFDEF DEBUG} 
    WriteToLog('C:\LeagueUtilityBox.log', 'MyDirect3D9 Created'); 
    {$ENDIF} 
    Result := @MyDirect3D9; 
    end; 
end; 

procedure InitializeHook; 
var 
    Process : String; 
    I : Integer; 
begin 
    SetLength(Process, 512); 
    GetModuleFileName(GetModuleHandle(nil), PChar(Process), 512); 
    For I := Length(Process) DownTo 1 Do 
    begin 
    If Process[I] = '\' Then Break; 
    end; 
    Process := Copy(Process, I + 1, Length(Process)); 
    If CompareString(LOCALE_SYSTEM_DEFAULT, NORM_IGNORECASE, PChar(GetTargetProcess), -1, PChar(Process), -1) = 2 Then 
    begin 
    {$IFDEF DEBUG} 
    WriteToLog('C:\LeagueUtilityBox.log', 'Found target: ' + GetTargetProcess); 
    {$ENDIF} 
    With D3DHook Do 
     begin 
     Name := 'D3D9.DLL'; 
     UseDefault := False; 
     DefaultFn := nil; 
     SetLength(Functions, 1); 
     Functions[0].Name := 'Direct3DCreate9'; 
     Functions[0].HookFn := @MyDirect3DCreate9; 
     Functions[0].OrigFn := nil; 
    end; 
    {$IFDEF DEBUG} 
    WriteToLog('C:\LeagueUtilityBox.log', 'About to hook: ' + String(AnsiString(D3DHook.Name))); 
    {$ENDIF} 
    HookAPICalls(@D3DHook); 
    {$IFDEF DEBUG} 
    WriteToLog('C:\LeagueUtilityBox.log', 'Hook completed: ' + String(AnsiString(D3DHook.Name))); 
    {$ENDIF} 
    end; 
end; 

procedure InitializeDLL; 
begin 
    SharedMem := TSharedMem.Create('LeagueUtilityBox', 1024); 
    Try 
    hHook := PDWORD(SharedMem.Buffer)^; 
    {$IFDEF DEBUG} 
    WriteToLog('C:\LeagueUtilityBox.log', 'Initializing DLL: ' + IntToStr(hHook)); 
    {$ENDIF} 
    Finally 
    SharedMem.Free; 
    end; 
end; 

procedure UninitializeDLL; 
begin 
    UnhookWindowsHookEx(hHook); 
end; 

function WindowsHookCallback(nCode: Integer; WPARAM: Integer; LPARAM: Integer): LRESULT; stdcall; 
begin 
    Result := CallNextHookEx(hHook, nCode, WPARAM, LPARAM); 
end; 

procedure EntryPoint(Reason: DWORD); 
begin 
    Case Reason Of 
    DLL_PROCESS_ATTACH: 
     begin 
     InitializeDLL; 
     InitializeHook; 
    end; 
    DLL_PROCESS_DETACH: 
     begin 
     UninitializeDLL; 
    end; 
    end; 
end; 

exports 
    WindowsHookCallback; 

begin 
    DLLProc := @EntryPoint; 
    EntryPoint(DLL_PROCESS_ATTACH); 
end. 

Zwyczaj IDirect3D9:

unit MyDirect3D9; 

interface 

uses Direct3D9, Windows, uMisc, uLog; 

type 
    PMyDirect3D9 = ^TMyDirect3D9; 
    TMyDirect3D9 = class(TInterfacedObject, IDirect3D9) 
    private 
    fD3D: PIDirect3D9; 
    public 
    constructor Create(D3D: PIDirect3D9); 

    function QueryInterface(riid: REFIID; ppvObj: PPointer): HRESULT; stdcall; 
    function _AddRef: DWORD; stdcall; 
    function _Release: DWORD; stdcall; 

    function RegisterSoftwareDevice(pInitializeFunction: Pointer): HResult; stdcall; 
    function GetAdapterCount: LongWord; stdcall; 
    function GetAdapterIdentifier(Adapter: LongWord; Flags: DWord; out pIdentifier: TD3DAdapterIdentifier9): HResult; stdcall; 
    function GetAdapterModeCount(Adapter: LongWord; Format: TD3DFormat): LongWord; stdcall; 
    function EnumAdapterModes(Adapter: LongWord; Format: TD3DFormat; Mode: LongWord; out pMode: TD3DDisplayMode): HResult; stdcall; 
    function GetAdapterDisplayMode(Adapter: LongWord; out pMode: TD3DDisplayMode): HResult; stdcall; 
    function CheckDeviceType(Adapter: LongWord; CheckType: TD3DDevType; AdapterFormat, BackBufferFormat: TD3DFormat; Windowed: BOOL): HResult; stdcall; 
    function CheckDeviceFormat(Adapter: LongWord; DeviceType: TD3DDevType; AdapterFormat: TD3DFormat; Usage: DWord; RType: TD3DResourceType; CheckFormat: TD3DFormat): HResult; stdcall; 
    function CheckDeviceMultiSampleType(Adapter: LongWord; DeviceType: TD3DDevType; SurfaceFormat: TD3DFormat; Windowed: BOOL; MultiSampleType: TD3DMultiSampleType; pQualityLevels: PDWORD): HResult; stdcall; 
    function CheckDepthStencilMatch(Adapter: LongWord; DeviceType: TD3DDevType; AdapterFormat, RenderTargetFormat, DepthStencilFormat: TD3DFormat): HResult; stdcall; 
    function CheckDeviceFormatConversion(Adapter: LongWord; DeviceType: TD3DDevType; SourceFormat, TargetFormat: TD3DFormat): HResult; stdcall; 
    function GetDeviceCaps(Adapter: LongWord; DeviceType: TD3DDevType; out pCaps: TD3DCaps9): HResult; stdcall; 
    function GetAdapterMonitor(Adapter: LongWord): HMONITOR; stdcall; 
    function CreateDevice(Adapter: LongWord; DeviceType: TD3DDevType; hFocusWindow: HWND; BehaviorFlags: DWord; pPresentationParameters: PD3DPresentParameters; out ppReturnedDeviceInterface: IDirect3DDevice9): HResult; stdcall; 
    end; 

implementation 

uses MyDirect3DDevice9; 

constructor TMyDirect3D9.Create(D3D: PIDirect3D9); 
begin 
    {$IFDEF DEBUG} 
    WriteToLog('C:\LeagueUtilityBox.log', 'TMyDirect3D9.Create'); 
    {$ENDIF} 
    fD3D := D3D; 
end; 

function TMyDirect3D9.QueryInterface(riid: REFIID; ppvObj: PPointer): HRESULT; stdcall; 
begin 
    {$IFDEF DEBUG} 
    WriteToLog('C:\LeagueUtilityBox.log', 'TMyDirect3D9.QueryInterface'); 
    {$ENDIF} 
    Result := fD3D^.QueryInterface(riid, ppvObj); 
end; 

function TMyDirect3D9._AddRef: DWORD; stdcall; 
begin 
    {$IFDEF DEBUG} 
    WriteToLog('C:\LeagueUtilityBox.log', 'TMyDirect3D9._AddRef'); 
    {$ENDIF} 
    Result := fD3D^._AddRef; 
end; 

function TMyDirect3D9._Release: DWORD; stdcall; 
var 
    count : DWORD; 
begin 
    {$IFDEF DEBUG} 
    WriteToLog('C:\LeagueUtilityBox.log', 'TMyDirect3D9._Release'); 
    {$ENDIF} 
    count := fD3D^._Release; 
    If count = 0 Then 
    begin 
    Self.Free; 
    end; 
    Result := count; 
end; 

function TMyDirect3D9.RegisterSoftwareDevice(pInitializeFunction: Pointer): HResult; stdcall; 
begin 
    {$IFDEF DEBUG} 
    WriteToLog('C:\LeagueUtilityBox.log', 'TMyDirect3D9.RegisterSoftwareDevice'); 
    {$ENDIF} 
    Result := fD3D^.RegisterSoftwareDevice(pInitializeFunction); 
end; 

function TMyDirect3D9.GetAdapterCount: LongWord; stdcall; 
begin 
    {$IFDEF DEBUG} 
    WriteToLog('C:\LeagueUtilityBox.log', 'TMyDirect3D9.GetAdapterCount'); 
    {$ENDIF} 
    Result := fD3D^.GetAdapterCount; 
end; 

function TMyDirect3D9.GetAdapterIdentifier(Adapter: LongWord; Flags: DWord; out pIdentifier: TD3DAdapterIdentifier9): HResult; stdcall; 
begin 
    {$IFDEF DEBUG} 
    WriteToLog('C:\LeagueUtilityBox.log', 'TMyDirect3D9.GetAdapterIdentifier'); 
    {$ENDIF} 
    Result := fD3D^.GetAdapterIdentifier(Adapter, Flags, pIdentifier); 
end; 

function TMyDirect3D9.GetAdapterModeCount(Adapter: LongWord; Format: TD3DFormat): LongWord; stdcall; 
begin 
    {$IFDEF DEBUG} 
    WriteToLog('C:\LeagueUtilityBox.log', 'TMyDirect3D9.GetAdapterModeCount'); 
    {$ENDIF} 
    Result := fD3D^.GetAdapterModeCount(Adapter, Format); 
end; 

function TMyDirect3D9.EnumAdapterModes(Adapter: LongWord; Format: TD3DFormat; Mode: LongWord; out pMode: TD3DDisplayMode): HResult; stdcall; 
begin 
    {$IFDEF DEBUG} 
    WriteToLog('C:\LeagueUtilityBox.log', 'TMyDirect3D9.EnumAdapterModes'); 
    {$ENDIF} 
    Result := fD3D^.EnumAdapterModes(Adapter, Format, Mode, pMode); 
end; 

function TMyDirect3D9.GetAdapterDisplayMode(Adapter: LongWord; out pMode: TD3DDisplayMode): HResult; stdcall; 
begin 
    {$IFDEF DEBUG} 
    WriteToLog('C:\LeagueUtilityBox.log', 'TMyDirect3D9.GetAdapterDisplayMode'); 
    {$ENDIF} 
    Result := fD3D^.GetAdapterDisplayMode(Adapter, pMode); 
end; 

function TMyDirect3D9.CheckDeviceType(Adapter: LongWord; CheckType: TD3DDevType; AdapterFormat, BackBufferFormat: TD3DFormat; Windowed: BOOL): HResult; stdcall; 
begin 
    {$IFDEF DEBUG} 
    WriteToLog('C:\LeagueUtilityBox.log', 'TMyDirect3D9.CheckDeviceType'); 
    {$ENDIF} 
    Result := fD3D^.CheckDeviceType(Adapter, CheckType, AdapterFormat, BackBufferFormat, Windowed); 
end; 

function TMyDirect3D9.CheckDeviceFormat(Adapter: LongWord; DeviceType: TD3DDevType; AdapterFormat: TD3DFormat; Usage: DWord; RType: TD3DResourceType; CheckFormat: TD3DFormat): HResult; stdcall; 
begin 
    {$IFDEF DEBUG} 
    WriteToLog('C:\LeagueUtilityBox.log', 'TMyDirect3D9.CheckDeviceFormat'); 
    {$ENDIF} 
    Result := fD3D^.CheckDeviceFormat(Adapter, DeviceType, AdapterFormat, Usage, RType, CheckFormat); 
end; 

function TMyDirect3D9.CheckDeviceMultiSampleType(Adapter: LongWord; DeviceType: TD3DDevType; SurfaceFormat: TD3DFormat; Windowed: BOOL; MultiSampleType: TD3DMultiSampleType; pQualityLevels: PDWORD): HResult; stdcall; 
begin 
    {$IFDEF DEBUG} 
    WriteToLog('C:\LeagueUtilityBox.log', 'TMyDirect3D9.CheckDeviceMultiSampleType'); 
    {$ENDIF} 
    Result := fD3D^.CheckDeviceMultiSampleType(Adapter, DeviceType, SurfaceFormat, Windowed, MultiSampleType, pQualityLevels); 
end; 

function TMyDirect3D9.CheckDepthStencilMatch(Adapter: LongWord; DeviceType: TD3DDevType; AdapterFormat, RenderTargetFormat, DepthStencilFormat: TD3DFormat): HResult; stdcall; 
begin 
    {$IFDEF DEBUG} 
    WriteToLog('C:\LeagueUtilityBox.log', 'TMyDirect3D9.CheckDepthStencilMatch'); 
    {$ENDIF} 
    Result := fD3D^.CheckDepthStencilMatch(Adapter, DeviceType, AdapterFormat, RenderTargetFormat, DepthStencilFormat); 
end; 

function TMyDirect3D9.CheckDeviceFormatConversion(Adapter: LongWord; DeviceType: TD3DDevType; SourceFormat, TargetFormat: TD3DFormat): HResult; stdcall; 
begin 
    {$IFDEF DEBUG} 
    WriteToLog('C:\LeagueUtilityBox.log', 'TMyDirect3D9.CheckDeviceFormatConversion'); 
    {$ENDIF} 
    Result := fD3D^.CheckDeviceFormatConversion(Adapter, DeviceType, SourceFormat, TargetFormat); 
end; 

function TMyDirect3D9.GetDeviceCaps(Adapter: LongWord; DeviceType: TD3DDevType; out pCaps: TD3DCaps9): HResult; stdcall; 
begin 
    {$IFDEF DEBUG} 
    WriteToLog('C:\LeagueUtilityBox.log', 'TMyDirect3D9.GetDeviceCaps'); 
    {$ENDIF} 
    Result := fD3D^.GetDeviceCaps(Adapter, DeviceType, pCaps); 
end; 

function TMyDirect3D9.GetAdapterMonitor(Adapter: LongWord): HMONITOR; stdcall; 
begin 
    {$IFDEF DEBUG} 
    WriteToLog('C:\LeagueUtilityBox.log', 'TMyDirect3D9.GetAdapterMonitor'); 
    {$ENDIF} 
    Result := fD3D^.GetAdapterMonitor(Adapter); 
end; 

function TMyDirect3D9.CreateDevice(Adapter: LongWord; DeviceType: TD3DDevType; hFocusWindow: HWND; BehaviorFlags: DWord; pPresentationParameters: PD3DPresentParameters; out ppReturnedDeviceInterface: IDirect3DDevice9): HResult; stdcall; 
var 
    hr : HRESULT; 
begin 
    {$IFDEF DEBUG} 
    WriteToLog('C:\LeagueUtilityBox.log', 'TMyDirect3D9.CreateDevice'); 
    {$ENDIF} 
    hr := fD3D^.CreateDevice(Adapter, DeviceType, hFocusWindow, BehaviorFlags, pPresentationParameters, ppReturnedDeviceInterface); 
    If Succeeded(hr) Then 
    begin 
    {$IFDEF DEBUG} 
    WriteToLog('C:\LeagueUtilityBox.log', 'fD3D^.CreateDevice Succeeded'); 
    {$ENDIF} 
    ppReturnedDeviceInterface := TMyDirect3DDevice9.Create(PIDirect3D9(@Self), @ppReturnedDeviceInterface); 
    end; 
    Result := hr; 
end; 

end. 

UPDATE: Tak, ponieważ interfejsy Delphi wydają się działać inaczej niż prawdziwy (Delphi posiada między aby mógł z powodzeniem rozmawiać z innymi interfejsami). Więc właśnie przekonwertowałem interfejs na tablicę wskaźników.

Teraz program pomyślnie wywołuje CreateDevice(). Widzę to zarówno w dziennikach, jak i w Ollydbgu.

Teraz dzieje się tak, że gdy CreateDevice wywoła oryginalną IDirect3D9.CreateDevice(), ponownie ulega awarii. Kiedy debuguję w Ollydbg, zauważam, że raz wyłączył on wskaźnik.

UPDATE 2: Ok, poprawiono kilka problemów Pointer z PIDirect3D9 vs IDirect3D9 w różnych miejscach. Tak więc wywoływana jest oryginalna IDirect3D9.CreateDevice(). Ale błędy z D3DERR_INVALIDCALL !!

Tak mylące.

AKTUALIZACJA 3: OK, z kilkoma debugowaniem wydaje się, że po wywołaniu funkcji dodatkowy parametr zostanie wciśnięty na stosie. Co powoduje, że pierwszy parametr jest nieważny. Zostało to udowodnione przez debugowanie DirectX, które mówi, że parametr iAdapter jest nieprawidłowy (pierwszy parametr).

UPDATE 4: Przy użyciu IntRefToMethPtr(), aby uzyskać bezpośredni odnośnik do oryginalnego połączenia CreateDevice udało mi się dostać to, aby zadzwonić z stosy samo. Ten sam wynik. Wygląda na to, że przeszedłem złą drogę, próbując podłączyć ją do Delphi.

UPDATE 5: Przepisanie metody zahaczania. Teraz zaczepiam zasadniczo EndScene(). Hook teraz działa dobrze w programie testowym (Vertices.exe, który był dołączony do wersji demonstracyjnej znajdującej się w pierwszym adresie URL w tym poście). Ale w głównej grze powoduje awarię gry. Tak czy inaczej wiele się nauczyłem.

Odpowiedz

3

Zrobiłem to już kilka razy, a szczegóły są dość obszerne, aby znaleźć odpowiedź, ale istnieje kilka typowych błędów i kilka konkretnych, nad którymi trzeba popracować.

Najpierw należy zaimplementować interfejsy IDirect3D9 i IDirect3DDevice9 (przynajmniej) dokładnie, ponieważ są one wykonywane w bibliotekach lub są kompatybilne z biblioteką binarną. Interfejsy oparte są na wirtualnych wywołaniach funkcji (nie są pewne odpowiednika Pascala), więc wszystkie metody muszą być wirtualne, metody powinny być w tej samej kolejności i przyjmować te same argumenty (które również powinny być w tej samej kolejności), itp.

Część, której bym się dokładnie przyjrzał, to jak pascal obsługuje funkcje, muszą być binarnie kompatybilne z Visual C++ - zbudowany kod (__thiscall, wirtualny, itp.).

Dodatkowo, za pomocą kilku prostych wyrażeń regularnych zwykle można wygenerować własny nagłówek i szkielet pliku kodu z istniejącego nagłówka D3D9. Zauważ, że chociaż może to zabrzmieć głupio, pełnowymiarowe opakowanie D3D9 może (tylko IDirect3DDevice9) wyjść do 2300 linii; generowanie podstaw z nagłówka wycina wiele pisania, które mogą powodować błędy.

Aby obsłużyć przyciski, należy również a) narysować na górze istniejącego renderowania i b) wprowadzić dane wejściowe.

a) jest trywialny: po prostu czekasz na device->Present() i robisz rysunek przed wywołaniem prawdziwej teraźniejszości. Jedynym prawdziwym problemem są stany urządzeń. Będziesz musiał zapisać istniejące stany, ustawić swoje stany do rysowania nakładek, a następnie zresetować stany urządzeń. Niewykonanie ich poprawnie powoduje różnego rodzaju problemy z zabawą. Stany, które wymagają ustawienia, zależą od Twojej aplikacji, ale zwykle są to: usuwanie, sortowanie/testowanie głębi i takie, które chcesz wyłączyć.

b) Przyciski do zrobienia, musisz też jakoś podłączyć się do wejścia okna. Implementacja tego samego rodzaju otoki, którą tu masz, ale dla DInput (jeśli jest używana) jest prawdopodobnie dobrym pomysłem. Następnie możesz wykonać sprawdzanie wejściowe, renderowanie i logikę w metodzie I ... Device9 Present.

Istnieje przyzwoity kod przy takich opakowaniach; Mam pełne d3d od 8 do 9 (tłumaczenie w czasie wykonywania) i 9, i wiem o 2 innych opakowaniach d3d9, które można ponownie wykorzystać. Warto się zastanowić, sprawdzić kod lub użyć istniejącego kodu.

Jeśli jest więcej informacji, które Cię interesują w związku z tym lub cokolwiek ciekawego, znajdę, chętnie pomogę/chcę wiedzieć.

+0

Kod C++, który kopiuję, działa poprawnie w grze. Skopiowałem nagłówki z bezpośredniego zestawu nagłówków x delphi. Zasadniczo kod C++ ma własną klasę opartą na IDirect3D9 'class MyDirect3D9: public IDirect3D9' I IDirect3DDevice9 w taki sam sposób. W jego konstruktorze zapisuje oryginalny IDirect3D9 wykonany z oryginalną Direct3DCreate9() i przekazuje wszystko oprócz CreateDevice(), w którym przekazuje on swój niestandardowy IDirect3DDevice9. Mój problem jest moją dokładną kopią w Delphi (według mojej wiedzy) ulega awarii podczas próby użycia IDirect3D9 *, który przekazałem z powrotem do niego. – ThievingSix

+0

Również znalazłem wiele przykładów C++, ale nie jeden działający przykład Direct3D9 w Delphi. Jeśli znasz jedną, byłoby to bardzo pożądane. – ThievingSix

+0

Nie znam żadnych przykładów Delphi, ale wiem, że awaria, którą widzisz, jest zwykle spowodowana przez nieodnalezienie lub zaimplementowanie niewłaściwej metody. Wygląda na to, że delphi ma słowo kluczowe "virtual", które może być przydatne (wszystkie metody COM w C++ są wirtualne). Dziedziczenie nie jest bezwzględnie konieczne, ale pozwala na pewne sprawdzanie błędów podczas kompilacji (aby upewnić się, że wszystkie metody są poprawnie zaimplementowane). – ssube

1

Możesz chcieć sprawdzić istniejące pakiety DirextX dla Delphi, nawet po to, aby potwierdzić (z ich przykładami), że użyte konstrukty są takie same jak używane.

Witryna znam najlepiej jest Clootie użytkownika: http://clootie.ru/delphi/index.html Ale AFAIK istnieje wiele prób

Istnieją zarówno DX9 i DX10 SDK wraz z przykładami tam.

+0

Mam, faktycznie kopiuję i wklejam nagłówki. – ThievingSix

+1

jakiekolwiek dostępne ponowne załadowanie? – Knobik