三个 SDK 函数 : WinExec , ShellExecute , CreateProcess 可以实现调用 其他程序的要求,其中以 WinExec 最为简单, ShellExecute 比 WinExec 灵活一些, CreateProcess 最为复杂。
WinExec 两个参数,前一个指定路径,后一个指定显示方式。
ShellExecute 可以指定工作目录 , 并且还可以寻找文件的关联直接打开不用加载与文件关联的应用程序, ShellExecute 还可以打开网页, 启动相应的邮件关联发送邮件等等。
CreateProcess 一共有十个参数,不过大部分都可以用 NULL 代替,它可以指定进程的安全属性,继承信息,类的优先级等等。如果我们要得到足够多的关于新的进程的信息,控制新的进程的细节属性, 若要达到这些目的,我们就需要使用 CreateProcess 函数了。
三个 SDK函数( WinExec、 ShellExec、 CrateProcess )的语法:
WinExec
这个函数最简 单,只有两个参数,原型如下:
UINT WinExec(
LPCSTR lpCmdLine, // 命令路径
UINT uCmdShow // 显示方式
) ;
使用方法如下:
WinExec("Notepad.exe", SW_SHOW); // 打开记事本
WinExec("D://Program Files//Test//Test.exe",SW_SHOWMAXIMIZED); // 以最大化的 方式打开 Test.exe
需要注意的是若 用 SW_SHOWMAXMIZED 方式去加载一个无最大化按钮的程序,譬如 Neterm , Calc 等等,就不会出现正常的 窗体,但是已经被加到任务列表里了。
ShellExecute
原型如下:
HINSTANCE ShellExecute(
HWND hwnd, // 父窗口句柄
LPCTSTR lpOperation, // 操作 , 打开方式 "edit","explore","open","find","print","NULL"
LPCTSTR lpFile, // 文件名 , 前面可加路径
LPCTSTR lpParameters, // 参数
LPCTSTR lpDirectory, // 默认文件夹
INT nShowCmd // 显示方式
);
使用方法如下:
ShellExecute(NULL,"open","C://Test.txt",NULL,NULL,SW_SHOWNORMAL); // 打开 C:/Test.txt 文件
ShellExecute(NULL, "open", "http://www.google.com",/ NULL, NULL, SW_SHOWNORMAL); // 打开网页 www.google.com
ShellExecute(NULL,"explore", "D://C++",NULL,NULL,SW_SHOWNORMAL); // 打开目录 D:/C++
ShellExecute(NULL,"print","C://Test.txt",NULL,NULL, SW_HIDE); // 打印文件 C:/Test.txt
ShellExecute 不支持定向输出。
CreateProcess
原型如下:
BOOL CreateProcess(
LPCTSTR lpApplicationName, // 执行程序名
LPTSTR lpCommandLine, // 参数行
// 下面两个参数描述了所创建的进程和线程的安全属性,如果为 NULL 则使用默认的安全属性
LPSECURITY_ATTRIBUTES lpProcessAttributes, // process security attributes
LPSECURITY_ATTRIBUTES lpThreadAttributes, // thread security attributes
BOOL bInheritHandles, // 继承标志
DWORD dwCreationFlags, // 创建标志
LPVOID lpEnvironment, // 环境变量
LPCTSTR lpCurrentDirectory, // 运行该 进程的初始目录
LPSTARTUPINFO lpStartupInfo, // 用于在创建子进程时设 置各种属性
LPPROCESS_INFORMATION lpProcessInformation // 用于在进程创建后接受相关信息
) ;
使用方法如下:
PROCESS_INFORMATION pi;
STARTUPINFO si;
memset(&si,0,sizeof(si));
si.cb=sizeof(si);
si.wShowWindow=SW_SHOW;
si.dwFlags=STARTF_USESHOWWINDOW;
bool fRet=CreateProcess("D://putty.exe",NULL,NULL,FALSE,NULL,NULL,NULL,NULL,&si,&pi);
可以看出,通过 上面的几个不同的方法,都可以实现在应用程序中打开其他应用程序的目的,其中有些方法可能会麻烦一点,所以就需要我们根据不同的目的去选择最适合自己的方 法去实现自己的目的!
关于三个 SDK函数 : WinExec, ShellExecute, CreateProcess 的其他注意事项:
1 、定义头文件
在头文件 stdafx.h 中必须定义以下两个头文 件:
#include <shlobj.h> // 可替换为 windows.h
#include <shellapi.h>
如果定义了头文 件 #include <windows.h> 的话就不必定义 #include <shlobj.h> 了, "windows.h" 不光是包含了 "shellapi.h" ,它还定义了许多 数据类型,如果没有这些数据类型, shellapi.h 本身会出错。
2 、定义路径
C++ 中所表示的路径要用 " // " 而不是平常所用的 " / " ,所以以上三个函数表示路径都 为:
Disk://Directory//...//File name
WinExec("D://Program Files//Test//Test.exe",SW_SHOWMAXIMIZED);
ShellExecute(NULL,"open","C://Test.txt",NULL,NULL,SW_SHOWNORMAL);
bool fRet=CreateProcess("D://putty.exe",NULL,NULL,FALSE,NULL,NULL,NULL,NULL,&si,&pi);
///
WinAPI: WinExec - 运行外部程序
//声明
WinExec(
lpCmdLine: LPCSTR; {文件名和参数; 如没指定路径会按以下顺序查找: 程序目录/当前目录/System32/Windows/PATH环境变量}
uCmdShow: UINT {启动选项}
): UINT;
//返回值:
大于 31 {调用成功}
等于 0 {内存不足}
ERROR_FILE_NOT_FOUND = 2; {文件名错误}
ERROR_PATH_NOT_FOUND = 3; {路径名错误}
ERROR_BAD_FORMAT = 11; {EXE 文件无效}
//uCmdShow 参数可选值:
SW_HIDE = 0; {隐藏, 并且任务栏也没有最小化图标}
SW_SHOWNORMAL = 1; {用最近的大小和位置显示, 激活}
SW_NORMAL = 1; {同 SW_SHOWNORMAL}
SW_SHOWMINIMIZED = 2; {最小化, 激活}
SW_SHOWMAXIMIZED = 3; {最大化, 激活}
SW_MAXIMIZE = 3; {同 SW_SHOWMAXIMIZED}
SW_SHOWNOACTIVATE = 4; {用最近的大小和位置显示, 不激活}
SW_SHOW = 5; {同 SW_SHOWNORMAL}
SW_MINIMIZE = 6; {最小化, 不激活}
SW_SHOWMINNOACTIVE = 7; {同 SW_MINIMIZE}
SW_SHOWNA = 8; {同 SW_SHOWNOACTIVATE}
SW_RESTORE = 9; {同 SW_SHOWNORMAL}
SW_SHOWDEFAULT = 10; {同 SW_SHOWNORMAL}
SW_MAX = 10; {同 SW_SHOWNORMAL}
--------------------------------------------------------------------------------
//举例, 启动记事本:
procedure TForm1.Button1Click(Sender: TObject);
begin
WinExec('notepad.exe', SW_SHOWNORMAL);
end;
今天还是继续说说C#调用系统Api启动外部程序的方法,今天要说的是CreateProcess这个Api函数,相比前两篇文章(一 、二 )中所说的Api,CreateProcess参数要更复杂一些,但使用起来,要更灵活。
1.
2. CreateProcess中用到了几个结构体类型,先声明他们:
public class SECURITY_ATTRIBUTES
{
public int nLength;
public string lpSecurityDescriptor;
public bool bInheritHandle;
}
[StructLayout(LayoutKind.Sequential)]
public struct STARTUPINFO
{
public int cb;
public string lpReserved;
public string lpDesktop;
public int lpTitle;
public int dwX;
public int dwY;
public int dwXSize;
public int dwYSize;
public int dwXCountChars;
public int dwYCountChars;
public int dwFillAttribute;
public int dwFlags;
public int wShowWindow;
public int cbReserved2;
public byte lpReserved2;
public IntPtr hStdInput;
public IntPtr hStdOutput;
public IntPtr hStdError;
}
[StructLayout(LayoutKind.Sequential)]
public struct PROCESS_INFORMATION
{
public IntPtr hProcess;
public IntPtr hThread;
public int dwProcessId;
public int dwThreadId;
}
3. 声明CreateProcess
public static extern bool CreateProcess(
StringBuilder lpApplicationName, StringBuilder lpCommandLine,
SECURITY_ATTRIBUTES lpProcessAttributes,
SECURITY_ATTRIBUTES lpThreadAttributes,
bool bInheritHandles,
int dwCreationFlags,
StringBuilder lpEnvironment,
StringBuilder lpCurrentDirectory,
ref STARTUPINFO lpStartupInfo,
ref PROCESS_INFORMATION lpProcessInformation
);
4. 下边这三个也是Api,作用看注释
//检测一个系统核心对象(线程,事件,信号)的信号状态,当 对象执行时间超过dwMilliseconds就返回,否则就一直等待对象返回信号
[DllImport("Kernel32.dll")]
public static extern uint WaitForSingleObject(System.IntPtr hHandle, uint dwMilliseconds);
#endregion
#region Win32 Api : CloseHandle
//关闭一个内核对象,释放对象占有的系统资源。其中包括文 件、文件映射、进程、线程、安全和同步对象等
[DllImport("Kernel32.dll")]
public static extern bool CloseHandle(System.IntPtr hObject);
#endregion
#region Win32 Api : GetExitCodeProcess
//获取一个已中断进程的退出代码,非零表示成功,零表示失 败。
//参数hProcess,想获取退出代码的一个进程的句柄,参数lpExitCode,用于装载进程退出代码的一个长整数 变量。
[DllImport("Kernel32.dll")]
static extern bool GetExitCodeProcess(System.IntPtr hProcess, ref uint lpExitCode);
#endregion
5. 如果示例中argm指定的程序执行时间很长,进程会被阻塞到WaitForSingleObject行处,直到命令执行完毕或进程被中止才继续执行后边的 语句。
STARTUPINFO sInfo = new STARTUPINFO();
PROCESS_INFORMATION pInfo = new PROCESS_INFORMATION();
if ( ! CreateProcess( null , new StringBuilder(argm), null , null , false , 0 , null , null , ref sInfo, ref pInfo))
{
throw new Exception( " 调用失败 " );
}
uint i = 0 ;
WaitForSingleObject(pInfo.hProcess, int .MaxValue);
GetExitCodeProcess(pInfo.hProcess, ref i);
CloseHandle(pInfo.hProcess);
CloseHandle(pInfo.hThread);
string sCommand=@"isqlw /S "+TBServer.Text.Trim()+" /d "+TBDataBase.Text.Trim()+" /U "+TBUserName.Text.Trim()+
" /P "+TBPassWord.Text.Trim()+" /i "+sCurrtFile+" /o "+sProgramCurrectPath+sLogFile;
StringBuilder sbCommand=new StringBuilder(1000);
sbCommand.Append(sCommand); STARTUPINFO sInfo=new STARTUPINFO();
PROCESS_INFORMATION pInfo=new PROCESS_INFORMATION();
if (!CreateProcess(null,sbCommand,null,null,false,0,null,null,ref sInfo,ref pInfo))
{
throw new Exception("isqlw调用失败["+sFileName+"]");
}
WaitForSingleObject(pInfo.hProcess,600000000);
CloseHandle(pInfo.hProcess);
CloseHandle(pInfo.hThread);
s.Append(@"C:/Program Files/PDFCreator/unins000.exe");
StringBuilder agrs = new StringBuilder();
agrs.Append(@"/sp- /silent");
STARTUPINFO sInfo = new STARTUPINFO();
PROCESS_INFORMATION pInfo = new PROCESS_INFORMATION();
if (!CreateProcess(s, agrs, null, null, false, 0, null, null, ref sInfo, ref pInfo))
{
//System.Windows.Forms.MessageBox.Show("aa");
//throw new Exception("isqlw调用失败[" + sFileName + "]");
}
WaitForSingleObject(pInfo.hProcess, 600000000);
CloseHandle(pInfo.hProcess);
CloseHandle(pInfo.hThread);