桌面

在桌面中嵌入窗体

前几天在网上看到一个软件的介绍:可以嵌入桌面,即使是“显示桌面”也不会影响此程序。看作者说的好像有多么的神奇一样。周未就回来试一下。最后发现,Windows这个桌面还真是复杂和有意思。
  首先要分析Windows桌面。
  打开老牌软件"Spy Window"。查看一下桌面。取得一个“SysListView32”类的句柄(本系统为XP版本)。将其最小化,可以看出刚才取得的控件好像是透明的。因为将其最小化之后,还可以看到你所设置的桌面图片。
  重新用"Spy Window"获取桌面上的控件句柄(也可以直接点击"Parent Window"取得其父窗口句柄),得到一个"SHELLDLL_DefView"类的句柄。将其最小化,可以看到桌面图片依然存在,难道又是一个透明控件吗?先不理会它,我们继续向“下”找。再一次取得“桌面”上一个类名为“Progman”的控件句柄。而且此时你会发现Spy Window的"Parent Window"按钮已不可用了。
  这个类为“Progman”的窗口“下面”真的没有其它窗口了吗?按“Ctrl+Alt+Del“在任务管理器里结束“explorer”,后再使用“Spy Window”看一下,是不是又有一个类名为“#32769”的窗口出了。试着对此窗口进行禁用,最小化,隐藏操作试一下。好像一切都是无效的。
  到此为至,应该说把这张桌面的结构搞清楚了。相当于图像处理中的四个图层,而且是透明图层。
  按类名由前至里的排序为:
  SysListView32
  SHELLDLL_DefView
  Progman
  #32769
  看来这个桌面果然不是一般的复杂。
  回忆一下以前用代码来隐藏桌面的操作:
  FindWindow(''''Progman'''',Nil);
  ShowWindow(...);
  这里的''''Progman''''就是第三层(本文中我们就以层来称呼它们)的窗口了。在结束进程“Explorer”时,此窗口消失,说明此窗口是由“Explorer.exe”建立的。
  下面进行将程序嵌入到桌面里的操作。
  这里所需要的只有一个语句:
  FrmMain.ParentWindow:=ParentHandle;其中,ParentHandle是你所要嵌人的控件句柄。
  按此实现,可以建立一个窗体,拖入一个TButton,一个TEdit。在Button的Click事件中写入代码FrmMain.ParentWindow:=StrToInt(EdtHandle.Text);
  下面,先来嵌入“第一层桌面”看一下。用"Spy Window”取得当前桌面句柄,也就是第一层''''SysListView32''''。转为十进制后复制到EdtHandle。点击按钮。
  程序是不是转为非焦点状态了。按一下“Win+D”(显示桌面)。是不是窗口仍停留在桌面上。
  好像文章开头的目的已经实现了。
  仔细测试一下当前的窗体,是不是与原来有很大的不同。首先,窗口的标题栏总是非焦点状态。第二窗体上的右击被桌面拦截了下来。
  第三Edit里表显不出TEdit本身对消息的响应。如点击时,拖动时,按键时右击时,Edit缺少相应的闪烁输入光标,抹黑所选字符,文字处理,显示上下文菜单等。这是因为窗体得不到焦点,而得不到焦点对于TEdit控件来说,一切都是无效的。
  动态取得第一层控件句柄的方法是:
  TmpHandle:=FindWindow(''''Progman'''',Nil);
  TmpHandle:=GetWindow(TmpHandle,GW_CHILD);
  TmpHandle:=GetWindow(TmpHandle,GW_CHILD);
  此时TmpHandle即是桌面的句柄了。
  依照此方法,我们可以将窗体嵌入第二层''''SHELLDLL_DefView''''了。当嵌入第二层时,你会发现。所嵌入的程序窗口不见了。当我们把第一层最小化时,可以看到我们所嵌入的窗口是存在的。只是被第一层所遮住了。所以说,第一层并不是透明的!
  第一层最小化之后,可以看到,桌面上的图标都不见了。再看一下第一层的类名“SysListView32”,可以确定,第一层这个控件的作用主要就是列出系统桌面上的图标。我们在当前第二层中点击一下右键。桌面菜单出来了吧?原来一切的消息及处理都是在这一层接收和处理的。这时可以用“新建”命令新建一个文档,之后再恢复第一层桌面,可以看到,新建的文档出现了。
  可以这样理解,第一层是“显示层”,第二层是“功能层”。我们的窗体在这里是显示不出来的。而且同样得不到焦点。
  现在,将我们的程序嵌入到第三层''''Progman'''',嵌入之后,出现了和第二层相同的结果,按功能来说这一层应该没有什么实际的用途,可能只是给上面两层提供一个容器。现在''''Progman''''中有了两个窗体,一个是原有的''''SHELLDLL_DefView'''',另一个便是这个嵌入窗体。但是前者用尽了所有的可视区域,所以才使得嵌入的窗体显示不出来。这种情况似乎平时也会遇到,那我们在嵌入时加入一句:BringWindowToTop(FrmMain.Handle);试试;
  呵呵,看到了什么?是不是嵌入的窗口出现了?按一下"Win+D"看一下。如何?还在吧?如果桌面上有图标的话,此时这个窗体应该是挡遮住了一部分图标的。
处理的办法就是将上一层窗体缩小。如:
  TmpHandle:=FindWindow(''''Progman'''',Nil);
  TmpHandle:=GetWindow(TmpHandle,GW_CHILD);
  MoveWindow(TmpHandle,0,20,1024,740,False);
  这样,在窗体顶部留出了二十象素的高度。可以放一个任务栏式的窗体了。
  现在只剩下最后一层"#32769"了。只要在系统登陆前的启动程序不变,此窗口的句柄应该是不变化的(有可能系统登陆前启动的程序有变化此句柄也不变,具体情况没试过)。
  按前面的方法将窗体嵌入到此窗口中。
  窗体又是得不到焦点的状态了。可以看出来这和嵌入到第一层差不多。但是我们拖动一下窗体看一下。此时窗体并不是实时跟随鼠标的。再仔细看一下,任务栏上出现了两个此程序的按钮。一个是程序的名称,一个是窗口的名称。这是一种奇怪的现象,从来没有见过的。或许我们可以这样解释它。Explorer会将符合要求的窗体显示在任务栏上(非ToolsWindows,并且可见)。本窗体就符合,而且Explorer又会将窗口"#32769"里的所有窗口放到任务栏上而不管它是否复。所以才会得到此结果。
  总结一下:
  Windows的桌面是分四层的。嵌入的窗体如果嵌入到第三层,并将Z轴顺序移到最上的话,程序就会一个正常的嵌入桌面的程序。这符合我们的要求。而且可以通过调整第二层的大小来使窗体不遮住桌面图标。所以,将窗体嵌入到此是很理想的。
  第一层的嵌入也是可以的。但是在这里窗体会得不到焦点和使用不了右键。所以这里的窗体受很多限制。
  第二层是一个根本不考虑嵌入窗体的地方,因为这里的窗体根本显示不出来。而且与第一层相同的得不到焦点。
  第四层是个意外的层。嵌在这里的窗体会表显出异样的情况。唯一值得我们嵌入的理由是:它不会随Explorer.exe进程的结束而关闭。

用mfc实现就是这样的代码
HWND hDesktop = ::FindWindow("Progman", NULL);
hDesktop = ::GetWindow(hDesktop, GW_CHILD);
CWnd* pWndDesktop = CWnd::FromHandle(hDesktop);
this->SetParent(pWndDesktop);
View Code

隐藏桌面图标和任务栏

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;

type
  TForm1 = class(TForm)
    CheckBox1: TCheckBox;
    CheckBox2: TCheckBox;
    procedure FormCreate(Sender: TObject);
    procedure CheckBox1Click(Sender: TObject);
    procedure CheckBox2Click(Sender: TObject);
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

{初始化}
procedure TForm1.FormCreate(Sender: TObject);
begin
  CheckBox1.Caption := '隐藏桌面图标';
  CheckBox2.Caption := '隐藏任务栏';
end;

{隐藏或显示桌面图标}
procedure TForm1.CheckBox1Click(Sender: TObject);
var
  h: HWND;
begin
  h := FindWindow('Progman', nil);   {Progman 是桌面窗口的类名}
  if TCheckBox(Sender).Checked then
    ShowWindow(h, SW_HIDE)
  else
    ShowWindow(h, SW_RESTORE);
end;

{隐藏或显示任务栏}
procedure TForm1.CheckBox2Click(Sender: TObject);
var
  h: HWND;
begin
  h := FindWindow('Shell_TrayWnd', nil); {Shell_TrayWnd 是任务栏窗口的类名}
  if TCheckBox(Sender).Checked then
    ShowWindow(h, SW_HIDE)
  else
    ShowWindow(h, SW_RESTORE);
end;

end.
View Code

虚拟桌面原理及实现

一、为什么要使用虚拟桌面。   
场景一、  上班的时候,我们经常会趁老板不注意,去一些工作时间不应该去的网站,或是运行一些不应该运行的程序,比如一些聊天工具,小游戏,股票软件等等。而且,经常会打开一大堆。当老板或其他同事来到你的桌前的时候,你正在手忙脚乱的关着这些程序,而且,还来不及保存想要保存的东西。  
场景二、  在你给别人做讲演的时候,需要在电脑桌面上展示很多资料。当然一个桌面经常是远远不够展示的,而且,需要经常的切换画面,由于打开的资料太多,每次还的任务栏里找上一阵。很影响讲演的流畅性。  虚拟桌面程序就是用来解决以上的问题。  场景一、  你可以用虚拟桌面程序同时生成多个桌面。一个桌面打开着你工作的资料,程序等等。一个桌面打开着你的聊天工具及一些你不想别人看到的东西。当然你还可以用一个桌面放一些你想访问的网站啊,股票信息啊等等。剩下的只是简单的按一下快捷键来切换不同的桌面。  
场景二、  同场景一,你可以用虚拟桌面程序生成多个桌面,把要讲演的资料提前分配到多个桌面。剩下的只是简单的按一下快捷键来切换不同的桌面。  
二、虚拟桌面实现原理   
1. 原理概况  每次开机的时候,我就创建多个桌面,然后定时监控快捷键(Ctrl+数字键),如果有快捷键被按下,就切换到数字键对应编号的桌面。  
2.什么是桌面?  每一个运行着Window NT 的系统中都有一个Window 工作站对象,这个对象是安全对象的第一层,是所有用户安全对象的继承之源,每一个Window 工作站对象可以拥有一些桌面对象,每一个桌面都拥有一个窗口链。窗口链里存放着显示在所属桌面的各种窗口。Window NT 用了两个桌面窗口对象,一个是用来处理登陆界面、屏蔽、锁住工作站等,一个是我们登陆之后进来操作的窗口了。  Window NT通过"explorer.exe"进程来管理这个桌面对象。这就是为什么我们在任务管理器里杀掉"explorer.exe",我们的桌面就会消失的原因。  
3.创建一个桌面。  
function CreateANewDesktop(DesktopName: string): Boolean;  var  sin : TStartupInfo;  pin : TProcessInformation;  hDesk : HDESK;  begin  result := false;  hDesk := CreateDesktop(PChar(DesktopName),nil,nil,0,MAXIMUM_ALLOWED,nil);  try  FillChar(sin,SizeOf(sin),0);  sin.cb := SizeOf(sin);  sin.lpDesktop := PChar(DesktopName);  CreateProcess(PChar(WindowDirectory+'explorer.exe'),nil,nil,nil,False,0,nil,nil,sin,pin);  Sleep(2000);  result := true;  finally  CloseDesktop(Desk);  end;  end;  
4.查询当前已经存在的桌面。  枚举桌面的API是EnumDesktops.  BOOL EnumDesktops( HWINSTA hwinsta, // 当前的WindowsStation句柄 DESKTOPENUMPROC lpEnumFunc, // 回调函数,由系统调用。 LPARAM lParam //传递给回调函数的参数指针 ); 通常我们定义个一回调函数,定义一个全局TStringList类对象,在回调函数里将枚举到的桌面的名称增加到TStringList里。  var   sttopList : TStringList;  function EnumDesktopProc(Desktop: LPTSTR; Param: LParam): Boolean; stdcall; begin if (Desktop<>'Winlogon') and (Desktop<>'Disconnect') then   DesktpList.Add(DeskTop);  result := True; end;  procedure EnumerateDesktops; begin EnumDesktops(GetProcessWindowStation, @EnumDesktopProc, nil); end;  5.切换桌面。  procedure DesktopSwitch(DesktopName: String); var hDesk: HDESK; begin hDesk:=OpenDesktop(PChar(DesktopName), DF_ALLOWOTHERACCOUNTHOOK, False, MXIMUM_ALLOWED); Sleep(100); SwitchDesktop(hDesk); CloseDesktop(hDesk); end;  
三、结束语   你可以把这个虚拟桌面程序做成一个服务,每次开机就自动加载。这样,你就可以每次都拥有多个桌面了。  附件VirtualDesktop.rar是运行程序,无须安装。  下载地址:http://d.download.csdn.net/down/985557/A00553344   
跟踪:  这个是csdn论坛 上的一个昵称为猴子的朋友发的。 但是错误非常多。经过改善后和修正错误后。发表出来! 为论坛做点贡献!  我们先要得到windows安装路径,例如C:/WINDOWS,当然有的可能D盘等等,需要一个函数 function GetWindows Path:String; var buf:Array[0..255] of Char; s: String; begin GetWindowsDirectory(@Buf,255); s:=StrPas(@Buf); if s[Length(s)] <> '\' then s:= s + '\'; Result:=s; end;   同时编写一个函数,进行虚拟桌面的创建,利用的是微软 的API:CreateDesktop function CreateANewDesktop(DesktopName: string): Boolean; var sin:TStartupInfo; pin:TProcessInformation; Desk:HDesk; begin result := false; Desk:= CreateDesktop(PChar(DesktopName),nil,nil,0,MAXIMUM_ALLOWED,nil); try FillChar(sin,SizeOf(sin),0); sin.cb := SizeOf(sin); sin.lpDesktop := PChar(DesktopName); CreateProcess(PChar(GetWindowsPath+'explorer.exe'),nil,nil,nil,False,0,nil,nil,sin,pin); Sleep(2000); result := true; finally CloseDesktop(Desk); end; end;   我在程序界面添加了一个listbox控件,进行虚拟桌面的存放。 procedure TForm1.Button1Click(Sender: TObject); begin CreateANewDesktop('desktop'+inttostr(listbox1.Items.Count+1));//创建一个虚拟桌面,名字是desktop+编号 listbox1.Items.Add('desktop'+inttostr(listbox1.Items.Count+1)); end;   进行虚拟桌面的切换 procedure DesktopSwitch(DesktopName: String); var Desk: HDESK; begin Desk:=OpenDesktop(PChar(DesktopName),DF_ALLOWOTHERACCOUNTHOOK,False,MAXIMUM_ALLOWED ); Sleep(100); SwitchDesktop(Desk); CloseDesktop(Desk); end;  这个函数是进行切换虚拟桌面的 ,当我们选择listbox里的一个项目时,则切换过去,。。。 procedure TForm1.Button3Click(Sender: TObject); begin DesktopSwitch(listbox1.Items.Strings[listbox1.ItemIndex]);//应该都明白吧?切换到选择项目的名字 end;    procedure TForm1.Button2Click(Sender: TObject); begin DesktopSwitch('Default'); //default代表默认桌面。呵呵! end;    接下来是关闭了。。。 procedure TForm1.Button4Click(Sender: TObject); var Desk:HDESK; begin desk:=OpenDesktop(pchar(listbox1.Items.Strings[listbox1.ItemIndex]),0,false,MAXIMUM_ALLOWED); closedesktop(desk); end;      
//******************************************************************  虚拟桌面服务程序  program Desktop;
  uses   SvcMgr,   Unit_Main in 'Unit_Main.pas' {Service_Desktop: TService},   Unit_Thread in 'Unit_Thread.pas';  {$R *.RES}  begin   Application.Initialize;   Application.CreateForm(TService_Desktop, Service_Desktop);   Application.Run; end.  ////  unit Unit_Main;  interface  uses   Windows,Classes,SvcMgr,activex, ExtCtrls;  type   TService_Desktop = class(TService)     Timer_Check: TTimer;     procedure ServiceStart(Sender: TService; var Started: Boolean);     procedure Timer_CheckTimer(Sender: TObject);     procedure ServiceStop(Sender: TService; var Stopped: Boolean);   private   public     function GetServiceController: TServiceController; override;     { Public declarations }   end;  var   Service_Desktop: TService_Desktop;  implementation  uses Unit_Thread,ShellApi;  {$R *.DFM}  procedure ServiceController(CtrlCode: DWord); stdcall; begin   Service_Desktop.Controller(CtrlCode); end;  function TService_Desktop.GetServiceController: TServiceController; begin   Result := ServiceController; end;  procedure TService_Desktop.ServiceStart(Sender: TService;   var Started: Boolean); begin   Timer_Check.Enabled:=True; end;  procedure TService_Desktop.ServiceStop(Sender: TService;   var Stopped: Boolean); begin   Timer_Check.Enabled:=False; end;  procedure TService_Desktop.Timer_CheckTimer(Sender: TObject); begin    Timer_Check.Enabled:=False;    with TThreadDesktop.Create do    try      FreeOnTerminate:=True;      WaitFor;    except end;    Timer_Check.Enabled:=True; end;  end. //  //Windows desktop application //Made by Daniel Vladutu //        www.free-soft.ro unit Unit_Thread;  interface  uses Classes,Windows,SysUtils;  type   TThreadDesktop = class(TThread)   private     procedure SwitchToDesktop(DesktopName: String);     function CreateDesktop(DesktopName: String): HDESK;     procedure EnumerateDesktops;   protected     procedure Execute; override;   published     constructor Create;     property ReturnValue;    end;  implementation  uses Unit_Main; var  List_Desktops:TStringList;  function EnumDesktopProc(Desktop: LPTSTR; Param: LParam): Boolean; stdcall; begin   if (Desktop<>'Winlogon') and (Desktop<>'Disconnect') then  List_Desktops.Insert(0,Desktop);   result := True; end;  constructor TThreadDesktop.Create; begin    List_Desktops:=TStringList.Create;    inherited Create(false); end;  procedure TThreadDesktop.Execute; var Desk: HDESK;     hDesk:THandle;     i:Integer; begin    ReturnValue:=0;    Desk := OpenDesktop('Default', 0, False, MAXIMUM_ALLOWED);    if Desk<>0 then    begin       if GetKeyState(VK_LMENU) < 0 then //We press on LeftAlt button       begin          EnumerateDesktops;          for i:=$31 to $39 do          if (GetKeyState(i)<0) and (List_Desktops.Count>i-$31)  then          begin             SwitchToDesktop(List_Desktops[i-$31]);             Break;          end;       end;    end;    CloseDesktop(Desk);    FreeAndNil(List_Desktops); end;  function TThreadDesktop.CreateDesktop(DesktopName: String): HDESK; var Desk: HDESK; begin   Desk := Windows.CreateDesktop(PChar(DesktopName), nil, nil, 0, MAXIMUM_ALLOWED, nil);   List_Desktops.Insert(0, DesktopName);   result := Desk; end;  procedure TThreadDesktop.EnumerateDesktops; begin    List_Desktops.Clear;    EnumDesktops(GetProcessWindowStation, @EnumDesktopProc, Integer(Self)); end;  procedure TThreadDesktop.SwitchToDesktop(DesktopName: String); var Desk: HDESK; begin   Desk:=OpenDesktop(PChar(DesktopName), DF_ALLOWOTHERACCOUNTHOOK, False, MAXIMUM_ALLOWED);   Sleep(100);   SwitchDesktop(Desk);   CloseDesktop(Desk); end;  end.    加载服务程序源代码  program DesktopLoader; //{$APPTYPE CONSOLE} uses Windows,WinSvc,ShellApi; var s:String;     iDesktops,jDesktops:Integer;     ServiceName:String='Service_Desktop';  procedure RunProgram(CmdLine:String); var StartupInfo:TStartUpInfo;     ProcessInformation:TProcessInformation;     Handle:THandle;     d:DWord; begin     FillChar(StartUpInfo,SizeOf(StartUpInfo),0);     StartUpInfo.cb:=SizeOf(TStartUpInfo);     if CreateProcess(nil,PChar(CmdLine),nil,nil,False, Create_Separate_WOW_VDM,nil,nil, StartUpInfo,ProcessInformation) then     begin        Handle:=OpenProcess(Synchronize or Standard_Rights_Required or $FFF, True, ProcessInformation.dwProcessID);        while GetExitCodeProcess(Handle,d) and (d=Still_Active) do sleep(10);     end; end;  function RegistryWriteStartup:boolean; var Key:HKEY; begin   result := false;   if cardinal(RegCreateKey(HKEY_LOCAL_MACHINE, PChar('SOFTWARE/Microsoft/Windows/CurrentVersion/Run'),Key))=0 then   try result := RegSetValueEx(Key, PChar('Desktop Service'), 0, REG_SZ, PChar(ParamStr(0)), Length(ParamStr(0)) + 1) = 0;   finally RegCloseKey(Key)end; end;  function IntToStr(Number:Cardinal):String; begin    Result:='';    if Number=0 then Result:='0';    while Number>0 do    begin       Result:=Char((Number mod 10)+Integer('0'))+Result;       Number:=Number div 10;    end; end;  function FileExists(FileName:String):boolean; var FindData: TWin32FindData; begin   result:=FindFirstFile(PChar(FileName), FindData)<> INVALID_HANDLE_VALUE; end;  function WindowDirectory:String ; var Buffer:PChar ; Begin    result:='';buffer:=nil;    try       getmem(buffer,255) ;       GetWindowsDirectory(Buffer,255);       Result:=Buffer;    finally       FreeMem(buffer);    end;    if Result[Length(Result)]<>'/' then Result:=Result+'/'; end;  function ServiceIsInstalled(Machine:string;ServiceType,ServiceState:DWord):boolean; type TSvc=array[0..4096] of TEnumServiceStatus;      PSvc=^TSvc; var j:integer;     SC:SC_Handle;     nBytesNeeded,nServices,nResumeHandle : DWord;     Svc:PSvc; begin   Result := false;   SC := OpenSCManager(PChar(Machine),Nil,SC_MANAGER_ALL_ACCESS);   if SC>0 then   begin     nResumeHandle := 0;     New(Svc);     EnumServicesStatus(SC,ServiceType,ServiceState,Svc^[0],SizeOf(Svc^),nBytesNeeded,nServices,nResumeHandle); //    for j := 0 to nServices-1 do MessageBox(0,Pchar(Svc^[j].lpServiceName),'',0);     for j := 0 to nServices-1 do if Svc^[j].lpServiceName=ServiceName then result:=true;     Dispose(Svc);     CloseServiceHandle(SC);   end; end;  function ServiceStart(Machine,Service:string):boolean; var SC1,SC2:SC_Handle;     Status:TServiceStatus;     c:PChar;     d:DWord; begin   Status.dwCurrentState := 0;   SC1 := OpenSCManager(PChar(Machine),Nil,SC_MANAGER_CONNECT);   if SC1>0 then   begin     SC2 := OpenService(SC1,PChar(Service),SERVICE_START or SERVICE_QUERY_STATUS);     if SC2>0 then     begin       c:=Nil;       if StartService(SC2,0,c) and QueryServiceStatus(SC2,Status)then       while SERVICE_RUNNING<>Status.dwCurrentState do       begin          d := Status.dwCheckPoint;          Sleep(Status.dwWaitHint);          if not QueryServiceStatus(SC2,Status) then break;          if Status.dwCheckPoint<d then break;       end;       CloseServiceHandle(SC2);     end;     CloseServiceHandle(SC1);   end;   Result:=SERVICE_RUNNING=Status.dwCurrentState; end;  function ServiceStop(Machine,Service:string):boolean; var SC1,SC2:SC_Handle;     Status:TServiceStatus;     d:DWord; begin   SC1:=OpenSCManager(PChar(Machine),Nil,SC_MANAGER_CONNECT);   if SC1>0 then   begin     SC2 := OpenService(SC1,PChar(Service),SERVICE_STOP or SERVICE_QUERY_STATUS);     if SC2>0 then     begin       if ControlService(SC2,SERVICE_CONTROL_STOP,Status) and QueryServiceStatus(SC2,Status) then       while SERVICE_STOPPED<>Status.dwCurrentState do       begin         d:=Status.dwCheckPoint;         Sleep(Status.dwWaitHint);         if not QueryServiceStatus(SC2,Status) then break;         if Status.dwCheckPoint<d then break;       end;       CloseServiceHandle(SC2);     end;     CloseServiceHandle(SC1);   end;   Result:=SERVICE_STOPPED=Status.dwCurrentState; end;  function ServiceCreate(Machine,Service,FileName:String ) : Boolean; var SC1,SC2:SC_Handle; begin MessageBox(0,PChar(Service),'service',0);    Result:=False;    SC1:=OpenSCManager(PChar(Machine),Nil,SC_MANAGER_Create_SERVICE);    if SC1>0 then    begin      SC2:=CreateService(SC1,PChar(Service),PChar(Service),SERVICE_ALL_ACCESS,SERVICE_WIN32_OWN_PROCESS,      SERVICE_AUTO_START,SERVICE_ERROR_NORMAL,PChar(FileName),nil,nil,nil,nil,nil);      Result:=SC2<>0;      If Result Then CloseServiceHandle(SC2);      CloseServiceHandle(SC1);    end; end;  function ServiceGetStatus(Machine,Service:string):DWord; var SC1,SC2:SC_Handle;     Status:TServiceStatus;     d:DWord; begin    SC1:=OpenSCManager(PChar(Machine),Nil,SC_MANAGER_CONNECT);    if SC1>0 then    begin      SC2:=OpenService(SC1,PChar(Service),SERVICE_QUERY_STATUS);      if SC2>0 then     begin       if QueryServiceStatus(SC2,Status) then d:=Status.dwCurrentState;       CloseServiceHandle(SC2);     end;     CloseServiceHandle(SC1);   end;   Result:=d; end;  function EnumDesktopProc(Desktop: LPTSTR; Param: LParam): Boolean; stdcall; begin   if (Desktop<>'Winlogon') and (Desktop<>'Disconnect') then inc(iDesktops);   result := True; end;  function NewDesktop:Boolean; var sDesktop:string;     sinfo:TStartupInfo;     pinfo:TProcessInformation;     Desk:HDESK; begin    result:=false;    sDesktop:='Desktop '+IntToStr(iDesktops);    Desk:=CreateDesktop(PChar(sDesktop), nil, nil, 0, MAXIMUM_ALLOWED, nil);    try      FillChar(sinfo, SizeOf(sinfo), 0);      sinfo.cb := SizeOf(sinfo);      sinfo.lpDesktop := PChar(sDesktop);      Sleep(500);      CreateProcess(PChar(WindowDirectory+'explorer.exe'), nil, nil, nil, False, 0, nil, nil, sinfo, pinfo);      Sleep(2000);      result:=true;      CloseDesktop(Desk);    except      CloseDesktop(Desk);    end; end;  begin    RegistryWriteStartup;    if not ServiceIsInstalled('',SERVICE_WIN32,SERVICE_STATE_ALL) then    begin       s:=ParamStr(0);       while (s<>'') and (s[Length(s)]<>'/') do Delete(s,Length(s),1);       s:=s+'Desktop.exe';       if not FileExists(s) then       begin          MessageBox(0,PChar('Desktop service "'+s+'" does not exits!'),PChar('Error'),0);          exit;       end;       RunProgram(s+' -install'); //      if not ServiceCreate('',ServiceName,s) then MessageBox(0,'Could not install the service','Error',0); //      if not ServiceIsInstalled('',SERVICE_WIN32,SERVICE_STATE_ALL) then //      begin //         MessageBox(0,'Could not install the Desktop service.','Error',0); //         exit; //      end;    end;    case ServiceGetStatus('',ServiceName) of      SERVICE_RUNNING:;      SERVICE_STOPPED: ServiceStart('',ServiceName);      SERVICE_PAUSED: ;    end;    if ServiceGetStatus('','Service_Desktop')<>SERVICE_RUNNING then    begin        MessageBox(0,PChar('Could not start the Desktop service'),'Error',0);        exit;    end;    iDesktops:=0;    EnumDesktops(GetProcessWindowStation, @EnumDesktopProc,0);    if iDesktops>3 then exit;    NewDesktop;    jDesktops:=iDesktops;iDesktops:=0;    EnumDesktops(GetProcessWindowStation, @EnumDesktopProc,0);    if (iDesktops=jDesktops+1) then     ShellExecute(0,nil,PChar(ParamStr(0)),nil,nil,SW_SHOWNORMAL); end.  ///  使用方法  ALT+1,ALT+2,ALT+3切换3个桌面  //*******************************************************************
View Code

虚拟桌面delphi全攻略

网上也有很多关于虚拟桌面的技术文章,但我却没有找到一个讲解得比较详细的,花了两天时间凑合网上的零碎片断做出个虚拟桌面的小程序出来,让高手们见笑了,现在我将我制作这个程序的全部流程详细地贴出来供大家参考:
虚拟桌面说白了,核心就是CreateDesktop和SwitchDesktop函数,这是别人的说法,但是要想做出一个完整的软件来还需要其它很多必不可少的函数,这里我先介绍下要用到的函数(参数我就不解释了,因为我自已现在不对每个个参数的具体含义的认识都比较模糊,很多参数是照抄网上的):
CreateDesktop//创建虚拟桌面
OpenDesktop//获取桌面句柄
SwitchDesktop//激活/转到指定的桌面
globaladdatom//创建全局原子
globalfindatom//查找全局原子
globaldeleteatom//删除全局原子
getasynckeystate//判断虚拟键的状态
CreateProcess//打开指定的进程
GetCurrentThreadId//获取当前ID
GetThreadDesktop//获取当前桌面句柄
好了就这些,下面我说下流程
        刚看网上的资料的时候,感觉好像只要CreateDesktop来创建桌面再用SwitchDesktop来转到指定桌面即可,然而事情却没这么简单.创建虚拟桌面后,我将SwitchDesktop函数输入进程序的按钮事件里,我一按按钮,令我痛哭流涕的事情发生了------转到的桌面干干净净什么都没有,没有桌面图标没有任务栏甚至打不开任务管理器,没办法,含泪按下电脑的重启按钮(好几千呢555).
       我继续在网上查找资料,发现要在新创建的桌面显示图标,必须先在新创建的桌面打开桌面进程explorer.exe(一般情问下我们结束掉这个进程桌面就会消失就是这个道理),现在就用到了CreateProcess函数,CreateProcess函数如何能在其它桌面创建进程呢?CreateProcess有个TStartupInfo结构的参数,该结构中有个叫lpDesktop的成员,它指定了在哪个桌面创建进程(不对其赋值则为当前桌面),请看代码:
var sin:TStartupInfo;s:string;
sin.cb:=sizeof(sin);
sin.wShowWindow:=SW_SHOW;
sin.dwFlags:=STARTF_USESHOWWINDOW;
s:='a';
sin.lpDesktop:=pchar(s);
CreateProcess('c:\WINDOWS\explorer.exe',nil,nil,nil,False,0,nil,nil,sin,pin);
其中的字符a为创建桌面的名称,该名称在创建桌面的函数中指定.
接下来的问题是转到新的桌面之后,运行的自身程序就不见了,怎样才能转回原来的桌面呢?我用了一个愚蠢的办法,在创建新桌面和新桌面进程的同时在新桌面上将本程序再次打开,这样实际上创建了几个新桌面自身程序就运行了几个实例,看代码:
CreateProcess(pchar(extractfilepath(application.ExeName)+'这里是程序的名字'),nil,nil,nil,False,0,nil,nil,sin,pin);
将这行代码放到创建桌面进程代码的后面,这个问题就解决了,一波未平一波又起新了问题又产生了,而且还是两个很严重的问题:
1。我创建桌面的代码是写在窗体载入的过程中的,这就意味着每创建一个自身实例就多了N个虚拟桌面。
2。新创建的实例进程并不能保存有第一个实例进程的句柄,这样就无法对桌面进行操作。
对于第一个问题我是用全局原子法来解决的,在程序启动时先使用globalfindatom查找全局原子,若不荐在则表示未运行过实例进程,那么就创建一个全局原子并创建虚拟桌面,若存在,而不创建虚拟桌面,但还是要创建一个全局原子(原因不用我说了吧~),在窗体的退出代码中别忘了globaldeleteatom掉创建的全局原子。
对于第二个问题,即然无法继承就自已查找句柄吧;前面说过在创建虚拟桌面时会为创建的桌面指定一个名称,现在这个名称的作用体现出来了,OpenDesktop函数其中一个参数为桌面的名称,该函数的返回值就是桌面的句柄。新创建的虚拟桌面可以用这个方法获得句柄,但是默认桌面怎么获取呢?这个更简单,因为默认的桌面名称就是“default”,只要把这个字符放入OpenDesktop函数中便能轻松获取默认桌面的句柄。在句柄得到了,只要使用SwitchDesktop(参数就是桌面句柄)函数就能转到指定桌面了。
PS:默认桌面的名称我开始也不知道,但我无意中在网上发现一个函数:getuserobjectinformation,这个函数可以根据桌面的句柄获取桌面的名称,当前桌面的句柄可以用GetThreadDesktop和GetCurrentThreadId()获取,GetCurrentThreadId()的功能是获得当前ID,这个ID作为GetThreadDesktop的参数用来获取当前桌面句柄。这样就得到了桌面的名称
不多说了附上我的源代码:
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, ExtCtrls;
type
TForm1 = class(TForm)
    Button1: TButton;
    Button2: TButton;
    Button4: TButton;
    Button5: TButton;
    Button6: TButton;
    Button7: TButton;
    Timer1: TTimer;
    Timer2: TTimer;
    procedure Button1Click(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure Button2Click(Sender: TObject);
    procedure Button4Click(Sender: TObject);
    procedure Button5Click(Sender: TObject);
    procedure Button6Click(Sender: TObject);
    procedure Button7Click(Sender: TObject);
    procedure Timer1Timer(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    procedure Timer2Timer(Sender: TObject);
private
    { Private declarations }
public
    { Public declarations }
end;
var
Form1: TForm1;
h1:thandle;
h2:thandle;
h3:thandle;
h4:thandle;
h5:thandle;
h6:thandle;
si:TStartupInfo;
sin:TStartupInfo;
pin:TProcessInformation;
s:string;
desk:thandle;
implementation
{$R *.dfm}
procedure TForm1.FormCreate(Sender: TObject); //创建桌面
begin
timer1.Interval:=50;
timer2.Interval:=1000;
sin.cb:=sizeof(sin);
sin.wShowWindow:=SW_SHOW;
sin.dwFlags:=STARTF_USESHOWWINDOW;
if globalfindatom('mfk')=0 then
begin
globaladdatom('mfk');
h1:=GetThreadDesktop(GetCurrentThreadId());
s:='a';
sin.lpDesktop:=pchar(s);
h2:=CreateDesktop(pchar(s),nil,nil,DF_ALLOWOTHERACCOUNTHOOK,GENERIC_ALL,nil);
CreateProcess('c:\WINDOWS\explorer.exe',nil,nil,nil,False,0,nil,nil,sin,pin);
CreateProcess(pchar(extractfilepath(application.ExeName)+'双开工具.exe'),nil,nil,nil,False,0,nil,nil,sin,pin);
s:='b';
sin.lpDesktop:=pchar(s);
h3:=CreateDesktop('b',nil,nil,0,MAXIMUM_ALLOWED,nil);
CreateProcess('c:\WINDOWS\explorer.exe',nil,nil,nil,False,0,nil,nil,sin,pin);
CreateProcess(pchar(extractfilepath(application.ExeName)+'双开工具.exe'),nil,nil,nil,False,0,nil,nil,sin,pin);
s:='c';
sin.lpDesktop:=pchar(s);
h4:=CreateDesktop('c',nil,nil,0,MAXIMUM_ALLOWED,nil);
CreateProcess('c:\WINDOWS\explorer.exe',nil,nil,nil,False,0,nil,nil,sin,pin);
CreateProcess(pchar(extractfilepath(application.ExeName)+'双开工具.exe'),nil,nil,nil,False,0,nil,nil,sin,pin);
s:='d';
sin.lpDesktop:=pchar(s);
h5:=CreateDesktop('d',nil,nil,0,MAXIMUM_ALLOWED,nil);
CreateProcess('c:\WINDOWS\explorer.exe',nil,nil,nil,False,0,nil,nil,sin,pin);
CreateProcess(pchar(extractfilepath(application.ExeName)+'双开工具.exe'),nil,nil,nil,False,0,nil,nil,sin,pin);
s:='e';
sin.lpDesktop:=pchar(s);
h6:=CreateDesktop('e',nil,nil,0,MAXIMUM_ALLOWED,nil);
CreateProcess('c:\WINDOWS\explorer.exe',nil,nil,nil,False,0,nil,nil,sin,pin);
CreateProcess(pchar(extractfilepath(application.ExeName)+'双开工具.exe'),nil,nil,nil,False,0,nil,nil,sin,pin);
end
else
begin
globaladdatom('mfk');
end;
end;
procedure TForm1.Button1Click(Sender: TObject);//切换至桌面1
begin
desk:=OpenDesktop('default',DF_ALLOWOTHERACCOUNTHOOK,False,MAXIMUM_ALLOWED);
SwitchDesktop(desk);
end;
procedure TForm1.Button2Click(Sender: TObject); //切换至桌面2
begin
desk:=OpenDesktop('a',DF_ALLOWOTHERACCOUNTHOOK,False,MAXIMUM_ALLOWED);
SwitchDesktop(desk);
end;
procedure TForm1.Button4Click(Sender: TObject); //切换至桌面3
begin
desk:=OpenDesktop('b',DF_ALLOWOTHERACCOUNTHOOK,False,MAXIMUM_ALLOWED);
SwitchDesktop(desk);
end;
procedure TForm1.Button5Click(Sender: TObject); //切换至桌面4
begin
desk:=OpenDesktop('c',DF_ALLOWOTHERACCOUNTHOOK,False,MAXIMUM_ALLOWED);
SwitchDesktop(desk);
end;
procedure TForm1.Button6Click(Sender: TObject); //切换至桌面5
begin
desk:=OpenDesktop('d',DF_ALLOWOTHERACCOUNTHOOK,False,MAXIMUM_ALLOWED);
SwitchDesktop(desk);
end;
procedure TForm1.Button7Click(Sender: TObject); //切换至桌面6
begin
desk:=OpenDesktop('e',DF_ALLOWOTHERACCOUNTHOOK,False,MAXIMUM_ALLOWED);
SwitchDesktop(desk);
end;
procedure TForm1.Timer1Timer(Sender: TObject);
begin
if (getasynckeystate(VK_Control)<>0) and (getasynckeystate(112)<>0) then
begin
desk:=OpenDesktop('default',DF_ALLOWOTHERACCOUNTHOOK,False,MAXIMUM_ALLOWED);
SwitchDesktop(desk);
end;
if (getasynckeystate(VK_Control)<>0) and (getasynckeystate(113)<>0) then
begin
desk:=OpenDesktop('a',DF_ALLOWOTHERACCOUNTHOOK,False,MAXIMUM_ALLOWED);
SwitchDesktop(desk);
end;
if (getasynckeystate(VK_Control)<>0) and (getasynckeystate(114)<>0) then
begin
desk:=OpenDesktop('b',DF_ALLOWOTHERACCOUNTHOOK,False,MAXIMUM_ALLOWED);
SwitchDesktop(desk);
end;
if (getasynckeystate(VK_Control)<>0) and (getasynckeystate(115)<>0) then
begin
desk:=OpenDesktop('c',DF_ALLOWOTHERACCOUNTHOOK,False,MAXIMUM_ALLOWED);
SwitchDesktop(desk);
end;
if (getasynckeystate(VK_Control)<>0) and (getasynckeystate(116)<>0) then
begin
desk:=OpenDesktop('d',DF_ALLOWOTHERACCOUNTHOOK,False,MAXIMUM_ALLOWED);
SwitchDesktop(desk);
end;
if (getasynckeystate(VK_Control)<>0) and (getasynckeystate(117)<>0) then
begin
desk:=OpenDesktop('e',DF_ALLOWOTHERACCOUNTHOOK,False,MAXIMUM_ALLOWED);
SwitchDesktop(desk);
end
end;
procedure TForm1.FormDestroy(Sender: TObject);
begin
globaldeleteatom(globalfindatom('mfk'));
end;
View Code

程序嵌入桌面效果的实现

delphi 绋嬪簭宓屽叆妗岄潰鏁堟灉鐨勫疄鐜? 浣滆€咃細admin 鏉ユ簮锛氭湭鐭?鏃ユ湡锛?010-5-9 23:59:47 浜烘皵锛?鏍囩锛?function Tform1.CreateRegion(wMask:TBitmap;wColor:TColor;hControl:THandle): HRGN; var  dc, dc_c: HDC;  rgn: HRGN;  x, y: integer;  coord: TPoint;  line: boolean; color: TColor;  begin  dc := GetWindowDC(hControl);  dc_c := CreateCompatibleDC(dc);  SelectObject(dc_c, wMask.Handle);  BeginPath(dc);  for x:=0 to wMask.Width-1 do  begin  line := false;  for y:=0 to wMask.Height-1 do  begin  color := GetPixel(dc_c, x, y);  if not (color = wColor) then  begin  if not line then  begin  line := true;  coord.x := x;  coord.y := y;  end;  end;  if (color = wColor) or (y=wMask.Height-1) then  begin  if line then  begin  line := false;  MoveToEx(dc, coord.x, coord.y, nil);  LineTo(dc, coord.x, y);  LineTo(dc, coord.x + 1, y);  LineTo(dc, coord.x + 1, coord.y);  CloseFigure(dc);  end;  end;  end;  end;  EndPath(dc);  rgn := PathToRegion(dc);  ReleaseDC(hControl, dc);  Result := rgn;  end;   procedure TForm1.FormCreate(Sender: TObject); var  w1:TBitmap;  w2:TColor;  rgn: HRGN;   deskHandle, ProgmanH, ShellDllH, DeskopICOH: Thandle; wc: TWinControl; i: Integer; begin i := 0; ProgmanH := FindWindow('Progman', 'Program Manager');  while (i < 100) and (ProgmanH = 0) do begin ProgmanH := FindWindow('Progman', 'Program Manager'); Inc(I); Sleep(100); end;  if ProgmanH = 0 then Close;  if (ProgmanH <> 0) and IsWindow(ProgmanH) and (GetParent(ProgmanH) = 0) then begin ShellDllH := FindWindowEx(ProgmanH, 0, PChar('SHELLDLL_DefView'), ''); if ShellDllH <> 0 then DeskopICOH := FindWindowEx(ShellDllH, 0, PChar('SysListView32'), 'FolderView');  if DeskopICOH <> 0 then windows.SetParent(Self.Handle, DeskopICOH) else Close; end;  w1:=TBitmap.Create;  w1.Assign(image1.Picture.Bitmap);  w2:=w1.Canvas.Pixels[0,0]; // w2 := clWhite;  rgn := CreateRegion(w1,w2,Handle); if rgn<>0 then  begin  SetWindowRgn(Handle, rgn, true); end;  w1.Free;  end;
View Code

如何取得系统中的桌面的路径

利用Api函数,现在我介绍两个Api函数,利用他们就可以轻松简单的获取这些特殊系统目录。
  Function SHGetSpecialFolderLocation(hwndOwner: HWND; nFolder: Integer;
  var ppidl: PItemIDList): HResult; stdcall;
  Function SHGetPathFromIDList(pidl: PItemIDList; pszPath: PChar): BOOL;stdcall;
  其中由nFolder参数指定的就是各个特殊系统目录:
  CSIDL_DESKTOP:毫无疑问这就是桌面;
  CSIDL_DRIVERS:我的电脑;
  CSIDL_FAVORITES:收藏夹;
  CSIDL_STARTUP:开始菜单;
  CSIDL_NETWORK:网上邻居;
uses shlobj;
  var
  pitem:PITEMIDLIST;
  s:string;
  begin
  shGetSpecialFolderLocation(handle,CSIDL_DESKTOP,pitem);
  setlength(s,100);
  shGetPathFromIDList(pitem,pchar(s));
  end;
vName:= copy(s,1, Length(s)-pos('桌面',s)-15)+'\'; //减15是为了减去 后面的 “#0#0.......”
---------------------------------------------------------------------------------------------------------------------------------
方法一:通过访问注册表 
uses registry; 
procedure Tsysdirfrm.FormShow(Sender: TObject); 
var reg:Tregistry; 
begin 
reg:=Tregistry.create;    reg.RootKey:=HKEY_USERS; 
reg.OpenKey('\.DEFAULT\Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders',false); 
listbox1.items.add(reg.readstring('Desktop')) ;//桌面目录 
listbox1.items.add(reg.readstring('Fonts'));//字体目录 
listbox1.items.add(reg.readstring('NetHood')) ;//网上邻居 
listbox1.items.add(reg.readstring('Personal'));//我的文档目录 
listbox1.items.add(reg.readstring('Programs'));//开始菜单程序目录 
listbox1.items.add(reg.readstring('Recent')) ;//存放用户最近访问文件快捷方式的目录 
listbox1.items.add(reg.readstring('SendTo'));//发送到目录 
listbox1.items.add(reg.readstring('Start Menu'));//开始菜单目录 
listbox1.items.add(reg.readstring('Startup'));//开始菜单启动项目录 
listbox1.items.add(reg.readstring('Favorites')) ;//收藏夹目录 
listbox1.items.add(reg.readstring('History'));//网页历史目录 
listbox1.items.add(reg.readstring('Cookies'));//cookies目录 
listbox1.items.add(reg.readstring('Cache')) ;//缓存目录 
listbox1.items.add(reg.readstring('AppData'));//应用程序数据目录 
listbox1.items.add(reg.readstring('PrintHood')) ;//打印目录 
reg.CloseKey ; 
reg.free; 
end; 

方法二:使用API函数SHGetSpecialFolderLocation和SHGetPathFromIDList 
uses shlobj; 
procedure TForm1.Button1Click(Sender: TObject); 
var 
pidl: PItemIDList; 
FavPath: array[0..MAX_PATH] of char; 
temp:array [1..17] of integer; i:byte; 
begin 

temp[1]:=CSIDL_DESKTOP; //桌面 
temp[2]:=CSIDL_DESKTOPDIRECTORY ; //桌面目录 
temp[3]:=CSIDL_FONTS ; //字体目录 
temp[4]:=CSIDL_NETHOOD ; //网络邻居 
temp[5]:=CSIDL_PERSONAL ; //我的文档目录 
temp[6]:=CSIDL_PROGRAMS ; //开始菜单程序目录 
temp[7]:=CSIDL_RECENT ; //存放用户最近访问文件快捷方式的目录 
temp[8]:=CSIDL_SENDTO ; //"发送到"目录 
temp[9]:=CSIDL_STARTMENU ; //开始菜单目录 
temp[10]:=CSIDL_STARTUP ; //开始菜单启动项目录 
temp[11]:=CSIDL_FAVORITES ; //收藏夹目录 
for i:=1 to 17 do 
begin 
SHGetSpecialFolderLocation(Handle, temp[i], pidl); 
SHGetPathFromIDList(pidl, favpath); 
listbox1.Items.Add(StrPas(FavPath)); 
end; 
end;
-------------------------------------------------------------------------------------------------------------------
uses shlobj;
procedure Tgongzhi1.dsbkSpeedButton1Click(Sender: TObject);
var vPath, vName,s: string;
    pitem:PITEMIDLIST;
begin
if DBGrid1.Enabled=False then
   MessageBox(handle,'请先查询再进行导出操作!','友情提醒:',mb_ok+MB_ICONASTERISK)
else
begin
   if Application.MessageBox('确定要导出EXCEL表? ','友情提醒:',MB_YESNO+MB_ICONQUESTION)   =   IDYES   then
begin
   shGetSpecialFolderLocation(handle,CSIDL_DESKTOP,pitem);
   setlength(s,100);
   shGetPathFromIDList(pitem,pchar(s));
   vPath:= copy(s,1, Length(s)-pos('桌面',s)-15)+'\';
//vPath := 'C:\Documents and Settings\Administrator\桌面\';
   vName :='工资汇总'+formatdatetime('yyyy-mm-dd',DateTimePicker1.date)+'~'+formatdatetime('yyyy-mm-dd',DateTimePicker2.date);
    if DBGrid1.Enabled=False then
     MessageBox(handle,'请先查询再进行删除操作!','友情提醒:',mb_ok+MB_ICONASTERISK)
   else
    savexls(ADOQuery1, VName, vPath);
    MessageBox(handle,PChar('文件: '+vName+'; 路径:'+vPath+'; 导出成功!'),'友情提醒:',mb_ok+MB_ICONASTERISK)
end;
end;
end;
View Code

完全控制你的Windows桌面

对于Windows的桌面界面相信大家已经十分熟悉了,占据屏幕大半部分的是桌面,在上面排列的是桌面图标。
任务栏一般位于桌面的下面,也可以在桌面其它边缘。在最左边是“开始按钮”,接下来是“快速启动按钮”区、
程序按钮区,再下来是任务栏图标区,在上面一般会有音量调节图标和输入法调节图标和时钟等。
本文首先介绍如何隐藏任务栏中的上面介绍的部分。我们知道利用Windows的Api函数ShowWindow可以隐藏或
者显示窗口,关键是如何得到窗口的句柄。在Windows下的每一个窗口不但有一个窗口句柄标示窗口,还有一个称
为类名的字符串标示窗口。如果知道窗口的类名,通过FindWindow函数就可以获得窗口的句柄。而Windows桌面
本身就是一个窗口,桌面图标区、任务栏以及任务栏下的开始按钮等都是它的子窗口。我们可以通过FindWindowEx
函数来寻找这些窗口。再利用ShowWindow函数隐藏或显示窗口。下面通过一个Delphi的范例来演示如何控制任务栏。
首先建立一个新的Delphi工程,然后在Form1中加入7个CheckBox控件,然后在Form1中添加下面的代码:

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  StdCtrls;

type
  TForm1 = class(TForm)
    CheckBox1: TCheckBox;
    CheckBox2: TCheckBox;
    CheckBox3: TCheckBox;
    CheckBox4: TCheckBox;
    CheckBox5: TCheckBox;
    CheckBox6: TCheckBox;
    CheckBox7: TCheckBox;
    procedure FormCreate(Sender: TObject);
  private
    procedure CheckButtonClick(Sender:TObject);
    { Private declarations }
  public
    { Public declarations }
  end;
Const
file://定义不同窗口的类名
sTrayWindow = 'Shell_TrayWnd';
sTrayNotify = 'TrayNotifyWnd';
sStartButton = 'Button';
sAppSwitchBar = 'ReBarWindow32';
sAppSwitch = 'MSTaskSwWClass';
sAppIcon = 'ToolbarWindow32';
sTrayClock = 'TrayClockWClass';
sDesktopIcon = 'ShellDll_DefView';
sProgman = 'Progman';

var
  Form1: TForm1;
  wnd:Integer;

implementation

{$R *.DFM}

procedure TForm1.FormCreate(Sender: TObject);
begin
  CheckBox1.Caption := '隐藏任务栏';
  CheckBox1.OnClick := CheckButtonClick;
  CheckBox2.Caption := '隐藏开始按钮';
  CheckBox2.OnClick := CheckButtonClick;
  CheckBox3.Caption := '隐藏任务栏图标';
  CheckBox3.OnClick := CheckButtonClick;
  CheckBox4.Caption := '隐藏程序按钮';
  CheckBox4.OnClick := CheckButtonClick;
  CheckBox5.Caption := '隐藏任务栏时钟';
  CheckBox5.OnClick := CheckButtonClick;
  CheckBox6.Caption := '隐藏桌面图标';
  CheckBox6.OnClick := CheckButtonClick;
  CheckBox7.Caption := '隐藏快速运行图标';
  CheckBox7.OnClick := CheckButtonClick;
end;

file://7个CheckBox控件的Click处理函数
procedure TForm1.CheckButtonClick(Sender:TObject);
var
  i:Integer;
begin
  file://找到任务栏窗口的窗口句柄
  wnd := FindWindow(sTrayWindow, nil);

  if (TCheckBox(Sender).Name)=  'CheckBox2' then
    wnd := FindWindowEx(wnd, 0, sStartButton, nil);

  if (TCheckBox(Sender).Name)=  'CheckBox3' then
    wnd := FindWindowEx(wnd, 0, sTrayNotify, nil);

  if (TCheckBox(Sender).Name)=  'CheckBox4' then begin
    wnd := FindWindowEx(wnd, 0, sAppSwitchBar, nil);
    wnd := FindWindowEx(wnd, 0, sAppSwitch, nil);
  end;

  if (TCheckBox(Sender).Name)=  'CheckBox5' then begin
    wnd := FindWindowEx(wnd, 0, sTrayNotify, nil);
    wnd := FindWindowEx(wnd, 0, sTrayClock, nil);
  end;

  if (TCheckBox(Sender).Name)=  'CheckBox6' then begin
    wnd := FindWindow(sProgman, nil);
    wnd := FindWindowEx(wnd, 0, sDesktopIcon, nil);
  end;

  if (TCheckBox(Sender).Name)=  'CheckBox7' then begin
    wnd := FindWindowEx(wnd, 0, sAppSwitchBar, nil);
    wnd := FindWindowEx(wnd, 0, sAppIcon, nil);
  end;

  if TCheckBox(Sender).Checked then
    ShowWindow (wnd, SW_HIDE)
  Else
    ShowWindow (wnd, SW_SHOW);
end;
end.
View Code

运行程序,分别点击不同的选择框,可以分别隐藏任务栏或任务栏上的不同部分。

下面再来介绍如何操控桌面图标。设置图标文本的背景和颜色以及设置图标的排列。通过上面的介绍
上面我们知道,Windows的桌面也是一个窗口,不同的它是一个ListView类窗口,对于ListView类窗口,有
一系列的以LVM_开头的消息,通过Windows API函数SendMessage向ListView类窗口发送这些消息就可以控
制窗口的一些属性,而且在Delphi中还有一系列的以ListView_开头的函数,这些函数可以代替LVM_类消息。
具体的范例如下:首先建立一个新的Delphi工程,然后在Form1中加入两个CommandButton控件,然后在
Form1中加入以下的代码:

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  ComCtrls, StdCtrls,Commctrl;

type
  TForm1 = class(TForm)
    Button1: TButton;
    Button2: TButton;
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
    procedure FormCreate(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.DFM}
procedure SetDesktopIconColor(Forground, Background: TColor; Trans: Boolean);
var
  Window: HWND;
begin
  Window := FindWindow('Progman', 'Program Manager');
  file://找到桌面窗口
  Window := FindWindowEx(Window, HWND(nil), 'SHELLDLL_DefView', '');
  file://找到放置桌面图标的ListView窗口
  Window := FindWindowEx(Window, HWND(nil), 'SysListView32', '');

  if Trans then         file://设置透明的文字背景色
    ListView_SetTextBkColor(Window, $ffffffff) // back color
  else                  file://设置不透明的文字背景色
    ListView_SetTextBkColor(Window, Background); // back color

  ListView_SetTextColor(Window, Forground); // foreground color
  file://重新绘制桌面图标
  ListView_RedrawItems(Window, 0, ListView_GetItemCount(Window) - 1);
  UpdateWindow(Window);   file://重新绘制窗口
end;

procedure SetDeskTopIconArr(iWidth,iHeight:Integer);
var
  Window: HWND;
  i,i1,i2,iCount:integer;
begin
  Window := FindWindow('Progman', 'Program Manager');
  Window := FindWindowEx(Window, HWND(nil), 'SHELLDLL_DefView', '');
  Window := FindWindowEx(Window, HWND(nil), 'SysListView32', '');

  file://设置图标与边界的距离。
  i1:=20;i2:=20;

  file://获得桌面图标的个数
  iCount:=ListView_GetItemCount(Window)-1;
  for i:=0 to iCount do begin
    file://设置图标位置
    ListView_SetItemPosition(Window,i,i1,i2);
    i1:=i1 iWidth;
    if i1>(Screen.Width-32) then begin
      i1:=20;
      i2:=i2 iHeight;
    end;
  end;
  ListView_RedrawItems(Window, 0, ListView_GetItemCount(Window) - 1);
  UpdateWindow(Window);
end;

procedure SetDefaultIconColors;
var
  Kind: Integer;
  Color: TColor;
begin
  Kind := COLOR_DESKTOP;
  Color := GetSysColor(COLOR_DESKTOP);
  SetSysColors(1, Kind, Color);
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  file://你可以改变clWhite,clBlack为其它的颜色值看看
  file://图标文本颜色的变化
  SetDesktopIconColor(clWhite,clBlack,True);
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
  file://设置图标的间距为100个像素
  SetDeskTopIconArr(100,100);
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  Button1.Caption := '设置图标文本颜色';
  Button2.Caption := '设置图标排列';
end;

end.
View Code

在上面的程序中,函数SetDesktopIconColor设置图标文本的前景色、背景色和透明,参数ForeGround
BackGround分别指定文本的前景色和背景色,参数Trans指定文本的背景是否透明(如果有背景图案的话)。
函数SetDeskTopIconArr排列桌面图标,参数iWidth,iHeight分别指定图标之间的横向纵向距离。如果要使
SetDeskTopIconArr函数生效,就需要将桌面图标的自动排列选项去掉。另外ListView类还有其它的控制消息
利用这些消息可以控制更多的桌面图标选项。有兴趣的朋友可以察看MSDN库。
以上程序由Delphi5编写,在Windows98 Windows2000下运行通过。

转载于:https://www.cnblogs.com/blogpro/p/11453784.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值