Crash while cleaning DirectX application - c++

I have a DirectX application. It's very simple but I have a problem with it. I create device, device context etc. and everything is working but when I quit, a crash occurs and the error is: HEAP: Free Heap block 3ad7d18 modified at 3ad7d98 after it was freed. It occurs only if I call IDXGISwapChain Present function at least once. If I don't, then the whole cleaning process goes well. Moreover I call Release on every COM object and the crash ALWAYS occurs only when I release the last COM object (order doesn't matter). I use DirectX 11 (Win8 SDK) on Windows 7, MS Visual 2012.
My message loop function:
int Engine::run( ){
MSG msg = { 0 };
mTimeCounter->restart( ); // doesn't matter
while( msg.message != WM_QUIT ){
if( PeekMessage( &msg, 0, 0, 0, PM_REMOVE ) ){
TranslateMessage( &msg );
DispatchMessage( &msg );
} else {
updateScene( mTimeCounter->deltaTime( ) );
drawScene( );
}
}
return static_cast<int>( msg.wParam );
}
updateScene do nothing now and draw scene only call this two functions:
void Engine::sceneBegin( ){
static FLOAT color[] = { 0.05f, 0.15f, 0.05f, 1.0f };
mDeviceContext->ClearRenderTargetView( mBackBufferView, color );
mDeviceContext->ClearDepthStencilView( mDepthStencilView, D3D11_CLEAR_DEPTH | D3D11_CLEAR_STENCIL, 1, 0 );
}
void Engine::sceneEnd( ){
mSwapChain->Present( 0, 0 ); // crash do not occure if i comment this line of code
}
Part of messages switch:
case WM_QUIT : // i do not receive it even once because i press window's X button and it destroy window before i could receive WM_QUIT ( or not? :P )
{
DestroyWindow( mMainWnd );
}
break;
case WM_DESTROY : // i receive it if press window's X button
{
PostQuitMessage( 0 );
}
break;
return DefWindowProc( hWnd, msg, wParam, lParam );
Main function in which i initialize and start my engine:
EngTest *eng = new EngTest( );
eng->initialize( hInstance, L"Hi", show );
int r = eng->run( );
delete eng; // crash occures here but only if i call Present at least once.
Shutdown:
// called in Engine's destructor
void Engine::shutdown( ){
RELEASE_COM( mDepthStencilView );
RELEASE_COM( mDepthStencilBuffer );
RELEASE_COM( mBackBufferView );
RELEASE_COM( mSwapChain );
if( mDeviceContext )
mDeviceContext->ClearState( );
RELEASE_COM( mDeviceContext );
RELEASE_COM( mDevice );
}
RELEASE_COM
#define RELEASE_COM( x ) { if( x != NULL ) { x->Release( ); x = NULL; } }

Ok... That is really annoying. This code seems to be good and problem was in drivers or sth. When i installed new drivers and reboot PC twice then problem disappeared.

For what is worth it, this is how I fixed the exactly same issue. Occurred with just Clear() in render code and only when D3D11_CREATE_DEVICE_DEBUG was on (to add to the mystery):
case WM_CLOSE: // X clicked or Alt+F4
::DestroyWindow(hWnd); // triggers WM_DESTROY
break;
case WM_DESTROY:
gD3d11Context->ClearState();
PostQuitMessage(0); // this triggers the WM_QUIT to break the loop
break;
Plus I have my pointers wrapped in a custom ComPtr implementation. They are members of the class and self-destruct in reverse order of construction. So no ->Release() stacks :)

Related

Win32 Main Message Loop for OpenGL [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 6 years ago.
Improve this question
My main message loop in a Win32 OpenGL application looks like this:
// Inside wWinMain
bool bQuit = false;
while( bQuit == false )
{
DWORD dwReturn = ::MsgWaitForMultipleObjects( 0, NULL, FALSE, 12, QS_ALLINPUT );
if( dwReturn == WAIT_OBJECT_0 )
{
MSG msg;
BOOL bReturn = ::PeekMessage( &msg, NULL, 0, 0, PM_REMOVE );
if( bReturn != FALSE )
{
if( msg.message == WM_QUIT )
bQuit = true;
::TranslateMessage( &msg );
::DispatchMessage( &msg );
}
}
if( dwReturn == WAIT_OBJECT_0 || dwReturn == WAIT_TIMEOUT )
{
RenderFrame();
::SwapBuffers( hDc );
}
}
It works almost fine, I have only one problem: if I press Alt+F4 to close the window, it does not quit right after I release the key, however, if I hover the mouse over the window, it quits instantly.
A) Why is this? How should I modify my loop?
B) The original code I found did not use MsgWaitForMultipleObjects but called RenderFrame continuously. I think this way too much CPU time is wasted on redrawing the screen. Am I right? What is the usual way, do you spend all your excess capacity on drawing?
your error that you call PeekMessage only once per WAIT_OBJECT_0 but you need run it in loop while (::PeekMessage( &msg, NULL, 0, 0, PM_REMOVE )) because we can have several messages here. and better use MsgWaitForMultipleObjectsEx instead - try this code:
bool bQuit = false;
while( !bQuit )// for (;;)
{
MSG msg;
switch(::MsgWaitForMultipleObjectsEx( 0, NULL, 12, QS_ALLINPUT, 0))
{
case WAIT_OBJECT_0:
while (::PeekMessage( &msg, NULL, 0, 0, PM_REMOVE ))
{
if( msg.message == WM_QUIT )
bQuit = true;// return;
::TranslateMessage( &msg );
::DispatchMessage( &msg );
}
case WAIT_TIMEOUT:
RenderFrame();
::SwapBuffers( hDc );
}
}
if I press Alt+F4 to close the window, it does not quit right after I
release the key
several messages posted to your thread queue when you press Alt+F4, MsgWaitForMultipleObjects return, but you process not all it but only one
however, if I hover the mouse over the window, it quits instantly
new messages (WM_MOUSEMOVE) placed, but main MsgWaitForMultipleObjects again return and you at the end process all messages related to close process

Boost Thread inside class can't access member variables

I have a class being instantiated dynamically ( as the pointer is passed back and forth through a C interface ) that has a member boost thread. In a member function the following code is executed:
_thrd = boost::thread( boost::bind( &cls::thrdProc, this, other vars ) );
I know the following:
The thread was created
Because the thread procedure is a non-static member function of the same class "this" is passed as the first argument.
I've tried it with and without boost::bind.
Also in that class is a member variable of a queue I wrote. The thread procedure creates a hidden message window, a communications library is initialized, and as data is received the library sends a Windows message to the message procedure (which is in the thread). The message procedure dispatches the message to a static window procedure which redirects it to a member function of the same class with the thread. Messages are received and the thread procedure is entered. The problem is inside it the queue appears to not have been initialized ( actually all member variables of the class are invalid ). Thus, since the thread procedure and the main application code use a boost::mutex to guard the queue data after a moment ( depends on the number of packets received by the communications library ) I get a runtime error on a boost::lock_guard ( tried boost::scoped_lock too ). It's because the thread procedure calls _queue.push which tries to lock the mutex which is uninitialized so BOOST_VERIFY complains.
I've read several questions and examples that mention the thread copies arguments but the arguments aren't the issue. It seems like this is pointing to something else or wrapper class object doesn't exist. It does though and I can confirm the original pointer is valid.
Is there some other copy issue I'm not aware of?
Thanks in advance!
HEADER FILE
interface language_proxy
{
virtual int connectToQ( int * id ) = 0;
virtual int deconnectFromQ( int const id ) = 0;
virtual int startDataCollection() = 0;
virtual int stopDataCollection() = 0;
...
};
class CMyThread : public language_proxy
{
public:
CMyThread( com lib args );
int connectToQ( int * id );
int deconnectFromQ( int const id );
int startDataCollection();
int stopDataCollection();
...
protected:
boost::mutex _mutex;
CMyQueue _queue;
boost::thread _thrd;
...
uint thrdProc( com lib args );
};
EXECUTABLE FILE(S)
int CMyThread::startDataCollection()
{
// guard against multiple starts
if( boost::thread:id() == _thrd.get_id() )
{
_thrd = boost::thread( boost::bind( &CMyThread::thrdProc, this, member vars for com lib ) );
}
}
uint CMyThread::thrdProc( com lib args )
{
// create hidden messaging window
WNDCLASSEX wc = { 0 };
// many parameters can be ignored since window will be hidden
wc.cbSize = sizeof( WNDCLASSEX );
wc.lpszClassName = MSG_WND_CLS;
wc.lpfnWndProc = &CMyThread::StaticWndProc;
wc.hInstance = GetModuleHandle( 0 );
// register the class with Windows
RegisterClassEx( &wc );
// create a window based on the above class parameters
_msg_hwnd = CreateWindowEx
(
0,
wc.lpszClassName,
L"HiddenMessageWindow",
0,
CW_USEDEFAULT,
CW_USEDEFAULT,
0,
0,
HWND_MESSAGE,
0,
0,
this
);
// initialize com lib
// process windows messages
while( true )
{
// process available messages
if( PeekMessage( &msg, _msg_hwnd, 0, 0, PM_REMOVE ) )
{
// break out of the loop if the quit message is found
if( WM_QUIT == msg.message )
{
printf( "Quit message found\n" );
break;
}
TranslateMessage( &msg );
DispatchMessage( &msg );
}
else
{
// throws boost::thread_interrupted if the thread has been interrupted
boost::this_thread::sleep_for( boost::chrono::milliseconds( _msg_loop_dly ) );
}
}
UnregisterClass( MSG_WND_CLS, GetModuleHandle( 0 ) );
}
LRESULT CALLBACK CMyThread::StaticWndProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
{
CMyThread * pWnd = 0;
try
{
// store class pointer for window being created
if( WM_NCCREATE == uMsg )
{
// use SetWindowLongPtr to be 64-bit compatible ( a class pointer will be 64 bits and a long is only 32 bits )
pWnd = ( CMyThread * )( ( LPCREATESTRUCT )lParam )->lpCreateParams;
SetWindowLongPtr( hWnd, GWLP_USERDATA, *reinterpret_cast< LONG_PTR * >( pWnd ) );
}
// access the class pointer
else
{
pWnd = ( CMyThread * )GetWindowLong( hWnd, GWL_USERDATA );
}
// if a class pointer for the window exists, call its procedure
if( pWnd )
{
return( pWnd->WndProc( hWnd, uMsg, wParam, lParam ) );
}
}
catch( ... )
{
int x = 5;
}
// call the default window procedure
return( DefWindowProc( hWnd, uMsg, wParam, lParam ) );
}
LRESULT CALLBACK CMyThread::WndProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
{
switch( uMsg )
{
// when a request to close the window is received, destroy the window
case WM_CLOSE:
{
DestroyWindow( hWnd );
} break;
// when a window is destroyed put a quit message in the queue to stop message processing
case WM_DESTROY:
{
PostQuitMessage( 0 );
} break;
// handle messages from com library
case UWM_RX_COM_LIB_MSG:
{
// use GetWindowLongPtr to be 64-bit compatible ( a class pointer will be 64 bits and a long is only 32 bits )
LONG_PTR lPtr = GetWindowLongPtr( hWnd, GWLP_USERDATA );
CMyThread * pWnd = reinterpret_cast< CMyThread * >( &lPtr );
pWnd->onRx();
} break;
// handle all other cases by default behaviour
default:
{
return( DefWindowProc( hWnd, uMsg, wParam, lParam ) );
}
}
return( 0 );
}
void CMyThread::onRx()
{
// extract packet(s) from com library
// add packet(s) to vector
// THIS QUEUE IS UNINITIALIZED!
_queue.push( pkts );
}
int C_Interface_create
(
com lib arguments,
language_proxy ** p
)
{
// instantiate the C++ object through the C interface
language_proxy * tmp_p = new CMyThread( com lib args );
if( tmp_p )
{
*p = tmp_p;
}
return( 0 );
}
int C_Interface_start_thread( language_proxy * p )
{
p->startDataCollection();
return( 0 );
}
// actually in a DLL but so you have some idea of what the operation flow is
void main()
{
static language_proxy * s_proxy = 0;
C_Interface_create( 1, 2, 3, &s_proxy );
c_Interface_start_thread( s_proxy );
// for debugging, endless loop to allow rx'd packets to be processed and guarantee
// s_proxy is still alive
while( 1 );
}
It was difficult to tell what your question actually was here, and there is not enough code to be sure, but judging from this:
The problem is inside it the queue [passed to the thread function by pointer] appears to not have been initialized
One possible reason for this (again, I'm guessing as I have nothing to go on), is that the this pointer you're passing to the thread is actually a pointer to a locally-instantiated automatic variable which subsequently is destroyed before your thread starts up.
For example:
void MyQueue::startTheThread()
{
_thrd = boost::thread( boost::bind( &cls::thrdProc, this, other vars ) );
}
int someFreeFunction()
{
MyQueue q;
q.startTheThread();
}
would replicate the behavior I describe. Note that what your'e actually seeing is Undefined Behavior, so anything could happen.

How can I render multiple windows with DirectX 9 in C?

I've already asked this question at https://gamedev.stackexchange.com/questions/50374/how-can-i-render-multiple-windows-with-directx-9-in-c but I have not yet received an answer.
I'm trying to render multiple windows, using DirectX 9 and swap chains, but even though I create 2 windows, I only see the first one that I've created. My RendererDX9 header is this:
#include <d3d9.h>
#include <Windows.h>
#include <vector>
#include "RAT_Renderer.h"
namespace RAT_ENGINE
{
class RAT_RendererDX9 : public RAT_Renderer
{
public:
RAT_RendererDX9();
~RAT_RendererDX9();
void Init(RAT_WindowManager* argWMan);
void CleanUp();
void ShowWin();
private:
LPDIRECT3D9 renderInterface; // Used to create the D3DDevice
LPDIRECT3DDEVICE9 renderDevice; // Our rendering device
LPDIRECT3DSWAPCHAIN9* swapChain; // Swapchain to make multi-window rendering possible
WNDCLASSEX wc;
std::vector<HWND> hwindows;
void Render(int argI);
};
}
And my .cpp file is this:
#include "RAT_RendererDX9.h"
static LRESULT CALLBACK MsgProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam );
namespace RAT_ENGINE
{
RAT_RendererDX9::RAT_RendererDX9() : renderInterface(NULL), renderDevice(NULL)
{
}
RAT_RendererDX9::~RAT_RendererDX9()
{
}
void RAT_RendererDX9::Init(RAT_WindowManager* argWMan)
{
wMan = argWMan;
// Register the window class
WNDCLASSEX windowClass =
{
sizeof( WNDCLASSEX ), CS_CLASSDC, MsgProc, 0, 0,
GetModuleHandle( NULL ), NULL, NULL, NULL, NULL,
"foo", NULL
};
wc = windowClass;
RegisterClassEx( &wc );
for (int i = 0; i< wMan->getWindows().size(); ++i)
{
HWND hWnd = CreateWindow( "foo", argWMan->getWindow(i)->getName().c_str(),
WS_OVERLAPPEDWINDOW, argWMan->getWindow(i)->getX(), argWMan->getWindow(i)->getY(),
argWMan->getWindow(i)->getWidth(), argWMan->getWindow(i)->getHeight(),
NULL, NULL, wc.hInstance, NULL );
hwindows.push_back(hWnd);
}
// Create the D3D object, which is needed to create the D3DDevice.
renderInterface = (LPDIRECT3D9)Direct3DCreate9( D3D_SDK_VERSION );
// Set up the structure used to create the D3DDevice. Most parameters are
// zeroed out. We set Windowed to TRUE, since we want to do D3D in a
// window, and then set the SwapEffect to "discard", which is the most
// efficient method of presenting the back buffer to the display. And
// we request a back buffer format that matches the current desktop display
// format.
D3DPRESENT_PARAMETERS deviceConfig;
ZeroMemory( &deviceConfig, sizeof( deviceConfig ) );
deviceConfig.Windowed = TRUE;
deviceConfig.SwapEffect = D3DSWAPEFFECT_DISCARD;
deviceConfig.BackBufferFormat = D3DFMT_UNKNOWN;
deviceConfig.BackBufferHeight = 1024;
deviceConfig.BackBufferWidth = 768;
deviceConfig.EnableAutoDepthStencil = TRUE;
deviceConfig.AutoDepthStencilFormat = D3DFMT_D16;
// Create the Direct3D device. Here we are using the default adapter (most
// systems only have one, unless they have multiple graphics hardware cards
// installed) and requesting the HAL (which is saying we want the hardware
// device rather than a software one). Software vertex processing is
// specified since we know it will work on all cards. On cards that support
// hardware vertex processing, though, we would see a big performance gain
// by specifying hardware vertex processing.
renderInterface->CreateDevice( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hwindows[0],
D3DCREATE_SOFTWARE_VERTEXPROCESSING,
&deviceConfig, &renderDevice );
this->swapChain = new LPDIRECT3DSWAPCHAIN9[wMan->getWindows().size()];
this->renderDevice->GetSwapChain(0, &swapChain[0]);
for (int i = 0; i < wMan->getWindows().size(); ++i)
{
renderDevice->CreateAdditionalSwapChain(&deviceConfig, &swapChain[i]);
}
renderDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_CCW); // Set cullmode to counterclockwise culling to save resources
renderDevice->SetRenderState(D3DRS_AMBIENT, 0xffffffff); // Turn on ambient lighting
renderDevice->SetRenderState(D3DRS_ZENABLE, TRUE); // Turn on the zbuffer
}
void RAT_RendererDX9::CleanUp()
{
renderDevice->Release();
renderInterface->Release();
}
void RAT_RendererDX9::Render(int argI)
{
// Clear the backbuffer to a blue color
renderDevice->Clear( 0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB( 0, 0, 255 ), 1.0f, 0 );
LPDIRECT3DSURFACE9 backBuffer = NULL;
// Set draw target
this->swapChain[argI]->GetBackBuffer(0, D3DBACKBUFFER_TYPE_MONO, &backBuffer);
this->renderDevice->SetRenderTarget(0, backBuffer);
// Begin the scene
renderDevice->BeginScene();
// End the scene
renderDevice->EndScene();
swapChain[argI]->Present(NULL, NULL, hwindows[argI], NULL, 0);
}
void RAT_RendererDX9::ShowWin()
{
for (int i = 0; i < wMan->getWindows().size(); ++i)
{
ShowWindow( hwindows[i], SW_SHOWDEFAULT );
UpdateWindow( hwindows[i] );
// Enter the message loop
MSG msg;
while( GetMessage( &msg, NULL, 0, 0 ) )
{
if (PeekMessage( &msg, NULL, 0U, 0U, PM_REMOVE ) )
{
TranslateMessage( &msg );
DispatchMessage( &msg );
}
else
{
Render(i);
}
}
}
}
}
LRESULT CALLBACK MsgProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam )
{
switch( msg )
{
case WM_DESTROY:
//CleanUp();
PostQuitMessage( 0 );
return 0;
case WM_PAINT:
//Render();
ValidateRect( hWnd, NULL );
return 0;
}
return DefWindowProc( hWnd, msg, wParam, lParam );
}
I've made a sample function to make multiple windows:
void RunSample1()
{
//Create the window manager.
RAT_ENGINE::RAT_WindowManager* wMan = new RAT_ENGINE::RAT_WindowManager();
//Create the render manager.
RAT_ENGINE::RAT_RenderManager* rMan = new RAT_ENGINE::RAT_RenderManager();
//Create a window.
//This is currently needed to initialize the render manager and create a renderer.
wMan->CreateRATWindow("Sample 1 - 1", 10, 20, 640, 480);
wMan->CreateRATWindow("Sample 1 - 2", 150, 100, 480, 640);
//Initialize the render manager.
rMan->Init(wMan);
//Show the window.
rMan->getRenderer()->ShowWin();
}
How do I get the multiple windows to work?
The "Swap Chain" approach you used for rendering the multiple windows is sounds good compare to creating multiple devices for multiple screens.
Have you checked the codesampler tutorial for rendering the multiple windows using swap chain. If not, pls find the below link which has a working sample project for rendering the multiple windows using swap chain. This code is purely windows Directx 9 specific but you could added your wrapper to achieve platform agnostic.
Creating Multiple Devices
Using Swap Chain
http://www.codesampler.com/dx9src/dx9src_1.htm

Trouble Closing Message-Only Window - C++

My application has a message-only window that is launched from a newly created thread. The thread function creates the message-only window and runs the message pump. The problem I am having is that the message pump never seems to get the WM_CLOSE message. I've removed error-handling to simplify the posted code. Does anyone know what I'm doing wrong?
Constructor:
this->m_hInstance = ::GetModuleHandle( NULL );
this->m_wcx.cbSize = sizeof(WNDCLASSEX); // size of structure
this->m_wcx.style = CS_HREDRAW | CS_VREDRAW; // initially minimized
this->m_wcx.lpfnWndProc = &WndProc; // points to window procedure
this->m_wcx.cbClsExtra = 0; // no extra class memory
this->m_wcx.cbWndExtra = 0; // no extra window memory
this->m_wcx.hInstance = m_hInstance; // handle to instance
this->m_wcx.hIcon = ::LoadIcon( NULL, IDI_APPLICATION ); // default app icon
this->m_wcx.hCursor = ::LoadCursor( NULL, IDC_ARROW ); // standard arrow cursor
this->m_wcx.hbrBackground = NULL; // no background to paint
this->m_wcx.lpszMenuName = NULL; // no menu resource
this->m_wcx.lpszClassName = s_pwcWindowClass; // name of window class
this->m_wcx.hIconSm = NULL; // search system resources for sm icon
this->m_atom = ::RegisterClassEx( &m_wcx );
this->m_hNotifyWindowThread = ::CreateThread(
NULL, // no security attributes
0, // use default initial stack size
reinterpret_cast<LPTHREAD_START_ROUTINE>(NotifyWindowThreadFn), // function to execute in new thread
NULL, // thread parameters
0, // use default creation settings
NULL // thread ID is not needed
);
Destructor:
::DestroyWindow( this->m_hWnd );
::WaitForSingleObject( this->m_hNotifyWindowThread, NW_DEFAULT_TIMEOUT ); // <-- Seems to get stuck here.
::UnregisterClass( s_pwcWindowClass, this->m_hInstance );
Thread function:
s_ptInterface->pobjNotifyWindow->m_hWnd = ::CreateWindow(
s_pwcWindowClass, // window class name
s_pwcWindowName, // window name
WS_ICONIC, // window style is minimized
0, // initial horizontal position
0, // initial vertical position
CW_USEDEFAULT, // window width
0, // window height
NULL, // no parent window
NULL, // no menu
s_ptInterface->pobjNotifyWindow->GetInstanceHandle(), // associated instance
NULL // no additional info for WM_CREATE
);
::ShowWindow( s_ptInterface->pobjNotifyWindow->GetWindowHandle(), SW_HIDE );
::UpdateWindow( s_ptInterface->pobjNotifyWindow->GetWindowHandle();
dbt.dbcc_size = sizeof(DEV_BROADCAST_DEVICEINTERFACE);
dbt.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE;
dbt.dbcc_classguid = s_guidForCP210xDevices;
m_hNotify = RegisterDeviceNotification( m_hWnd, &dbt, DEVICE_NOTIFY_WINDOW_HANDLE );
while ( (blRetVal = ::GetMessage(
&msg, // message structure
NULL, // retrieve messages for all windows on this thread
0, // lowest message value to retrieve
0 // highest message value to retrieve
)) != 0 )
{
if ( blRetVal == -1 )
{
return ::GetLastError();
}
else
{
::TranslateMessage( &msg );
::DispatchMessage( &msg );
}
}
Window procedure:
switch ( uMsg )
{
case WM_CLOSE:
if ( m_hNotify != NULL )
{
::UnregisterDeviceNotification( m_hNotify );
m_hNotify = NULL;
}
::DestroyWindow( hWnd );
break;
case WM_DESTROY:
::PostQuitMessage( 0 );
break;
case WM_DEVICECHANGE:
if ( pHeader != NULL )
{
if ( pHeader->dbch_devicetype == DBT_DEVTYP_PORT )
{
switch ( wParam)
{
case DBT_DEVICEREMOVECOMPLETE: // Device is gone
::EnterCriticalSection( &(s_ptInterface->csSerialPort) );
s_ptInterface->pobjSerialPort->Close();
::LeaveCriticalSection( &(s_ptInterface->csSerialPort) );
break;
case DBT_DEVICEARRIVAL: // System detected device
::EnterCriticalSection( &(s_ptInterface->csSerialPort) );
s_ptInterface->pobjSerialPort->Open();
::LeaveCriticalSection( &(s_ptInterface->csSerialPort) );
break;
default:
// Do nothing.
break;
}
}
}
break;
default:
// Do nothing.
break;
}
return ::DefWindowProc( hWnd, uMsg, wParam, lParam );
WM_CLOSE is sent when Windows asks your app to close the window. When the user clicks the upper right Close button or presses Alt+F4 for example. None of that is going to happen, you called DestroyWindow(). You need to use WM_DESTROY instead. Which is fine, no need to veto the close request.

Closing Window and Thread Generates Invalid Window Handle Error - C++

My console application spawns a new (invisible) window in its own thread. Prior to exiting the application, it attempts to clean up, and the last call to GetMessage in the window's message pump fails. GetLastError returns 1400, "Invalid window handle."
This is how the clean up proceeds in the application thread:
if ( s_hNotifyWindowThread != NULL )
{
ASSERT(s_pobjNotifyWindow != NULL);
::PostMessage( s_pobjNotifyWindow->m_hWnd, WM_CLOSE, 0, 0 );
::WaitForSingleObject( s_hNotifyWindowThread, 50000L ); // Step 1: breakpoint here
::CloseHandle( s_hNotifyWindowThread ); // Step 4: breakpoint here
s_hNotifyWindowThread = NULL;
}
This WndProc exists in the new thread created for the window:
static LRESULT CALLBACK WndProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
{
switch ( uMsg )
{
case WM_CLOSE:
::DestroyWindow( hWnd ); // Step 2: breakpoint here
break;
case WM_DESTROY:
::PostQuitMessage( 0 ); // Step 3: breakpoint here
break;
case WM_DEVICECHANGE:
/* Handle device change. */
break;
default:
// Do nothing.
break;
}
return ::DefWindowProc( hWnd, uMsg, wParam, lParam );
}
This is in the window's thread function where the new window is created and my message pump is located:
s_pobjNotifyWindow = new CNotifyWindow( pParam );
while ( (bRetVal = ::GetMessage(
&msg, // message structure
s_pobjNotifyWindow->m_hWnd, // handle to window whose messages are to be retrieved
0, // lowest message value to retrieve
0 // highest message value to retrieve
)) != 0 )
{
switch ( bRetVal )
{
case -1: // Error generated in GetMessage.
TRACE(_T("NotifyWindowThreadFn : Failed to get notify window message.\r\n\tError: %d\r\n\tFile: %s\r\n\tLine: %d\r\n"), ::GetLastError(), __WFILE__, __LINE__);
return ::GetLastError(); // Step 5: breakpoint here: Returns error 1400
break;
default: // Other message received.
::TranslateMessage( &msg );
::DispatchMessage( &msg );
break;
}
}
What am I doing wrong? Thanks.
You are passing an invalid window handle to GetMessage, which is why it's failing and reporting that a window handle is invalid.
You'll see the same error if you run this code with a made-up window handle:
MSG msg = {0};
BOOL b = ::GetMessage(&msg, (HWND)(0x123000), 0, 0);
if (b == -1)
{
DWORD dwErr = ::GetLastError();
wprintf(L"%lu\n", dwErr);
}
The problem is that you are still using the window handle after the window has been destroyed. As soon as a window is destroyed its handle is invalid (or, worse, re-used by some other window). The message pump won't exit until it processes the quit-message. Since the quit-message is posted during window destruction it will be processed after window destruction is complete. i.e. Your message pump keeps running for a short time after your window is destroyed.
Just pass NULL to GetMessage for the window argument, so that it retrieves messages for all windows on that thread. Since the thread only exists for that one window it's only going to get messages for that window anyway. (Plus the quit-message posted to the thread itself, and potentially messages for other windows which things like COM creates if you use COM on that thread... You'd definitely want to process those messages, so telling GetMessage to filter by window is doing nothing at best and could prevent something from working at worst, in addition to the error you're seeing GetMessage return.)