ShellExecuteEX打开iqy文件导致excel hang的原委分析

1. 问题

try
{
fs = new Stream里德r(new FileStream(path, FileMode.Open,
FileAccess.Read),
Encoding.GetEncoding(“gb2312”));//不荒谬读取文件,要是被excel程序独占的话,此时会抛出尤其
}
catch(Exception e)
{
//抛出越发后,那么就足以拷贝此文件到一时半刻文件夹下生成的多个4意文件中,然后读取此一时半刻文件即可
亚洲必赢app,string tempFile = Path.GetTempPath() + Path.GetRandomFileName();
File.Copy(path, tempFile);
fs = new StreamReader(new FileStream(tempFile, FileMode.Open,
FileAccess.Read), Encoding.GetEncoding(“gb2312”));
}

当在console中调用API
ShellExecuteEx打开”test.iqy”文件时,发现excel会hang住,console退出后excel才会响应,但一向双击”test.iqy”是从未难题的,有意思的是其一情景唯有在xp发生,在win7上并未有这么些题材。

 

贰. 复出步骤

复发环境:XP sp三 / 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\n", shell_exec_info.hProcess);

    return ret;
}

 

3. 原因剖析

3.1 excel hang在哪里?

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

亚洲必赢app 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住

 

三.二 为了验证三.一.1的狐疑,用API Monitor一下ShellExecuteEx

三.贰.一按照微软的文书档案可见,发送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的调用,果然搜到一条

亚洲必赢app 2

call stack显示的确是ShellExecuteEx所调用

亚洲必赢app 3

消息1000为WM_DDE_EXECUTE,Post窗口句柄为0x003拾17贰。

专注到下四个API GetWindowThreadProcessId ( 0x003拾172 , 0x0012fb70
),刚好是得到那一个窗口的pid和tid,查看下参数窗口:

这么些窗口所属的历程PID =
0xc5四,正好是excel的长河,说明ShellExecuteEx确实发送了DDE消息给excel,而且可执发送的新闻的thread正是主线程

亚洲必赢app 4

基于DDE的音讯参数,可见wParam正是发送音信的窗口,其句柄为2425190 =
0x25016六,反向查询知这是ShellExecuteEx创造的”WorkerW”窗口

亚洲必赢app 5

亚洲必赢app 6

 

三.2.2 为了验证3.贰.一的下结论,在PostMessageW上下断点跟踪一下

亚洲必赢app 7

查看一下buff的地方:

亚洲必赢app 8

正要正是打开test.iqy的指令,表达ShellExecuteEx就是先成立了excel的进程,然后发送test.iqy的文本命令给excel打开。

 

3.3 总结

1> ShellExecuteEx打开test.iqy的时先创设excel进度

贰> 然后制造叁个”WorkerW”的窗口用于DDE通讯

3> Post WM_DDE_EXECUTE给excel,告知打开test.iqy的吩咐

四> ShellExecuteEx执行完毕,但并不destroy “WorkerW”窗口

5>
excel收到WM_DDE_EXECUTE音信后会广播WM_DDE_INITIATE音信,”WorkerW”窗口所在的console进度由于没有定义音讯处理函数,ShellExecuteEx定义的”WorkerW”窗口音信处理函数得不到CPU执行机会,导致不会response该新闻,从而造成excel
hang住

接近,大家能够创建1个带窗口的次第,运转后将其挂起,那时,即便直接双击打开test.iqy也会hang住。

 

四. 为啥双击打开excel不会hang住

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

 

5. 怎么win柒上不会有这么的难题

5.1 在API Monitor中看下PostMessageW

亚洲必赢app 9

小心到win柒下PostMessageW是用的线程二调用的,搜一下线程创设API
CreateThread

亚洲必赢app 10

能够是ShellExecuteEx内部创制的线程,所以win七上ShellExecuteEx创制了二个线程专门用来处理和excel的DDE新闻通讯,那样就能平常的收纳处理excel发过来的WM_DDE_INITIATE消息了

发表评论

电子邮件地址不会被公开。 必填项已用*标注

网站地图xml地图