VC++中关于运行外部程序

  • Post author:
  • Post category:其他


有三个API函数可以运行可执行文件WinExec、ShellExecute和CreateProcess。CreateProcess因为使用复杂,比较少用。

WinExec主要运行EXE文件。如:WinExec(‘Notepad.exe Readme.txt’, SW_SHOW);  ShellExecute不仅可以运行EXE文件,也可以运行已经关联的文件。

首先必须引用shellapi.pas单元:uses ShellAPI;


1.标准用法


ShellExecute函数原型及参数含义如下:

function ShellExecute(hWnd: HWND; Operation, FileName, Parameters,Directory: PChar; ShowCmd: Integer): HINST; stdcall;

●hWnd:用于指定父窗口句柄。当函数调用过程出现错误时,它将作为Windows消息窗口的父窗口。例如,可以将其设置为应用程序主窗口句柄,即Application.Handle,也可以将其设置为桌面窗口句柄(用GetDesktopWindow函数获得)。

●Operation:用于指定要进行的操作。其中“open”操作表示执行由FileName参数指定的程序,或打开由FileName参数指定的文件或文件夹;“print”操作表示打印由FileName参数指定的文件;“explore”操作表示浏览由FileName参数指定的文件夹。当参数设为nil时,表示执行默认操作“open”。

●FileName:用于指定要打开的文件名、要执行的程序文件名或要浏览的文件夹名。

●Parameters:若FileName参数是一个可执行程序,则此参数指定命令行参数,否则此参数应为nil或PChar(0)。

●Directory:用于指定默认目录。

●ShowCmd:若FileName参数是一个可执行程序,则此参数指定程序窗口的初始显示方式,否则此参数应设置为0。

若ShellExecute函数调用成功,则返回值为被执行程序的实例句柄。若返回值小于32,则表示出现错误。

上述仅仅是ShellExecute函数的标准用法,下面将介绍它的特殊用法。


2.特殊用法


如果将FileName参数设置为“http:”协议格式,那么该函数将打开默认浏览器并链接到指定的URL地址。若用户机器中安装了多个浏览器,则该函数将根据Windows 9x/NT注册表中http协议处理程序(Protocols Handler)的设置确定启动哪个浏览器。

格式一:http://网站域名。

如:ShellExecute(handle,  ‘open’,  ‘http://

www.honkwin.com’

, nil, nil, SW_SHOWNORMAL);

格式二:http://网站域名/网页文件名。

如:ShellExecute(handle, ‘open’, ‘http:// bbs

.honkwin.com/default.htm’

, SW_SHOWNORMAL);

如果将FileName参数设置为“mailto:”协议格式,那么该函数将启动默认邮件客户程序,如Microsoft Outlook(也包括Microsoft Outlook Express)或Netscape Messanger。若用户机器中安装了多个邮件客户程序,则该函数将根据Windows 9x/NT注册表中mailto协议处理程序的设置确定启动哪个邮件客户程序。

格式一:mailto:

如:ShellExecute(handle, ‘open’, ‘mailto:’, nil, nil, SW_SHOWNORMAL);打开新邮件窗口。

格式二:mailto:用户账号@邮件服务器地址

如:ShellExecute(handle, ‘open’, ‘

mailto:who@mail.neu.edu.cn’

, nil, nil, SW_SHOWNORMAL);打开新邮件窗口,并自动填入收件人地址。若指定多个收件人地址,则收件人地址之间必须用分号或逗号分隔开(下同)如:ShellExecute(this->m_hWnd, “open”,

mailto:nishinapp@yahoo.com

, “”, “”, SW_SHOW);这个可以激活Outlook  Express。

格式三:mailto:用户账号@邮件服务器地址?subject=邮件主题&body=邮件正文

如:ShellExecute(handle, ‘open’, ‘mailto:who@mail.neu.edu.cn?subject=Hello&Body=This is a test’, nil, nil, SW_SHOWNORMAL);打开新邮件窗口,并自动填入收件人地址、邮件主题和邮件正文。若邮件正文包括多行文本,则必须在每行文本之间加入换行转义字符%0a。

例子(delphi):

在一个应用程序调用c:Project1.exe;

ShellExecute(handle, ‘open’, ‘c:Project1.exe’, ‘字串内容’,nil, SW_SHOWNORMAL);

在Project1.exe里可以调用:

procedure TForm1.FormCreate(Sender: TObject);

var i: integer;

begin

for i := 1 to paramcount do

if ParamStr(i) <> ” then showmessage(ParamStr(i));

end;

最后的那个参数,为窗口指定可视性方面的一个命令。

请用下述任何一个常数

SW_HIDE 隐藏窗口,活动状态给令一个窗口

SW_MINIMIZE 最小化窗口,活动状态给令一个窗口

SW_RESTORE 用原来的大小和位置显示一个窗口,同时令其进入活动状态

SW_SHOW 用当前的大小和位置显示一个窗口,同时令其进入活动状态

SW_SHOWMAXIMIZED 最大化窗口,并将其激活

SW_SHOWMINIMIZED 最小化窗口,并将其激活

SW_SHOWMINNOACTIVE 最小化一个窗口,同时不改变活动窗口

SW_SHOWNA 用当前的大小和位置显示一个窗口,不改变活动窗口

SW_SHOWNOACTIVATE 用最近的大小和位置显示一个窗口,同时不改变活动窗口

SW_SHOWNORMAL 与SW_RESTORE相同

深入浅出ShellExecute

译者:徐景周(原作:Nishant       S)

Q:       如何打开一个应用程序?

ShellExecute(this->m_hWnd, “open”, “calc.exe”, “”, “”, SW_SHOW);

或       ShellExecute(this->m_hWnd, “open”, “notepad.exe”, “c://MyLog.log”, “”, SW_SHOW);

正如您所看到的,我并没有传递程序的完整路径。

Q:       如何打开一个同系统程序相关连的文档?

ShellExecute(this->m_hWnd, “open”,  “c://abc.txt”, “”, “”, SW_SHOW);

Q:       如何打开一个网页?

ShellExecute(this->m_hWnd,”open”,

http://www.google.com

, “”, “”, SW_SHOW);

Q:       如何激活相关程序,发送EMAIL?

ShellExecute(this->m_hWnd,”open”,

mailto:wanglei2258@yahoo.com

, “”, “”, SW_SHOW);

Q:       如何用系统打印机打印文档?

ShellExecute(this->m_hWnd, “print”,  “c://abc.txt”, “”, “”, SW_HIDE);

Q:       如何用系统查找功能来查找指定文件?

ShellExecute(m_hWnd, “find”, “d://nish”,  NULL, NULL, SW_SHOW);

Q:       如何启动一个程序,直到它运行结束?

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

或:       PROCESS_INFORMATION       ProcessInfo;

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

}

Q:       如何显示文件或文件夹的属性?

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函数?
函数原型
BOOL CreateProcess(
  LPCTSTR lpApplicationName,                 // name of executable module
  LPTSTR lpCommandLine,                      // command line string
  LPSECURITY_ATTRIBUTES lpProcessAttributes, // SD
  LPSECURITY_ATTRIBUTES lpThreadAttributes,  // SD
  BOOL bInheritHandles,                      // handle inheritance option
  DWORD dwCreationFlags,                     // creation flags
  LPVOID lpEnvironment,                      // new environment block
  LPCTSTR lpCurrentDirectory,                // current directory name
  LPSTARTUPINFO lpStartupInfo,               // startup information
  LPPROCESS_INFORMATION lpProcessInformation // process information
);

(1) LPCTSTR lpApplicationName

想运行的可执行文件的名字的字符串(应含扩展名)。如果找不到该文件,CreateProcess运行失败。应该设为NULL。

(2) LPTSTR lpCommandLine

传递给新进程的命令行字符串,应当为非常量字符串的地址。可以设定一个完整的命令行,如果第一个标记没有扩展名,CreateProcess将其假设为.exe。如果找不到该文件,CreateProcess按环境设置目录搜索运行。

(3) LPSECURITY_ATTRIBUTES

设定进程对象的安全性。可以为这些参数传递NULL,在这种情况下,系统为这些对象赋予默认安全性描述符。 (不明白)

(4) LPSECURITY_ATTRIBUTES lpThreadAttributes

设定线程对象的安全性。可以为这些参数传递NULL,在这种情况下,系统为这些对象赋予默认安全性描述符。 (不明白)

(5) BOOL bInheritHandles

决定子进程对父进程继承性,一般设为FALSE。

(6) DWORD dwCreationFlags

用于标识标志,以便用于规定如何来创建新进程。

标志 说明

EBUG_PROCESS 父进程想要调试子进程和子进程将来生成的任何进程。当任何子进程(被调试进程)中发生某些事件时,将情况通知父进程。 (不明白)

DEBUG_ONLY_THIS_PROCESS 与DEBUG_PROCESS标志相类似,调试程序只被告知紧靠父进程的子进程中发生的特定事件。 (不明白)

CREATE_SUSPENDED 新进程被创建,但是,它的主线程则被挂起。

DETACHED_PROCESS 阻止基于CUI的进程对它的父进程的控制台窗口的访问,并告诉系统将它的输出发送到新的控制台窗口。

CREATE_NEW_CONSOLE 为新进程创建一个新控制台窗口。如果同时设定CREATE_NEW_CONSOLE和DETACHED_PROCESS标志,就会产生一个错误。

CREATE_NO_WINDOW 不为应用程序创建任何控制台窗口。

CREATE_NEW_PROCESS_GROUP 修改用户在按下Ctrl+C或Ctrl+Break键时得到通知的进程列表。

CREATE_DEFAULT_ERROR_MODE 不继承父进程使用的错误模式。

CREATE_SEPARATE_WOW_VDM 只能当你在Windows2000上运行16位Windows应用程序时使用。告诉系统创建一个单独的DOS虚拟机(VDM),并且在该VDM中运行16位Windows应用程序。 (不明白)

CREATE_SHARED_WOW_VDM 只能当你在Windows2000上运行16位Windows应用程序时使用。在系统的共享VDM中运行16位Windows应用程序。 (不明白)

CREATE_UNICODE_ENVIRONMENT 告诉系统,子进程的环境块应该包含Unicode字符。按照默认设置,进程的环境块包含的是ANSI字符串。

CREATE_FORCEDOS 强制系统运行嵌入16位OS/2应用程序的MOS-DOS应用程序。

CREATE_BREAKAWAY_FROM_JOB 使作业中的进程生成一个与作业相关联的新进程 (不明白)。

IDLE_PRIORITY_CLASSBELOW_NORMAL_PRIORITY_CLASSNORMAL_PRIORITY_CLASSABOVE_NORMAL_PRIORITY_CLASSHIGH_PRIORITY_CLASSREALTIME_PRIORITY_CLASS 空闲低于正常(Windows2000)正常高于正常(Windows2000)高实时

对于大多数应用程序来说不应该设定优先级类。

(7) LPVOID lpEnvironment

指向包含新进程将要使用的环境字符串的内存块。在大多数情况下,为该参数传递NULL,使子进程能够继承它的父进程正在使用的一组环境字符串。也可以使用GetEnvironmentStrings函数当不再需要该内存块时,应该调用FreeEnvironmentStrings函数将内存块释放。

(8) LPCTSTR lpCurrentDirectory

设置子进程的当前驱动器和目录。如果本参数是NULL,则新进程的工作目录将与生成新进程的应用程序的目录相同。如果本参数不是NULL,那么必须指向包含需要的工作驱动器和工作目录的以0 结尾的字符串。注意,必须设定路径中的驱动器名。

(9) LPSTARTUPINFO lpStartupInfo

使用时应首先进行初始化。

成员 窗口/控制台 作用

cb 两者兼有 用作版本控制手段。必须初始化为sizeof(STARTUPINFO)

lpReserved 两者兼有 保留。必须初始化为NULL (不为NULL也可以)

lpDesktop 两者兼有 标识启动应用程序所在桌面的名字。如果桌面不存在,便创建一个带有默认属性的桌面,并使用为新进程指定的名字。其值为NULL时,与当前桌面相关联。 (不明白)

lpTitle 控制台 设定控制台窗口的名称。其值为NULL,则把可执行文件的名字用作窗口名。

dwXdwY 两者兼有 设定应用程序窗口在屏幕上的位置(以像素为单位)。只有当子进程用CW_USEDEFAULT作为CreateWindow的x参数来创建它的第一个重叠窗口时,才使用这两个坐标。

dwXSizedwYsize 两者兼有 设定应用程序窗口的宽度和长度(以像素为单位)只有当子进程将CW_USEDEFAULT用作CreateWindow的nWidth参数来创建它的第一个重叠窗口时,才使用这些值。

dwXCountCharsdwYCountChars 控制台 设定子应用程序的控制台窗口的宽度和高度(以字符为单位)

dwFillAttribute 控制台 设定控制台窗口的文本和背景颜色

dwFlags 两者兼有 后面以表格说明。

wShowWindow 窗口 设定如果子应用程序初次调用的ShowWindow将SW_SHOWDEFAULT作为nCmdShow参数传递时,该应用程序的第一个重叠窗口应该如何出现。

cbReserved2 两者兼有 保留。必须被初始化为0 (非0也可以)

lpReserved2 两者兼有 保留。必须被初始化为NULL (为什么)

hStdInputhStdOutputhStdError 控制台 设定控制台输入输出缓存的句柄。照默hStdInput标识键盘缓存,hStdOutput和hStdError标识控制台窗口缓存。

dwFlags使用方法:

标志 含义

STARTF_USESIZE 使用dwXSize和dwYSize成员

STARTF_USESHOWWINDOW 使用wShowWindow成员

STARTF_USEPOSITION 使用dwX和dwY成员

STARTF_USECOUNTCHARS 使用dwXCountChars和dwYCountChars成员

STARTF_USEFILLATTRIBUTE 使用dwFillAttribute成员

STARTF_USESTDHANDLES 使用hStdInput、hStdOutput和hStdError成员

STARTF_RUN_FULLSCREEN 强制在x86计算机上运行的控制台应用程序以全屏幕方式运行

STARTF_FORCEONFEEDBACK 启动进程时,临时将系统的箭头光标改为沙漏箭头光标。

STARTF_FORCEOFFFEEDBACK 启动进程时,不将光标改为沙漏。

(10) LPPROCESS_INFORMATION lpProcessInformation

新进程的返回信息。hProcess为新进程内核对象的句柄;hThread为新线程内核对象的句柄。在使用后应当用CloseHandle释放,使该内核的使用计数减一。dwProcessId新进程ID号;dwThreadId新线程ID号。0不能为ID号。虽然系统不会同时有相同的ID号,但是当一个进程的内核句柄被释放后其ID号又可能被新的进程使用。若要确保进程ID或线程ID不被重复使用,唯一的方法是保证进程或线程的内核对象不会被撤消。如果刚刚创建了一个新进程或线程,只要不关闭这些对象的句柄,就能够保证进程对象不被撤消。一旦应用程序结束使用该ID,那么调用CloseHandle就可以释放内核对象,要记住,这时使用或依赖进程ID,对来说将不再安全。如果使用的是子进程,将无法保证父进程或父线程的有效性,除非父进程复制了它自己的进程对象或线程对象的句柄,并让子进程继承这些句柄。

#include <Windows.h>

#include <stdio.h>

int main()

{

    • if(ReadFile(hOutputRead,buffer,4095,&bytesRead,NULL) == NULL)

      {

      break;

      }

      printf(buffer);// 输出

      Sleep(500);
  • SECURITY_ATTRIBUTES sa,sa2;

    HANDLE hInputRead,hInputWrite;

    HANDLE hOutputRead,hOutputWrite;

    //CreatePipe1

    sa.nLength = sizeof(SECURITY_ATTRIBUTES);

    sa.lpSecurityDescriptor = NULL;

    sa.bInheritHandle = TRUE;

    if (!CreatePipe(&hOutputRead,&hOutputWrite,&sa,0))

    {

    printf(“Error On CreatePipe1”);

    return 0;

    }

    //CreatePipe2

    sa2.nLength = sizeof(SECURITY_ATTRIBUTES);

    sa2.lpSecurityDescriptor = NULL;

    sa2.bInheritHandle = TRUE;

    if (!CreatePipe(&hInputRead,&hInputWrite,&sa2,0))

    {

    printf(“Error On CreatePipe2”);

    return 0;

    }

    //CreateProcess

    STARTUPINFO si;

    PROCESS_INFORMATION pi;

    si.cb = sizeof(STARTUPINFO);

    GetStartupInfo(&si);

    si.hStdError = hOutputWrite;

    si.hStdOutput = hOutputWrite;

    si.hStdInput = hInputRead;

    si.wShowWindow = SW_HIDE;

    si.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES;

    DWORD dwWritten;

    if (!CreateProcess(NULL, (program name), NULL, NULL, TRUE, NULL, NULL, NULL, &si, &pi))

    {

    printf(“Error On CreateProcess”);

    return 0;

    }

    CloseHandle(hInputRead);

    CloseHandle(hOutputWrite);

    //Write and read

    char szInPut[20] = … ;// 设置输入内容

    WriteFile(hInputWrite, szInPut, strlen(szInPut), &dwWritten, NULL);

    char buffer[4096] = {0};

    DWORD bytesRead;

    while (true)

    {

    }

    CloseHandle(hInputWrite);

    CloseHandle(hOutputRead);

    system(“pause”);

}

ZZ:http://pzj521.spaces.live.com/blog/cns!7C4820937CC66072!135.entry