亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 編程 > Delphi > 正文

后臺調用外部程序的完美實現(Delphi)

2019-11-18 18:00:41
字體:
來源:轉載
供稿:網友
最近在做的一個軟件,其中有一部分功能需要調用其它的軟件來完成,而那個軟件只有可執行文件,根本沒有源代碼,幸好,我要做的事不難,只需要在我的程序啟動后,將那個軟件打開,在需要的時候,對其中的一個文本礦設置一些文字,再點擊一個按鈕就可以了。

說到這里,相信你也有了對該功能的一些初步設想了,沒錯,其基本思路就是:
1)調用CreatePRocess()打開目標程序。
2)用FindWindow()找到目標程序的窗口Handle。
3)找到文本框的Handle,以及按鈕的MessageID,用SendMessage()方法設置文字,并觸發事件。

好了,這樣確實很簡單吧,但是當我實現它后,卻發現這樣做的結果則是:當我的程序啟動并打開目標程序時,它的Splash窗口,以及主窗口都將顯示出來,即使當我用FindWindow()找到主窗口Handle后,調用SendMessage(WindowHandle, SW_HIDE)來隱藏該窗口,還是會有一瞬主窗口被顯示出來的,這樣的效果實在是最求完美的我不忍心看到的。

那么怎么解決這個問題呢,首先我當然在CreateProcess()上面尋找方法,可惜,它只有一個參數可以設置窗口的默認顯示方式,但是一旦這個窗口自己重設了顯示方式,它就沒有任何作用了。。。。繼續查找文檔,這時我看到CreateProcess()的一個參數TStartupInfo中有 lpDesktop這么一個屬性,按照MSDN的說法,如果該指針為NULL,那么新建的Process將在當前Desktop上啟動,而如果對其賦了一個Desktop的名稱后,Process將在指定的Desktop上啟動,恩,看來不錯,就從它入手了:

1)首先,建立一個虛擬的Desktop,
const
  DesktopName = 'MYDESK';

FDesktop:=CreateDesktop(DesktopName,nil,nil,0,GENERIC_ALL,nil);
Windows中可以建立多個Desktop,可以使用SwitchDesktop()來切換哪個Desktop被顯示出來,以前有過將Windows模擬成linux的形式,可以在多個虛擬Desktop中切換的程序,其實那種程序也是用的Windows本身的虛擬Desktop功能來實現的,另外 Windows的啟動畫面,以及屏保畫面也都是用虛擬Desktop實現的,好了,關于這方面不多介紹了,感興趣的話,可以到MSDN中查看更詳細資料:
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dllproc/base/enumdesktops.asp

2)在CreateProcess的時候,指定程序在我新生成的Desktop上運行:
var
  StartInfo:TStartupInfo;

  FillChar(StartInfo, sizeof(StartInfo), 0);
  StartInfo.cb:=sizeof(StartInfo);
  StartInfo.lpDesktop:=PChar(DesktopName);      //指定Desktop的名稱即可
  StartInfo.wShowWindow:=SW_HIDE;
  StartInfo.dwFlags:=STARTF_USESHOWWINDOW;
  StartInfo.hStdError:=0;
  StartInfo.hStdInput:=0;
  StartInfo.hStdOutput:=0;
  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 (5).',PChar(Application.Title),MB_ICONWARNING);
    exit;
  end;

3)用FindWindow去找程序的主窗口
開始我直接寫下了這樣的代碼:
  for I:=0 to 60 do begin //wait 30 seconds for open the main window
    WindowHandle:=FindWindow(nil,'WindowCaption');
    if WindowHandle<>0 then begin
      break;
    end;
    Sleep(500);
  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:=0 to 60 do begin //wait 30 seconds for open the main window
    FWindowHandle:=FindWindow(nil,PChar('WindowCaption'));
    if FWindowHandle<>0 then begin
      break;
    end;
    Sleep(500);
  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=0 then begin
    MessageBox(Application.Handle,'Error when init voice (6).',PChar(Application.Title),MB_ICONWARNING);
    exit;
  end;

呵呵,成功,這樣果然可以順利的找到窗口Handle了。

4)最后,再用這個主窗口Handle,找出里面的EditBox的Handle,如這樣:
  FEditWindow:=FindWindowEx(FMainWindowHandle,0,PChar('Edit'),nil);
我在這里指定了這個文本框的ClassName,這個名稱可以用Spy++得到。

初始化的工作就到此結束了,如果順利,程序就真正在后臺被運行了起來。那么功能調用呢,還是和一般的做法一樣:

  if (FMainWindowHandle=0) or (FEditWindow=0) then begin
    exit;
  end;
  SendMessage(FEditWindow,WM_SETTEXT,0,LongInt(@AText[1]));
  SendMessage(FMainWindowHandle,WM_COMMAND,$8012,$0);
其中$8012這個數字,也是用Spy++來得到的資源ID。

最后,別忘了關閉程序,以及釋放虛擬Desktop:
  if FProceInfo.hProcess<>0 then begin
    TerminateProcess(FProceInfo.hProcess,0);
  end;
  if FDesktop<>0 then begin
    CloseDesktop(FDesktop);
  end;

好了,這樣就幾乎完美的實現了一個后臺調用程序的功能,它對最終客戶來說將是完全透明的,客戶根本感覺不到后臺還有另一個程序在工作。是不是很爽啊,這樣別人的很多程序我們都可以直接拿來用了(當然了,得在遵守版權的基礎上才行拉)。

有任何改進意見,或交流,可以Mail至:tonyki[at]citiz.net


上一篇:DELPHI基礎開發技巧

下一篇:利用VFI提高Delphi程序的重用性

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
學習交流
熱門圖片

新聞熱點

疑難解答

圖片精選

網友關注

亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
欧美日韩成人黄色| 国产成人精品一区| 国产精品成人v| 久久亚洲影音av资源网| 久久久久久久影院| 国产精品久久久久久久久久久久久久| 中文字幕免费精品一区| 欧美天天综合色影久久精品| 在线日韩欧美视频| 久久人91精品久久久久久不卡| 91在线高清免费观看| 日韩av电影手机在线观看| 91老司机在线| 韩国精品久久久999| 91国内精品久久| 成人免费xxxxx在线观看| 亚洲最新中文字幕| 国产精品影片在线观看| 日韩中文第一页| 日韩在线免费av| 亚洲高清免费观看高清完整版| 久久免费视频这里只有精品| 色www亚洲国产张柏芝| 国产日韩一区在线| 日韩免费在线观看视频| 国产区精品在线观看| 日韩一区二区精品视频| 欧美富婆性猛交| 国产精品久久久久久久久免费看| 国产香蕉精品视频一区二区三区| 欧美激情欧美激情| 亚洲最大av在线| 亚洲国产成人在线播放| 国产亚洲精品综合一区91| 国产网站欧美日韩免费精品在线观看| 欧美精品情趣视频| 亚洲国产第一页| 欧美精品电影在线| 亚洲成人精品视频在线观看| 97人人做人人爱| 国语对白做受69| 日韩国产欧美精品在线| 欧美激情视频一区二区三区不卡| 欧美成人sm免费视频| 精品久久久久久亚洲国产300| 久久久精品免费视频| 91精品国产高清久久久久久久久| 欧美激情一区二区三级高清视频| 欧美一区二区三区免费观看| 日韩欧美亚洲一二三区| 亚洲午夜久久久影院| 国产精品爽黄69| 欧美xxxx14xxxxx性爽| 欧美激情在线观看| 精品久久久久久久久久| 久久久午夜视频| 色天天综合狠狠色| 久久中文字幕在线| 日韩av手机在线观看| 久久99久久亚洲国产| 日韩国产欧美精品一区二区三区| 国产精品视频网| 亚洲国模精品私拍| 久久的精品视频| 国产精品视频专区| 国产一区二区精品丝袜| 亚洲国产欧美一区| 久久亚洲精品中文字幕冲田杏梨| 国产精品视频地址| 中文字幕日韩视频| 91视频国产一区| 欧美精品videossex88| 欧美专区在线播放| 中文字幕欧美视频在线| 欧美成aaa人片在线观看蜜臀| 久操成人在线视频| 国产精品爽黄69| 亚洲国产毛片完整版| 久久综合伊人77777| 国产精品久久久久久一区二区| 亚洲第一级黄色片| 日韩av网站电影| 日韩经典一区二区三区| 欧美精品videosex牲欧美| 欧美精品久久久久久久久久| 午夜精品久久久99热福利| 亚洲片国产一区一级在线观看| 欧美一区二区三区……| 亚洲一区www| 精品成人在线视频| 久久久久久成人精品| www亚洲欧美| 日韩在线视频网| 国外视频精品毛片| 国产又爽又黄的激情精品视频| 91av在线播放视频| 亚洲综合成人婷婷小说| 日韩小视频在线| 91亚洲人电影| 久久躁日日躁aaaaxxxx| 国产99久久精品一区二区| 中文字幕欧美日韩精品| 中文.日本.精品| 久久视频这里只有精品| 亚洲欧洲美洲在线综合| 92看片淫黄大片看国产片| 色综合久久精品亚洲国产| 欧美极品少妇xxxxⅹ喷水| 欧美日韩中文字幕在线视频| 欧美综合国产精品久久丁香| 色婷婷亚洲mv天堂mv在影片| 国产精品劲爆视频| 国产精品老牛影院在线观看| 亚洲国内高清视频| 欧美黄色免费网站| 中文字幕久久亚洲| 日韩av手机在线看| 亚洲一区二区日本| 欧美成年人视频网站欧美| 永久免费看mv网站入口亚洲| 久久天堂av综合合色| 色综合色综合久久综合频道88| 青草热久免费精品视频| 国产精品久久久久影院日本| 亚洲色图第三页| 国产精品第三页| 欧美精品久久久久久久久| 日韩欧美aⅴ综合网站发布| www.日韩视频| 亚洲国内精品在线| 久久久久久尹人网香蕉| 欧美猛交ⅹxxx乱大交视频| 91精品免费视频| 日韩av综合中文字幕| 久久精品亚洲精品| 国产精品电影网| 97精品国产aⅴ7777| 国产欧美在线观看| 亚洲品质视频自拍网| 国产精品成人aaaaa网站| 成人免费视频在线观看超级碰| 欧美一区深夜视频| 久久久久久久爱| 欧美xxxx做受欧美| 136fldh精品导航福利| 欧美一区深夜视频| 精品亚洲aⅴ在线观看| 亚洲第一天堂无码专区| 成人在线精品视频| 色婷婷成人综合| 亚洲另类xxxx| 国产精品久久久久福利| 中文字幕在线国产精品| 亚洲伊人第一页| 亚洲热线99精品视频| 久久成人这里只有精品| 亚洲精品国产精品国自产在线| 精品人伦一区二区三区蜜桃免费| 菠萝蜜影院一区二区免费| 亚洲图片在区色| 亚洲第一页在线| 日韩中文字幕视频| 久久国产精品久久久久久久久久| 在线精品播放av|