-1

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 ?

Maverick
  • 1,105
  • 12
  • 41
  • 1
    Hungarian notation prefixes like `lp` were nice in the late 1980s, giving much needed hints to the help system in Microsoft's Programmer's Workbench console UI IDE. But consider: that's like 30 years back. Indeed, the `l` is short for `long`, a "long pointer", which is a concept that's meaningless in 32-bit and 64-bit C and C++ application programming. It gets just **ridiculous** when the `lp` prefix is used for something that decidedly is not a pointer, at all. – Cheers and hth. - Alf Feb 14 '16 at 11:25
  • I am still using Hungarian notation but yes I should agree with you about using long pointer notation for something that is not pointer at all but I think that this code snippet belongs to the Microsoft itself. Anyway I am not sure if simple or long pointers are meaningless in 32/64 bit system. I should make a refresh to my memory. – Maverick Feb 14 '16 at 18:10

1 Answers1

0

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( &params );
    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;
}
Cheers and hth. - Alf
  • 142,714
  • 15
  • 209
  • 331
  • Thanks for the answer. Any example of how to process window messages with WaitForSingleObject ? Does this mean that the paint message will go back to caller ? – Maverick Feb 14 '16 at 12:33
  • @Maverick: [MsgWaitForMultipleObjects](https://msdn.microsoft.com/en-us/library/windows/desktop/ms684242.aspx). – IInspectable Feb 14 '16 at 14:23
  • I tried the to disable the main window with the EnableWindow(FALSE). Returning from the program, I lose the focus of the mainwindow. Is there any solution for that? – Maverick Feb 15 '16 at 16:15
  • @Maverick: You might try out SetFocus, SetActiveWindow, SetForegroundWindow. Probably these functions exist. But if you want to leave the user in control then this is tricky. – Cheers and hth. - Alf Feb 15 '16 at 17:47
  • @Alf: I tried SetFocus, SetActiveWindow, SetForegroundWindow and BringWindowToTop, nothing seem to work.... I wonder why this window-thing its so mysterous when you need to build something simple ! – Maverick Feb 16 '16 at 15:10
  • @Maverick: Forgive me for asking, but have remembered to enable the window again after the program you launch, finishes? – Cheers and hth. - Alf Feb 16 '16 at 19:07
  • @Alf: Yes of course. I use EnableWindow(TRUE). Using the pair ShowWindow( SW_HIDE );ShowWindow( SW_SHOWMINNOACTIVE); it works but the parent window is minimized and i dont want that. – Maverick Feb 16 '16 at 19:16
  • Okay, I need to get my brain going again. I'll code up an API-level example. – Cheers and hth. - Alf Feb 16 '16 at 19:27