在桌面中嵌入窗体
前几天在网上看到一个软件的介绍:可以嵌入桌面,即使是“显示桌面”也不会影响此程序。看作者说的好像有多么的神奇一样。周未就回来试一下。最后发现,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);
隐藏桌面图标和任务栏
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.
虚拟桌面原理及实现
一、为什么要使用虚拟桌面。 场景一、 上班的时候,我们经常会趁老板不注意,去一些工作时间不应该去的网站,或是运行一些不应该运行的程序,比如一些聊天工具,小游戏,股票软件等等。而且,经常会打开一大堆。当老板或其他同事来到你的桌前的时候,你正在手忙脚乱的关着这些程序,而且,还来不及保存想要保存的东西。 场景二、 在你给别人做讲演的时候,需要在电脑桌面上展示很多资料。当然一个桌面经常是远远不够展示的,而且,需要经常的切换画面,由于打开的资料太多,每次还的任务栏里找上一阵。很影响讲演的流畅性。 虚拟桌面程序就是用来解决以上的问题。 场景一、 你可以用虚拟桌面程序同时生成多个桌面。一个桌面打开着你工作的资料,程序等等。一个桌面打开着你的聊天工具及一些你不想别人看到的东西。当然你还可以用一个桌面放一些你想访问的网站啊,股票信息啊等等。剩下的只是简单的按一下快捷键来切换不同的桌面。 场景二、 同场景一,你可以用虚拟桌面程序生成多个桌面,把要讲演的资料提前分配到多个桌面。剩下的只是简单的按一下快捷键来切换不同的桌面。 二、虚拟桌面实现原理 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个桌面 //*******************************************************************
虚拟桌面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;
程序嵌入桌面效果的实现
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;
如何取得系统中的桌面的路径
利用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;
完全控制你的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.
运行程序,分别点击不同的选择框,可以分别隐藏任务栏或任务栏上的不同部分。
下面再来介绍如何操控桌面图标。设置图标文本的背景和颜色以及设置图标的排列。通过上面的介绍
上面我们知道,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.
在上面的程序中,函数SetDesktopIconColor设置图标文本的前景色、背景色和透明,参数ForeGround
BackGround分别指定文本的前景色和背景色,参数Trans指定文本的背景是否透明(如果有背景图案的话)。
函数SetDeskTopIconArr排列桌面图标,参数iWidth,iHeight分别指定图标之间的横向纵向距离。如果要使
SetDeskTopIconArr函数生效,就需要将桌面图标的自动排列选项去掉。另外ListView类还有其它的控制消息
利用这些消息可以控制更多的桌面图标选项。有兴趣的朋友可以察看MSDN库。
以上程序由Delphi5编写,在Windows98 Windows2000下运行通过。