Using the following code to update my application with an external exe file, I get paint corruption (not update or refresing) to window under -which is the main app and the caller- when I move this window. It seems that under Windows 7 works fine but under window XP I have this problem.
void CMainFrame::OnBtnUpdateApp() {
SHELLEXECUTEINFO lpExecInfo;
DWORD dwExitCode;
HINSTANCE hProcess = 0;
BOOL bResult;
ZeroMemory(&lpExecInfo,sizeof(lpExecInfo));
lpExecInfo.cbSize = sizeof(SHELLEXECUTEINFO);
lpExecInfo.fMask = SEE_MASK_NOCLOSEPROCESS;
lpExecInfo.hwnd = GetSafeHwnd();
lpExecInfo.lpVerb = _T("open");
lpExecInfo.lpFile = _T("Update.exe");
lpExecInfo.lpParameters = _T("");
lpExecInfo.lpDirectory = _T("");
lpExecInfo.nShow = SW_SHOWNORMAL;
lpExecInfo.hInstApp = NULL;
lpExecInfo.hProcess = hProcess;
bResult = ShellExecuteEx(&lpExecInfo);
if(bResult) {
WaitForSingleObject( lpExecInfo.hProcess, INFINITE );
if (!GetExitCodeProcess(lpExecInfo.hProcess, &dwExitCode)) {
//failed to terminate normally
}
CloseHandle(lpExecInfo.hProcess);
} else {
//failed to execute the exe file
}
}
What seems to be wrong here ?
You're not processing any window messages during WaitForSingleObject
.
Re the difference between Windows XP and Windows 7, the Desktop Window Manager technology in Windows 7 was introduced with Windows Vista, and was not available in Windows XP. Essentially it provides a layer of indirection between each app's painting actions and the result on screen.
A reasonable way to launch and wait for a program is to disable the main window the window's user interface parts and then poll the program's exit status in a peek-message loop.
Example, except that it uses CreateProcess
(I coded it up without remembering to check the question, and now it's pretty late in the evening, but better with imperfect help than no help, I think):
#include <windows.h> // UNICODE, NOMINMAX, STRICT, WIN32_LEAN_AND_MEAN
#include <windowsx.h> // Message cracker macros, e.g. HANDLE_WM_DESTROY
#include <assert.h>
#include <stdexcept>
#include <string>
using namespace std;
auto hopefully( bool const condition ) -> bool { return condition; }
auto fail( string const& s ) -> bool { throw runtime_error( s ); }
struct Window_class_id
{
ATOM value;
auto as_pointer() const -> wchar_t const* { return MAKEINTATOM( value ); }
};
auto get_message( MSG& m )
-> bool
{
int const result = GetMessage( &m, 0, 0, 0 );
hopefully( result != -1 )
|| fail( "GetMessage failed" );
return !!result;
}
auto peek_message( MSG& m )
-> bool
{
int const result = PeekMessage( &m, 0, 0, 0, TRUE );
hopefully( result != -1 )
|| fail( "PeekMessage failed" );
return !!result;
}
void empty_message_queue()
{
MSG m;
while( peek_message( m ) )
{
TranslateMessage( &m );
DispatchMessage( &m );
}
}
auto dispatch_messages()
-> DWORD // Exit code from WM_QUIT
{
MSG msg;
while( get_message( msg ) )
{
TranslateMessage( &msg );
DispatchMessage( &msg );
}
assert( msg.message == WM_QUIT );
return msg.wParam;
}
auto run( wchar_t const command[] )
-> HANDLE
{
wstring commandline = command;
hopefully( commandline.length() > 0 )
|| fail( "run: Empty command line" );
STARTUPINFO in_params = { sizeof( STARTUPINFO ) };
PROCESS_INFORMATION out_params = {};
bool const success = !!CreateProcess(
nullptr, // app name
&commandline[0],
nullptr, // process attributes
nullptr, // thread attributes
false, // inherit handles
0, // creation flags
nullptr, // environment block
nullptr, // current directory
&in_params, // startup info
&out_params // process info
);
hopefully( success )
|| fail( "run: CreateProcess failed" );
CloseHandle( out_params.hThread );
return out_params.hProcess;
}
namespace main_window
{
namespace command_id {
int const run_fun = 101;
} // namespace command
namespace run_button {
int const id = command_id::run_fun;
} // namespace run_button
namespace command {
void run_fun( HWND const window )
{
EnableWindow( GetDlgItem( window, run_button::id ), false );
UpdateWindow( window );
empty_message_queue();
HANDLE const process = run( L"notepad" );
for( ;; )
{
DWORD const result = WaitForSingleObject( process, 100 );
if( result == WAIT_OBJECT_0 )
{
break;
}
empty_message_queue();
}
CloseHandle( process );
EnableWindow( GetDlgItem( window, run_button::id ), true );
}
} // namespace command
void on_command( HWND const window, int const id )
{
switch( id )
{
case command_id::run_fun: return command::run_fun( window );
}
}
void on_wm_command(
HWND const window,
int const control_or_command_id,
HWND const control,
UINT const notification_code
)
{
if( control == 0 )
{
int const command_id = control_or_command_id;
on_command( window, command_id );
}
else
{
int const control_id = control_or_command_id;
switch( control_id )
{
case run_button::id:
if( notification_code == BN_CLICKED )
{
int const command_id = control_id;
on_command( window, command_id );
}
}
}
}
auto on_wm_create( HWND const window, CREATESTRUCT const* const p_params )
-> bool // `true` if creation succeeded.
{
(void) p_params;
HWND const button_handle = CreateWindow(
L"button", L"Run the fun", WS_CHILD | WS_VISIBLE,
10, 10, 120, 26,
window, // parent
reinterpret_cast<HMENU>( run_button::id ),
GetModuleHandle( 0 ),
0 // lpParam
);
return (button_handle != 0);
}
void on_wm_destroy( HWND const window )
{
(void) window;
PostQuitMessage( 0 );
}
auto CALLBACK message_handler(
HWND const window,
UINT const message_id,
WPARAM const word_param,
LPARAM const long_param
)
-> LRESULT
{
switch( message_id )
{
case WM_COMMAND: return HANDLE_WM_COMMAND(
window, word_param, long_param, on_wm_command );
case WM_CREATE: return HANDLE_WM_CREATE(
window, word_param, long_param, on_wm_create );
case WM_DESTROY: return HANDLE_WM_DESTROY(
window, word_param, long_param, on_wm_destroy );
}
return DefWindowProc( window, message_id, word_param, long_param );
}
} // namespace main_window
auto register_window_class()
-> Window_class_id
{
WNDCLASS params = {};
params.style = CS_DBLCLKS;
params.lpfnWndProc = main_window::message_handler;
params.hInstance = GetModuleHandle( 0 );
params.hIcon = LoadIcon( 0, IDI_APPLICATION );
params.hCursor = LoadCursor( 0, IDC_ARROW );
params.hbrBackground = reinterpret_cast<HBRUSH>( COLOR_WINDOW );
params.lpszClassName = L"MainWindow_class";
ATOM const id = RegisterClass( ¶ms );
hopefully( id != 0 )
|| fail( "RegisterClass failed" );
return {id};
}
auto create_window( Window_class_id const& class_id )
-> HWND
{
HWND const handle = CreateWindow(
class_id.as_pointer(),
L"Fun run",
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT, 380, 221, // x, y, w, h
0, 0, // parent, menu
GetModuleHandle( 0 ),
0 // lpParam
);
hopefully( handle != 0 )
|| fail( "CreateWindow failed" );
return handle;
}
void cpp_main()
{
Window_class_id const class_id = register_window_class();
HWND const window = create_window( class_id );
ShowWindow( window, SW_SHOWDEFAULT );
int const exit_code = static_cast<int>( dispatch_messages() );
hopefully( exit_code == 0 )
|| fail( "WM_QUIT indicated failure" );
}
auto main() -> int
{
try{ cpp_main(); } catch( ... ) { return E_FAIL; }
return 0;
}