locked
ShellExecute interrupt the windows message loop? RRS feed

  • Question

  • void CtestfunDlg::OnBnClickedButton1() 
    { 
     // TODO: 在此添加控件通知处理程序代码
    
     OutputDebugString(L"start#############\r\n");
     ShellExecute(NULL ,L"open",L"e:/abc.txt",0,0,SW_SHOW);
     OutputDebugString(L"end#############\r\n");
    }

     When i quickly click the button ,i think the correct output is: start#########,end###########,start#########,end###########

    But the program actual output is start#########,start#########,end###########,end###########,why?

    Thursday, May 7, 2020 1:25 AM

Answers

  • Further to my previous comments the following call stack using the wnd_0301 sample code demonstrates how ShellExecute causes the window procedure to be reentered before it returns from handling WM_LBUTTONDOWN.

    wnd_0301!MainWndProc+0xe3
    USER32!_InternalCallWinProc+0x2b
    USER32!UserCallWinProcCheckWow+0x13e
    USER32!DispatchMessageWorker+0x1a1
    USER32!DispatchMessageW+0x10
    SHELL32!SHProcessMessagesUntilEventsEx+0x102
    SHELL32!CShellExecute::_RunThreadMaybeWait+0x83
    SHELL32!CShellExecute::ExecuteNormal+0xa8
    SHELL32!ShellExecuteNormal+0x47
    SHELL32!ShellExecuteExW+0x26
    SHELL32!ShellExecuteExA+0x5c
    SHELL32!ShellExecuteA+0x65
    wnd_0301!MainWndProc+0xbb
    USER32!_InternalCallWinProc+0x2b
    USER32!UserCallWinProcCheckWow+0x13e
    USER32!DispatchMessageWorker+0x1a1
    USER32!DispatchMessageA+0x10
    wnd_0301!WinMain+0x173
    wnd_0301!invoke_main+0x1e
    wnd_0301!__scrt_common_main_seh+0x150
    wnd_0301!__scrt_common_main+0xd
    wnd_0301!WinMainCRTStartup+0x8
    KERNEL32!BaseThreadInitThunk+0x24
    ntdll!__RtlUserThreadStart+0x2b
    ntdll!_RtlUserThreadStart+0x1b
    

    • Marked as answer by qiudm Tuesday, May 12, 2020 7:50 AM
    Saturday, May 9, 2020 1:06 PM
  • Hi qiudm,

    Thanks for your project.

    Unfortunately, I still cannot reproduce the problem. The finding after my research is consistent with the description of RLWA32.

    I suggest you add the SEE_MASK_ASYNCOK flag which mentioned by @RLWA32.

    Or you can try another api -> CreateProcess to see if the same problem. 

    Best regards,

    Strive


    MSDN Community Support
    Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com.


    Monday, May 11, 2020 9:59 AM
  • To be fair, besides SendMessage, it isn't as if Windows actually disallows re-entrant window procedures.

    For example, Windows allows DispatchMessage to be called during a window procedure.

    While we try to make sure that the window procedure is written in such a way that we avoid re-entrancy, it is not as if re-entrancy is impossible, especially when you call functions that pump messages inside a window procedure. Anything that uses COM can potentially pump messages, the default STA marshaller is built on the Windows message queue after all.


    This is a signature. Any samples given are not meant to have error checking or show best practices. They are meant to just illustrate a point. I may also give inefficient code or introduce some problems to discourage copy/paste coding. This is because the major point of my posts is to aid in the learning process.

    • Marked as answer by qiudm Tuesday, May 12, 2020 7:44 AM
    Monday, May 11, 2020 11:41 PM
  • Also, calling ShellExecuteEx and passing SEE_MASK_ASYNCOK seemed to avoid the problem of the window procedure being reentered -- presumably because a background thread was being used.
    • Marked as answer by qiudm Tuesday, May 12, 2020 7:45 AM
    Friday, May 8, 2020 6:58 PM

All replies

  • Hi qiudm,

    When i quickly click the button ,i think the correct output is: start#########,end###########,start#########,end###########

    But the program actual output is start#########,start#########,end###########,end###########,why?

    After my test, the program's acutal output is start#########,end###########,start#########,end###########.

    You can add Sleep function to test again.

    OutputDebugString(L"start#############\r\n");
    ShellExecute(NULL, L"open", L"e:/abc.txt", 0, 0, SW_SHOW);
    Sleep(100);
    OutputDebugString(L"end#############\r\n");

    Best regards,

    Strive


    MSDN Community Support
    Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com.


    Thursday, May 7, 2020 2:27 AM
  • Unless ShellExecute does its own message loop or does a "yield", this shouldn't happen.  How are you determining the "output"?  Are you watching this in the Visual Studio debugger?

    Tim Roberts | Driver MVP Emeritus | Providenza & Boekelheide, Inc.

    Thursday, May 7, 2020 6:38 AM
  • Yes,you can test in the  Visual Studio debugger.
    Friday, May 8, 2020 12:42 AM
  • I tested it early,Do you click fast enough,It needs to be like double clicking.
    Friday, May 8, 2020 12:48 AM
  • Hi Strive,
    I tested the Sleep function early,it is not effect .Do you click fast enough,
    It needs to be like double clicking and you must test in the CallBack WindowProc or MESSAGE_MAP functions for MFC.
    Friday, May 8, 2020 1:35 AM
  • Hi qiudm,

    It needs to be like double clicking and you must test in the CallBack WindowProc or MESSAGE_MAP functions for MFC.

    Yes, I has done this.

    But I still cannot reproduce your question.

    Can you share your computer operation system version and vs debugger version?

    If convenient, please provide some screenshots or video to illustrate the problem or some code that needs to be added.

    Best regards,

    Strive


    MSDN Community Support
    Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com.



    Friday, May 8, 2020 7:18 AM
  • Hi Strive,

    I uploaded a test project in GitHub,You can visit this website:https://github.com/qiuduming1981/QtCtrl/tree/master/wnd_0301.

    You can click on the window to test.

    My computer operation system version is Windows 10 Enterprise .

    The IDE is VS2015.

    Friday, May 8, 2020 8:47 AM
  • Instead of having ShellExecute use a handler to open a text file try using it to execute a program like notepad directly.

    In my experiment I found that the out-of-sequence mouse messages did not happen in this circumstance.

    Friday, May 8, 2020 12:45 PM
  • Also, the recommended way to handle things is to perform your action when receiving WM_LBUTTONUP.

    If you call ShellExecute in the WM_LBUTTONUP handler then mouse messages are processed in the expected sequence.

    Friday, May 8, 2020 1:31 PM
  • Also, calling ShellExecuteEx and passing SEE_MASK_ASYNCOK seemed to avoid the problem of the window procedure being reentered -- presumably because a background thread was being used.
    • Marked as answer by qiudm Tuesday, May 12, 2020 7:45 AM
    Friday, May 8, 2020 6:58 PM
  • Hi Strive,

    I sent you an email at msdnfsf@microsoft.com. It's my screen recording video for testing ShellExecute.


    Saturday, May 9, 2020 2:30 AM
  • Further to my previous comments the following call stack using the wnd_0301 sample code demonstrates how ShellExecute causes the window procedure to be reentered before it returns from handling WM_LBUTTONDOWN.

    wnd_0301!MainWndProc+0xe3
    USER32!_InternalCallWinProc+0x2b
    USER32!UserCallWinProcCheckWow+0x13e
    USER32!DispatchMessageWorker+0x1a1
    USER32!DispatchMessageW+0x10
    SHELL32!SHProcessMessagesUntilEventsEx+0x102
    SHELL32!CShellExecute::_RunThreadMaybeWait+0x83
    SHELL32!CShellExecute::ExecuteNormal+0xa8
    SHELL32!ShellExecuteNormal+0x47
    SHELL32!ShellExecuteExW+0x26
    SHELL32!ShellExecuteExA+0x5c
    SHELL32!ShellExecuteA+0x65
    wnd_0301!MainWndProc+0xbb
    USER32!_InternalCallWinProc+0x2b
    USER32!UserCallWinProcCheckWow+0x13e
    USER32!DispatchMessageWorker+0x1a1
    USER32!DispatchMessageA+0x10
    wnd_0301!WinMain+0x173
    wnd_0301!invoke_main+0x1e
    wnd_0301!__scrt_common_main_seh+0x150
    wnd_0301!__scrt_common_main+0xd
    wnd_0301!WinMainCRTStartup+0x8
    KERNEL32!BaseThreadInitThunk+0x24
    ntdll!__RtlUserThreadStart+0x2b
    ntdll!_RtlUserThreadStart+0x1b
    

    • Marked as answer by qiudm Tuesday, May 12, 2020 7:50 AM
    Saturday, May 9, 2020 1:06 PM
  • Hi qiudm,

    Thanks for your project.

    Unfortunately, I still cannot reproduce the problem. The finding after my research is consistent with the description of RLWA32.

    I suggest you add the SEE_MASK_ASYNCOK flag which mentioned by @RLWA32.

    Or you can try another api -> CreateProcess to see if the same problem. 

    Best regards,

    Strive


    MSDN Community Support
    Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com.


    Monday, May 11, 2020 9:59 AM
  • That's very interesting and, to my mind, unexpected.  In most circumstances, we expect Windows message handlers not to be re-entrant.

    Tim Roberts | Driver MVP Emeritus | Providenza & Boekelheide, Inc.

    Monday, May 11, 2020 5:12 PM
  • To be fair, besides SendMessage, it isn't as if Windows actually disallows re-entrant window procedures.

    For example, Windows allows DispatchMessage to be called during a window procedure.

    While we try to make sure that the window procedure is written in such a way that we avoid re-entrancy, it is not as if re-entrancy is impossible, especially when you call functions that pump messages inside a window procedure. Anything that uses COM can potentially pump messages, the default STA marshaller is built on the Windows message queue after all.


    This is a signature. Any samples given are not meant to have error checking or show best practices. They are meant to just illustrate a point. I may also give inefficient code or introduce some problems to discourage copy/paste coding. This is because the major point of my posts is to aid in the learning process.

    • Marked as answer by qiudm Tuesday, May 12, 2020 7:44 AM
    Monday, May 11, 2020 11:41 PM