I want to modify a DirectX-Application's behavior (namely I want to implement a program similar to the Statman-Application by OrfeasZ [https://github.com/OrfeasZ/Statman/releases] as Onscreen-Info for Hitman 2) by injecting code (as DLL) into it and hooking the DirectX DeviceInterface VMT.
Since there are very limited resources on how to do this for DirectX11-Applications, I first wanted to learn how to do this in DX9 by creating a program that gets the DeviceInterface pointer of any DirectX9-Application. I wrote this code in the DllMain() function of my DLL (which is almost a 1:1 copy/paste of the third answer to this thread Hooking DirectX EndScene from an injected DLL):
HMODULE hDLL = GetModuleHandleA("d3d9");
LPDIRECT3D9(__stdcall*pDirect3DCreate9)(UINT) = (LPDIRECT3D9(__stdcall*)(UINT))GetProcAddress(hDLL, "Direct3DCreate9");
LPDIRECT3D9 pD3D = pDirect3DCreate9(D3D_SDK_VERSION);
D3DDISPLAYMODE d3ddm;
HRESULT hRes = pD3D->GetAdapterDisplayMode(D3DADAPTER_DEFAULT, &d3ddm);
D3DPRESENT_PARAMETERS d3dpp;
ZeroMemory(&d3dpp, sizeof(d3dpp));
d3dpp.Windowed = true;
d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
d3dpp.BackBufferFormat = d3ddm.Format;
//WNDPROC TempWndProc;
WNDCLASSEX wc = { sizeof(WNDCLASSEX),CS_CLASSDC, WndProc,0L,0L,GetModuleHandle(NULL),NULL,NULL,NULL,NULL,TEXT("1"),NULL };
RegisterClassEx(&wc);
HWND hWnd = CreateWindow(TEXT("1"), NULL, WS_OVERLAPPEDWINDOW, 100, 100, 300, 300, GetDesktopWindow(), NULL, wc.hInstance, NULL);
ShowWindow(hWnd, SW_SHOW);
IDirect3DDevice9 * ppReturnedDeviceInterface;
hRes = pD3D->CreateDevice(
D3DADAPTER_DEFAULT,
D3DDEVTYPE_HAL,
hWnd,
D3DCREATE_SOFTWARE_VERTEXPROCESSING,
&d3dpp, &ppReturnedDeviceInterface);
pD3D->Release();
DestroyWindow(hWnd);
if (pD3D == NULL) {
//printf ("WARNING: D3D FAILED");
return false;
}
unsigned long* pInterface = (unsigned long*)*((unsigned long*)ppReturnedDeviceInterface);
When I inject the DLL into a DirectX9-Application (I've tried this with Civilization V and Total War: Shogun 2), it opens a window, so it actually is able to get the Direct3DCreate9 function from the d3d9.dll within the game, but pD3D->CreateDevice() always returns `D3DERR_INVALIDCALL. I don't really get what could be the reason for this, especially since the rest of this program works flawlessly. Does anybody have any idea what is missing/wrong?
D3DERR_INVALIDCALL
The method call is invalid. For example, a method's parameter may not
be a valid pointer.
Based on the error information this issue may caused by invalid parameter of IDirect3D9::CreateDevice method. You need initialize the pointer:
IDirect3DDevice9 *pReturnedDeviceInterface = NULL;
Also check if hWnd is a valid window handle and d3ddm.Format etc.
I'm trying to make a window transparent so that only part of its contents are visible, I've tried using SetLayeredWindowAttributes to make this happen, this made the window transparent as I wanted, however it only works that way when part of the windows picture is outside of the visible area of my desktop. For some reason whenever the window is fully on screen it re-draws its black background (the color I use for transparency that's meant not to be seen.) Here is a video example of the problem. I'm not sure what exactly is causing this to just to be safe I'm posting the full code.
#define _WIN32_WINNT 0x501
#include "C:\Program Files\Microsoft DirectX SDK (August 2008)\Include\D3dx9core.h"
#include "C:\Documents and Settings\Death\My Documents\Downloads\DXSprite\DXSprite\resource.h"
#include <windows.h>
#include <string>
#include <stdio.h>
//-----------------------------------------------------------------------------
// GLOBALS
//-----------------------------------------------------------------------------
HWND g_hWnd = NULL;
LPDIRECT3D9 g_pD3D = NULL;
LPDIRECT3DDEVICE9 g_pD3DDevice = NULL;
ID3DXSprite * g_pD3DXSprite = NULL;
LPDIRECT3DTEXTURE9 g_pTexture = NULL;
const int SCREEN_WIDTH = 800;
const int SCREEN_HEIGHT = 600;
//-----------------------------------------------------------------------------
// PROTOTYPES
//-----------------------------------------------------------------------------
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
HRESULT InitializeD3D ( );
void RenderFrame ( );
//-----------------------------------------------------------------------------
// Name: WinMain()
// Desc: The application's entry point
//-----------------------------------------------------------------------------
int WINAPI WinMain( HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow )
{
WNDCLASSEX winClass;
MSG uMsg;
HRESULT hr;
memset(&uMsg,0,sizeof(uMsg));
winClass.lpszClassName = "MY_WINDOWS_CLASS";
winClass.cbSize = sizeof(WNDCLASSEX);
winClass.style = CS_HREDRAW | CS_VREDRAW;
winClass.lpfnWndProc = WindowProc;
winClass.hInstance = hInstance;
winClass.hIcon = LoadIcon(hInstance, (LPCTSTR)IDC_DXSPRITE);
winClass.hIconSm = LoadIcon(hInstance, (LPCTSTR)IDC_DXSPRITE);
winClass.hCursor = LoadCursor(NULL, IDC_ARROW);
winClass.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
winClass.lpszMenuName = NULL;
winClass.cbClsExtra = 0;
winClass.cbWndExtra = 0;
if( !RegisterClassEx(&winClass) )
return E_FAIL;
g_hWnd = CreateWindowEx( WS_EX_LAYERED, "MY_WINDOWS_CLASS",
"Direct3D 9 - ID3DXSprite Example",
WS_OVERLAPPEDWINDOW | WS_VISIBLE ,
0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, NULL, NULL, hInstance, NULL );
if( g_hWnd == NULL )
return E_FAIL;
SetLayeredWindowAttributes(g_hWnd, RGB(0x00,0x00,0x00), 0, LWA_COLORKEY});
ShowWindow( g_hWnd, nCmdShow );
//----------------------------------------------------------------
// Create the DirectX device
//----------------------------------------------------------------
if (FAILED( InitializeD3D()))
return 0;
//----------------------------------------------------------------
// CREATE THE ID3DXSprite
//----------------------------------------------------------------
// Create the ID3DXSprite interface object
hr = D3DXCreateSprite(g_pD3DDevice, &g_pD3DXSprite );
if( FAILED(hr) )
return hr;
//----------------------------------------------------------------
// LOAD THE TEXTURE FOR THE SPRITE
//----------------------------------------------------------------
// --------------------------------------------------------
// Load the texture. I decided to use the extended
// version of the texture loading function just to show what
// it would look like.
// The texture was created with Photoshop with a transparent
// background to start with. Then line cross hairs were added.
//
// Note - If you don't use a texture image that has a power of
// 2 size for the width or height then the image may not load
// properly. This image is 256x256.
//
D3DXCreateTextureFromFileEx(
g_pD3DDevice,
"C:\\Documents and Settings\\Death\\My Documents\\45handold2.tga", // Our texture image!
D3DX_DEFAULT, // width
D3DX_DEFAULT, // height
D3DX_DEFAULT, // MIP levels
0, // usage
D3DFMT_DXT1, // texture format
D3DPOOL_MANAGED, // mem pool
D3DX_DEFAULT, // filter
D3DX_DEFAULT, // MIP filter
0, // transparent color key
NULL, // image info struct
NULL, // palette
&g_pTexture); // the returned texture, if success
if ( FAILED(hr) )
return hr;
// ---------
// Main Loop
// ---------
while( uMsg.message != WM_QUIT )
{
if( PeekMessage( &uMsg, NULL, 0, 0, PM_REMOVE ) )
{
TranslateMessage( &uMsg );
DispatchMessage( &uMsg );
}
}
// -------------------------
// Release directx resources
// -------------------------
if (g_pD3DXSprite)
{
g_pD3DXSprite->Release();
g_pD3DXSprite = NULL;
}
if (g_pTexture)
{
g_pTexture->Release();
g_pTexture = NULL;
}
if (g_pD3DDevice)
{
g_pD3DDevice->Release();
g_pD3DDevice = NULL;
}
UnregisterClass( "MY_WINDOWS_CLASS", winClass.hInstance );
return (int)uMsg.wParam;
}
//-----------------------------------------------------------------------------
// Name: WindowProc()
// Desc: The window's message handler
//-----------------------------------------------------------------------------
LRESULT CALLBACK WindowProc( HWND hWnd,
UINT msg,
WPARAM wParam,
LPARAM lParam )
{
switch( msg )
{
case WM_KEYDOWN:
{
switch( wParam )
{
case VK_ESCAPE:
PostQuitMessage(0);
break;
}
}
break;
case WM_CLOSE:
{
PostQuitMessage(0);
}
case WM_DESTROY:
{
PostQuitMessage(0);
}
break;
default:
{
RenderFrame();
return DefWindowProc( hWnd, msg, wParam, lParam );
}
break;
}
return 0;
}
//-----------------------------------------------------------------------------
// Name: InitializeD3D()
// Desc: Create DirectX interface objects
// Initialize the view matrix.
// Setup render states that will not need changing throughout
// the life of the application.
//-----------------------------------------------------------------------------
HRESULT InitializeD3D( )
{
HRESULT hr;
// Create a direct 3D interface object
g_pD3D = Direct3DCreate9( D3D_SDK_VERSION );
if( g_pD3D == NULL )
{
// TO DO: Respond to failure of Direct3DCreate9
return E_FAIL;
}
D3DDISPLAYMODE d3ddm;
if( FAILED( hr = g_pD3D->GetAdapterDisplayMode( D3DADAPTER_DEFAULT, &d3ddm ) ) )
{
// TO DO: Respond to failure of GetAdapterDisplayMode
return hr;
}
//
if( FAILED( hr = g_pD3D->CheckDeviceFormat( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL,
d3ddm.Format, D3DUSAGE_DEPTHSTENCIL,
D3DRTYPE_SURFACE, D3DFMT_D16 ) ) )
{
if( hr == D3DERR_NOTAVAILABLE )
// POTENTIAL PROBLEM: We need at least a 16-bit z-buffer!
return hr;
}
//
// Do we support hardware vertex processing? If so, use it.
// If not, downgrade to software.
//
D3DCAPS9 d3dCaps;
if( FAILED( hr = g_pD3D->GetDeviceCaps( D3DADAPTER_DEFAULT,
D3DDEVTYPE_HAL, &d3dCaps ) ) )
{
// TO DO: Respond to failure of GetDeviceCaps
return hr;
}
DWORD dwBehaviorFlags = 0;
if( d3dCaps.VertexProcessingCaps != 0 )
dwBehaviorFlags |= D3DCREATE_HARDWARE_VERTEXPROCESSING;
else
dwBehaviorFlags |= D3DCREATE_SOFTWARE_VERTEXPROCESSING;
//
// Everything checks out - create a simple, windowed device.
//
D3DPRESENT_PARAMETERS d3dpp;
memset(&d3dpp, 0, sizeof(d3dpp));
d3dpp.BackBufferFormat = d3ddm.Format;
d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
d3dpp.Windowed = TRUE;
d3dpp.EnableAutoDepthStencil = TRUE;
d3dpp.AutoDepthStencilFormat = D3DFMT_D16;
d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;
// Attempt to create a HAL device, end app on failure just to keep things
// simple. In other words we are not trying to create a REF device if the
// HAL fails.
if( FAILED( hr = g_pD3D->CreateDevice( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, g_hWnd,
dwBehaviorFlags, &d3dpp, &g_pD3DDevice ) ) )
{
// char blah[100];
// snprintf (blah, 1000, "%d", hr);
//MessageBox (NULL,blah,NULL,NULL);
}
// If we get here everything worked!
return S_OK;
}
//-----------------------------------------------------------------------------
// Name: RenderFrame()
// Desc: Draw the image to the framebuffer.
//-----------------------------------------------------------------------------
void RenderFrame( )
{
if (!g_pD3DDevice && !g_pD3DXSprite && !g_pTexture)
return;
// Clear the frame & depth buffer ready for drawing (Black color)
g_pD3DDevice->Clear( 0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, 0x00000000, 1.0f, 0 );
g_pD3DDevice->BeginScene();
{
//-------------------------
// Render the sprite
//
D3DXVECTOR3 vecPos = D3DXVECTOR3(0,0,0);
if (g_pD3DXSprite && g_pTexture)
{
g_pD3DXSprite->Begin( D3DXSPRITE_ALPHABLEND );
g_pD3DXSprite->Draw(g_pTexture, NULL, NULL, &vecPos, 0xffffffff);
g_pD3DXSprite->End();
}
}
g_pD3DDevice->EndScene();
// Frame buffer to Front buffer
g_pD3DDevice->Present( NULL, NULL, NULL, NULL );
}
The problem you're running into is basically that there used to be two entirely separate rendering stacks in Windows: GDI and Direct3D. They didn't really talk to one another at all, so standard windowing and GDI APIs don't really know anything about Direct3D. When Vista came along they unified the two driver stacks, but the GDI code (generally speaking) still knows nothing about Direct3D, even if it internally uses some Direct3D behind the scenes (for desktop composition).
In short, SetLayeredWindowAttributes as well as UpdateLayeredWindow cannot and do not know about your Direct3D swapchain. If you had tried this back on Windows XP or 2000 I expect you would have gotten some really funky visual results. There are some really good reasons for this, I should add. For example, in the GDI world, using UpdateLayeredWindow to set a bitmap with per-pixel alpha actually results in places with an alpha value of zero being treated as not part of the window. In other words, clicks pass through to the window underneath. In order to implement this with Direct3D, the system would have to read back the Direct3D texture from GPU to CPU memory, which is quite expensive, and then perform the hit test.
One solution, of course, is to use GDI to render the window, including the color key. I'm assuming you ruled that out for performance reasons.
I'm not entirely sure of the visual results you are expecting, but if you want to render arbitrary alpha-blended content in a window with full hardware acceleration and no window border, you can create a borderless window (e.g. just WS_POPUP for its window style) and call DwmExtendFrameIntoClientArea passing -1 for all the margins. Then, create your swap-chain with the D3DFMT_A8R8G8B8 pixel format or the DXGI equivalent for Direct3D 10/11 (which is the native format DWM uses to render windows) and render into it. You now have a window that contains only your alpha-blended content superimposed on the desktop. There is an older article on CodeProject about this very topic.
After continuously capture mouse input ie. left and right click, the pc will become very lag when switching to another software such as Google Chrome but when you end the framework for few seconds will back to normal with no lag.
The framework works fine until I create Graphics object. So, I doubt there is something wrong with Graphics class but I still cannot find out which part cause this performance issue.
Graphics class
Graphics.h
#ifndef GRAPHICS_H
#define GRAPHICS_H
#include <d3d9.h>
class Graphics
{
public:
Graphics();
~Graphics();
void initialize(HWND hWnd, int backBufferWidth, int backBufferHeight);
void BeginFrame();
void EndFrame();
private:
IDirect3D9* direct3D9;
IDirect3DDevice9* d3dDevice;
};
#endif
Graphics.cpp
#include "Graphics.h"
Graphics::Graphics()
{
}
Graphics::~Graphics()
{
// Release the device when exiting.
d3dDevice->Release();
// Reset pointer to NULL.
d3dDevice = NULL;
}
void Graphics::initialize(HWND hWnd, int backBufferWidth, int backBufferHeight)
{
// Define Direct3D 9.
direct3D9 = Direct3DCreate9(D3D_SDK_VERSION);
// Define how the screen presents.
D3DPRESENT_PARAMETERS d3dPP;
ZeroMemory(&d3dPP, sizeof(d3dPP));
d3dPP.Windowed = true;
d3dPP.SwapEffect = D3DSWAPEFFECT_DISCARD;
d3dPP.BackBufferFormat = D3DFMT_X8R8G8B8;
d3dPP.BackBufferCount = 1;
d3dPP.BackBufferWidth = backBufferWidth;
d3dPP.BackBufferHeight = backBufferHeight;
d3dPP.hDeviceWindow = hWnd;
// Create a Direct3D 9 device.
direct3D9->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd,
D3DCREATE_SOFTWARE_VERTEXPROCESSING, &d3dPP, &d3dDevice);
}
void Graphics::BeginFrame()
{
// Clear the back buffer.
d3dDevice->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0, 0, 0), 1.0f, 0);
// Begin the scene
d3dDevice->BeginScene();
}
void Graphics::EndFrame()
{
// End the scene
d3dDevice->EndScene();
// Present the back buffer to screen
d3dDevice->Present(NULL, NULL, NULL, NULL);
}
Here is my whole project if you want to check all the codes : https://www.dropbox.com/s/p4nm57fzqse12t7/Zero%20DirectX%20Framework.rar
Kindly Pardon me if my doubt is silly or foolish. I am totally new to DirectX programming. Just have C++ knowledge (Very basic COM knowledge).
Below code sample is from MSDN Creating D3D device which explains how to create a D3D device from scratch.
MyDoubt is :
Here the function "pD3D->CreateDeviceEx()" takes in a parameter
HWND hwnd. What if I am trying to create a D3D device from a
commadline C++ win32 app where I need to use some of the functions in D3D device's interfaces. How do I get the HWND field. In this case
how do I create D3D device. PLease explain in detail.
HRESULT InitD3D9Ex( /* IN */ HWND hWnd, /* OUT */ IDirect3DDevice9Ex ** ppD3DDevice )
{
HRESULT hr = E_FAIL;
IDirect3D9Ex * pD3D = NULL;
IDirect3DDevice9Ex * pDevice = NULL;
if(ppD3DDevice == NULL)
{
return hr;
}
// Create the D3D object, which is needed to create the D3DDevice.
if(FAILED(hr = Direct3DCreate9Ex( D3D_SDK_VERSION, &pD3D )))
{
*ppD3DDevice = NULL;
return hr;
}
// Set up the structure used to create the D3DDevice.
D3DPRESENT_PARAMETERS d3dpp;
ZeroMemory( &d3dpp, sizeof(d3dpp) );
d3dpp.Windowed = TRUE;
d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
d3dpp.BackBufferFormat = D3DFMT_UNKNOWN;
// Create the Direct3D device.
if( FAILED( hr = pD3D->CreateDeviceEx( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd,
D3DCREATE_SOFTWARE_VERTEXPROCESSING,
&d3dpp, NULL, &pDevice ) ) )
{
*ppD3DDevice = NULL;
return hr;
}
// Device state would normally be set here
*ppD3DDevice = pDevice;
return hr;
}
In Windows all the visual things are controlled by window handles. You cannot create the D3D "device" and attach it to "nothing". You must associate the "D3D device" with some window (your own one or a desktop).
Your console window is created by the system and you do not control its creation flags, so even if you use the GetConsoleWindow function, you cannot use this HWND in Direct3D device creation functions (this might have changed with the introduction of Aero).
You cannot avoid creating getting yet another window handle in your console application. Use the RegisterWindowClass and CreateWindow functions to create a new window or find the handle to your desktop (I doubt you would want that).
Is it possible to create device/directx application when pc uses vgasave mode?
This is my init function:
d3d = Direct3DCreate9(D3D_SDK_VERSION); // create the Direct3D interface
D3DPRESENT_PARAMETERS d3dpp; // create a struct to hold various device information
ZeroMemory(&d3dpp, sizeof(d3dpp)); // clear out the struct for use
d3dpp.Windowed = TRUE; // program windowed, not fullscreen
d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD; // discard old frames
d3dpp.hDeviceWindow = hWnd; // set the window to be used by Direct3D
// create a device class using this information and the info from the d3dpp stuct
d3d->CreateDevice(D3DADAPTER_DEFAULT,
D3DDEVTYPE_HAL,
hWnd,
D3DCREATE_SOFTWARE_VERTEXPROCESSING,
&d3dpp,
&d3ddev);
However when i call later
d3ddev->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0, 40, 100), 1.0f, 0);
Program crashes, reporting about unhandled violation. Or maybe it isn't about vga, just I'm making something wrong?
CreateDevice returns D3DERR_NOTAVAILABLE
You've filled out way too few parameters in the D3DPRESENT_PARAMETERS. You've alomst certainly got bad settings for the back buffer and that kind of thing. If CreateDevice returns D3DERR_NOTAVAILABLE, then the d3ddev pointer is NULL, resulting in the access violation when you try to clear the back buffer- since there is no device.
D3DDeviceParameters.Windowed = true;
D3DDeviceParameters.BackBufferHeight = 0;
D3DDeviceParameters.BackBufferWidth = 0;
D3DDeviceParameters.BackBufferCount = 1;
D3DDeviceParameters.BackBufferFormat = D3DFMT_X8R8G8B8;
D3DDeviceParameters.MultiSampleQuality = 0;
D3DDeviceParameters.MultiSampleType = D3DMULTISAMPLE_NONE;
D3DDeviceParameters.SwapEffect = D3DSWAPEFFECT_DISCARD;
D3DDeviceParameters.hDeviceWindow = OS->GetHWND();
D3DDeviceParameters.EnableAutoDepthStencil = true;
D3DDeviceParameters.AutoDepthStencilFormat = D3DFMT_D24S8;
D3DDeviceParameters.Flags = 0;
D3DDeviceParameters.FullScreen_RefreshRateInHz = 0;
D3DDeviceParameters.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE; // Vsync.
This is my D3DPRESENT_PARAMETERS.