虚拟桌面服务程序 [转载]

来源:互联网 发布:美国步枪协会 知乎 编辑:程序博客网 时间:2024/05/22 06:16

一、为什么要使用虚拟桌面。

 

场景一、

上班的时候,我们经常会趁老板不注意,去一些工作时间不应该去的网站,或是运行一些不应该运行的程序,比如一些聊天工具,小游戏,股票软件等等。而且,经常会打开一大堆。当老板或其他同事来到你的桌前的时候,你正在手忙脚乱的关着这些程序,而且,还来不及保存想要保存的东西。

 

场景二、

在你给别人做讲演的时候,需要在电脑桌面上展示很多资料。当然一个桌面经常是远远不够展示的,而且,需要经常的切换画面,由于打开的资料太多,每次还的任务栏里找上一阵。很影响讲演的流畅性。

 

虚拟桌面程序就是用来解决以上的问题。

场景一、

你可以用虚拟桌面程序同时生成多个桌面。一个桌面打开着你工作的资料,程序等等。一个桌面打开着你的聊天工具及一些你不想别人看到的东西。当然你还可以用一个桌面放一些你想访问的网站啊,股票信息啊等等。剩下的只是简单的按一下快捷键来切换不同的桌面。

 

场景二、

同场景一,你可以用虚拟桌面程序生成多个桌面,把要讲演的资料提前分配到多个桌面。剩下的只是简单的按一下快捷键来切换不同的桌面。

 

二、虚拟桌面实现原理

 

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

//******************************************************************

虚拟桌面服务程序

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个桌面

//*******************************************************************

 

原创粉丝点击