Suppose I have 3 monitors. How do I get the handle of the second one only by its index? EnumDisplayMonitors() won't work because it enumerates the pseudo-devices as well and EnumDisplayDevices() doesn't give me the handle.
You need to use EnumDisplayMonitors() instead of EnumDisplayDevices() to access the HMONITOR handle of each monitor.
However, monitors are not identified by index. GetMonitorInfo() can tell you which monitor is "primary", but that is all. There is no way to know which monitor is "second", "third", etc. And you can't use monitor locations to determine that, either, as the "second" monitor could be positioned anywhere in relation to the "primary" monitor, and then the "third" monitor can be positioned anywhere in relation to either "first" or "second" monitor.
So you have to hope that EnumDisplayMonitors() enumerates in the order that the monitors are installed, then you can do something like this:
struct sEnumInfo
{
int iIndex;
HMONITOR hMonitor;
};
BOOL CALLBACK GetMonitorByIndex(HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcMonitor, LPARAM dwData)
{
sEnumInfo *info = (sEnumInfo*) dwData;
if (--info->iIndex < 0)
{
info->hMonitor = hMonitor;
return FALSE;
}
return TRUE;
}
sEnumInfo info;
info.iIndex = 1;
info.hMonitor = NULL;
EnumDisplayMonitors(NULL, NULL, GetMonitorByIndex, (LPARAM)&info);
if (info.hMonitor != NULL)
{
//...
}
You can enumerate devices with EnumDisplayMonitors() and check if it is pseudo monitor with EnumDisplayDevices()
While you iterating through display monitors using GetMonitorInfo() you can get MONITORINFOEX with a name of a monitor's device.
Then using EnumDisplayDevices() you can get DISPLAY_DEVICE which contains StateFlags with info if current monitor is a pseudo monitor (or as in case bellow attached to desktop)
BOOL DispayEnumeratorProc(_In_ HMONITOR hMonitor, _In_ HDC hdcMonitor, _In_ LPRECT lprcMonitor, _In_ LPARAM dwData)
{
TClass* self = (TClass*)dwData;
if (self == nullptr)
return FALSE;
MONITORINFOEX monitorInfo;
::ZeroMemory(&monitorInfo, sizeof(monitorInfo));
monitorInfo.cbSize = sizeof(monitorInfo);
BOOL res = ::GetMonitorInfo(hMonitor, &monitorInfo);
if (res == FALSE)
return TRUE;
DISPLAY_DEVICE displayDevice;
::ZeroMemory(&displayDevice, sizeof(displayDevice));
displayDevice.cb = sizeof(displayDevice);
res = ::EnumDisplayDevices(monitorInfo.szDevice, 0, &displayDevice, 0);
if (res == FALSE)
return TRUE;
if (displayDevice.StateFlags & DISPLAY_DEVICE_ATTACHED_TO_DESKTOP)
self->RegisterDisplay(monitorInfo);
return TRUE;
}
void TClass::EnumerateDisplayMonitors()
{
BOOL res = ::EnumDisplayMonitors(NULL, NULL, &DispayEnumeratorProc, (LPARAM)this);
if (res == FALSE)
Print("Failed");
}
Also you can sort your monitors by iterating through EnumDisplayDevices()
If you pass NULL as first parameter to EnumDisplayDevices() it will return adapter's info based on second parameter. In this case your devices will have determined order.
You can compare DeviceName from DISPLAY_DEVICE with szDevice from MONITORINFOEX that you stored before to sort your HMONITORs
void TClass::SortDisplayMonitors()
{
DISPLAY_DEVICE displayDevice;
::ZeroMemory(&displayDevice, sizeof(displayDevice));
displayDevice.cb = sizeof(displayDevice);
std::map<std::string, DWORD> devices;
for (DWORD iDevNum = 0; ::EnumDisplayDevices(NULL, iDevNum, &displayDevice, 0) != FALSE; ++iDevNum)
devices.insert({displayDevice.DeviceName, iDevNum});
auto compare = [&devices](MONITORINFOEX& l, MONITORINFOEX& r)
{
DWORD il = -1;
DWORD ir = -1;
auto foundL = devices.lower_bound(l.szDevice);
if (foundL != devices.end())
il = foundL->second;
auto foundR = devices.lower_bound(r.szDevice);
if (foundR != devices.end())
ir = foundR->second;
return (il < ir);
};
std::sort(m_monitors.begin(), m_monitors.end(), compare);
}
PS: You can write
DWORD il = std::numeric_limits< DWORD >::max();
insted of
DWORD il = -1;
but don't forget to define NOMINMAX before you include Windows.h
you can exclude primary monitor, here is sample code (styles may vary) :
if DEVMODE dmPosition x == 0 and y == 0, then it is primary monitor.
For display devices only, a POINTL structure that indicates the
positional coordinates of the display device in reference to the
desktop area. The primary display device is always located at
coordinates (0,0).
check x, y to define second or third.
LONG second_x=0;
LONG second_y=0;
DWORD deviceNum = 0;
DISPLAY_DEVICE displayDevice;
DEVMODE devMode;
memset(&displayDevice, 0, sizeof(displayDevice));
displayDevice.cb = sizeof(DISPLAY_DEVICE);
while(EnumDisplayDevices(NULL, deviceNum, &displayDevice, 0))
{
EnumDisplaySettings(displayDevice.DeviceName, ENUM_CURRENT_SETTINGS, &devMode);
if (devMode.dmPosition.x == 0 && devMode.dmPosition.y == 0)
{
// primary monitor
}
else
{
// second or third monitor
second_x = devMode.dmPosition.x;
second_y = devMode.dmPosition.y;
}
++deviceNum;
}
m_pMainWnd->SetWindowPos(NULL,(int)second_x,(int)second_y,0,0,SWP_SHOWWINDOW | SWP_NOSIZE);
Related
What I am trying to do is combining the regions of the top windows and checking if the specified window is present in the region if it is then displaying result. It does not giving results very accurately. And also I have problem when windows are non-overlapped. Does any one have any idea how to overcome this situation.
p is the foreground process
while (p != NULL)
{
if (IsWindowVisible(p)) {
if ((GetWindowLongPtr(p, GWL_STYLE) & WS_ICONIC) || GetWindowLong(p, GWL_EXSTYLE) & WS_EX_TOOLWINDOW) {
}
else
{
RECT a;
if (GetWindowText(p, str, 255)) {
if ((_wcsicmp(str, _T("Program Manager"))))
{
GetWindowThreadProcessId(p, &proc_id);
proc_hnd = OpenProcess(PROCESS_ALL_ACCESS, TRUE, proc_id);
flag = GetProcessImageFileName(proc_hnd, proc_name, 1024);
wstring test(&proc_name[0]); //convert to wstring
string test2(test.begin(), test.end());
LOGGER->info(test2);
GetWindowRect(p, &a);
z = CreateRectRgn(a.left, a.top, a.right, a.bottom);
if (wcsstr(proc_name, L"chrome.exe")) {
RECT op;
GetWindowRect(p, &op);
HRGN j1 = CreateRectRgn(op.left, op.top, op.right, op.bottom);
CombineRgn(j1, j1, y, RGN_DIFF); emphasized text
CombineRgn(y, y, z, RGN_OR); //combining the region
switch (GetRgnBox(j1, &a))
{
case NULLREGION:
LOGGER->info("null region");
break;
case SIMPLEREGION:
LOGGER->info("simple region");
break;
case COMPLEXREGION:
LOGGER->info("complex region");
break;
default:
LOGGER->info("default region");
}
}
else
{
CombineRgn(y, y, z, RGN_OR); //combining the region
}
}
}
}
}
p = GetWindow(p, GW_HWNDNEXT); //getting the next window
}
I use the IsOverlapped sample here, but it is used to detect whether it is overlapped by any window. I modified this sample to check whether the window is visible:
BOOL IsVisible(HWND window)
{
HWND hWnd = window;
RECT thisRect;
if (!IsWindowVisible(window))
return FALSE;
GetWindowRect(window, &thisRect);
HWND explorer = FindWindow(L"Shell_TrayWnd", NULL);
DWORD explorer_pid;
GetWindowThreadProcessId(explorer, &explorer_pid);
HRGN hrgn_above = CreateRectRgn(0, 0, 0, 0);
HRGN hrgn_window = CreateRectRgnIndirect(&thisRect);
while ((hWnd = GetWindow(hWnd, GW_HWNDPREV)) != NULL)
{
DWORD pid;
GetWindowThreadProcessId(hWnd, &pid);
if (pid == explorer_pid || !IsWindowVisible(hWnd))
continue;
RECT rc = {};
GetWindowRect(hWnd, &rc);
HRGN hrgn_hWnd = CreateRectRgn(rc.left, rc.top, rc.right, rc.bottom);
CombineRgn(hrgn_above, hrgn_above, hrgn_hWnd, RGN_OR);
DeleteObject(hrgn_hWnd);
}
int ret = CombineRgn(hrgn_window, hrgn_window, hrgn_above, RGN_DIFF);
DeleteObject(hrgn_above);
DeleteObject(hrgn_window);
if (ret != NULLREGION && ret)
return TRUE;
return FALSE;
}
Use GetWindow + GW_HWNDPREV to get the windows list above the hWnd in Z order.
I'm interested in getting the monitor index (1-based, to match Windows numbering) given the monitor handle.
Case of use: given a window's rect I want to know the monitor it belongs to. I can get the handle of the monitor using MonitorFromRect:
// RECT rect
const HMONITOR hMonitor = MonitorFromRect(rect, MONITOR_DEFAULTTONEAREST);
How can I get the monitor index from this handle?
PS: not sure if duplicate, but I've been looking around with no luck.
I found this post with the opposite question: finding the handle given the index (0-based in that case).
Based on it I worked this solution:
struct sEnumInfo {
int iIndex = 0;
HMONITOR hMonitor = NULL;
};
BOOL CALLBACK GetMonitorByHandle(HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcMonitor, LPARAM dwData)
{
auto info = (sEnumInfo*)dwData;
if (info->hMonitor == hMonitor) return FALSE;
++info->iIndex;
return TRUE;
}
int GetMonitorIndex(HMONITOR hMonitor)
{
sEnumInfo info;
info.hMonitor = hMonitor;
if (EnumDisplayMonitors(NULL, NULL, GetMonitorByHandle, (LPARAM)&info)) return -1;
return info.iIndex + 1; // 1-based index
}
As none of you already know, I am quite fed up with DirectX at the moment. I have tried and tried, and no matter what I do, I cannot seem to get any hooks to work. I have scoured the web and studied hooks; I have combined bits of code together to scrap together my own hook; I have flat out plagiarized hooks to find out how they worked; I have even written a few from scratch. However, I cannot seem to get one to work. I'm trying to make a simple D3D mod-menu for CrossFire. What I have tried:
Hooking via VTable [had issues with getting a device pointer]
Hooking via pattern + mask scanning, etc and detours [unsure how to get a pattern, and cannot find one that works reliably for win10]
Creating a dummy device to get the addresses, etc, etc [caused an immediate shut-down of the game (detected)]
No matter what I do, the menu either flat out refuses to appear once programmed into the detoured EndScene, I get shut-down, I crash, or nothing happens.
Are there any good starter materials with sample code that I can learn from, as well as get this off the ground?
I already have the hack menu programmed, the variables set, the features programmed, the DllMain, the dependencies, you name it. All I need is to get a proper hook working - the only one I got to work had a weird bug where text drawing in EndScene & wall-hack in DrawIndexedPrimitive didn't work.
This is a large amount of code for a SO answer but here we go.
Get correct window
Create a dummy device
Get address of endscene from vtable
Do a standard x86 trampoline hook
Inside hook do whatever initialize stuff you need to
Get a copy of the correct device pointer
Draw stuff
call original function with correct device pointer
#pragma comment(lib, "d3d9.lib")
#pragma comment(lib, "d3dx9.lib")
#include <windows.h>
#include <d3d9.h>
#include <d3dx9.h>
bool Hook(char* src, char* dst, int len)
{
if (len < 5) return false;
DWORD curProtection;
VirtualProtect(src, len, PAGE_EXECUTE_READWRITE, &curProtection);
memset(src, 0x90, len);
uintptr_t relativeAddress = (uintptr_t)(dst - src - 5);
*src = (char)0xE9;
*(uintptr_t*)(src + 1) = (uintptr_t)relativeAddress;
DWORD temp;
VirtualProtect(src, len, curProtection, &temp);
return true;
}
char* TrampHook(char* src, char* dst, unsigned int len)
{
if (len < 5) return 0;
// Create the gateway (len + 5 for the overwritten bytes + the jmp)
char* gateway = (char*)VirtualAlloc(0, len + 5, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
// Put the bytes that will be overwritten in the gateway
memcpy(gateway, src, len);
// Get the gateway to destination addy
uintptr_t gateJmpAddy = (uintptr_t)(src - gateway - 5);
// Add the jmp opcode to the end of the gateway
*(gateway + len) = (char)0xE9;
// Add the address to the jmp
*(uintptr_t*)(gateway + len + 1) = gateJmpAddy;
// Place the hook at the destination
if (Hook(src, dst, len))
{
return gateway;
}
else return nullptr;
}
typedef HRESULT(APIENTRY* tEndScene)(LPDIRECT3DDEVICE9 pDevice);
static HWND window;
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;
}
void DrawFilledRect(int x, int y, int w, int h, D3DCOLOR color, IDirect3DDevice9* dev)
{
D3DRECT BarRect = { x, y, x + w, y + h };
dev->Clear(1, &BarRect, D3DCLEAR_TARGET | D3DCLEAR_TARGET, color, 0, 0);
}
bool bInit = false;
tEndScene oEndScene = nullptr;
LPDIRECT3DDEVICE9 pD3DDevice = nullptr;
void* d3d9Device[119];
HRESULT APIENTRY hkEndScene(LPDIRECT3DDEVICE9 pDevice)
{
if (bInit == false)
{
pD3DDevice = pDevice;
bInit = true;
}
//draw stuff here like so:
DrawFilledRect(200, 200, 200, 200, D3DCOLOR_ARGB(255, 255, 0, 0), pDevice);
return oEndScene(pDevice);
}
DWORD WINAPI Init(HMODULE hModule)
{
if (GetD3D9Device(d3d9Device, sizeof(d3d9Device)))
{
oEndScene = (tEndScene)TrampHook((char*)d3d9Device[42], (char*)hkEndScene, 7);
}
return 0;
}
BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
{
CloseHandle(CreateThread(nullptr, 0, (LPTHREAD_START_ROUTINE)Init, hModule, 0, nullptr));
}
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
Credits to me, Broihon, Solaire & 0xDEC0DE for this barebones d3d9 endscene hook
We have desktop app which uses Qt 4.8.
We are trying to support different DPI screens like Mac retina, Surface Pro 4 devices.
For Mac we can get the device pixel ratio by just single function call:
CGFloat devicePixelRatio = [[NSScreen mainScreen] backingScaleFactor];
Is there any utility function available in WinAPI to get device pixel ratio?
thanks.
Finally I found the solution use below code snippet to get the scaling factor,
FLOAT dpiX, dpiY;
HDC screen = GetDC(0);
dpiX = static_cast<FLOAT>(GetDeviceCaps(screen, LOGPIXELSX));
dpiY = static_cast<FLOAT>(GetDeviceCaps(screen, LOGPIXELSY));
ReleaseDC(0, screen);
FLOAT scaleFactor = dpiX / 96.0f; // this is same as devicePixelRatio
Now need to make your app DPI aware. For that set Enable DPI Awareness flag to Yes in Project Settings > Manifest Tool > Input and Output property page.
Here's how I calculate the DPI.
Do replace the assertions with actual error checking, as some of those situations actually occur sometimes.
#include <QString>
#include <Windows.h>
#include <SetupApi.h>
#include <cfgmgr32.h>
#include <assert.h>
#include <vector>
#include <stdint.h>
const GUID GUID_CLASS_MONITOR = { 0x4d36e96e, 0xe325, 0x11ce, 0xbf, 0xc1, 0x08, 0x00, 0x2b, 0xe1, 0x03, 0x18 };
// Assumes hEDIDRegKey is valid
bool GetMonitorSizeFromEDID(const HKEY hEDIDRegKey, short& WidthMm, short& HeightMm)
{
DWORD dwType, AcutalValueNameLength = 128;
TCHAR valueName[128];
BYTE EDIDdata[1024];
DWORD edidsize = sizeof(EDIDdata);
for (LONG i = 0, retValue = ERROR_SUCCESS; retValue != ERROR_NO_MORE_ITEMS; ++i)
{
retValue = RegEnumValue(hEDIDRegKey, i, &valueName[0],
&AcutalValueNameLength, NULL, &dwType,
EDIDdata, // buffer
&edidsize); // buffer size
if (retValue != ERROR_SUCCESS || QString(valueName) != "EDID")
continue;
WidthMm = ((EDIDdata[68] & 0xF0) << 4) + EDIDdata[66];
HeightMm = ((EDIDdata[68] & 0x0F) << 8) + EDIDdata[67];
return true; // valid EDID found
}
return false; // EDID not found
}
bool GetSizeForDevID(const QString& TargetDevID, short& WidthMm, short& HeightMm)
{
HDEVINFO devInfo = SetupDiGetClassDevsExA(
&GUID_CLASS_MONITOR, //class GUID
NULL, //enumerator
NULL, //HWND
DIGCF_PRESENT | DIGCF_PROFILE, // Flags //DIGCF_ALLCLASSES|
NULL, // device info, create a new one.
NULL, // machine name, local machine
NULL);// reserved
if (NULL == devInfo)
return false;
bool success = false;
for (ULONG i = 0; ERROR_NO_MORE_ITEMS != GetLastError(); ++i)
{
SP_DEVINFO_DATA devInfoData;
memset(&devInfoData, 0, sizeof(devInfoData));
devInfoData.cbSize = sizeof(devInfoData);
if (SetupDiEnumDeviceInfo(devInfo, i, &devInfoData))
{
CHAR Instance[MAX_DEVICE_ID_LEN];
SetupDiGetDeviceInstanceIdA(devInfo, &devInfoData, Instance, MAX_DEVICE_ID_LEN, NULL);
if (!QString(Instance).contains(TargetDevID))
continue;
HKEY hEDIDRegKey = SetupDiOpenDevRegKey(devInfo, &devInfoData,
DICS_FLAG_GLOBAL, 0, DIREG_DEV, KEY_READ);
if (!hEDIDRegKey || (hEDIDRegKey == INVALID_HANDLE_VALUE))
continue;
success = GetMonitorSizeFromEDID(hEDIDRegKey, WidthMm, HeightMm);
RegCloseKey(hEDIDRegKey);
if (success)
break;
}
}
SetupDiDestroyDeviceInfoList(devInfo);
return success;
}
static bool DisplayDeviceFromHMonitor(HMONITOR hMonitor, DISPLAY_DEVICE& ddMonOut)
{
MONITORINFOEX mi;
mi.cbSize = sizeof(MONITORINFOEX);
GetMonitorInfoA(hMonitor, &mi);
DISPLAY_DEVICE dd;
dd.cb = sizeof(dd);
for (DWORD devIdx = 0; EnumDisplayDevicesA(nullptr, devIdx, &dd, 0); ++devIdx)
{
if (QString(dd.DeviceName) != QString(mi.szDevice))
continue;
DISPLAY_DEVICE ddMon;
memset(&ddMon, 0, sizeof(ddMon));
ddMon.cb = sizeof(ddMon);
if (EnumDisplayDevicesA(dd.DeviceName, 0, &ddMon, 0))
{
ddMonOut = ddMon;
return true;
}
memset(&dd, 0, sizeof(dd));
dd.cb = sizeof(dd);
}
return false;
}
BOOL CALLBACK MonitorEnumProc(
_In_ HMONITOR hMonitor,
_In_ HDC /*hdcMonitor*/,
_In_ LPRECT /*lprcMonitor*/,
_In_ LPARAM context
)
{
std::vector<HMONITOR> * monitors = (std::vector<HMONITOR>*)context;
assert(monitors);
monitors->push_back(hMonitor);
return TRUE;
}
uint32_t CSystemMetrics::screenDpi(void* window, const CRect& rect)
{
// Identify the HMONITOR of interest via the callback MyMonitorEnumProc
HDC dc = GetWindowDC((HWND)window);
assert(dc);
RECT windowRect;
windowRect.top = rect.top;
windowRect.left = rect.left;
windowRect.right = rect.right;
windowRect.bottom = rect.bottom;
std::vector<HMONITOR> monitors;
EnumDisplayMonitors(dc, rect.size().area() > 0 ? (&windowRect) : nullptr, MonitorEnumProc, (LPARAM)&monitors);
ReleaseDC((HWND)window, dc);
assert(!monitors.empty());
DISPLAY_DEVICE ddMon;
assert(DisplayDeviceFromHMonitor(monitors.front(), ddMon));
MONITORINFO monitorInfo;
monitorInfo.cbSize = sizeof(MONITORINFO);
assert(GetMonitorInfoA(monitors.front(), &monitorInfo));
const auto deviceIdSections = QString(ddMon.DeviceID).split("\\");
assert(deviceIdSections.size() > 1);
short widthMm, heightMm;
assert(GetSizeForDevID(deviceIdSections[1], widthMm, heightMm));
const float hDPI = (monitorInfo.rcMonitor.right - monitorInfo.rcMonitor.left) * 25.4f / widthMm;
const float vDPI = (monitorInfo.rcMonitor.bottom - monitorInfo.rcMonitor.top) * 25.4f / heightMm;
const uint32_t dpi = uint32_t(((float)hDPI + (float)vDPI / 2.0f) + 0.5f);
assert(dpi < 700 && widthMm > 100 && heightMm > 100);
return dpi;
}
Now there's a complicated issue camouflaged in a simple question :-) I cannot really answer that, but merely provide some minor hints:
Firstly, Windows does not have the device-pixel vs. logical-pixel paradigm known from OSX, so your question about the "device pixel ratio" may cause irritation among non-OSX-developers.
For Qt, there have been some substantial changes from versions 4.x to 5.x. In fact, you might actually want to consider "upgrading" to Qt 5.
http://doc.qt.io/qt-5/highdpi.html
To quote from this link:
"Qt 5.4 introduces experimental support for scaling by by device pixel ratio similar to OS X to the platform plugins for Windows and Unix (XCB)."
Qt 4 on the other hand offers only those tips for "scalable applications":
http://doc.qt.io/qt-4.8/scalability.html
Related SO question:
Automatic rescaling of an application on high-dpi Windows platform?
Sometimes, not all the time... when creating a D3D device, I get the error code D3DERR_DRIVERINVALIDCAL and then other times I get S_OK.
I've been stuck on this issue for the past 3 days, going on number 4.
Looking at the documentation on this error code, it describes it as not used, which is very confusing.
Can anybody shed some light?
HRESULT hr = S_OK;
HWND hwnd = NULL;
HMONITOR hMonitor = NULL;
UINT uAdapterID = D3DADAPTER_DEFAULT;
DWORD vp = 0;
D3DCAPS9 ddCaps;
ZeroMemory(&ddCaps, sizeof(ddCaps));
IDirect3DDevice9* pDevice = NULL;
// Hold the lock because we might be discarding an exisiting device.
AutoLock lock(m_ObjectLock);
if (!m_pD3D9 || !m_pDeviceManager)
{
return MF_E_NOT_INITIALIZED;
}
hwnd = GetDesktopWindow();
// Note: The presenter creates additional swap chains to present the
// video frames. Therefore, it does not use the device's implicit
// swap chain, so the size of the back buffer here is 1 x 1.
D3DPRESENT_PARAMETERS pp;
ZeroMemory(&pp, sizeof(pp));
pp.BackBufferWidth = 1;
pp.BackBufferHeight = 1;
pp.Windowed = TRUE;
pp.SwapEffect = D3DSWAPEFFECT_COPY;
pp.BackBufferFormat = D3DFMT_UNKNOWN;
pp.hDeviceWindow = hwnd;
pp.Flags = D3DPRESENTFLAG_VIDEO;
pp.PresentationInterval = D3DPRESENT_INTERVAL_DEFAULT;
// Find the monitor for this window.
if (m_hwnd)
{
hMonitor = MonitorFromWindow(m_hwnd, MONITOR_DEFAULTTONEAREST);
// Find the corresponding adapter.
CHECK_HR(hr = FindAdapter(m_pD3D9, hMonitor, &uAdapterID));
}
// Get the device caps for this adapter.
CHECK_HR(hr = m_pD3D9->GetDeviceCaps(uAdapterID, D3DDEVTYPE_HAL, &ddCaps));
if(ddCaps.DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT)
{
vp = D3DCREATE_HARDWARE_VERTEXPROCESSING;
}
else
{
vp = D3DCREATE_SOFTWARE_VERTEXPROCESSING;
}
IDirect3DDevice9Ex * pDeviceEx;
// Create the device.
CHECK_HR(hr = m_pD3D9->CreateDeviceEx(uAdapterID,
D3DDEVTYPE_HAL,
pp.hDeviceWindow,
vp | D3DCREATE_NOWINDOWCHANGES | D3DCREATE_MULTITHREADED | D3DCREATE_FPU_PRESERVE,
&pp,
NULL,
&pDeviceEx));
UPDATE
wrapping CreateDeviceEx in a while loop until it does equal S_OK will eventually work... but what can cause this to happen in the first place?