注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

BCB-DG's Blog

...

 
 
 

日志

 
 

如何實現桌面切換  

2008-02-22 08:59:11|  分类: VNC |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |

進行桌面切換需要有System權限,如果是以服務啟動的話就是了,也可以用注入或其它的方式。在進行屏傳時要注意切換到當前輸入桌面,或則就出現黑屏和控制不靈了。

下面就貼下VNC的實現代碼(VNC是個好東東,有空還是看看的好),Delphi的也差不多了,翻譯下就行。如果是模擬Ctrl+Alt+Delete,也可以用下面的代碼實現,切換到登錄桌面,Post一下WM_HOTKEY消息就行了,唯一要注意的是Post的線程不要有任何GUI元素,所以最好是一個新線程。

// - SelectDesktop(HDESK)
// Switches the current thread into a different desktop by deskto handle
// This call takes care of all the evil memory management involved

BOOL
vncService::SelectHDESK(HDESK new_desktop)
{
 // Are we running on NT?
 if (IsWinNT())
 {
  HDESK old_desktop = GetThreadDesktop(GetCurrentThreadId());

  DWORD dummy;
  char new_name[256];

  if (!GetUserObjectInformation(new_desktop, UOI_NAME, &new_name, 256, &dummy)) {
   vnclog.Print(LL_INTERR, VNCLOG("!GetUserObjectInformation \n"));
   return FALSE;
  }

  vnclog.Print(LL_INTERR, VNCLOG("SelectHDESK to %s (%x) from %x\n"), new_name, new_desktop, old_desktop);

  // Switch the desktop
  if(!SetThreadDesktop(new_desktop)) {
   vnclog.Print(LL_INTERR, VNCLOG("SelectHDESK:!SetThreadDesktop \n"));
   return FALSE;
  }

  // Switched successfully - destroy the old desktop
  if (!CloseDesktop(old_desktop))
   vnclog.Print(LL_INTERR, VNCLOG("SelectHDESK failed to close old desktop %x (Err=%d)\n"), old_desktop, GetLastError());

  return TRUE;
 }

 return TRUE;
}

// - SelectDesktop(char *)
// Switches the current thread into a different desktop, by name
// Calling with a valid desktop name will place the thread in that desktop.
// Calling with a NULL name will place the thread in the current input desktop.
BOOL
vncService::SelectDesktop(char *name)
{
 //return false;
 // Are we running on NT?
 if (IsWinNT())
 {
  HDESK desktop;
  vnclog.Print(LL_INTERR, VNCLOG("SelectDesktop \n"));
  if (name != NULL)
  {
   vnclog.Print(LL_INTERR, VNCLOG("OpenInputdesktop2 named\n"));
   // Attempt to open the named desktop
   desktop = OpenDesktop(name, 0, FALSE,
    DESKTOP_CREATEMENU | DESKTOP_CREATEWINDOW |
    DESKTOP_ENUMERATE | DESKTOP_HOOKCONTROL |
    DESKTOP_WRITEOBJECTS | DESKTOP_READOBJECTS |
    DESKTOP_SWITCHDESKTOP | GENERIC_WRITE);
  }
  else
  {
   vnclog.Print(LL_INTERR, VNCLOG("OpenInputdesktop2 NULL\n"));
   // No, so open the input desktop
   desktop = OpenInputDesktop(0, FALSE,
    DESKTOP_CREATEMENU | DESKTOP_CREATEWINDOW |
    DESKTOP_ENUMERATE | DESKTOP_HOOKCONTROL |
    DESKTOP_WRITEOBJECTS | DESKTOP_READOBJECTS |
    DESKTOP_SWITCHDESKTOP | GENERIC_WRITE);
  }

  // Did we succeed?
  if (desktop == NULL) {
    vnclog.Print(LL_INTERR, VNCLOG("OpenInputdesktop2 \n"));
    return FALSE;
  }
  else vnclog.Print(LL_INTERR, VNCLOG("OpenInputdesktop2 OK\n"));

  // Switch to the new desktop
  if (!SelectHDESK(desktop)) {
   // Failed to enter the new desktop, so free it!
   if (!CloseDesktop(desktop))
    vnclog.Print(LL_INTERR, VNCLOG("SelectDesktop failed to close desktop\n"));
   return FALSE;
  }

  // We successfully switched desktops!
  return TRUE;
 }

 return (name == NULL);
}

// NT only function to establish whether we're on the current input desktop

BOOL
vncService::InputDesktopSelected()
{
// vnclog.Print(LL_INTERR, VNCLOG("InputDesktopSelected()\n"));
 // Are we running on NT?
 if (IsWinNT())
 {
  // Get the input and thread desktops
  HDESK threaddesktop = GetThreadDesktop(GetCurrentThreadId());
  HDESK inputdesktop = OpenInputDesktop(0, FALSE,
    DESKTOP_CREATEMENU | DESKTOP_CREATEWINDOW |
    DESKTOP_ENUMERATE | DESKTOP_HOOKCONTROL |
    DESKTOP_WRITEOBJECTS | DESKTOP_READOBJECTS |
    DESKTOP_SWITCHDESKTOP);


  // Get the desktop names:
  // *** I think this is horribly inefficient but I'm not sure.
  if (inputdesktop == NULL)
  {
   DWORD lasterror;
   lasterror=GetLastError();
   vnclog.Print(LL_INTERR, VNCLOG("OpenInputDesktop I\n"));
   if (lasterror==170) return TRUE;
   vnclog.Print(LL_INTERR, VNCLOG("OpenInputDesktop II\n"));
   return FALSE;
  }

  DWORD dummy;
  char threadname[256];
  char inputname[256];

  if (!GetUserObjectInformation(threaddesktop, UOI_NAME, &threadname, 256, &dummy)) {
   if (!CloseDesktop(inputdesktop))
    vnclog.Print(LL_INTERR, VNCLOG("failed to close input desktop\n"));
   vnclog.Print(LL_INTERR, VNCLOG("!GetUserObjectInformation(threaddesktop\n"));
   return FALSE;
  }
  _ASSERT(dummy <= 256);
  if (!GetUserObjectInformation(inputdesktop, UOI_NAME, &inputname, 256, &dummy)) {
   if (!CloseDesktop(inputdesktop))
    vnclog.Print(LL_INTERR, VNCLOG("failed to close input desktop\n"));
   vnclog.Print(LL_INTERR, VNCLOG("!GetUserObjectInformation(inputdesktop\n"));
   return FALSE;
  }
  _ASSERT(dummy <= 256);

  if (!CloseDesktop(inputdesktop))
   vnclog.Print(LL_INTERR, VNCLOG("failed to close input desktop\n"));

  if (strcmp(threadname, inputname) != 0)
  {
   vnclog.Print(LL_INTERR, VNCLOG("threadname, inputname differ\n"));
     return FALSE;
  } 
 }

 return TRUE;
}


// Static routine used to fool Winlogon into thinking CtrlAltDel was pressed

void *
SimulateCtrlAltDelThreadFn(void *context)
{
 HDESK old_desktop = GetThreadDesktop(GetCurrentThreadId());

 // Switch into the Winlogon desktop
 if (!vncService::SelectDesktop("Winlogon"))
 {
  vnclog.Print(LL_INTERR, VNCLOG("failed to select logon desktop\n"));
  vncTimedMsgBox::Do(
         sz_ID_CADERROR,
         sz_ID_ULTRAVNC_WARNING,
         MB_ICONINFORMATION | MB_OK
         );
  return FALSE;
 }

 vnclog.Print(LL_ALL, VNCLOG("generating ctrl-alt-del\n"));

 // Fake a hotkey event to any windows we find there.... :(
 // Winlogon uses hotkeys to trap Ctrl-Alt-Del...
 PostMessage(HWND_BROADCAST, WM_HOTKEY, 0, MAKELONG(MOD_ALT | MOD_CONTROL, VK_DELETE));

 // Switch back to our original desktop
 if (old_desktop != NULL)
   vncService::SelectHDESK(old_desktop);
 return NULL;
}

// Static routine to simulate Ctrl-Alt-Del locally

BOOL
vncService::SimulateCtrlAltDel()
{
 vnclog.Print(LL_ALL, VNCLOG("preparing to generate ctrl-alt-del\n"));

 // Are we running on NT?
 if (IsWinNT())
 {
  vnclog.Print(LL_ALL, VNCLOG("spawn ctrl-alt-del thread...\n"));

  // *** This is an unpleasant hack.  Oh dear.

  // I simulate CtrAltDel by posting a WM_HOTKEY message to all
  // the windows on the Winlogon desktop.
  // This requires that the current thread is part of the Winlogon desktop.
  // But the current thread has hooks set & a window open, so it can't
  // switch desktops, so I instead spawn a new thread & let that do the work...

  omni_thread *thread = omni_thread::create(SimulateCtrlAltDelThreadFn);
  if (thread == NULL)
   return FALSE;
  thread->join(NULL);

  return TRUE;
 }

 return TRUE;
}

 

  评论这张
 
阅读(1761)| 评论(0)
推荐 转载

历史上的今天

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017