Используя следующий код для обновления моего приложения внешним exe-файлом, я получаю повреждение краски (а не обновление или обновление) в окне, которое является основным приложением и вызывающей стороной, когда я перемещаю это окно. Кажется, что под Windows 7 работает нормально, но под Windows XP у меня есть эта проблема.
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
}}
Что здесь не так?
Вы не обрабатываете никаких оконных сообщений во время WaitForSingleObject
,
В отличие от Windows XP и Windows 7, Диспетчер окон рабочего стола Технология в Windows 7 была представлена в Windows Vista и не была доступна в Windows XP. По сути, он обеспечивает слой косвенности между действиями рисования каждого приложения и результатом на экране.
Разумный способ запуска и ожидания программы — отключить главное окно части пользовательского интерфейса окна, а затем опрашивают состояние завершения программы в цикле просмотра сообщений.
Пример, кроме того, что он использует CreateProcess
(Я закодировал его, не забывая проверить вопрос, и теперь уже довольно поздно вечером, но я думаю, что лучше с неполной помощью, чем без помощи):
#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;
}
Других решений пока нет …