CnPack Forum


 
Subject: 用虚拟桌面实现后台调用外部程序
bahamut8348
灌水司司长
Rank: 6Rank: 6


UID 4743
Digest Posts 14
Credits 337
Posts 79
点点分 337
Reading Access 10
Registered 2007-1-18
Status Offline
Post at 2007-1-21 11:50  Profile | Blog | P.M. 
用虚拟桌面实现后台调用外部程序

最近需要实现一个无线通信的功能,X他XX的,该死的硬件厂商竟然不提供接口函数,只提供一个EXE可执行文件-_-!
    这样就需要我在程序里调用他的这个EXE可执行文件。
    调用EXE文件,可以用WINEXEC()、SHELLEXECUTE()和CreateProcess()等函数来实现,我这里就用CreateProcess()来调用。
    但是一个软件,两个EXE文件,这叫什么??实在没办法,我想在打开的时候不让用户看到这个执行文件:首先调用FINDWINDOW来查找窗口的句柄,之后再用SendMessage()来隐藏窗口,但是还是会有一瞬主窗口被显示出来的,或许你会说我BT吧,但是我实在是不忍心看到……
    那么怎么解决这个问题呢,首先我当然在CreateProcess()上面寻找方法,可惜,它只有一个参数可以设置窗口的默认显示方式,但是一旦这个窗口自己重设了显示方式,它就没有任何作用了。。。。继续查找文档,这时我看到CreateProcess()的一个参数TStartupInfo中有 lpDesktop这么一个属性,按照MSDN的说法,如果该指针为NULL,那么新建的Process将在当前Desktop上启动,而如果对其赋了一个Desktop的名称后,Process将在指定的Desktop上启动,恩,看来不错,就从它入手了;

   首先,建立一个虚拟的Desktop,
const
  DesktopName: PChar = 'NewDesktop';
FDesktop:= CreateDesktop(DesktopName, nil, nil, 0, GENERIC_ALL, nil);

    然后,在CreateProcess的时候,指定程序在我新生成的Desktop上运行:
var
  SI: TStartupInfo;
begin
  FillChar(SI, SizeOf(SI), 0);
  SI.cb:= SizeOf(SI);
  SI.lpDesktop:= DesktopName;
  SI.wShowWindow:= SW_HIDE;
  SI.dwFlags:= STARTF_USESHOWWINDOW;
  SI.hStdError:= 0;
  SI.hStdInput:= 0;
  SI.hStdOutput:= 0;
  if not CreateProcess(PChar('……'), nil, nil, nil, True, CREATE_NEW_CONSOLE + HIGH_PRIORITY_CLASS, nil,
                       PChar('……'), SI, FProceInfo) then
    begin
      Application.MessageBox('Error', 'Error', $10);
      Exit;
    end;
end;

    再用FindWindow去找程序的主窗口
开始我直接写下了这样的代码:
  WindowHandle:= FindWindow(nil, '……');

但是,这样是找不到不在当前Desktop中的Window的,那怎么办呢?

这个时候,我突然看到一位同事在上班时间偷偷打游戏,我问他:“你不怕被抓到??”
他说:“给你看一个工具!”
原来是一个叫“玩游戏一键隐藏”的小工具,仔细想想,他应该是利用各桌面之间的切换来达到这种效果的,于是又开始查看MSDN,终于看到可以用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).

    对不起,我的E文水平实在有够呛-_-!!
具体是什么意思我就不太清楚了,PASSION帮我翻译的时候,我也没怎么记得,只记得是要切换Desktop的线程要“干净”

不好意思,我对这个“干净”的理解就是一个新的线城,于是抱着试一试的心情,我写下了:
  TFindWindowThread = class(TThread)
  private
    FDesktop, FWindowHandle: THandle;
  protected
    procedure Execute(); override;
  public
    constructor Create(Suspended: Boolean; const ADesktop: THandle); reintroduce;
    property WindowHandle: THandle read FWindowHandle;
  end;

而主程序中的代码变成这样:
  FindWindowThread:= TFindWindowThread.Create(False, FDesktop);
  try
    FindWindowThread.WaitFor;
    WindowHandle:= FindWindowThread.WindowHandle;
  finally
    FindWindowThread.Free;
  end;
  if WindowHandle = 0 then
    begin
      Application.MessageBox('Error', 'Error', $10);
      Exit;
    end;

呵呵,成功,这样果然可以顺利的找到窗口Handle了。
好了,这样就几乎完美的实现了一个后台调用程序的功能,它对最终客户来说将是完全透明的,客户根本感觉不到后台还有另一个程序在工作。

爽啊,最后,我要说一句,我从学习第一个计算机语言到现在才三年时间,哎……
感谢PASSION和冬仔,BS下空气,竟然说“放弃吧,API不适合你”-_-!!超级BS、BS、BS……^_^
还有就是DELPHI的TTHREAD类这是第一次用,不知道有没有那里不合理的地方,希望大家指出来,谢谢

[ 本帖最后由 bahamut8348 于 2007-1-21 12:21 编辑 ]
Top
skyjacker
版主
Rank: 7Rank: 7Rank: 7
茶农


UID 2239
Digest Posts 9
Credits 617
Posts 269
点点分 617
Reading Access 100
Registered 2006-6-8
Status Offline
Post at 2007-1-21 11:59  Profile | Blog | P.M.  | QQ
不错。
最后的爽阿有个性。

签个名。

[ 本帖最后由 skyjacker 于 2007-1-21 12:06 编辑 ]




一壶清茶煮青春.
Top
Passion (LiuXiao)
管理员
Rank: 9Rank: 9Rank: 9


UID 359
Digest Posts 19
Credits 6756
Posts 3554
点点分 6756
Reading Access 102
Registered 2004-3-28
Status Offline
Post at 2007-1-21 12:23  Profile | Blog | P.M. 
写的不错!
小建议:标题可改为“用虚拟桌面实现后台调用外部程序” 或类似的有点针对性的标题。现在的显得有点笼统。
Top
jAmEs_
灌水部部长
Rank: 8Rank: 8



Medal No.1  
UID 886
Digest Posts 0
Credits 1134
Posts 600
点点分 1134
Reading Access 10
Registered 2005-6-5
Location 广东
Status Offline
Post at 2007-1-22 09:39  Profile | Blog | P.M. 
很有用。。。
Top
Passion (LiuXiao)
管理员
Rank: 9Rank: 9Rank: 9


UID 359
Digest Posts 19
Credits 6756
Posts 3554
点点分 6756
Reading Access 102
Registered 2004-3-28
Status Offline
Post at 2007-1-22 11:50  Profile | Blog | P.M. 
constructor Create(Suspended: Boolean; const ADesktop: THandle); reintroduce;

这里Create里头没写怎样使用ADesktop,也没写怎样设置下面的属性:

? ? property WindowHandle: THandle read FWindowHandle;

看着似乎有点不连贯完整。虽然知道是调SetThreadDesktop的API和FindWindow
Top
kendling (小冬)
高级版主
Rank: 8Rank: 8
MyvNet


Medal No.1  
UID 703
Digest Posts 5
Credits 978
Posts 580
点点分 978
Reading Access 101
Registered 2005-2-18
Location 广东
Status Offline
Post at 2007-1-23 14:27  Profile | Site | Blog | P.M.  | QQ | Yahoo!
哈哈,灌水来了。




小冬
http://MyvNet.com
Top
volcano
新警察
Rank: 1



UID 6375
Digest Posts 0
Credits 5
Posts 5
点点分 5
Reading Access 10
Registered 2007-3-1
Status Offline
Post at 2007-4-20 13:31  Profile | Blog | P.M. 
是啊 强烈要求巴哈贴完整的代码.
Top
kendling (小冬)
高级版主
Rank: 8Rank: 8
MyvNet


Medal No.1  
UID 703
Digest Posts 5
Credits 978
Posts 580
点点分 978
Reading Access 101
Registered 2005-2-18
Location 广东
Status Offline
Post at 2007-4-20 15:30  Profile | Site | Blog | P.M.  | QQ | Yahoo!
呵呵,他可能想带你胃口呢。




小冬
http://MyvNet.com
Top
volcano
新警察
Rank: 1



UID 6375
Digest Posts 0
Credits 5
Posts 5
点点分 5
Reading Access 10
Registered 2007-3-1
Status Offline
Post at 2007-4-25 09:23  Profile | Blog | P.M. 
我在玩一个游戏 只有窗体active的时候 才接受键盘输入.  当我开启我的小工具(向游戏窗口sendmessage 完成自动杀怪)和虚拟桌面  游戏窗口就被隐藏了  但是,只要我在任何其他窗口点鼠标  虚拟桌面内的游戏窗口马上失去焦点 处于不激活状态,刷怪就中止了.

所以,是不是 无论有几个虚拟桌面  激活的窗口永远只有1个?
Top
 




All times are GMT++8, the time now is 2024-4-20 01:44

    本论坛支付平台由支付宝提供
携手打造安全诚信的交易社区 Powered by Discuz! 5.0.0  © 2001-2006 Comsenz Inc.
Processed in 0.008679 second(s), 7 queries , Gzip enabled

Clear Cookies - Contact Us - CnPack Website - Archiver - WAP