DirectX9 CreateDevice() returns D3DERR_INVALIDCALL in injected DLL for VMT hooking - c++

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.

Related

I am trying to send a window (application) from the main monitor (touch screen) to a secondary monitor using the same graphics card on the same host

I am trying to send a window (application) from the main monitor (touch screen) to a secondary monitor using the same graphics card on the same host
I spent a long time gathering data, trying to get a clear idea:
The MoveDown MOVEDEV_PARAMS
BOOL GetWindowRect(
HWND hWnd, // handle to window
LPRECT lpRect // window coordinates
);
AND...
And the following, but my brain can't put them together into something useful for me
BOOL EnumDisplayDevices(
LPCTSTR lpDevice, // device name
DWORD iDevNum, // display device
PDISPLAY_DEVICE lpDisplayDevice, // device information
DWORD dwFlags // reserved);
BOOL EnumDisplayMonitors(
HDC hdc, // handle to display DC
LPCRECT lprcClip, // clipping rectangle
MONITORENUMPROC lpfnEnum, // callback function
LPARAM dwData // data for callback function
);
BOOL EnumDisplaySettings(
LPCTSTR lpszDeviceName, // display device
DWORD iModeNum, // graphics mode
LPDEVMODE lpDevMode // graphics mode settings);
How to open a window on a specific display in Windows?
//VisualAPP Open
SHELLEXECUTEINFO sei;
ZeroMemory(&sei, sizeof(SHELLEXECUTEINFO));
sei.cbSize = sizeof(SHELLEXECUTEINFO);
sei.fMask = SEE_MASK_NOCLOSEPROCESS;
sei.lpVerb = _T("open");
sei.lpFile = _T("C:\\Users\\Administrator\\Desktop\\xxx.lnk");
sei.nShow = SW_SHOW;
if(ShellExecuteEx(&sei)) // Execute successfully
{
MoveApp(); // Moving program window
if (sei.hProcess)
WaitForSingleObject(sei.hProcess, INFINITE);
}
else
{
CString s;
s.Format(_T("ShellExecuteEx error,errer code:%d"), GetLastError());
// s = GetLastError();
MessageBox(s);
}
and the like...
There was a lot of enthusiastic user data that was very helpful to me, now how do I do development in VC6 is also important.
There is no problem in Visual stubio 2019, but not in Visual c++ 6.0 (maybe different support standards).
It made my feature development very difficult, and we were using VC6.
We cannot upgrade vc6 to vs19(VSCode) in a short time. Do you have a better way to solve the imminent problem.
This is probably the most important thing for ‘me to achieve immortality ’

Different D3D9 devices dont share the same VTable address

Lately I've been messing around with VTables and virtual pointers,
and I've found that every vptr from the same class type (should) point to the same VTable.(They point to the same address).
And I've searched for information about how COM objects work, and I've found that they also share the same VTable.(Objects of the same class ofc )
https://www.codeproject.com/articles/153096/intercepting-calls-to-com-interfaces]
First of all, when you set a method hook, it will work not only for the current instance of the COM object. It’ll work for all objects of the same class (but not for all the classes implementing the interface hooked).
The problem I have is as follows: I created in a test app 3 different d3d9 devices and I checked their pointer to the VTable but they are not the same!
if( NULL == ( g_pD3D = Direct3DCreate9( D3D_SDK_VERSION ) ) )
return E_FAIL;
if (NULL == (g_pD3D2 = Direct3DCreate9(D3D_SDK_VERSION)))
return E_FAIL;
D3DPRESENT_PARAMETERS d3dpp;
ZeroMemory( &d3dpp, sizeof( d3dpp ) );
d3dpp.Windowed = TRUE;
d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
d3dpp.BackBufferFormat = D3DFMT_UNKNOWN;
D3DPRESENT_PARAMETERS d3dpp2;
ZeroMemory(&d3dpp2, sizeof(d3dpp2));
d3dpp2.Windowed = TRUE;
d3dpp2.SwapEffect = D3DSWAPEFFECT_DISCARD;
d3dpp2.BackBufferFormat = D3DFMT_UNKNOWN;
if( FAILED( g_pD3D->CreateDevice( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd,
D3DCREATE_SOFTWARE_VERTEXPROCESSING,
&d3dpp, &g_pd3dDevice ) ) )
{
return E_FAIL;
}
if (FAILED(g_pD3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd,
D3DCREATE_SOFTWARE_VERTEXPROCESSING,
&d3dpp2, &g_pd3dDevic)))
{
return E_FAIL;
}
WNDCLASSEX wc = { sizeof(WNDCLASSEX),CS_CLASSDC,TempWProc,0L,0L,GetModuleHandle(NULL),NULL,NULL,NULL,NULL,(LPCWSTR)("1"),NULL };
RegisterClassEx(&wc);
HWND hWndd = CreateWindow((L"1"), NULL, WS_OVERLAPPEDWINDOW, 100, 100, 300, 300, GetDesktopWindow(), NULL, wc.hInstance, NULL);
if (FAILED(g_pD3D2->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWndd,
D3DCREATE_SOFTWARE_VERTEXPROCESSING | D3DCREATE_DISABLE_DRIVER_MANAGEMENT,
&d3dpp2, &g_pd3dDevic3)))
{
return E_FAIL;
}
(As a last resort I also created a different window and initialized a new D3D Interface just in case it would make the new d3d9 device point to the same VTable.)
In the debugger I checked the values of the device's pointers and this is what they yield:
g_pd3dDevice(The first one) : __vfptr = 0x00b75d1c { 0x6a976f19 }
g_pd3dDevic(The second one) : __vfptr = 0x0512a75c { 0x6a976f19 }
g_pd3dDevic3(The third one) : __vfptr = 0x0524393c { 0x6a976f19 }
The 3 VTables are the same, but they are in different places. (The three pointers point to the same function)
(And I also checked and the VTable is offseted by 0x2D9C from the object)
So this is what I dont really understand:
Do D3D9 devices always use the same VTable?
Why don't they use the same VTable as COM objects do as pointed by the link I've given?
Is it a problem related to having more than one device in the same HWND?
Is it some compiler optimization- related thingie?
Are they really VTables?
P.S: Sorry for my poor English, and my way of explaining things :C
Thanks a lot for reading this wall of text, seriously, thanks.
Thanks in advance!!!
(And sorry if it is a really dumby question)

Screenshot of game window

How can i take a screenshot of a full screen game in c++? I know it can be done with directx and i have written a simple code which can take a screenshot of a window but i don't know how to get a HWND of game.
Here is my code.
#include <d3dx9.h>
#include <d3dx9tex.h>
#include <stdio.h>
#pragma comment(lib,"d3d9.lib")
#pragma comment(lib,"d3dx9.lib")
int main()
{
IDirect3DSurface9 *surface;
IDirect3DDevice9 *g_pd3dDevice;
IDirect3D9 *g_pD3D;
D3DDISPLAYMODE d3ddm;
D3DPRESENT_PARAMETERS d3dpp;
HWND hWnd = GetConsoleWindow();
if((g_pD3D = Direct3DCreate9(D3D_SDK_VERSION)) == NULL)
{
printf("fail 1");
}
if(FAILED(g_pD3D->GetAdapterDisplayMode(D3DADAPTER_DEFAULT, &d3ddm)))
{
printf("fail 2");
}
ZeroMemory(&d3dpp, sizeof(D3DPRESENT_PARAMETERS));
d3dpp.Windowed = TRUE;
d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
d3dpp.BackBufferFormat = d3ddm.Format;
d3dpp.BackBufferHeight = d3ddm.Height;
d3dpp.BackBufferWidth = d3ddm.Width;
if(FAILED(g_pD3D->CreateDevice(D3DADAPTER_DEFAULT,
D3DDEVTYPE_HAL, hWnd,
D3DCREATE_SOFTWARE_VERTEXPROCESSING,
&d3dpp, &g_pd3dDevice)))
{
printf("fail 3");
}
g_pd3dDevice->CreateOffscreenPlainSurface(800, 600, D3DFMT_A8R8G8B8, D3DPOOL_SCRATCH, &surface, NULL);
g_pd3dDevice->GetFrontBufferData(0, surface);
D3DXSaveSurfaceToFile("c:\\tmp\\output.jpg", D3DXIFF_JPG, surface, NULL, NULL);
surface->Release();
return 0;
}
I don't have any experience with Direct3D, but with OpenGL.
But both APIs provide almost the same functionality.
You should read back the back buffer (using Direct3D and not some Windows functionality) to host memory. Then simply save that bitmap to a file using an image library or something like that.
It's actually an extremely simple process.
These two links might be helpful to you:
http://www.mvps.org/directx/articles/screengrab.htm
How to save backbuffer to file in DirectX 10?

Creating a D3D device without HWND input parameter to MSFT CreateDevice() function

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).

OpenOffice Automation Issue when Launched from Separate Thread

I have a C++ application that sometimes needs to export information to a spreadsheet. It is designed to do so using COM and ActiveX integration with Microsoft Excel and OpenOffice Calc.
I noticed with one of the newer versions of OpenOffice that my program would timeout and fail any time I tried doing the export.
I did quite a bit of research before figuring out that the failure required the following two events:
1.) Creation of a simple UI window with a custom procedure (even if that procedure did not do anything more than pass everything on to the default procedure)
2.) Creation of a separate thread in which the code to launch OpenOffice (via COM and ActiveX) is executed
I should note that any given time, there is only ONE thread doing OpenOffice integration. It just happens to be a different thread from the one handling the UI.
I also noticed some other oddities.
If the window class does NOT involve a custom procedure, no error occurs. However, if ANY custom procedure is involved it does occur. Even if the custom window procedure does absolutely nothing but pass all messages to the default window procedure, the error occurs.
If no UI window is made, the code in the separate thread executes flawlessly.
If the integration code is launched from the same thread as the UI, no error occurs. If the integration is first carried out within the same thread as the UI, subsequent creation and execution of a separate thread runs without error.
And this is the weirdest observation: I'm using Visual Studio 2005 for debugging. If I set a breakpoint just prior to the invocation of "loadComponentFromURL", the hang will NOT occur. However, if I do NOT set a break point, when the hang occurs I can break execution and I'll find that the call stack indicates that it is stuck somewhere within the process of RPC invocation awaiting a return from WaitForMultipleObjectsEx(...).
Below is a complete code example. If you compile and run this on a machine with the newest version of OpenOffice, it will hang. Within the WinMain(...) function, there is a call to TestOOCalc that is commented out. If you uncomment it, you'll find the program now launches OpenOffice Calc perfectly.
Given that there are NOT multiple threads attempting to access OpenOffice at the same time, this doesn't seem like it should be a threading issue at all.
I can't find anything anywhere about this phenomenon or what the root cause is. I really don't want to resort to putting all of the work in the same thread as the UI as this would make the UI unresponsive during lengthy operations.
Thoughts? Ideas?
#include <windows.h>
#include <atlbase.h>
#include <process.h>
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
return DefWindowProc(hwnd, message, wParam, lParam);
}
BOOL MakeUIWindow(HINSTANCE hInstance)
{
// Class definition for Main Window
WNDCLASS wndclass;
ZeroMemory(&wndclass, sizeof(wndclass));
wndclass.style = CS_HREDRAW | CS_VREDRAW;
wndclass.lpfnWndProc = WndProc;
wndclass.hInstance = hInstance;
wndclass.lpszClassName = TEXT("Problem Window Class");
// Register the Main Window class
if (!RegisterClass(&wndclass))
return FALSE;
HWND hwnd = CreateWindowEx(0, TEXT("Problem Window Class"),
TEXT("Problem"), WS_OVERLAPPEDWINDOW,
10, 10, 500, 500,
NULL, NULL, hInstance, NULL);
ShowWindow(hwnd, SW_NORMAL);
return TRUE;
}
BOOL ActiveX_MethodCall(CComPtr<IDispatch> &rcpPropInterface, const WCHAR *wszMethod, const UINT uiArgs, VARIANTARG *pArgs, CComPtr<IDispatch> &rcpResult)
{
DISPID dispid;
HRESULT hr = rcpPropInterface.GetIDOfName(wszMethod, &dispid);
if (FAILED(hr))
return FALSE;
DISPPARAMS dp;
EXCEPINFO ei;
VARIANT varReturn;
ZeroMemory(&varReturn, sizeof(varReturn));
ZeroMemory(&dp, sizeof(dp));
ZeroMemory(&ei, sizeof(ei));
varReturn.vt = VT_EMPTY;
dp.cArgs = uiArgs;
dp.rgvarg = pArgs;
hr = rcpPropInterface->Invoke(dispid, IID_NULL, NULL, DISPATCH_METHOD, &dp, &varReturn, NULL, NULL);
if (FAILED(hr))
return FALSE;
rcpResult.Attach(varReturn.pdispVal);
return TRUE;
}
// Performs an initialization of OpenOffice
BOOL TestOOCalc()
{
if (FAILED(CoInitialize(NULL)))
return FALSE;
// Get class IDs for the ActiveX object specified
CLSID clsid;
if (FAILED(CLSIDFromProgID(L"com.sun.star.ServiceManager", &clsid)))
return FALSE;
CComPtr<IDispatch> cpSvcMgr;
if (FAILED(cpSvcMgr.CoCreateInstance(clsid, NULL, CLSCTX_LOCAL_SERVER)))
return FALSE;
CComPtr<IDispatch> cpDesktop;
{ // context change for local variants
VARIANTARG varArg;
ZeroMemory(&varArg, sizeof(varArg));
varArg.scode = DISP_E_PARAMNOTFOUND;
varArg.vt = VT_BSTR;
varArg.bstrVal = SysAllocString(L"com.sun.star.frame.Desktop");
if (!ActiveX_MethodCall(cpSvcMgr, L"createInstance", 1, &varArg, cpDesktop))
{
VariantClear(&varArg);
return FALSE;
}
VariantClear(&varArg);
}
// Call Desktop.loadComponentFromURL Method
CComPtr<IDispatch> cpWorkbook;
{ // context change for local variants
VARIANTARG pvarArgs[4];
ZeroMemory(&pvarArgs, sizeof(pvarArgs));
pvarArgs[3].scode = DISP_E_PARAMNOTFOUND;
pvarArgs[3].vt = VT_BSTR;
pvarArgs[3].bstrVal = SysAllocString(L"private:factory/scalc");
pvarArgs[2].scode = DISP_E_PARAMNOTFOUND;
pvarArgs[2].vt = VT_BSTR;
pvarArgs[2].bstrVal = SysAllocString(L"_blank");
pvarArgs[1].scode = DISP_E_PARAMNOTFOUND;
pvarArgs[1].vt = VT_I4;
pvarArgs[1].lVal = 0;
SAFEARRAYBOUND saBound;
saBound.lLbound = 0;
saBound.cElements = 0;
SAFEARRAY *psaArgs = SafeArrayCreate(VT_VARIANT, 1, &saBound);
pvarArgs[0].scode = DISP_E_PARAMNOTFOUND;
pvarArgs[0].vt = VT_ARRAY | VT_VARIANT;
pvarArgs[0].parray = psaArgs;
if (!ActiveX_MethodCall(cpDesktop, L"loadComponentFromURL", 4, pvarArgs, cpWorkbook))
{
SafeArrayDestroy(psaArgs);
VariantClear(&pvarArgs[3]);
VariantClear(&pvarArgs[2]);
VariantClear(&pvarArgs[1]);
VariantClear(&pvarArgs[0]);
return FALSE;
}
SafeArrayDestroy(psaArgs);
VariantClear(&pvarArgs[3]);
VariantClear(&pvarArgs[2]);
VariantClear(&pvarArgs[1]);
VariantClear(&pvarArgs[0]);
}
return TRUE;
}
unsigned int __stdcall thrTestOOCalc(void *vShare)
{
TestOOCalc();
return 0;
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow)
{
if (!MakeUIWindow(hInstance))
return 0;
//TestOOCalc();
HANDLE hThread = (HANDLE)_beginthreadex(NULL, 0, thrTestOOCalc, NULL, 0, NULL);
WaitForSingleObject(hThread, INFINITE);
return 0;
}
It has been a long time since a worked in a daily basis with COM, but to me this looks like the classic failure of pumping messages in an APARTMENT thread.
Check the following:
Are OpenOffice component declared as apartment threaded ?
If not, try to initialize your thread in MTA using CoInitializeEx.
If OO components are declared as apartment thread, you'll need to pump messages on your newly created thread.
Hope this helps.