The problem occurs when I try to play with one of the Rastertek DirectX 11 tutorials.
I changed the const bool fullscreen value to false so the program runs under window mode
I changed the window style from CLIPPINGWINDOW to OVERLAPPEDWINDOW
It works fine except that the program throws an exception when the window is destroyed:
Unhandled exception at 0x779715ee in FrustumCulling.exe: 0xC0000005: Access violation reading location 0xfeeeff5e.
it's tutorial 16 at http://www.rastertek.com/dx11tut16.html
The only modifications I made are:
In graphicsclass.h
const bool FULL_SCREEN = true //false;
and
SystemClass::InitializeWindows
{
...
m_hwnd = CreateWindowEx(WS_EX_APPWINDOW, m_applicationName, m_applicationName,
WS_OVERLAPPEDWINDOW,
posX, posY, screenWidth, screenHeight, NULL, NULL, m_hinstance, NULL);
...
}
Is it possible you're still setting up your swapchain in fullscreen mode?
When I was running into this issue, adding this to my DxClass' destructor solved it
if(_swapChain != nullptr)
{
_swapChain->SetFullscreenState(false, NULL);
_swapChain->Release();
_swapChain = nullptr;
}
As per one of the Rastertek comments in one of the tutorials, the swapchain has to have the fullscreen set to false prior to being released.
When you set up your DXGI_SWAP_CHAIN_DESC assure you are using swapChainDesc.Windowed = !FULL_SCREEN and not a literal bool value, and make sure you set FULL_SCREEN to false, FULL_SCREEN = true //false; wouldn't do that and shouldn't compile.
Related
I am writing a C++ Windows program that displays game stats/friends info over games using a Win32 window and a DirectX11 renderer. (that renders a UI that is controlled with the mouse and keyboard)
The window is overlaid on top of the game’s window and has the flags WS_EX_TRANSPARENT and WS_POPUP set.
When the window is activated, I set WS_EX_LAYERED to capture inputs.
The created window is positioned on top of the target window if GetWindow(target_, GW_HWNDPREV) is different from the handle of the created window.
It is placed on top of it by calling SetWindowPos with SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | SWP_ASYNCWINDOWPOS.
I’ve double-checked that the flags are set correctly and that the functions are being called.
I also tried using ShowWindow with the SW_SHOW flag, but the result remained unchanged.
I’m currently running my tests on Portal 2, but ideally, I would want this to work on the majority of games. (OS used is Windows 11 22H2)
To activate the window and release the mouse capture from the game, I am calling SetForegroundWindow, SetActiveWindow, and SetFocus, all with the HWND of my window.
This approach works correctly when I run the program from Visual Studio, but when I run the compiled executable, the mouse remains locked in the game.
Both builds were tested in debug and release mode, and I really can't figure out why this is happening.
LRESULT Renderer::WndProc(...) {
switch (message) {
case WM_SIZE:
// resize buffers and recreate render target view
return 0;
case WM_DESTROY:
PostQuitMessage(0);
return 0;
}
return DefWindowProc(handle, message, w_param, l_param);
}
bool Window::Create(...) {
// ...
hwnd_ = CreateWindowEx(
wndclass,
class_name_.c_str(),
title_.c_str(),
WS_POPUP,
0, 0, 10, 10,
nullptr,
nullptr,
nullptr,
nullptr
);
SetLayeredWindowAttributes(hwnd_, 0, 255, LWA_ALPHA);
UpdateWindow(hwnd_);
constexpr MARGINS margin = {-1, -1, -1, -1};
const auto result = DwmExtendFrameIntoClientArea(hwnd_, &margin);
// ...
}
void Window::Activate() {
// Remove the WS_EX_LAYERED attribute.
SetClickThrough(false);
SetForegroundWindow(hwnd_);
SetActiveWindow(hwnd_);
SetFocus(hwnd_);
}
// ----------------------
// Sample main routine pseudocode:
// ----------------------
renderer->window.Create(...);
while (renderer->is_running()) {
renderer->BeginFrame();
// Position the window on top of the game found.
renderer->window().FollowTarget();
// Toggle the visibility using the F2 key.
// If transitioning from hidden to visible, call the window
// activation routine.
if (utils::KeyPressed(VK_F2)) {
if (ui->is_visible()) {
// .. window deactivation not included
ui->set_visible(false);
}
else {
renderer->window().Activate();
ui->set_visible(true);
}
}
ui->Draw(renderer);
renderer->Present();
}
I considered using a low-level keyboard/mouse hook to capture inputs, or offscreen rendering and presenting it in the game using a DirectX hook, but I’d rather avoid it as it would require many games to manually whitelist it.
Is there something else I’m missing or a different approach I should be taking?
I am trying to create a swapchain from a dll.
My process creates a window, initializes Direct3D11 and loads the dll.
It works perfectly fine when the process creates a non fullscreen window.
But as soon as the process creates a fullscreen window I get an access violation when calling D3D11CreateDeviceAndSwapChain from the dll.
The call occurs in a separate thread. (not from the dllmain thread.)
Now unfortunately I can't even debug properly since breakpoints freeze the fullscreen window and it is on top of my debugger window.
What causes the access violation?
EDIT: I have done some static analysis of dxgi.dll and found that when creating the swapchain it checks for a series of extended and basic window styles. Also I noticed that it should print a debug message before crashing so I hooked up a remote debugger to capture it. The message just says what I already knew:
DXGI ERROR: IDXGIFactory::CreateSwapChain: The specified output window has a style that is incompatible with DXGI. Output windows must have at least one of:
WS_POPUP
WS_BORDER
WS_CAPTION
WS_SYSMENU
WS_MAXIMIZEBOX
WS_MINIMIZEBOX
WS_THICKFRAME
WS_EX_CLIENTEDGE
WS_EX_CONTEXTHELP
WS_EX_DLGMODALFRAME
WS_EX_TOOLWINDOW
WS_EX_WINDOWEDGE
or not have WS_EX_TOPMOST. [ MISCELLANEOUS ERROR #78: ]
The error code is: DXGI_ERROR_INVALID_CALL
So why does intializing direct3d work from my executable but using the window it creates in my dll doesn't?
EDIT2: Apparently calling D3D11CreateDeviceAndSwapChain with DXGI_SWAP_CHAIN_DESC::Windowed set to FALSE in the executable changes the window styles causing the next call to D3D11CreateDeviceAndSwapChain to fail.
CODE SNIPPET:
IDXGISwapChain* swapChain;
ID3D11Device* device;
ID3D11DeviceContext* deviceContext;
DXGI_SWAP_CHAIN_DESC desc;
ZeroMemory(&desc, sizeof(desc));
desc.BufferCount = 1;
desc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
desc.BufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED;
desc.BufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;
desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
desc.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH;
desc.OutputWindow = FindWindowW(L"Window Title", NULL);
desc.SampleDesc.Count = 1;
desc.Windowed = ((GetWindowLongPtr(desc.OutputWindow, GWL_STYLE) & WS_POPUP) != 0) ? false : true;
desc.BufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;
desc.BufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED;
desc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
desc.BufferDesc.Width = 1;
desc.BufferDesc.Height = 1;
desc.BufferDesc.RefreshRate.Numerator = 0;
desc.BufferDesc.RefreshRate.Denominator = 1;
if (!desc.OutputWindow)
{
return nullptr;
}
D3D_FEATURE_LEVEL featureLevel;
const D3D_FEATURE_LEVEL featureLevelArray[] = { D3D_FEATURE_LEVEL_11_0, D3D_FEATURE_LEVEL_10_1, };
if (FAILED(D3D11CreateDeviceAndSwapChain(NULL, D3D_DRIVER_TYPE_HARDWARE, NULL, D3D11_CREATE_DEVICE_DEBUG, featureLevelArray, ARRAYSIZE(featureLevelArray), D3D11_SDK_VERSION, &desc, &swapChain, &device, &featureLevel, &deviceContext)))
{
return nullptr;
}
Calling D3D11CreateDeviceAndSwapChain with DXGI_SWAP_CHAIN_DESC::Windowed set to FALSE in the executable changes the window styles causing the next call to D3D11CreateDeviceAndSwapChain to fail.
I have made single instance running Qt application (Qt version 5.11.1) in Visual Studio. Once it executed the first time, my main window will open and I am closing it. It keeps running in the background.
When I run .exe the second time, I want to open the previous mainWindow which I opened the first time.
I am enumerating available windows title and I am getting "Test Window" title. but using this HWND I am trying to set in the foreground on top of every other window using SetForegroundWindow(hwnd);.
BOOL CALLBACK EnumWindowsProc(HWND hwnd, LPARAM lParam)
{
if (IsWindowVisible(hwnd)) // check whether window is visible
{
char wnd_title[256];
GetWindowText(hwnd, wnd_title, sizeof(wnd_title));
MessageBox(0, wnd_title, "Installation Error", MB_OK | MB_ICONEXCLAMATION);
if (strcmp(wnd_title, "Test Window") == 0)
{
SetForegroundWindow(hwnd);
int err = GetLastError();
string msg = "error code " + std::to_string(err);
MessageBox(0, msg.c_str(),"Installation Error ", MB_OK | MB_ICONEXCLAMATION);
return false;
}
}
return true; // function must return true if you want to continue enumeration
}
How do I open on Qt MainWindow on top of all other windows when I run second time.
check out the project QtSingleApplication found in https://github.com/qtproject/qt-solutions.
In QtSingleApplication class there is a method named activateWindow. In the Loader Example this method gets called whenever a second instance of the program is run.
To make the main window go on top when you try to open a second instance you've got to modify this method like this.
void QtSingleApplication::activateWindow()
{
if (actWin) {
actWin->setWindowState(actWin->windowState() & ~Qt::WindowMinimized);
actWin->activateWindow();
actWin->raise();
//winapi call
SetWindowPos((HWND)actWin->winId() , HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
//hack to prevent sticking window to the fore
SetWindowPos((HWND)actWin->winId() , HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
}
}
Warning: this is a windows-only solution and it works on my machine. Be also sure to include windows.h in the implementation.
[edit] My code had the problem that once activated, window stayed to the fore. This hack sort of fixes it.
So I've got an OpenGL application running that can toggle between fullscreen mode and windowed mode. It currently does this by resizing the window and changing styles.
However, it seems to not invalidate the screen when switching from fullscreen mode to windowed mode, which leaves things I've drawn lingering onscreen after the switch.
Interestingly, it only exhibits this behavior in single monitor mode. If I'm running with multiple monitors, it invalidates okay, and clears my drawing.
I don't think this is a driver bug, as it's happening on two separate computers using two separate video cards(although admittedly they are both nVidia.), I'm thinking I'm doing something wrong somewhere.
I've tried a bunch of methods for getting Windows to clear the screen of my previously fullscreen drawings, but nothing seems to work. InvalidateRect(), RedrawWindow(), ChangeDisplaySettings()...
Specifically:
InvalidateRect(m_hwnd, &rectx, true); // rect being the dimensions of either the screen or my window.
InvalidateRect(HWND_DESKTOP, NULL, TRUE); // Doesn't seem to do anything.
RedrawWindow(NULL, NULL, NULL, RDW_INVALIDATE | RDW_ALLCHILDREN | RDW_UPDATENOW);
ChangeDisplaySettings(NULL, 0);
Well, actually, one thing that does seem to work is ShowWindow(hwnd, SW_HIDE) before resizing. However that loses focus for a moment, allowing other applications to grab my application's input, and seems a bad way to go about it.
I should note that I'm not doing any actual display mode changes when I'm seeing this behavior; just staying at the current resolution for fullscreen.
I'm a bit clueless where I'm going wrong. Simplified code:
if(m_isFullscreen)
{
ChangeDisplaySettings(&dmScreenSettings, CDS_FULLSCREEN);
}
else
{
ChangeDisplaySettings(&m_dmSavedScreenSettings, 0);
}
if(m_isFullscreen)
{
dwExStyle = WS_EX_APPWINDOW;
dwStyle = WS_POPUP;
ShowCursor(false);
}
else
{
dwExStyle = WS_EX_APPWINDOW | WS_EX_WINDOWEDGE;
dwStyle = WS_OVERLAPPEDWINDOW;
if(m_isRunning) // Because ShowCursor uses a counter to indicate, and windowed mode defaults to cursor on, we don't need to increment the counter and double it being on.
{
ShowCursor(true);
}
}
RECT rect;
rect.left = 0;
rect.top = 0;
if(m_isFullscreen) { rect.right = 1280; } else { rect.right = 640; }
if(m_isFullscreen) { rect.bottom = 1024; } else { rect.bottom = 480; }
AdjustWindowRectEx(&rect, dwStyle, false, dwExStyle);
SetWindowLongPtr(m_hwnd, GWL_STYLE, dwStyle | WS_CLIPCHILDREN | WS_CLIPSIBLINGS);
SetWindowLongPtr(m_hwnd, GWL_EXSTYLE, dwExStyle);
if(m_isFullscreen)
{
MoveWindow(m_hwnd, 0, 0, 1280, 1024, true);
}
else
{
MoveWindow(m_hwnd, 0, 0, 640, 480, true); // windowed
}
And that's more or less it. Some other supporting code and error checking, but that's what I'm doing... dmSavedSettings is saved before m_hwnd is assigned from NULL, and not afterwards. My initial window creation works fine, and fullscreen works fine. It's just returning to Windowed after being fullscreen that's the issue.
If you set a null background brush in your window class, windows will not be cleared automatically. You must add a WM_PAINT handler that calls your OpenGL display handler, which in turn clears the viewport (glClearColor) and redraws.
As datenwolf mentions in another answer's comment, you want to use SetWindowPos() instead of MoveWindow() when making use of SetWindowLongPtr().
My dirty background problems were solved by calling ChangeDisplaySettings(NULL, 0) AFTER resizing my window. Doing it before does little, but afterwards appears to work fine.
I am registering my Class in the following method:
BOOL CNDSClientDlg::InitInstance()
{
//Register Window Updated on 16th Nov 2010, #Subhen
// Register our unique class name that we wish to use
WNDCLASS wndcls;
memset(&wndcls, 0, sizeof(WNDCLASS));
wndcls.style = CS_DBLCLKS | CS_HREDRAW | CS_VREDRAW;
wndcls.lpfnWndProc = ::DefWindowProc;
wndcls.hInstance = AfxGetInstanceHandle();
wndcls.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
wndcls.lpszMenuName = NULL;
//Class name for using FindWindow later
wndcls.lpszClassName = _T("CNDSClientDlg");
// Register new class and exit if it fails
if(!AfxRegisterClass(&wndcls)) // [C]
{
return FALSE;
}
}
and then calling the InitInstance method and creating the window in constructor of the Class:
CNDSClientDlg::CNDSClientDlg(CWnd* pParent /*=NULL*/)
: CDialog(CNDSClientDlg::IDD, pParent)
{
InitInstance();
HWND hWnd;
hInst = AfxGetInstanceHandle(); // Store instance handle in our global variable
hWnd = CreateWindow(_T("CNDSClientDlg"), "NDS", WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInst, NULL);
}
Now in my other application I am finding the window and trying to bring to top:
Edit
Able to bring newlyCreated Windows with below code
CWnd *pWndPrev = NULL;
CWnd *FirstChildhWnd = NULL;
pWndPrev = CWnd::FindWindow(_T("CNDSClientDlg"),NULL);
if(pWndPrev != NULL)
{
//pWndPrev->BringWindowToTop();
WINDOWPLACEMENT wndplacement;
pWndPrev->GetWindowPlacement(&wndplacement);
wndplacement.showCmd = SW_RESTORE;
pWndPrev->SetWindowPlacement(&wndplacement);
pWndPrev->SetForegroundWindow();
FirstChildhWnd = pWndPrev->GetLastActivePopup();
if (pWndPrev != FirstChildhWnd)
{
// a pop-up window is active, bring it to the top too
FirstChildhWnd->GetWindowPlacement(&wndplacement);
wndplacement.showCmd = SW_RESTORE;
FirstChildhWnd->SetWindowPlacement(&wndplacement);
FirstChildhWnd->SetForegroundWindow();
}
I am able to find the window as pWndPrev is not NULL , but It is not bringing up my application to front. Do I need to register any other class Instead of CNDSClientDlg. I want to bring my MFC application to top.
A few things to look at...
1) Try SetForegroundWindow() instead of BringWindowToTop(). It's been awhile since I've done Win32 programming, but I seem to recall that BringWindowToTop() has some limitations (especially when working with windows in different processes).
2) There are some rules that Microsoft put in place regarding SetForegroundWindow() starting with Windows 2000. The short version is that only the front-most application can change the foreground window. The idea is that an application that is not front-most cannot "jump in front of" the active application. If a background application calls SetForegroundWindow(), Windows will flash the taskbar button for the app, but will not actually bring the app to the front. The user must do that. I'm oversimplifying the rules, but this may be something to look at depending on your specific scenario.
BringWindowToTop() only works if the calling process is the foreground process or if it received the last input event.
Call CWnd::SetForegroundWindow() instead.
You may need to call AllowSetForegroundWindow in your "other" application before calling SetForegroundWindow.
That is assuming your other application is the foreground app and is trying to pass on its foreground status to the application with the window.
If neither app is the foreground app then you're not supposed to be able to bring a window to the front, although there are ways to do it (both accidentally and on purpose).
SetWindowPos(&wndTopMost, -1, -1, -1, -1, SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW);
SetForegroundWindow();