zoukankan      html  css  js  c++  java
  • ShellExecuteEX打开iqy文件导致excel hang的原因分析

    1. 问题

    当在console中调用API ShellExecuteEx打开"test.iqy"文件时,发现excel会hang住,console退出后excel才会响应,但直接双击"test.iqy"是没有问题的,有意思的是这个情况只有在xp发生,在win7上没有这个问题。

    2. 重现步骤

    重现环境:XP sp3 / Office 2007(其他office版本应该也可以,没有测试)

    https://files.cnblogs.com/files/organic/iqy_test.zip

    1> 解压iqy_test.zip

    2> 运行http_server.py(需先安装python)

    3> 执行"shell_execute.exe test.iqy"

    shell_execute.exe的主要code:

    bool shell_execute_file(wstring file_path)
    {
        SHELLEXECUTEINFOW shell_exec_info = { 0 };
        shell_exec_info.cbSize = sizeof(SHELLEXECUTEINFOW);
        shell_exec_info.fMask = SEE_MASK_NOCLOSEPROCESS | SEE_MASK_FLAG_NO_UI;
        shell_exec_info.hwnd = NULL;
        shell_exec_info.lpVerb = NULL;
        shell_exec_info.lpFile = file_path.c_str();
        shell_exec_info.lpParameters = NULL;
        shell_exec_info.lpDirectory = NULL;
        shell_exec_info.nShow = SW_SHOW;
        shell_exec_info.hInstApp = NULL;
        bool ret = ShellExecuteExW(&shell_exec_info);
        printf("process handle is %p
    ", shell_exec_info.hProcess);
    
        return ret;
    }

    3. 原因分析

    3.1 excel hang在哪里?

    3.1.1 用windbg附加到excel上,输入如下命令查看主线程hang住的地方

    Image

    可以看到Excel hang在NtUserMessageCall()中,经过查询知,SendMessage()内部就是调用NtUserMessageCall()来发送消息的。

    查看参数知excel调用NtUserMessageCall()类似如下:

    NtUserMessageCall(HWND_BROADCAST, WM_DDE_INITIATE)

    说明excel给所有顶层窗口发送一个WM_DDE_INITIATE消息,但是有窗口没有response

    由此可以怀疑是由于console进程在和excel用DDE消息通信时,console没有响应excel发送的DDE消息,导致excel hang住

    3.2 为了验证3.1.1的猜想,用API Monitor一下ShellExecuteEx

    3.2.1 根据微软的文档可知,发送DDE消息除了WM_DDE_INITIATE和WM_DDE_ACK之外用的都是PostMessage

    https://msdn.microsoft.com/en-us/library/windows/desktop/ff468829(v=vs.85).aspx

    在API Monitor中搜索一下PostMessage的调用,果然搜到一条

    Image(1)

    call stack显示确实是ShellExecuteEx所调用

    Image(2)

    消息1000为WM_DDE_EXECUTE,Post窗口句柄为0x00310172。

    注意到下一个API GetWindowThreadProcessId ( 0x00310172 , 0x0012fb70 ),刚好是获取这个窗口的pid和tid,查看下参数窗口:

    这个窗口所属的进程PID = 0xc54,正好是excel的进程,说明ShellExecuteEx确实发送了DDE消息给excel,而且可执发送的消息的thread就是主线程

    Image(3)

    根据DDE的消息参数,可知wParam就是发送消息的窗口,其句柄为2425190 = 0x250166,反向查询知这是ShellExecuteEx创建的”WorkerW”窗口

    Image(4)

    Image(5)

    3.2.2 为了验证3.2.1的结论,在PostMessageW上下断点跟踪一下

    Image(6)

    查看一下buff的地址:

    Image(7)

    刚好就是打开test.iqy的命令,说明ShellExecuteEx就是先创建了excel的进程,然后发送test.iqy的文件命令给excel打开。

    3.3 总结

    1> ShellExecuteEx打开test.iqy的时先创建excel进程

    2> 然后创建一个"WorkerW"的窗口用于DDE通信

    3> Post WM_DDE_EXECUTE给excel,告知打开test.iqy的命令

    4> ShellExecuteEx执行结束,但并不destroy "WorkerW"窗口

    5> excel收到WM_DDE_EXECUTE消息后会广播WM_DDE_INITIATE消息,"WorkerW"窗口所在的console进程由于没有定义消息处理函数,ShellExecuteEx定义的"WorkerW"窗口消息处理函数得不到CPU执行机会,导致不会response该消息,从而导致excel hang住

    类似,我们可以创建一个带窗口的程序,启动后将其挂起,这时,即使直接双击打开test.iqy也会hang住。

    4. 为什么双击打开excel不会hang住

    因为双击打开实际是用explorer.exe打开,而explorer.exe是有窗口的,能够正常的接收处理WM_DDE_INITIATE消息

    5. 为什么win7上不会有这样的问题

    5.1 在API Monitor中看下PostMessageW

    Image(8)

    注意到win7下PostMessageW是用的线程2调用的,搜一下线程创建API CreateThread

    Image(9)

    可知是ShellExecuteEx内部创建的线程,所以win7上ShellExecuteEx创建了一个线程专门用来处理和excel的DDE消息通信,这样就能正常的接收处理excel发过来的WM_DDE_INITIATE消息了

  • 相关阅读:
    得到相对Plugin的路径
    GEF常见问题4:非矩形图元
    在Eclipse的About对话框上添加自己的图标
    用GMF生成简化的数据库设计器
    全超实用的Javascript类库和jQuery插件大全之一:图片,地图和图形
    #敏捷个人# 第二批敏捷个人推广者实践团报名
    2012年最新的12款超棒jQuery插件
    《敏捷个人》周刊 第14期 (可下载)
    时间管理:敏捷个人时中法卡片
    #敏捷个人# 实践团报名
  • 原文地址:https://www.cnblogs.com/organic/p/9175276.html
Copyright © 2011-2022 走看看