国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁(yè) > 學(xué)院 > 開(kāi)發(fā)設(shè)計(jì) > 正文

再談后臺(tái)調(diào)用外部程序的完美實(shí)現(xiàn)

2019-11-18 17:59:09
字體:
來(lái)源:轉(zhuǎn)載
供稿:網(wǎng)友

上次介紹了如何在Delphi中使用發(fā)送消息的方式控制外部程序,一開(kāi)始我在自己的項(xiàng)目中也確實(shí)是這么做的,但是后來(lái)遇到了這么一個(gè)問(wèn)題:

我所調(diào)用的程序,會(huì)在執(zhí)行一段處理過(guò)程中,將結(jié)果顯示到一個(gè)ListView中,那么為了知道我發(fā)出的命令,到底被那個(gè)程序執(zhí)行后結(jié)果如何,我就必須監(jiān)視ListView中的內(nèi)容,察看最后出現(xiàn)的結(jié)果文字是什么,從而知道到底是成功還是失敗了。那么,我的想法是,不斷的查詢ListView中Items的個(gè)數(shù),并且當(dāng)個(gè)數(shù)大于0的時(shí)候,取出最后一條Item(就是最后加入的結(jié)果描述),然后取得其中的文字,通過(guò)判斷字符串,就可以知道結(jié)果了。

首先,ListView的窗口Handle我當(dāng)然是有了,然后取得ListView中的Item個(gè)數(shù),我發(fā)現(xiàn)有這么個(gè)函數(shù)可以使用:ListView_GetItemCount(),它在CommCtrl模塊中有定義,其實(shí)只是對(duì)SendMessage的一個(gè)封裝而已,同樣的,該模塊中還有另一個(gè)函數(shù):ListView_GetItemText(),使用它可以取得指定行處的Item文字。

那么只要在我的程序中使用這兩個(gè)函數(shù)就可以了咯?很抱歉,我用實(shí)際經(jīng)歷告訴你:這樣將會(huì)導(dǎo)致外部程序的崩潰!!

要說(shuō)明為什么,首先讓我們來(lái)看一下ListView_GetItemText()函數(shù)到底做了什么(另外還有ListView_GetItemTextA和ListView_GetItemTextW這兩個(gè)函數(shù),暫時(shí)不用去理它們):

function ListView_GetItemText(hwndLV: HWND; i, iSubItem: Integer;
  pszText: PChar; cchTextMax: Integer): Integer;
var
  Item: TLVItem;
begin
  Item.iSubItem := iSubItem;
  Item.cchTextMax := cchTextMax;
  Item.pszText := pszText;
  Result := SendMessage(hwndLV, LVM_GETITEMTEXT, i, Longint(@Item));
end;

相信你能看明白,它將一個(gè)字符串指針pszText放到item結(jié)構(gòu)中,再用SendMessage將該結(jié)構(gòu)地址傳給ListView窗口,在本地程序中這當(dāng)然不會(huì)有問(wèn)題,但是試想一下在外部exe中的情況,Item和pszText都是我的程序中的變量,外部exe有自己的獨(dú)立進(jìn)程空間,同樣的變量地址在它的進(jìn)程空間中指向的是完全不同的數(shù)據(jù),并且很有可能該數(shù)據(jù)正在被其它程序段使用,那么當(dāng)外部程序收到Message,并向該錯(cuò)誤的地址中寫入數(shù)據(jù)的時(shí)候,程序就這么崩潰了!

難道就沒(méi)有辦法解決這個(gè)問(wèn)題了嗎?當(dāng)然有!很簡(jiǎn)單,我只需要保證外部程序收到Message時(shí),將數(shù)據(jù)寫入到本地進(jìn)程空間中的地址中就可以了,那么這就意味著我必須在外部程序中開(kāi)辟一塊內(nèi)存,讓SendMessage來(lái)寫入,并且能夠從中將數(shù)據(jù)讀回來(lái),有什么辦法呢?在這里就要感謝Robert Kuster這個(gè)大師級(jí)人物了,他在以下這篇文章中詳細(xì)的介紹了多種將代碼注入外部程序的方法:

Three Ways to inject Your Code into Another PRocess

我選擇了第二種,即制作一個(gè)dll,由主程序?qū)⑦@個(gè)dll注入到外部程序的進(jìn)程空間中,以后就可以為所欲為了,哈哈!Robert Kuster的例子中,只需要用dll中的代碼取一個(gè)文本框中的密碼就可以了,而我的稍有不同,我需要不斷的監(jiān)視ListView中的狀態(tài),所以我使用了一個(gè)線程,dll被注入后,立即啟動(dòng)自己的線程,并進(jìn)入線程循環(huán),一直到外部程序關(guān)閉,線程會(huì)被自動(dòng)關(guān)閉(所以關(guān)閉的事,我就不管了)。

另外,既然有了線程,連控制外部程序的代碼都可以放在線程中,這么一來(lái)就變成這樣的一個(gè)流程了:

1。主程序再虛擬桌面上啟動(dòng)外部程序,并將自制dll注入外部程序的進(jìn)程

2。被注入的dll啟動(dòng)線程,線程的開(kāi)始,先找到所有需要使用的窗口的WindowHandle,這一點(diǎn)還是用FindWnidow方法。接著打開(kāi)一個(gè)共享內(nèi)存區(qū),用來(lái)和主程序通訊使用。

3。進(jìn)入dll的線程循環(huán),循環(huán)中使用一個(gè)event進(jìn)入等待狀態(tài)。

4。當(dāng)主程序中需要使用外部程序的功能時(shí),將控制命令寫入共享內(nèi)存中,然后觸發(fā)event。

5。被注入dll中的線程的event被觸發(fā),它從共享內(nèi)存中取得控制命令,然后使用SendMessage啟動(dòng)外部程序的功能,并進(jìn)入循環(huán),等待ListView中出現(xiàn)結(jié)束文字。

6。外部程序中的功能執(zhí)行結(jié)束后,dll中的線程再以event的方式通知主程序。

好了,這下真的是“完美”實(shí)現(xiàn)了!

由于商業(yè)上的原因,代碼我就不能公開(kāi)了,如果你還有什么疑問(wèn),倒是隨時(shí)歡迎來(lái)信討論:tonyki[at]citiz.net

http://www.tonixsoft.com



上一篇:關(guān)于TButton類型不能響應(yīng)OnDBClick事件

下一篇:OTA:使用本地IDE對(duì)象[D4]

發(fā)表評(píng)論 共有條評(píng)論
用戶名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
學(xué)習(xí)交流
熱門圖片

新聞熱點(diǎn)

疑難解答

圖片精選

網(wǎng)友關(guān)注

主站蜘蛛池模板: 舒城县| 隆安县| 遂宁市| 恩平市| 离岛区| 灵寿县| 丰顺县| 阿拉善盟| 桐乡市| 宿松县| 临桂县| 马山县| 石棉县| 平顶山市| 黑山县| 犍为县| 定襄县| 邢台县| 玉门市| 集贤县| 安图县| 彭泽县| 巴青县| 宜阳县| 贵港市| 沭阳县| 武安市| 八宿县| 凤阳县| 石城县| 兴仁县| 天峻县| 施秉县| 秭归县| 左云县| 繁昌县| 桐庐县| 昆山市| 昭苏县| 凤庆县| 丹棱县|