知识大全 后台调用外部程序的完美实现(Delphi)

Posted

篇首语:一箫一剑平生意,负尽狂名十五年。本文由小常识网(cha138.com)小编为大家整理,主要介绍了知识大全 后台调用外部程序的完美实现(Delphi)相关的知识,希望对你有一定的参考价值。

后台调用外部程序的完美实现(Delphi)  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!

其基本思路就是    )调用CreateProcess()打开目标程序    )用FindWindow()找到目标程序的窗口Handle    )找到文本框的Handle 以及按钮的MessageID 用SendMessage()方法设置文字 并触发事件     好了 这样确实很简单吧 但是当我实现它后 却发现这样做的结果则是 当我的程序启动并打开目标程序时 它的Splash窗口 以及主窗口都将显示出来 即使当我用FindWindow()找到主窗口Handle后 调用SendMessage(WindowHandle SW_HIDE)来隐藏该窗口 还是会有一瞬主窗口被显示出来的 这样的效果实在是最求完美的我不忍心看到的     那么怎么解决这个问题呢 首先我当然在CreateProcess()上面寻找方法 可惜 它只有一个参数可以设置窗口的默认显示方式 但是一旦这个窗口自己重设了显示方式 它就没有任何作用了 继续查找文档 这时我看到CreateProcess()的一个参数TStartupInfo中有 lpDesktop这么一个属性 按照MSDN的说法 如果该指针为NULL 那么新建的Process将在当前Desktop上启动 而如果对其赋了一个Desktop的名称后 Process将在指定的Desktop上启动 恩 看来不错 就从它入手了      )首先 建立一个虚拟的Desktop   const  DesktopName = MYDESK ;    FDesktop:=CreateDesktop(DesktopName nil nil GENERIC_ALL nil);  Windows中可以建立多个Desktop 可以使用SwitchDesktop()来切换哪个Desktop被显示出来 以前有过将Windows模拟成Linux的形式 可以在多个虚拟Desktop中切换的程序 其实那种程序也是用的Windows本身的虚拟Desktop功能来实现的 另外 Windows的启动画面 以及屏保画面也都是用虚拟Desktop实现的 好了 关于这方面不多介绍了 感兴趣的话 可以到MSDN中查看更详细资料   sp     )在CreateProcess的时候 指定程序在我新生成的Desktop上运行   var  StartInfo:TStartupInfo;    FillChar(StartInfo sizeof(StartInfo) );  StartInfo cb:=sizeof(StartInfo);  StartInfo lpDesktop:=PChar(DesktopName);   //指定Desktop的名称即可  StartInfo wShowWindow:=SW_HIDE;  StartInfo dwFlags:=STARTF_USESHOWWINDOW;  StartInfo hStdError:= ;  StartInfo hStdInput:= ;  StartInfo hStdOutput:= ;  if not CreateProcess(PChar(FileName) nil nil nil true CREATE_NEW_CONSOLE+HIGH_PRIORITY_CLASS nil PChar(ExtractFilePath(FilePath)) StartInfo FProceInfo) then begin  MessageBox(Application Handle Error when init voice ( ) PChar(Application Title) MB_ICONWARNING);  exit;  end;     )用FindWindow去找程序的主窗口  开始我直接写下了这样的代码   for I:= to do begin //wait seconds for open the main window  WindowHandle:=FindWindow(nil WindowCaption );  if WindowHandle<> then begin  break;  end;  Sleep( );  end;  但是 实践证明 这样是找不到不在当前Desktop中的Window的 那怎么办呢   答案是 可以用SetThreadDesktop()函数 这个函数可以设置当前Thread工作所在的Desktop 于是我在以上代码前又加了一句   if not SetThreadDesktop(FDesktop) then begin  exit;  end;    但是 程序运行后 该函数却返回了false 说明方法调用失败了 再仔细看MSDN 发现有这么一句话     The SetThreadDesktop function will fail if the calling thread has any windows or hooks on its current desktop (unless the hDesktop parameter is a handle to the current desktop)     原来需要切换Desktop的线程中不能有任何UI方面的东西 而我是在程序的主线程中调用该方法的 当然会失败拉 知道了这点就好办了 我只需要用一个 干净 的线程 让它绑定到新的Desktop上 再让它用FindWindow()方法找到我要找的WindowHandle 不就可以了吗 于是 这一步就需要借助一个线程了 线程的代码如下     TFindWindowThread = class(TThread)  private  FDesktop:THandle;  FWindowHandle:THandle;  protected  procedure Execute();override;  public  constructor Create(ACreateSuspended:Boolean;const ADesktop:THandle);reintroduce;  property WindowHandle:THandle read FWindowHandle;  end;     TFindWindowThread     procedure TFindWindowThread Execute();  var  I:Integer;  begin  //make the current thread find window on the new desktop!  if not SetThreadDesktop(FDesktop) then begin  exit;  end;  for I:= to do begin //wait seconds for open the main window  FWindowHandle:=FindWindow(nil PChar( WindowCaption ));  if FWindowHandle<> then begin  break;  end;  Sleep( );  end;  end;    constructor TFindWindowThread Create(ACreateSuspended:Boolean;const ADesktop:THandle);  begin  inherited Create(ACreateSuspended);  FDesktop:=ADesktop;  end;    而主程序中的代码变成这样   FindWindowThread:=TFindWindowThread Create(false FDesktop);  try  FindWindowThread WaitFor;  FMainWindowHandle:=FindWindowThread WindowHandle;  finally  FindWindowThread Free;  end;  if FMainWindowHandle= then begin  MessageBox(Application Handle Error when init voice ( ) PChar(Application Title) MB_ICONWARNING);  exit;  end;    呵呵 成功 这样果然可以顺利的找到窗口Handle了      )最后 再用这个主窗口Handle 找出里面的EditBox的Handle 如这样   FEditWindow:=FindWindowEx(FMainWindowHandle PChar( Edit ) nil);  我在这里指定了这个文本框的ClassName 这个名称可以用Spy++得到       初始化的工作就到此结束了 如果顺利 程序就真正在后台被运行了起来 那么功能调用呢 还是和一般的做法一样     if (FMainWindowHandle= ) or (FEditWindow= ) then begin  exit;  end;  SendMessage(FEditWindow WM_SETTEXT LongInt(@AText[ ]));  SendMessage(FMainWindowHandle WM_MAND $ $ );  其中$ 这个数字 也是用Spy++来得到的资源ID     最后 别忘了关闭程序 以及释放虚拟Desktop   if FProceInfo hProcess<> then begin  TerminateProcess(FProceInfo hProcess );  end;  if FDesktop<> then begin  CloseDesktop(FDesktop);  end; cha138/Article/program/Delphi/201311/8390

相关参考

知识大全 Java调用外部程序技巧

Java调用外部程序技巧  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!  &n

知识大全 c#调用外部程序

  //本来看似非常简单的程序是一个界面左边一个提示有个checkbox提示用户我知道了请不要再显示右边是运行QQ的一个按钮但是弄的时候弄了四个小时左右经常是调试的时候是对的但是有的时候点了按钮过后没

知识大全 工作流引擎Shark中调用外部程序的方法

工作流引擎Shark中调用外部程序的方法  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!  最近看了

知识大全 在PB中调用外部程序并判断其运行结束

在PB中调用外部程序并判断其运行结束  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!  您正在看的P

知识大全 用Delphi编写系统进程监控程序

用Delphi编写系统进程监控程序  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!本程序通过调用ke

知识大全 JavaScript获取后台C#变量以及调用后台方法

JavaScript获取后台C#变量以及调用后台方法  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!

知识大全 在ACCESS 中调用后台存储过程

在ACCESS中调用后台存储过程  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!  ACCESS是一

知识大全 在ACCESS中调用后台存储过程

在ACCESS中调用后台存储过程  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!  ACCESS是一

知识大全 java中调用matlab代码

  MATLAB的最新版本b中新添了一个产品-MATLABBuilderforJava其实本来Matlab就有Java外部程序接口不过原来的接口只能在m文件中调用Java而无法在Java程序中调用Ma

知识大全 Delphi的8个技巧

Delphi的8个技巧  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!  delphi怎样调用外部E