C#启动一个外部程序(3)-CreateProcess

三个 SDK 函数 : WinExecShellExecute CreateProcess 可以实现调用 其他程序的要求,其中以 WinExec 最为简单, ShellExecuteWinExec 灵活一些, 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 方式去加载一个无最大化按钮的程序,譬如 NetermCalc 等等,就不会出现正常的 窗体,但是已经被加到任务列表里了。

 

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.

using  System.Runtime.InteropServices;

2. CreateProcess中用到了几个结构体类型,先声明他们:

        [System.Runtime.InteropServices.StructLayout(LayoutKind.Sequential)]
        
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

        [DllImport( " Kernel32.dll " , CharSet  =  CharSet.Ansi)]
        
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,作用看注释

        #region Win32 Api : WaitForSingleObject
        //检测一个系统核心对象(线程,事件,信号)的信号状态,当 对象执行时间超过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行处,直到命令执行完毕或进程被中止才继续执行后边的 语句。

             string  argm  =   " cmd.exe " ;

            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);

例子 1 :
在程序中使用CreateProcess:
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);
例子 2 :
StringBuilder s = new StringBuilder();
            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);
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值