- 浏览: 95671 次
- 性别:
- 来自: 南京
最新评论
-
Afewij:
謝了,樓主..
Godex条码打印机(EZ-PL打印语言)集成开发小结 -
explorer:
tt54321
字符集编码开发总结-BMP查看器 -
openeyes:
问题是RO只支持RO定义的array\struct\enum类 ...
RemObjects SDK 简介 -
explorer:
Delphi中一个宽字符其实就是两个字节的Byte,对应到un ...
字符集编码开发总结-BMP查看器 -
十一文:
原理在哪里啊???
字符集编码开发总结-BMP查看器
julian V.Moss
想由您的Delphi程式控制应用程式的执行吗?这篇文章告诉您如何经由Delphi 1.0以及32 bit的Delphi 2.0执行另处的程式,开启或列印档案,并示 如何在Delphi 2.0中得知所执行的应用程式已经执行完毕,并取得它的结束码(exit code).)
引言部份 在Delphi程式开发者眼中, 有一个经常困扰着大家的问题,那就是如何由自己的Delphi程式控制外部程式的执行.由於Delphi本身并没有提供这方面的功能,因此我们就必须借助於Window API.总括来说,我们有几个选择:在16位元 Window下有二个API可供呼叫,在32位元Window下也有不同的二个API可以运用. 比较简单的方式:WinExec 如果你想要的只是去执行另一个个应用程式,那最简单的方法就是利用户WinExec函式. WinExec可以在WINPROCS单元中找到,它是以下列方式宣告: function WinExec(CmdLine:PChar;CmdShow:Word):Word;
这个函式有二个参数,第一个参数CmdLine是指到包含要执行的命令而且以null字元结尾的字串指标,字串内容包含所要执行程式的名称以及所需的任何选择参数.由於Window本身会依照正常程序来执行这个程式,因此它并不需要一定要以 .exe,.com或者是.bat为副档名,而且如果这个档案在目前的目录,Window的根目录或是系统目录,Delphi程式所在的目录或者是在系统设定的PATH下找得到的话,我们也可以不给完整的路径资讯. 参数CmdShow则用来指定该应用程式开始执行时的状态,其中可能的值可以是WINTYPES单元中的Window常数中定义的任何一个值.你比较可能用到的有SW_SHOW ,SW_SHOWMAXIMIZED以及SW_SHOWMINIMIZED.其中SW_SHOW表示将程式用它预设值或初始值的设定状态显示出来,另外二个我就不多做解释,大家看字面就应该会明白了. 你也可以用SW_SHOWNOACTIVE来把应用程式叫出并停留在初始状态,然後依然把上前的执行权交回给你写的Delphi程式.指定SW_SHOWMINNOACTIVE时状况大致和上述的一样,只不过被执行的应用程式会保留在最小化的状态. WinExec会传回一个16位元instance,其实它是一个用来辨别所执行程式(正确一点应该是程式模组)的数字.合法 instance handle值必须大於或等於32,如果小於32时,Window会给你一个error code来告诉你WinExec执行失败的原因. 用ShellExecute玩些把戏 WinExec虽然简单好用,但是却只能用来执行程式而已.
从Windows 3.1开始多了一个新的函式叫做 ShellExecute,在Delphi的SHELLAPI单元中有定义.就如它字面上意义一样,ShellExecute提供像Program Maneger之类Windows Shell程式的功能.这个函式除了提供执行应用程式的功能之外,你可以利用WIN.INI Registration Database或Windows 95 Registry中有关的资讯来开启或列印档案. ShellExecute也可以在我们没有加上.PIF副档名的情况下执行PIF,并且会寻找在WIN.INI或95 registry下(Program)项目中有关该程式的径设定. ShellExecute用起来有点比较复杂,它的宣告如下: functionShellExecute(Wnd:HWnd;Operation,FileName,Parameters,Directory:PChar;ShowCmd:Integer):THandle;
其中Wnd参数为用来设定系统任何可能发生的错误讯息的父视窗的handle,可以把它设为0.而四个PChar参数Operation.FileName.Parameters以及Dircetory 则为指到以null字元结尾字串的指标值,这些值都必须由Pascal型式的字串转换过来. Operation参数指定要执行的功能,在Windows 3.1下只有二个选择: open 以及 print .Windows 95则增加了如 printto 利用rgeistry机制的新功能,可以用来扩充到包含别的执行功能. open 操作的效果和double-click程式的小图式一样,如果在Filename参数中指定的是一个执行档的话,它就会被执行.如果是一个资料档,那麽就会执行它所连结的程式,如果它本身并没有连结到任何程式的话,你会得到一个Windows的错误讯息. print 操作则是用所连结的列印程式把档案内容列印出来,列印的方式则与所安装的列印该型式格式资料的程式有关,如果没有安装可以列印该格式资料的列印程式,那麽Windows就会显示一个错误讯息对话框. Parameters参数包含Filename中所指定程式的命令行参数,如果Filename中指定不是一个可执行的程式,那麽Parameters的内容应该设为NULL. Windows95相容的程式通常都能够支援它所能辨识档案型式的 操作.在这种情况下, 字串就必须包含如印表机,驱动程式和装置类别的名称,请参考以下的例子. ' Microsoft Fax WPSUNI.DRV FAV:' 'Olivetti JP 250 JP350.DRVLPT1:' 由於印表机名称之中包含空格,因此必须用双引号括起来.利用 printto 操作我们可以把文件送到非预设的印表机上,这在Windows 3.1下是无法做到的. Directory参数让你指定Shell操作的启始目录,如果不指定,就使用目前的目录. ShellExecute的传回值THandle和WinExec一样都是程式的instance handle.同样的,我们必须测试它的值是否大於等於32. 程式还在执行吗? 如果想要知道你由WinExec或者是ShellExecute所执行的程式是否还在执行中,我们应该要储存传回来的instance handle值,GetModuleUsage函式(在WINPROCS中宣告)传回由你所给的instance handle所指到的程式模组载入的次数,宣告如下: function GetModuleUsage(Module:THandle):integer;通常这个传回值在程式还在执行时为1,执行结束后为0.以下的程式可以用来测试Hanle值为ih的程式是否还在执行. isRunning:=GetModuleUsage(ih)>0;在通常情况下,我们会肥如上的指令放在一个回圈内,以方便别的程式使用CPU的资源,并一直等到GetModuleUsage的传回值变为0. 把WinExec及ShellExecute重新包装 程式列表一以及列表二分别包含了可以使用WinExec或ShellExecute执行程式的Delphi函式.你必须传给它一个命令行参数,一个用来指定视窗初始状态的SW_SHOW常数以及一个Boolean参数Wait,以告诉这个函式要在开始末执行外部应用程式后就直接跳出,或者是要等到所执行的应用程式执行完毕后才离开.这二个函数会在执行成功后传回True,失败则传回False.
程式列表一:利用WinExec执行程式
function Execute(const commandstr:String;show:Word;wait:Boolean):Boolean;
var ih:Word;
cmdbuf:Array[0..255]of Char;
begin ih:=WinExec(StrPCopy(cmdbuf,commandstr),show);
Result:=ih>=32;
if Result and wait then repeat Application.ProcessMessages until GetModuleUsage(ih)=0;
end;
程式列表二:利用ShellExecute执行程式
function ShellExec(const op,fn,par,dir:String show:Word;wait:Boolean):Boolean;
var ih:Word;
Operation,FileName,Parameters,Directory:PChar;
begin GetMem(Operation,Length(op)+1);
GetMem(Filename,Length(fn)+1);
GetMem(Parameters,Length(par)+1);
GetMem(Directory,Length(dir)+1);
try StrPCopy(Operation,op);
StrPCopy(Filename,fn);
StrPCopy(Parameters,par);
StrPCopy(Directory,dir);
ih:=ShellExecute(0,Opeation,Filename, Parameters,Directory,SW_SHOW);
Result and wait then repeat Application.ProcessMessages until GetModuleUsage(ih)=0;
finally FreeMem(Directory,Length(dir)+1);
FreeMem(Parameters,Length(par)+1);
FreeMem(Filename,Length(fn)+1);
FreeMem(Operation,Length(op)+1);
end;
end;
你可以利用本期所附磁片中的 例程式Exec16来试试这两个函式的功能.
如果你写的程式是打算在Windows95下运作的,那麽利用GetModuleUsage这个函式来测试一个程式是否已经执行结束就会发生一些问题.问题的根源在於在 Win32 底下,instance handle ih 并不是用来辨识某个应用程式的唯一handle.举例来说,如果你一次执行了两个Notepad,那GetModuleUsage会一直等到两个Notepad都结束执行以后才会传回0这个值.幸运的是,这种情况不常发生,不过却也没甚麽好的解决方法,除非使用Win32中新提供的函式来执行外部程式.当然,要这麽做的话,我们就必须要用到Delphi 2.0版了. Delphi2.0和Windows 95 在把使用WinExec或者ShellExec函式的Delphi1.0程式移植到Delphi2.0的环境中并不会造成任何问题,然而由於Win32 API并不支援GetModuleUsage这个函式,因此在像程式列表一或二中这类使用情况下,Delphi2.0的编译器就会给你一个错误讯息.加此如果我想要在Win32底下测试一个程式是否已经执行完毕,就必须利用 32 bit的API函式重写我们的程式. 在Win32中有二个函式可以用来控制应用程式的执行,分别为CreateProcessc以及ShellExecuteEx.其中CreateProcessc大致上具备WinExec的所有功能,不过参数多得吓人,共有10个.其中有4个是指到记录结构(record structure)的指标值,这些记录包含程式安全属性(process security attributes),执行绪安全属性(thread security attributes),启始属性(startup attributes)以及关於这个程序的传回资讯(return information).CreateProcess事实上是一个具有相当多功能的通用函式,执行程式只是其中的一个功能.如果你要的只是执行一个外部的应用和一式的话,使用ShellExecuteEx应该会简单一些.ShellExecuteEx的功用基本上各16位元版本的hellExecute函式差不多,其中Ex代表的是Extended的意思,这个字通常用来标示具有类似功能16位元函式的32位元版本. ShellExecuteEx 定义如下: function ShellExecuteEx(PShellExecuteinfo):Boolean;PShellExecuteinfo 是指到型态为TShellExecuteinfo的一笔记录的指标值,另外这个函式也会在执行成功后传回True,失败则传回False.传给ShellExecuteEx 函式的资讯是以参数方式进行,并且使用TshellExecuteInfo结构,这个结构同时也用来将资讯传回给原呼叫程序. TshellExecuteInfo结构的定义如下:
TShellExecuteInfo=Record cbSize:DWord;
fMask:ULong;
ipVerb:PChar;
ipFile:PChar;
ipParameters:PChar;
ipDirectory:PChar;
nShow:Word;
hlnstApp:ULong;
iplDList:Pointer;
ipClass:PChar;
hkeyClass:hKey;
dwHotKey:DWord;
hlcon:THandle;
hProcess:THandle;
end;
Delphi2.0编译器能接受如C++语言中DWord以及ULong等32位元的无正负号值,这些东西虽然看起来没有Pascal的味道,但是在参考以C++为准所撰写的文件时会变得比较容易. 在使用TShellEXecuteInfo结构之前,我们必须把它初始化为0,并且得在cbSize 栏位中填入结构的大小.fMask栏位含了一些告诉ShellExecuteEx如何来处理结构中其它资料的旗标值(flag),其中最基本的一个是SEE_MASK_NOCLOSEPROCESS,这会使得函式传回在hProcess栏位中所建立的Process的handle值.另外的指标值则用来指出允许的hotKey或者是改变该程式执行时的小图示(icon). 旗标SEE_MASK_CONNECTNETDRY指出lpFile字串是一个在网路上UNC(Universal Naming Convention)路径上的档案,因此系统须连到网路磁碟机.SEE_MASK_DOENVSUBST指出lpFile或lpDirectory字串内的环境变数会被展开.由於这些旗标值都是用位元做mask,因此在同时需要指定两个以上的功能时,我们可以直接将这些SEE_MASK_XXX常数加起来. lpVerb,lpFile,lpParameter和lpDirectory分别是指到代表要进行的操作,档案名称,命令行参数以及启始目录的null结尾字串.nShow的值则可以是SW_SHOW数值中的任一个,用来指定被执行的应用程式起始的状态.lpIDList,lpClass,hKeyClass,dwHotKey以及hIcon栏位通常都没有用到,除非你在fMask中设定一个到目前为止我们还没有提到的旗标值.如果各位读者想写一个 Windows Shell程式,那麽建议你参考Win32 API方面的文件以获得更详细的资讯,因为每个栏位都蛮有用处的,然而如果你只想要由Delphi执行一个程式或者列印档案,你也可以不管上述的这些参数. 函式中还有一个栏位用来收取所执行程式的相关资讯.hInstApp栏位的内容就相当於16元的WinExce或者是ShellExecute呼叫所传回的值.ShellExecuteEx的传回值则包含要被执行程式如果无法启动时的错误码,不过不管怎麽说,最重要的还是hProcess这个代表新执行程序的唯一handle值. 程式还在执行吗?32位元版
我们可以利用hProcess以及新的32位元函式WaitForSingleObject来测试程序是否已经执行完毕.
WaitForSingleObject的宣告如下:
function WaitForSingleObject(hObject:Thandle;dwTimeout:Dword):DWord;
hObject是我们要等待的物件的handle值,在这个例子中就是hProcess程序的handle.dwTimeOut则为此函式要等待的最长时间,以millisecond为单位.传回值DWord则有两种可能,第一是常数WAIT_TIMEOUT,告诉我们经过所设定的时间之后,这个程式还在执行,第二则是传回WAIT_OBJECT_0,用来告诉我们程式已经执行完毕.
用来等待程式执行结束的回圈大致如下:
while WaitForSingleObject(hProcess,100)=WAIT_TIMEOUT do Application.ProcessMessage;其中WaitForSingleObject将你的Delphi程式(或者更精确地,执行绪,不过通常都一样,除非你写的是一个多执行绪的程式)在等待timeout的期间完全进入睡眠状态. 当程式在睡眠状态时它并不能处理传进来的讯息,也就是说,如果程式在最小化状态或者因为有别的程式执行遮盖到它的视窗画面之后又结束时,它便无法再重绘自己的视窗,因此在选择dwTimeOut的值时必须不能太长,譬如说100ms,以便在程式的执行效率以及程式必须要能回应发生事件所需等待的时间两者之间取得最佳的协调. 取得结束码 32位元Windows API提供了程式师长久以来想要的东西,那就是提供被叫用程式(通常为DOS程式,虽然Windows程式也会传回结束码)的结束码.要取得结束码相当简单,只要在程序结束时使用GetExitCodeProcess呼叫即可,
函式宣告如下:
function GetExitCodeProcess(hProcess:THandle;var lpExitCode:DWord):Boolean;
这时,hProcess这个handle依旧是代表这个程式的唯一值,传回的值(或者例外情况下传回的例外值)会被放到变数lpExitCode中,如果这个程式还在运作,lpExitCode的值就是STILL_ACTIVE.如果有某些原因造成它执行错误,GetExitCodeProcess会传回false. 32位元版的ShellExec 程表式列表叁是一个32位元版的ShellExec函式,它用的参数与程式列表二中的16位元版本一样,不同的是,传回的是一个32位元的值.其中wait参数如果设为 True,函式将会等到所执行程式结束才回传回它的结束码,如果设为False的话,那麽就会因为无法得到结束码而只传回0.如果其中呼叫ShellExecEx或者是GetExitCodeProcess的过程有问题的话,传回值则为-1. 程式列表叁是,利用ShellExecuteEx执行程式
fumction ShellExec(op,fn,par,dir:PChar;show:Word;wait:Boolean):Longlnt;
var ih:Word;
OK:Boolean;
info:TShellExecutelnfo;
begin FillChar(info,SizeOf(info),Chr(0));
info.cbSize:=SizeOf(info);
info.fMask:=SEE_MASK_NOCLOSEPROCESS;
info.ipVerb:=op info.ipFile:=fn;
info.lpParameters:=par;
info.lpDirectory:=dir;
info.nShow:=show;
OK:Boolean(ShellExecuteEx(@info));
if OK then bgein if wait then bgein while WaitForSingleObject(info.hProcess,100)=WAIT_TINEOUT do Application.ProcessMessages;
OK:=GetExitCodeProcess(info.hProcess,DWord(Result));
end else Result:=0;
end;
if not OK then Result:=-1;
end;
磁片中的 例程式必须用Delphi 2.0来编译,它使得你可以在把ShellExec 函式并入你的应用程式之前先试一试函式的功能. 总结 由所撰写的Delphi应用程式来控制外部不管是DOS或者是Windows程式的执行可以应用在许多的场合.藉由本篇文章所介绍的函式可以轻易地把这个功能加到你的程式中,如果你使用了上述的ShellExec函式,那麽由於它在16位元以及32位元版本上的定义相当类似,因此在需要把程式由16位元转换到Delphi 2.0时,事情将会变得非常简单,只要做一些小修改就可完成.
发表评论
-
TStringList实例调用AddStrings 跟踪
2012-04-11 17:22 2466创建了一个TStringList的实例并调用AddString ... -
Godex条码打印机(EZ-PL打印语言)集成开发小结
2012-03-15 22:32 3864Godex条码打印机 以EZ-1100p为例,使用简单可靠,集 ... -
Office MODI 因KB973507补丁导致异常
2012-03-11 22:17 1144回忆整理一下。 2009年8月,因微软发布了 KB973507 ... -
Brother 打印机集成开发总结
2012-03-10 22:14 2474[搬家贴] 作者: explorer ... -
SleuthQA CodeWatch 跟踪后台服务资源泄漏
2012-03-10 22:08 1248某日,一个我编写的Delphi 应用(dll 插件)被发现运行 ... -
远程桌面连接后Desktop没有托盘图标的解决方案
2012-03-10 20:02 1819缘由: 我们的某 services应用会在服 ... -
JPEG2000 集成开发 之三
2012-03-09 20:48 1609应用背景 需 ... -
JPEG2000 集成开发 之二
2012-03-09 17:32 2595寻找到的核心SDK Pega ... -
AQTime 跟踪 D7程序一瞥
2012-03-08 22:15 954总 ... -
VCL StringReplace Bug跟踪纪要
2012-03-07 21:56 1076为了解析一段字符串,使用了sysutils 中的 Str ... -
PDF相关开发总结
2009-08-04 10:59 0PDFlib 功能强大、齐全,sdk 说明帮助多。ser ... -
字符集编码开发总结-BMP查看器
2009-07-30 17:43 2020最近一个application需要用到分语种过滤widestr ... -
JPEG2000 集成开发 之一
2012-03-09 17:23 1298前言 jpeg2000与jpeg相比 ... -
Office MODI进行OCR
2008-12-05 14:07 9216转载,原文出处: http://www.comicer.com ... -
基于Office MODI 进行OCR二次开发
2008-12-04 17:22 9134最近在开发 Delphi 7中需要使用Office 2003的 ... -
Delphi 编码规范
2007-09-07 09:48 26变量规范 bPHandle : Boolean; -
nt上获取父进程
2007-09-05 18:14 2465用ToolHelp APi 取进程列表,获取父进程的代码, ... -
DLL ActiveForm 线程同步问题
2007-07-27 09:44 2893DLL/ActiveForm中的线程同步处理 经常看到 ...
相关推荐
在Windows编程中,有时我们需要调用外部程序或者执行DOS命令。本文将对在VC++环境中常用的三种方法进行总结:System、WinExec和ShellExecute,它们都是用来启动新进程的有效方式。 一、System (一)函数原型: ``...
在Windows程序设计中,我们经常会遇到需要打开一个新窗口或者启动一个外部应用程序的需求,例如打开网页、执行文件等。`WinExec`和`ShellExecute`是两个常用的API函数,它们能够帮助我们实现这些功能。 `WinExec`...
Delphi 调用外部程序详解 Delphi 调用外部程序是 Delphi programming 中一...Delphi 调用外部程序是 Delphi programming 中一个非常重要的知识点,使用 WinExec 和 ShellExecute 两个函数可以实现调用外部程序的功能。
WinExec 函数用于执行一个外部程序或命令。它的声明如下: UINT WinExec(lpCmdLine: LPCSTR, uCmdShow: UINT); 其中,lpCmdLine 是要执行的命令或程序名,uCmdShow 是启动选项。该函数返回一个 UINT 类型的值,...
然而,它也存在一些缺点,例如完全与本进程脱离,无法对外部程序进行控制,也无法得知外部程序的退出码。 二、ShellExecute函数 ShellExecute函数也是Windows API提供的一种方法,它可以用来执行外部应用程序或者...
在 C++ 中,我们可以使用三种方法来运行外部程序,即 WinExec、ShellExecute 和 CreateProcess。下面我们将详细介绍这三种方法的使用和注意事项。 WinExec WinExec 是一个简单的函数,可以用来启动一个外部程序。...
在LabWindows/CVI中,有时我们需要调用外部程序来扩展功能或者与其他软件进行数据交换。本资源提供了调用外部程序的六种方法的源代码,这对于开发者来说是一份宝贵的学习和参考材料。 1. **系统调用函数system()** ...
在 C++ 中,运行外部程序可以使用多种方法,包括使用 WinExec、ShellExecute 和 CreateProcess 函数。在本文中,我们将详细介绍这三个函数的使用方法和注意事项。 一、WinExec 函数 WinExec 函数用于执行外部程序...
本文总结了C++程序启动外部程序的两种方法:使用WinExec命令和使用ShellExecute命令。这些方法可以用来启动外部应用程序、打开文档文件或搜索文件夹。 WinExec命令 WinExec命令是一个简单的方式来启动外部程序。...
C++ 中有多种方式可以运行外部程序,包括使用 WinExec、ShellExecute 和 CreateProcess 等 SDK 函数。这些函数可以满足不同的需求,但也存在一些注意事项和限制。 首先,需要定义相关的头文件,包括 `<windows.h>` ...
在VC++编程环境中,有三种主要的SDK函数用于调用外部程序:WinExec,ShellExecute,以及CreateProcess。这些函数提供了不同的功能和灵活性,适用于不同的应用场景。 首先,WinExec是最简单的调用外部程序的方法,它...
在 C++ 程序中,启动外部程序有多种方法,本文总结了两种常用的方法:使用 WinExec 命令和使用 ShellExecute 命令。 使用 WinExec 命令 WinExec 函数原型为:UINT WinExec(LPCSTR lpCmdLine, UINT uCmdShow); 其中...
本文主要介绍了两种在Windows环境下启动外部程序的方法:WinExec和ShellExecute。 1. WinExec函数 WinExec是Windows API中的一个函数,常用于启动外部程序。函数原型如下: ```cpp UINT WinExec(LPCSTR lpCmdLine,...
C++程序启动外部程序的方法总结可以分为两种,即使用WinExec函数和使用ShellExecute函数。 使用WinExec函数 WinExec函数是一个在C++程序中启动外部程序的常用方法。其函数原型为:UINT WinExec(LPCSTR lpCmdLine, ...
在VC++编程中,有三种主要的方法用于调用外部程序:WinExec,ShellExecute和CreateProcess。每种方法都有其特点和适用场景。 1. **WinExec** - `WinExec`是最简单的调用外部程序的方式,仅需两个参数:一个是程序...
WinExec函数是Delphi中调用外部程序的一种简单方式。它接受两个参数:被调用程序的路径和名称,以及程序的显示模式(例如,最大化、最小化或隐藏)。例如: ```delphi WinExec('Notepad.exe', SW_MAXIMIZE); ```...
在VC++编程中,有三种主要的函数用于调用外部程序:WinExec,ShellExecute,以及CreateProcess。这些函数在不同的场景下各有优劣,可以根据实际需求选择合适的调用方式。 1. **WinExec** - WinExec是最简单的调用...