ShellExecuteEX张开iqy文件导致excel hang的缘故分析

1. 问题

1. 窗口进程 
每一种窗口会有多少个堪当窗口进程的回调函数(WndProc),它包涵三个参数,分别为:窗口句柄(Window Handle),新闻ID(Message ID),和四个音讯参数(wParam, lParam),当窗口收到音信时系统就能调用此窗口进程来拍卖消息。(所以叫回调函数)

当在console中调用API ShellExecuteEx张开"test.iqy"文件时,开采excel会hang住,console退出后excel才会响应,但一向双击"test.iqy"是绝非难点的,风趣的是以此情形唯有在xp发生,在win7上未曾这一个主题素材。

2 音讯类型 
1) 系统定义新闻(System-Defined Messages)
 
在SDK中优先定义好的信息,非客商定义的,其范围在[0x0000, 0x03ff]里头, 能够分成以下三类:
1>窗口音信(Windows Message) 
与窗口的里边运行有关,如创造窗口,绘制窗口,销毁窗口等。可以是形似的窗口,也得以是Dialog,控件等。
如:WM_CREATE, WM_PAINT, WM_MOUSEMOVE, WM_CTLCOLOR, WM_HSCROLL...
2>命令音讯(Command Message):注意那类音讯通称为WM_COMMAND
与处理客户诉求有关, 如单击菜单项或工具栏或控件时, 就能生出命令音信。
WM_COMMAND, LOWORAV4D(wParam)表示菜单项,工具栏按键或控件的ID。借使是控件, HIWOSportageD(wParam)表示控件音信类型
3> 控件公告(Notify Message) 
控件文告音信, 那是最灵敏的音信格式, 其Message, wParam, lParam分别为:WM_NOTIFY, 控件ID,指向NMHDSportage的指针。NMHDSportage包涵控件文告的剧情, 能够随心所欲扩充。
2) 程序定义新闻(Application-Defined Messages) 
客户自定义的音讯, 对于其范围有如下规定:
WM_USER: 0x0400-0x7FFF    (ex. WM_USER+10)
WM_APP(winver>4.0): 0x8000-0xBFFF (ex.WM_APP+4)
RegisterWindowMessage: 0xC000-0xFFFF

 

3 新闻队列(Message Queues) 
Windows中有三种档期的顺序的音信队列
1) 系统音讯队列(System Message Queue) 那是二个系统独一的Queue,设备驱动(mouse, keyboard)会把操作输入转化成音讯存在系统队列中,然后系统会把此新闻放到目的窗口所在的线程的新闻队列(thread-specific message queue)中伺机管理
2) 线程音讯队列(Thread-specific Message Queue) 每叁个GUI线程都会维护这么三个线程音信队列。(这几个行列独有在线程调用GDI函数时才会创制,暗中同意不制造)。然后线程新闻队列中的新闻会被送到相应的窗口进度(WndProc)管理.
只顾: 线程消息队列中WM_PAINT,WM_TIME奇骏唯有在Queue中尚无其他消息的时候才会被管理,WM_PAINT音讯还恐怕会被统一以进步作用。其余具有音讯以先进先出(FIFO)的不二秘籍被管理。

2. 复出步骤

4 队列消息(Queued Messages)和非队列音讯(Non-Queued Messages)
1)队列新闻(Queued Messages)
 
音讯会先保存在音信队列中,音讯循环会从此队列中取音信并散发到各窗口管理
如鼠标,键盘音信。
2) 非队列新闻(NonQueued Messages) 信息会绕过系统音讯队列和线程音讯队列直接发送到窗口进程被管理
如: WM_ACTIVATE, WM_SETFOCUS, WM_SETCURSOR, WM_WINDOWPOSCHANGED 
潜心: postMessage发送的新闻是队列音信,它会把音讯Post到新闻队列中; SendMessage发送的音讯是非队列新闻, 被直接送到窗口进度处理

复发景况:XP sp3 / Office 2005(其余office版本应该也足以,没有测验)

5 PostMessage(PostThreadMessage), SendMessage 
PostMessage:把信息放到钦命窗口所在的线程消息队列中后及时回去。 PostThreadMessage:把新闻放到内定线程的音讯队列中后立马回到。
SendMessage:直接把音讯送到窗口进程管理,管理完了才回到。

6 GetMessage, PeekMessage 
PeekMessage会立刻回去能够保存音信
GetMessage在有音讯时再次回到会删除新闻

1> 解压iqy_test.zip

7 TranslateMessage, TranslateAccelerator 
TranslateMessage: 把一个virtual-key音信转化成字符新闻(character message),并放置当前线程的新闻队列中,音信循环下二遍抽出管理。
TranslateAccelerator:将急速键对应到对应的美食指南命令。它会把WM_KEYDOWN 或 WM_SYSKEYDOWN转化成赶快键表中相应的WM_COMMAND或WM_SYSCOMMAND音信, 然后把转化后的 WM_COMMAND或WM_SYSCOMMAND直接发送到窗口过程管理, 管理完后才会回来。

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

8(音讯死锁( Message Deadlocks) 
万一有线程A和B, 以往有以下下步骤
1) 线程A SendMessage给线程B, A等待音信在线程B中拍卖后重回
2) 线程B收到了线程A发来的音信,并实行拍卖, 在管理进程中,B也向线程A SendMessgae,然后等待从A再次来到。
因为那时, 线程A正等待从线程B重回, 不恐怕管理B发来的新闻, 进而导致了/线程A,B相互等待, 产生死锁。五个线程也可以产生环形死锁。
能够选择 SendNotifyMessage或SendMessage提姆eout来防止出现死锁。

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

9 BroadcastSystemMessage 
大家平常所接触到的消息都以发送给窗口的,其实, 音讯的收信人能够是出乖露丑的,它能够是应用程序(applications), 可设置驱动(installable drivers),网络设施(network drivers), 系统级设备驱动(system-level device drivers)等, 
布RhodescastSystemMessage那个API可以对以上系统组件发送音信。

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 %pn", shell_exec_info.hProcess);

    return ret;
}

 

3. 原因解析

3.1 excel hang在哪里?

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

图片 1

能够观察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

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

图片 2

call stack呈现的确是ShellExecuteEx所调用

图片 3

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

本文由2020欧洲杯官方投注-2020欧洲杯官方投注网址发布于win7,转载请注明出处:ShellExecuteEX张开iqy文件导致excel hang的缘故分析

相关阅读