D3D9创建设备,在Alt选项卡后获得vtable黑屏



所以我想在游戏中钩住directx 9。游戏有3种模式:全屏,无边框窗口,窗口模式。我使用虚拟设备方法来获取 vtable,然后用 minhook 钩住结局。在无边框窗口模式下一切正常,但是,在全屏模式下,当我从游戏中 alt 选项卡然后再次打开它时,我唯一看到的是黑屏。有时它只是屏幕左上角的一个黑色小矩形,有时整个屏幕都是黑色的。即使没有钩子也会发生这种情况。只是创建一个虚拟设备而没有实际挂钩任何东西,然后 alt 跳出然后返回将我的屏幕染成黑色。当然,我可以在无边框窗口模式下运行游戏,但这将是轻微的 FPS 损失,我宁愿避免。那么,我需要做些什么来避免alt标签上的黑屏?忘了提:如果我使用 ctrl+alt+delete 而不是 alt+tabbing,那么当我再次打开游戏时一切都很好。因此,作为最后的手段,我可以养成使用 ctrl+alt+del 而不是 alt+tab 的习惯,但这会很奇怪,不是吗? 以下是我创建设备并复制 vtable 的方法:

WNDCLASSEX wCl;
wCl.cbSize = sizeof(WNDCLASSEX);
wCl.style = CS_HREDRAW | CS_VREDRAW;
wCl.lpfnWndProc = DefWindowProc;
wCl.cbClsExtra = 0;
wCl.cbWndExtra = 0;
wCl.hInstance = GetModuleHandle(NULL);
wCl.hIcon = NULL;
wCl.hCursor = NULL;
wCl.hbrBackground = NULL;
wCl.lpszMenuName = NULL;
wCl.lpszClassName = L"whatever";
wCl.hIconSm = NULL;
::RegisterClassEx(&wCl);
HWND window = ::CreateWindow(wCl.lpszClassName, L"shit", WS_OVERLAPPEDWINDOW, 0, 0, 100, 100, NULL, NULL, wCl.hInstance, NULL);
HMODULE d3dll;
if ((d3dll = ::GetModuleHandle(L"d3d9.dll")) == NULL)
{
::DestroyWindow(window);
::UnregisterClass(wCl.lpszClassName, wCl.hInstance);
}
void* Direct3DCreate9;
if ((Direct3DCreate9 = ::GetProcAddress(d3dll, "Direct3DCreate9")) == NULL)
{
::DestroyWindow(window);
::UnregisterClass(wCl.lpszClassName, wCl.hInstance);
}
LPDIRECT3D9 direct3D9;
if ((direct3D9 = ((LPDIRECT3D9(__stdcall*)(uint32_t))(Direct3DCreate9))(D3D_SDK_VERSION)) == NULL)
{
::DestroyWindow(window);
::UnregisterClass(wCl.lpszClassName, wCl.hInstance);
}
D3DDISPLAYMODE displayMode;
if (direct3D9->GetAdapterDisplayMode(D3DADAPTER_DEFAULT, &displayMode) < 0)
{
::DestroyWindow(window);
::UnregisterClass(wCl.lpszClassName, wCl.hInstance);
}
pp.BackBufferWidth = 0;
pp.BackBufferHeight = 0;
pp.BackBufferFormat = displayMode.Format;
pp.BackBufferCount = 0;
pp.MultiSampleType = D3DMULTISAMPLE_NONE;
pp.MultiSampleQuality = NULL;
pp.SwapEffect = D3DSWAPEFFECT_DISCARD;
pp.hDeviceWindow = window;
pp.Windowed = 1;
pp.EnableAutoDepthStencil = 0;
pp.AutoDepthStencilFormat = D3DFMT_UNKNOWN;
pp.Flags = NULL;
pp.FullScreen_RefreshRateInHz = 0;
pp.PresentationInterval = 0;
LPDIRECT3DDEVICE9 device;
if (direct3D9->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL,
window, D3DCREATE_SOFTWARE_VERTEXPROCESSING | D3DCREATE_DISABLE_DRIVER_MANAGEMENT, &pp, &device) < 0) // I think this is the culprit.
{
direct3D9->Release();
::DestroyWindow(window);
::UnregisterClass(wCl.lpszClassName, wCl.hInstance);
}
vmt = (uint64_t*)::calloc(119, sizeof(uint64_t));
::memcpy(vmt, *(uint64_t * *)device, 119 * sizeof(uint64_t));
direct3D9->Release();
direct3D9 = NULL;
device->Release();
device = NULL;
::DestroyWindow(window);
::UnregisterClass(wCl.lpszClassName, wCl.hInstance);

那么,我该如何解决这个问题呢?我是否可能以错误的方式创建设备?

你不需要使用 GetProcAddress(( 你可以直接调用 d3d9 函数,它们将被正确解析。

CreateWindow(( 是不必要的,只需使用 EnumWindows 获取实际的游戏窗口,然后将该句柄传递给 CreateDevice。

D3DCREATE_DISABLE_DRIVER_MANAGEMENT是不必要的。

您应该通过检查它是否等于S_OK来检查创建设备的返回。

这是许多人毫无问题地使用的一些代码,我希望它能解决您的问题。

BOOL CALLBACK EnumWindowsCallback(HWND handle, LPARAM lParam)
{
DWORD wndProcId;
GetWindowThreadProcessId(handle, &wndProcId);
if (GetCurrentProcessId() != wndProcId)
return TRUE; // skip to next window
window = handle;
return FALSE; // window found abort search
}
HWND GetProcessWindow()
{
window = NULL;
EnumWindows(EnumWindowsCallback, NULL);
return window;
}
bool GetD3D9Device(void** pTable, size_t Size)
{
if (!pTable)
return false;
IDirect3D9* pD3D = Direct3DCreate9(D3D_SDK_VERSION);
if (!pD3D)
return false;
IDirect3DDevice9* pDummyDevice = NULL;
// options to create dummy device
D3DPRESENT_PARAMETERS d3dpp = {};
d3dpp.Windowed = false;
d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
d3dpp.hDeviceWindow = GetProcessWindow();
HRESULT dummyDeviceCreated = pD3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, d3dpp.hDeviceWindow, D3DCREATE_SOFTWARE_VERTEXPROCESSING, &d3dpp, &pDummyDevice);
if (dummyDeviceCreated != S_OK)
{
// may fail in windowed fullscreen mode, trying again with windowed mode
d3dpp.Windowed = !d3dpp.Windowed;
dummyDeviceCreated = pD3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, d3dpp.hDeviceWindow, D3DCREATE_SOFTWARE_VERTEXPROCESSING, &d3dpp, &pDummyDevice);
if (dummyDeviceCreated != S_OK)
{
pD3D->Release();
return false;
}
}
memcpy(pTable, *reinterpret_cast<void***>(pDummyDevice), Size);
pDummyDevice->Release();
pD3D->Release();
return true;
}

最新更新