Delphi 调用外部 运行程序的方法(300分)

  • 主题发起人 主题发起人 BigMango
  • 开始时间 开始时间
B

BigMango

Unregistered / Unconfirmed
GUEST, unregistred user!
当我用delphi调用一个外部程序(任意程序)的时候希望可以做到类似 Form.ShowModal<br>的功能. 我用了很多方法都不行.<br><br>WinExecAndWait32 &nbsp;虽然可以做到,可是,我的主程序就不能刷新了.<br><br>我用线程在主程序里面作刷新,可是也不管用!!!
 
把鼠标限制在这个窗口内可以吗
 
shellexecute,不过不知道怎么让它showmodal
 
我的程序也有这个问题,好象没有办法
 
我想你关键在于无法从外部进程的Process Info获取它的Main Form Handle,因为<br>ShellExecuteEx和CreateProcess创建进程后,只可以获得Process Handle、ID,而一个<br>Process可能有多个Form,也可能是通过cmd shell调用的dos program,如果你把范围<br>缩小到只有一个Main Form的Process,我想可以实现的,<br><br>var<br>&nbsp; dwProcessID : Cardinal;<br><br>procedure TForm1.Button1Click(Sender: TObject);<br>var<br>&nbsp;StartupInfo:TStartupInfo;<br>&nbsp;ProcessInfo:TProcessInformation;<br>begin<br>&nbsp;FillChar(StartupInfo,SizeOf(StartupInfo),#0);<br>&nbsp;StartupInfo.cb:=SizeOf(StartupInfo);<br>&nbsp;StartupInfo.dwFlags:=STARTF_USESHOWWINDOW;<br>&nbsp;StartupInfo.wShowWindow:=SW_SHOWNORMAL;<br>&nbsp;// 创建notepad 进程并保存Process ID, 并不是Process Handle<br>&nbsp;if CreateProcess(nil,'notepad',nil,nil,false,Create_new_console or Normal_priority_class,nil,nil,StartupInfo,ProcessInfo) then<br>&nbsp; &nbsp;dwProcessID := processinfo.dwProcessId ;<br>end;<br><br>通过Process ID 获取窗口Handle,我没有什么好办法,我用了 EnumWindows(@EnumWindowsProc, 0);<br>枚举所有窗口并使用GetWindowThreadProcessID(HWND, var dwProcessID)来判断该窗口Handle<br>隶属于那个Process ID,<br><br>通过前后的ProcessID对比,我可以准确的找到Notepad窗口Handle,(我已经实验通过了)<br>有了句柄,我想下面就好办了,你可以SetWindowLong(GWL_WNDPROC ...)建立一个窗口进程,<br>截获所有它的WM_ACTIVATE(WA_INACTIVE Deactivated )以及WM_SYSCOMMAND里面的最小化、关闭消<br>息之类的。 也可以建立线程不断的让它SetWindowPos Top显示。
 
试试这一个, 来自 Peter Below(TeamB):<br>{-- WinExecAndWait32V2 ------------------------------------------------}<br>{: Executes a program and waits for it to terminate<br>@Param FileName contains executable + any parameters<br>@Param Visibility is one of the ShowWindow options, e.g. SW_SHOWNORMAL<br>@Returns -1 in case of error, otherwise the programs exit code<br>@Desc In case of error SysErrorMessage( GetlastError ) will return an<br>&nbsp; error message. The routine will process paint messages and messages<br>&nbsp; send from other threads while it waits.<br>}{ Created 27.10.2000 by P. Below<br>-----------------------------------------------------------------------}<br>Function WinExecAndWait32V2( FileName: String; Visibility: integer ): DWORD;<br>&nbsp; Procedure WaitFor( processHandle: THandle );<br>&nbsp; &nbsp; Var<br>&nbsp; &nbsp; &nbsp; msg: TMsg;<br>&nbsp; &nbsp; &nbsp; ret: DWORD;<br>&nbsp; &nbsp; Begin<br>&nbsp; &nbsp; &nbsp; Repeat<br>&nbsp; &nbsp; &nbsp; &nbsp; ret := MsgWaitForMultipleObjects(<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;1, { 1 handle to wait on }<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;processHandle, { the handle }<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;False, { wake on any event }<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;INFINITE, { wait without timeout }<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;QS_PAINT or { wake on paint messages }<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;QS_SENDMESSAGE { or messages from other threads }<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;);<br>&nbsp; &nbsp; &nbsp; &nbsp; If ret = WAIT_FAILED Then Exit; { can do little here }<br>&nbsp; &nbsp; &nbsp; &nbsp; If ret = (WAIT_OBJECT_0 + 1) Then Begin<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; { Woke on a message, process paint messages only. Calling<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; PeekMessage gets messages send from other threads processed. }<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; While PeekMessage( msg, 0, WM_PAINT, WM_PAINT, PM_REMOVE ) Do<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; DispatchMessage( msg );<br>&nbsp; &nbsp; &nbsp; &nbsp; End;<br>&nbsp; &nbsp; &nbsp; Until ret = WAIT_OBJECT_0;<br>&nbsp; &nbsp; End; { Waitfor }<br>&nbsp; Var { V1 by Pat Ritchey, V2 by P.Below }<br>&nbsp; &nbsp; zAppName:array[0..512] of char;<br>&nbsp; &nbsp; StartupInfo:TStartupInfo;<br>&nbsp; &nbsp; ProcessInfo:TProcessInformation;<br>&nbsp; Begin { WinExecAndWait32V2 }<br>&nbsp; &nbsp; StrPCopy(zAppName,FileName);<br>&nbsp; &nbsp; FillChar(StartupInfo,Sizeof(StartupInfo),#0);<br>&nbsp; &nbsp; StartupInfo.cb := Sizeof(StartupInfo);<br>&nbsp; &nbsp; StartupInfo.dwFlags := STARTF_USESHOWWINDOW;<br>&nbsp; &nbsp; StartupInfo.wShowWindow := Visibility;<br>&nbsp; &nbsp; If not CreateProcess(nil,<br>&nbsp; &nbsp; &nbsp; zAppName, { pointer to command line string }<br>&nbsp; &nbsp; &nbsp; nil, { pointer to process security attributes }<br>&nbsp; &nbsp; &nbsp; nil, { pointer to thread security attributes }<br>&nbsp; &nbsp; &nbsp; false, { handle inheritance flag }<br>&nbsp; &nbsp; &nbsp; CREATE_NEW_CONSOLE or { creation flags }<br>&nbsp; &nbsp; &nbsp; NORMAL_PRIORITY_CLASS,<br>&nbsp; &nbsp; &nbsp; nil, { pointer to new environment block }<br>&nbsp; &nbsp; &nbsp; nil, { pointer to current directory name }<br>&nbsp; &nbsp; &nbsp; StartupInfo, { pointer to STARTUPINFO }<br>&nbsp; &nbsp; &nbsp; ProcessInfo) { pointer to PROCESS_INF }<br>&nbsp; &nbsp; Then<br>&nbsp; &nbsp; &nbsp; Result := DWORD(-1) { failed, GetLastError has error code }<br>&nbsp; &nbsp; Else Begin<br>&nbsp; &nbsp; &nbsp; &nbsp;Waitfor(ProcessInfo.hProcess);<br>&nbsp; &nbsp; &nbsp; &nbsp;GetExitCodeProcess(ProcessInfo.hProcess, Result);<br>&nbsp; &nbsp; &nbsp; &nbsp;CloseHandle( ProcessInfo.hProcess );<br>&nbsp; &nbsp; &nbsp; &nbsp;CloseHandle( ProcessInfo.hThread );<br>&nbsp; &nbsp; End; { Else }<br>&nbsp; End; { WinExecAndWait32V2 }
 
bbkxjy:果真高手,看了你的代码倒是解决了我的一个问题,<br>thank you very much
 
你可以试试在一个线程里执行WinExecAndWait32,线程执行完后再交控制权给用户:<br>var<br>&nbsp; Thread: TExecThread;<br>begin<br>&nbsp; Thread := TExecThread.Create; //执行WinExecAndWait32<br>&nbsp; try<br>&nbsp; &nbsp; while not Thread.Terminated do //等待线程执行完毕<br>&nbsp; &nbsp; begin<br>&nbsp; &nbsp; &nbsp; MainForm.Refresh; //刷新主窗体<br>&nbsp; &nbsp; &nbsp; Sleep(1);<br>&nbsp; &nbsp; end;<br>&nbsp; finally<br>&nbsp; &nbsp; Thread.Free;<br>&nbsp; end;<br>end;<br>随手写的,不一定正确,但你可以试试,相信没什么大问题。
 
试了一下,效果还过得去吧:<br>&nbsp; TExecThread = class(TThread)<br>&nbsp; private<br>&nbsp; &nbsp; FExeName: string;<br>&nbsp; &nbsp; procedure SetExeName(const Value: string);<br>&nbsp; public<br>&nbsp; &nbsp; procedure Execute; override;<br>&nbsp; &nbsp; property ExeName: string read FExeName write SetExeName;<br>&nbsp; end;<br><br>{ TExecThread }<br><br>procedure TExecThread.Execute;<br>begin<br>&nbsp; WinExecAndWait(FExeName, SW_SHOWNORMAL);<br>&nbsp; Terminate;<br>end;<br><br>procedure TExecThread.SetExeName(const Value: string);<br>begin<br>&nbsp; FExeName := Value;<br>end;<br><br><br>procedure TFormMain.Button3Click(Sender: TObject);<br>var<br>&nbsp; Thread: TExecThread;<br>begin<br>&nbsp; Thread := TExecThread.Create(True); //执行WinExecAndWait32<br>&nbsp; try<br>&nbsp; &nbsp; Thread.ExeName := Edit1.Text;<br>&nbsp; &nbsp; Thread.Resume;<br>&nbsp; &nbsp; while not Thread.Terminated do //等待线程执行完毕<br>&nbsp; &nbsp; begin<br>&nbsp; &nbsp; &nbsp; Self.Update; //刷新主窗体<br>&nbsp; &nbsp; &nbsp; Sleep(1);<br>&nbsp; &nbsp; end;<br>&nbsp; finally<br>&nbsp; &nbsp; Thread.Free;<br>&nbsp; end;<br>end;<br>
 
application.onactivate的事件发生时激活已经打开的程序,打开的时候获得handle即可。
 
很有意思。<br>现在的程序越来越无聊,<br>什么功能,全是浪费资源。<br>我们要做简单实用的程序。<br>现在的程序说是人性化,<br>可是却越来越使人难使用,<br>只是要你,<br>付出更大的代价!!<br>
 
关键是WaitForSingleObject函数,你用以下代码吧<br>void __fastcall TForm1::Button1Click(TObject *Sender)<br>{<br>&nbsp;STARTUPINFO si;<br>&nbsp; &nbsp; &nbsp; &nbsp; PROCESS_INFORMATION pi;<br><br>&nbsp; &nbsp; &nbsp; &nbsp; si.cb = sizeof(STARTUPINFO);<br>&nbsp; &nbsp; &nbsp; &nbsp; si.dwFlags = STARTF_USESHOWWINDOW;<br>&nbsp; &nbsp; &nbsp; &nbsp; si.wShowWindow = &nbsp;SW_SHOWDEFAULT;<br><br>&nbsp; &nbsp; &nbsp; &nbsp; if(CreateProcess("c://windows//notepad.exe",<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;NULL,NULL,NULL,FALSE,<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;CREATE_DEFAULT_ERROR_MODE,NULL,NULL,<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&amp;si,&amp;pi))<br>&nbsp; &nbsp; &nbsp; &nbsp; {<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; WaitForSingleObject((HANDLE)pi.hProcess,INFINITE);<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ShowMessage("Success");<br>&nbsp; &nbsp; &nbsp; &nbsp; }<br>&nbsp; &nbsp; &nbsp; &nbsp; else<br>&nbsp; &nbsp; &nbsp; &nbsp; {<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ShowMessage("Failure");<br>&nbsp; &nbsp; &nbsp; &nbsp; }
 
后退
顶部