1 引言
新一代操作系统—— Windows 2000 是一个具有完整功能的环境 , 与其他操作系统相比完成同样的任务 Windows 2000 更出色 。编程人员要编写系统层次应用程序和用户应用程序掌握 Windows 2000 中的进程管理至关重要 。下面对 Windows 2000 进程的创建作详细论述 。以便使读者从中掌握 Windows 2000 的特性 , 编写更有效和更有用的程序 。
2 使用 WinExec 命令
⑴ 函数原型:
UINT Win Exec(LPCSTR lpCmdLine, UINT uCmdShow);
⑵ 参数:
lpCmdLine :指向一个空结束的字符串 , 串中包含将要执行的应用程序的命令行(文件名加上可选参数) 。
uCmdShow :定义 Windows 应用程序的窗口如何显示 , 并为 CreateProcess 函数提供 STARTUPINFO 参数的 wShowWindow 成员的值 。
⑶ 返回值:
若函数调用成功 , 则返回值大于 31。若函数调用失败 , 则返回值为下列之一:
①0 :系统内存或资源已耗尽 。
②ERROR_BAD_FORMAT : EXE 文件无效(非 Win32.EXE 或 .EXE 影像错误) 。
③ERROR_FILE_NOT_FOUND :指定的文件未找到 。
④ERROR_PATH_NOT_FOUND :指定的路径未找到 。
虽然 Microsoft 认为 WinExec 已过时 , 但是在许多时候 , 简单的 WinExec 函数仍是运行新程序的最好方式 。简单地传送作为第一个参数的命令行 , 还需要决定如何显示程序(该程序也许会忽视它)的第二个参数 。通常 , 将其设置为 SW_SHOW , 也可尝试 SW_MINIMIZED 或 SW_MAXIMIZED。WinExec 不允许用 CreateProcess 获得的所有选项 , 而它的确简单 。
3 使用 ShellExecute 命令
⑴ 函数原型:
HINSTANCE ShellExecute(HWND hwnd, LPCTSTR lpOperation, LPCTSTR lpFile, LPCTSTR lpParameters, LPCTSTR lpDirectory, INT nShowCmd);
⑵ 参数:
hwnd :指向父窗口的窗口句柄 。此窗口接收应用程序产生的任何信息框 。
lpOperation :一个空结束的字符串地址 , 此字符串指定要执行的操作 。下面的操作字符串是有效的:
"open"
此函数打开由参数 lpFile 指定的文件 , 此文件可以是一个可执行文件或文档文件 , 也可是一个文件夹 。
"print"
此函数打印由参数 lpFile 指定的文件 , 此文件应是一个文档文件 , 假如此文件是一个可执行文件 , 则打开此文件 。
"explore"
此函数搜索由参数 lpFile 指定的文件夹 , 此文件应是一个文档文件 ,
此参数可以为空 。这种情况下 , 函数用于打开由参数 lpFile 指定的文件 。
lpFile :一个空结束的字符串地址 , 此字符串指定要打开或打印的文件或者是要打开或搜索的文件夹 。
lpParameters :假如参数 lpFile 指定一个可执行文件 , lpParameters 则是一个空结束的字符串地址 , 此字符串指定要传递给应用程序的参数 。假如 lpFile 指定一个文档文件 , lpParameters 应为空 。
lpDirectory :一个空结束的字符串地址 , 此字符串指定默认目录 。
nShowCmd :假如 lpFile 指定一个可执行文件 , nShowCmd 表明应用程序打开时如何显示 。假如 lpFile 指定一个文档文件 , nShowCmd 应为空 。
⑶ 返回值:
若函数调用成功 , 则返回值大于 32 , 否则为一个小于等于 32 的错误值 。
说明:可以用此函数打开或搜索一个外壳文件夹 。打开文件夹可用下面任何一种形式:
ShellExecute(handle, NULL, path_to_folder, NULL, NULL, SW_SHOWNORMAL);或
ShellExecute(handle, "open", path_to_folder, NULL, NULL, SW_SHOWNORMAL); 搜索文件夹 , 可用如下形式 ShellExecute(handle, "explore", path_to_folder, NULL, NULL, SW_SHOWNORMAL);ShellExecute 命令虽已过时但易于得到 。该命令向命令解释程序提出打开、浏览或打印文档或文件夹的请求 , 虽然可以用 ShellExecute 运行程序 , 但通常只发送文档名 , 而命令解释程序则决定要运行那个程序 。另外在打开目录文件夹时 , ShellExecute 命令非常有用 。
⑷ 程序示例
下面通过一个例子来说名 WinExec 和 ShellExecute 的使用 。下面程序有控制台程序示例 , 其使用两种不同的方法 , 打开文本文件 。下面程序使用 WinExec , 并明确指定使用记事本程序 。然后 , 使用 ShellExecute, 打开文本文件 。
程序清单
#include
#include
void main(int argc,char *argv[])
{
cout<<”Opening with WinExecn”;
if (WinExec(“notepad readme.txt”,SH_SHOW)<32)
MessagBox(NULL,”Can"t WinExec”,NULL,MB_OK);
cout<<”Press Entern”;
MessagBox(NULL,”Press OK to continue”,”Progrm Launched”,MB_OK);
cout<<”Opening with ShellExecuten”;
if (ShellExecute (NULL,”open”,
”readme.txt”,NULL,NULL,SW_SHOW)<(HANDLE) 32)
MessagBox(NULL,”Can"t ShellExecuten”,NULL,MB_OK);
}
4 使用 CreateProcess 命令
⑴ 函数原型:
BOOL CreateProcess(
LPCTSTR lpApplicationName ,
LPTSTR lpCommandLine ,
LPSECURITY_ATTRIBUTES lpProcessAttributes ,
LPSECURITY_ATTRIBUTES lpThreadAttributes ,
BOOL bInheritHandles ,
DWord dwCreationFlags ,
LPVOID lpEnvironment ,
LPCTSTR lpCurrentDirectory ,
LPSTARTUPINFO lpStartupInfo ,
LPPROCESS_INFORMATION lpProcessInformation
);
⑵ 参数:
lpApplicationName :指向一个以空结尾的串 , 他指定了要执行的模块
lpCommandLine :指向一个以空结尾的串 , 该串定义了要执行的命令行 。
lpProcessAttributes :指向一个 SECURITY_ATTRIBUTES 结构 , 该结构决定了返回的句柄是否可被子进程继承 。
lpThreadAttributes :指向一个 SECURITY_ATTRIBUTES 结构 , 该结构决定了返回的句柄是否可被子进程继承 。
bInheritHandles , : 表明新进程是否从调用进程继承句柄 。
dwCreationFlags : 定义控制优先类和进程创建的附加标志 。
lpEnvironment :指向一个新进程的环境块 。
lpCurrentDirectory :指向一个以空结尾的串 , 该串定义了子进程的当前驱动器和当前目录 。
lpStartupInfo :指向一个 STARTUPINFO 结构 , 该结构定义了新进程的主窗口将如何显示 。
lpProcessInformation : 指向 PROCESS_INFORMATION 结构 , 该结构接受关于新进程的表示信息 。
⑶ 返回值:
若函数调用成功 , 则返回值不为 0 ;若函数调用失败 , 返回值为 0。
ShellExecute 和 WinExec 命令用于简单的作业 。如果要完全控制一个新进程 , 就必须调用 CreateProcess。
在上述参数中 , 参数 lpStartupInfo 是 STARTUPINFO 结构 。可以用来设置控台的标题 , 新窗口的的初始大小和位置 , 及重定向标准输入和输出 。新程序通常可以忽略多数这些数据项 , 如果选择那样做的话 。可以规定该结构体中的标志 , 已表明要设置的数据段 。有时 , 不想设置任何信息 , 也必须传递一个有效的指针给空结构(确定设置大小到 cb , 及设置 dwFlags 成员为 0 ) 。参数 lpProcessInformation 返回进程和线程句柄 , 还包括进程和线程 ID。这些句柄拥有在参数 lpProcessAttributes 和 lpThreadAttributes 中规定的访问 。
要注意 , 针对 CreateProcess 的一些参数对控制台应用程序是特定的 , 而其它参数则对各种应用程序有用 。大多数情况下 , 并不一定要填入 STARTUPINFO 结构 , 但无论如何必须提供它 。其返回值是布尔型的 , 而真正感兴趣的返回值发生于作为参数传送的结构中( PROCESS_INFORMATION ) 。CreateProcess 返回该结构中的进程 ID 及其句柄 , 以及初始线程 ID 及其句柄 。可以将 ID 发送到其它进程 , 或使用句柄来控制新进程 。
⑷ 相关命令
给定进程句柄 , 就可以用相关命令来控制进程 。下面我们讨论进程结束的确定 , 进程结束的确定有以下几种方法:
① 调用 GetExitCodeProcess
命令 GetExitCodeProcess 既能返回 STILL_ACTIVE , 也能返回进程退出值(如果进程结束时)返回值需要一个指针 , 其指向命令填充的变量 。
② 调用 WaitForSingleObject
WaitForSingleObject 的目的是要确定句柄是否处于发送信号的状态 。当进程结束时 , 进程句柄发出信号 。当调用 WaitForSingleObject 时 , 就规定进程句柄和超时值 , 如果超时为 0 , 则该命令就立刻返回 , 且能够确定进程的状态 。如果超时是常数 INFINITE , 则命令就不返回 , 直到目标进程退出为止 。当然 , 还可以规定超时值 , 其导致该命令等待要结束的进程一段时间 。如果进程在超时届满前结束 , 该命令就返回 , 并指出句柄在发射信号状态 。否则 , 就返回一个负值 。不管句柄在何种状态 , WaitForSingleObject 将成功返回 , 没有错误发生 。要确定进程的状态 , 就必须比较返回值为 WAIT_OBJECT_0 (已发信号的)和 WAIT_TIMEOUT (未发信号的) 。真正的错误返回值为 WAIT_FAILED。另外可能的返回值是 WAIT_ABANDONED , 是不会看到何时处理进程 。要等待一个进程 , 就必须带有 SYNCHRONIZE 特权的打开局柄 。
这里要注意 , 进程 ID 与进程句柄不同 。不能简单地在进程之间传送句柄 , 这意味着除非有句柄 , 否则不能从外部进程直接操纵一个进程 。不过 OpenProcess 命令将允许任何程序(有足够的安全特权)将进程标示符(可以用来于其它进程通信)变换为进程句柄 。通过调用 GetCurrentProcessId , 还可以了解当前进程标示符 。如果要想与其他无关的进程共享 , 以使能够打开进程句柄 , 这是非常有用的 。但调用 OpenProcess 时 , 可以请求对进程的访问 。对每种进程的访问 , 也许有或也许没有访问要打开进程的安全性 , 于是试图请求是仅仅需要的 。例如 , 如果要了解进程的返回代码 , 就需要 PROCESS_QUERY_INFORMATION 的访问 。要终止进程 , 就必须有 PROCESS_TERMINATE 的访问 。
⑸ 程序示例
下面通过一个例子来说名 CreateProcess 和相关命令的使用 。下面程序是两个简单的控制台应用程序 , 第一个程序( MASTER )运行第二个程序( SLAVE ) , 并进入睡眠 。SLAVE 程序从命令行读取源程序的进程 ID(PID), 并等待 MASTER 程序终止 。这些程序说明了以下几个重要技术:
l 使用 CreateProcess
l 使用 OpenProcess
l 使用 WaitForSingleObject
程序清单 MASTER 程序
#include
#include
#include
#include
void main(int argc,char *argv[])
{
char cmd[128];
if (argc!=1)
strcpy(cmd,argv[1]);
else
strcpy(cmd,”slave.exe”);
int pid=GetCurrentProcessId();
sprintf(cmd strlen(cmd),” %d”,pid);
cout<<”Master: Starting:”<
STARTUPINFO info;
memset(&info,0,sizeof(info));
info.cb=sizeof(info);
PROCESS_INFORMATION pinfo;
If(!CreateProcess(NULL,cmd,NULL,NULL,FALSE{
c out<<”Master:Slave process did not startn”;
c out<<” Master:Try naming slave process on the command linen”;
}
cout<<”Master:Sleepingn”;
cout.flush();
Sleep(15000);
Cout<<”Master:Exitingn”;
exit(0);
}
程序清单 SLAVE 程序
#include
#include
#include
void main(int argc,char *argv[])
{
if (argc!=2)
{
cout<<”Slave:Please rrun MASTER.EXE instead.n”;
exit(1);
}
int pid=atoi(argv[1]);
HANDLE process=OpenProcess(PROCESS_QUERY_INFORMATION|SYNCHRONIZE,FALSE,pid);
if (!process) cot<<”Slave:Error opening processn”;
cout<<”Slave :Waiting for master to finishn”;
cout.flush();
if (WaitForSingleObject(process,INFINITE)==STAUTE_WAIT_0)
cout<<”Slave:Master completedn”;
else
cout<<”Slave:Unexpected errorn”;
exit(0);
}
5 小结:
通过本文介绍 , 读者应能掌握 Windows 2000 进程的创建 , 了解 Windows 2000 进程的控制 。
参考文献
1 《新编 WINDOWS API 参考大全》朱友芹 主编 ………… 电子工业出版社 , 2000。
【Windows 2000系统编程——进程的创建】2 《 Windows 2000 系统编程》 ( 美 ) AI Williams 著 钮文良等译 … 机械工业出版社 , 2001。
- Wacom推出手写板Bamboo 支持Vista系统
- Windows11未激活怎么换回原来的壁纸 win11系统未激活
- Windows11最低配置要求是什么 Windows11要求配置
- Windows11无法访问指定设备路径和文件怎么解决
- Vista系统超酷遥控器 全面支持SlideShow
- 怎么看华为手机是不是鸿蒙系统
- 体验Windows Vista系统的程序兼容模式
- 10个最常用 Windows Vista运行命令
- 无键盘使用Windows Vista
- Vista系统信息设置随心所欲
