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