winvnc源码阅读笔记(四)---------vncDesktopThread线程

来源:互联网 发布:linux创建多级子目录 编辑:程序博客网 时间:2024/06/03 04:00

   此线程的核心函数是run_undetached(),我们从这个函数开始阅读。

  该函数的核心功能是:

(1)    该线程调用vncDesktop::Startup()进行所有的初始化工作:
    1.    设置象素格式和位图信息
    2.    设置各种系统 Hook, 添加系统挂钩,包括屏幕, 键盘,鼠标。
    3.    设置一个定时器来处理拉模式(polling mode),每一秒钟执行一次. 这样 TriggerUpdate 例程每秒钟被执行一次.

(2)    设置处理剪切板消息
(3)    创建一个缓存区域对象。所有的区域更新消息都被缓存在该对象中,仅当 TriggerUpdate被触发时,才把这些消息传给所有的客户端。

   我们来看代码:

   void *
vncDesktopThread::run_undetached(void *arg)
{

 if(Q_init() == NULL)  //debug by qz,初始化工作。
  return NULL;
 rfb::SimpleUpdateTracker clipped_updates;
 rfb::ClippedUpdateTracker updates(clipped_updates, m_desktop->m_Cliprect);
 Q_process_desktop(); //debug by qz,处理桌面信息

 while (looping && !fShutdownOrdered)
 {  

   result=WaitForMultipleObjects(6,m_desktop->trigger_events,FALSE,waittime);//debug by qz,等待其中一个事件发送信号,有屏幕更新事件、鼠标更新事件、用户1、2、退出、定时器超时事件等。
   //debug by qz,等待100毫秒时间让客户端连接
   DWORD status=WaitForSingleObject(m_desktop->restart_event,100);//debug by qz,参数hHandle是一个事件的句柄,第二个参数dwMilliseconds是时间间隔。如果事件是有信号状态返回WAIT_OBJECT_0,如果时间超过dwMilliseconds值但时间事件还是无信号状态则返回WAIT_TIMEOUT。 保证这段函数不被其他线程打断.
   if (status==WAIT_TIMEOUT) looping=false;
   switch(result)
   {
    case WAIT_TIMEOUT:
    case WAIT_OBJECT_0:
    {
      waiting_update=0;
      ResetEvent(m_desktop->trigger_events[0]);
        Q_30fps(); //保持最大30帧每秒

        handle_driver_changes(rgncache,updates); //重要,处理驱动视频更新数据      

        g_update_triggered = FALSE;
       Q_execl_hookdll(); //每次开启、关闭钩子库调用都需要被线程加载               
        
        //当网络上没有数据在交换(传输),并且server端屏幕没有发生变化时,退出本线程,等待主程序重启该线程,以节省系统开销
        if (!m_server->IsThereFileTransBusy())//有数据交换时返回1,无则返回0
         handle_display_change(threadHandle, rgncache, clipped_updates, updates);//屏幕有变化时返回1,无则返回0
     
        Q_single_window(updates); //给window发送信号                

        m_desktop->m_UltraEncoder_used=m_desktop->m_server->IsThereAUltraEncodingClient();   //看是否有ultra编码的客户端
        tmp<<"vncDesktopThread---run_undetached:"<<(unsigned   long)GetCycleCount()<<"------"<<"beep over"<<endl;

        omni_mutex_lock l(m_desktop->m_update_lock);  //重要,此处可能消耗32s时间
        if (m_desktop->m_server->UpdateWanted())  //这个函数耗时较多,64s-100s之间,重点注意
        {

         Q_handle_cursorpos(); //处理光标信息          

         Q_pooling_or_driver(); //轮询或驱动模式 

         Q_process_mouse_pointer(); //处理鼠标信息
         omni_mutex_lock ll(m_desktop->m_update_lock);// 防止任何客户端接触到缓冲区
         if (!m_desktop->m_hookdriver && !m_server->SingleWindow()) // 检查窗口的位置
          m_desktop->CalcCopyRects(updates);
          Q_grab_display(); //捕捉屏幕信息 
          tmp<<"vncDesktopThread---run_undetached:"<<(unsigned   long)GetCycleCount()<<"------"<<"grab display over"<<endl;
 //         capture=true;
          Q_handle_mouse(); //处理鼠标信息,主要是处理客户端的鼠标触发和移动操作
      
          Q_scan_changed_region(clipped_updates);//扫描整个屏幕以确定有哪些区域改变了       
          updates.add_changed(changedrgn);  //增加需要更新的区域,耗时16ms,添加数据到发送缓冲里面  
          updates.add_cached(cachedrgn);   
          clipped_updates.get_update(m_server->GetUpdateTracker()); //触发socket发送更新数据,重要.
          Q_clear_update_tracker(clipped_updates);
        } //end if UpdateWanted
        //newtick = timeGetTime();
      }//end case
     break;
 
    case WAIT_OBJECT_0+1:
     ResetEvent(m_desktop->trigger_events[1]);
     m_desktop->lock_region_add=true;
     rgncache.assign_union(m_desktop->rgnpump);
     m_desktop->rgnpump.clear();
     m_desktop->lock_region_add=false;
     waiting_update++;
     break;
    case WAIT_OBJECT_0+2:
     ResetEvent(m_desktop->trigger_events[2]);
     break;
    case WAIT_OBJECT_0+3:
     if (MyGetCursorInfo)
     {
      MyCURSORINFO cinfo;
      cinfo.cbSize=sizeof(MyCURSORINFO);
      MyGetCursorInfo(&cinfo);
      m_desktop->SetCursor(cinfo.hCursor);
     }
     ResetEvent(m_desktop->trigger_events[3]);
     break;
    case WAIT_OBJECT_0+4:
     rgncache.assign_union(m_desktop->m_Cliprect);
     ResetEvent(m_desktop->trigger_events[4]);
     break;
    case WAIT_OBJECT_0+5:
     //break to close
     looping=false;
     ResetEvent(m_desktop->trigger_events[5]);
     break;
   }//end switch
 }//while

 stop_hookwatch=true;
 if (threadHandle)
 {
  WaitForSingleObject( threadHandle, 5000 );
  CloseHandle(threadHandle);
 }
 
 m_desktop->SetClipboardActive(FALSE);
 vnclog.Print(LL_INTINFO, VNCLOG("quitting desktop server thread/n"));
 
 // Clear all the hooks and close windows, etc.
    m_desktop->SetBlockInputState(false);
 m_server->SingleWindow(false);
 vnclog.Print(LL_INTINFO, VNCLOG("quitting desktop server thread:SetBlockInputState/n"));
 
 // Clear the shift modifier keys, now that there are no remote clients
 vncKeymap::ClearShiftKeys();
 vnclog.Print(LL_INTINFO, VNCLOG("quitting desktop server thread:ClearShiftKeys/n"));
 
 // Switch back into our home desktop, under NT (no effect under 9x)
 //TAG14
 HWND mywin=FindWindow("blackscreen",NULL);
 if (mywin)SendMessage(mywin,WM_CLOSE, 0, 0);
 g_DesktopThread_running=false;
 vnclog.Print(LL_INTINFO, VNCLOG("quitting desktop server thread:g_DesktopThread_running=false/n"));
 m_desktop->Shutdown();
 vnclog.Print(LL_INTINFO, VNCLOG("quitting desktop server thread:m_desktop->Shutdown/n"));
 return NULL;
}

原创粉丝点击