初学者创建进程的入门指南






4.92/5 (57投票s)
对 ShellExecute/ShellExecuteEx、CreateProcess、WaitForSingleObject 的基本用法进行介绍。如何打开“查找”窗口、“属性”窗口。
引言
我们经常看到新手提问,如何启动一个新进程,如何用关联的程序打开一个特定的文档,如何启动一个网站,如何弹出邮件客户端的撰写窗口,如何等待一个程序完成,如何打印一个文件等等。其中很多都可以通过调用 CreateProcess
来实现。但不幸的是,新手们常常发现 CreateProcess
并不是那么容易理解。但对新手来说,好消息是你可以使用 shell32.dll 提供的一些 shell 函数来完成上述任务。
本文可以看作一个微型 FAQ,提供一些简单的代码片段,详细说明如何完成特定任务。你必须在 MSDN 上查阅此处讨论的函数。如果大家能发送更多类似的问题,我将非常高兴。文章最后我还对 CreateProcess
进行了极简的介绍。这种方法非常不全面,但我认为它能为新手提供一个简单的入门基础。
ShellExecute 及其作用
此函数声明在 Shellapi.h 中,你需要包含它。你还必须链接 Shell32.lib。ShellExecute
是一个非常省力的 API 调用。我们将通过微型 FAQ 的形式介绍它的用法。在 MSDN 上查阅该函数,以了解每个参数的含义。
问:如何在 Windows 中启动一个应用程序?
答:很简单。只需调用 ShellExecute
,传入要执行的文件名的完整路径。
ShellExecute(this->m_hWnd,"open","calc.exe","","", SW_SHOW );
你还可以像下面这样为应用程序传递参数:
ShellExecute(this->m_hWnd,"open","notepad.exe", "c:\\MyLog.log","",SW_SHOW );
如你所见,我没有传递程序的完整路径。如果你不指定完整路径,ShellExecute
会在 PATH 环境变量中查找。
问:我想使用与文档类型关联的程序来打开一个特定的文档。
答:你可以将文档的路径传递给 ShellExecute
,ShellExecute
会用其关联的程序打开文件。很简单吧?
ShellExecute(this->m_hWnd,"open", "c:\\abc.txt","","",SW_SHOW );
问:我想以编程方式在浏览器窗口中启动我的主页。
答:天哪!如果你知道这有多容易。只需将 URL 传递给 ShellExecute
。我敢打赌你现在嘴边露出一丝苦笑,好像在说:“该死!我不相信。”
ShellExecute(this->m_hWnd,"open", "http://www.google.com","","", SW_SHOW );
问:如何启动默认电子邮件客户端的撰写窗口,并将我指定的地址作为收件人地址?
答:这次我们将一个 mailto 链接传递给 ShellExecute
。
ShellExecute(this->m_hWnd,"open", "mailto:nishinapp@yahoo.com","","", SW_SHOW );
问:老板要求我从程序中打印那个许可协议文本文件。
答:别担心,ShellExecute
在这里。[我希望我没有过度推销]
ShellExecute(this->m_hWnd,"print", "c:\\abc.txt","","", SW_HIDE);
问:我想在特定文件夹上打开 Windows 的“查找”窗口。
答:我们使用 find
动词作为操作参数,然后 Windows 的“查找”窗口就会以我们指定的目录作为根目录打开。如果你想让用户在某个文件夹中查找文件,这会非常方便。只需让他们指定文件夹,然后弹出一个以他们的文件夹为根目录的“查找”窗口。
ShellExecute(m_hWnd,"find","d:\\nish", NULL,NULL,SW_SHOW);
更强大的工具 - ShellExecuteEx
ShellExecuteEx
是一个更灵活的调用,它允许我们检索刚刚启动的程序的信息。你需要填充 SHELLEXECUTEINFO
结构,并将它的地址传递给 ShellExecuteEx
。请在你的 MSDN 副本中查找这两个函数。
问:如何启动一个程序,并暂停当前程序的执行,直到该程序退出?
答:使用 ShellExecuteEx
启动程序,然后对进程句柄调用 WaitForSingleObject
。
SHELLEXECUTEINFO ShExecInfo = {0}; ShExecInfo.cbSize = sizeof(SHELLEXECUTEINFO); ShExecInfo.fMask = SEE_MASK_NOCLOSEPROCESS; ShExecInfo.hwnd = NULL; ShExecInfo.lpVerb = NULL; ShExecInfo.lpFile = "c:\\MyProgram.exe"; ShExecInfo.lpParameters = ""; ShExecInfo.lpDirectory = NULL; ShExecInfo.nShow = SW_SHOW; ShExecInfo.hInstApp = NULL; ShellExecuteEx(&ShExecInfo); WaitForSingleObject(ShExecInfo.hProcess,INFINITE);
问:我想显示一个文件或文件夹的“文件/文件夹属性”窗口。
答:这次我们将 properties
作为操作动词传递。我们还需要在 SHELLEXECUTEINFO
结构的 fMask
参数中指定 SEE_MASK_INVOKEIDLIST
。这就是为什么这里必须使用 ShellExecuteEx
而不是 ShellExecute
。这个技巧要归功于 Microsoft MVP David Lowndes,因为正是 David 提供了关于 SEE_MASK_INVOKEIDLIST
标志的提示。
SHELLEXECUTEINFO ShExecInfo ={0}; ShExecInfo.cbSize = sizeof(SHELLEXECUTEINFO); ShExecInfo.fMask = SEE_MASK_INVOKEIDLIST ; ShExecInfo.hwnd = NULL; ShExecInfo.lpVerb = "properties"; ShExecInfo.lpFile = "c:\\"; //can be a file as well ShExecInfo.lpParameters = ""; ShExecInfo.lpDirectory = NULL; ShExecInfo.nShow = SW_SHOW; ShExecInfo.hInstApp = NULL; ShellExecuteEx(&ShExecInfo);
CreateProcess - 极简介绍
CreateProcess
函数属于 Kernel32.dll。Windows 使用此调用来创建一个新进程和新进程的主线程。主线程然后开始执行指定的程序。通常,如果这是一个 C++ 程序,执行将从 WinMain
开始 [实际上在此之前,CRT 库已被加载和初始化]。有关 CreateProcess
用法的更全面教程,我推荐阅读 Joseph M Newcomer 的文章 进程简介:异步进程通知。
PROCESS_INFORMATION ProcessInfo; //This is what we get as an [out] parameter STARTUPINFO StartupInfo; //This is an [in] parameter ZeroMemory(&StartupInfo, sizeof(StartupInfo)); StartupInfo.cb = sizeof StartupInfo ; //Only compulsory field if(CreateProcess("c:\\winnt\\notepad.exe", NULL, NULL,NULL,FALSE,0,NULL, NULL,&StartupInfo,&ProcessInfo)) { WaitForSingleObject(ProcessInfo.hProcess,INFINITE); CloseHandle(ProcessInfo.hThread); CloseHandle(ProcessInfo.hProcess); } else { MessageBox("The process could not be started..."); }
正如你所见,我正在对进程句柄使用 WaitForSingleObject
。但由于 CreateProcess
除了创建进程对象外,还会创建线程对象,我也可以像这样等待线程句柄:
WaitForSingleObject(ProcessInfo.hThread,INFINITE);
但这可能会引起问题,如果由于某些原因,你的一个或多个辅助线程在主线程完成后仍然处于活动状态。MSDN 说,只有当所有线程都停止执行时,进程才会被完全终止。所以我建议你等待进程句柄而不是线程句柄。
最后更新
- 2002 年 8 月 3 日 - 添加了打开“查找”窗口的技巧
- 2002 年 8 月 3 日 - 添加了打开“属性”窗口的技巧