Windows 服務程式、視窗介面、案頭互動、與遠端桌面

來源:互聯網
上載者:User

標籤:

昨天用c寫了一個windows服務(服務內部帶一個gui視窗+系統托盤),在windows xp sp3上測試,啟動服務後,系統托盤顯示正常。

但在另一台windows 2003 sp2 上測試(通過遠端桌面登入),暈了,服務是啟動了(在進程管理器中能看到),但系統托盤看不到,也就是在案頭的右下角看不到系統托盤的表徵圖。

到網上找原因,找到這麼幾篇:

http://blog.s135.com/windows_mstsc/

http://chenjava.blog.51cto.com/374566/80250

http://www.sldd.cn/web/bbsxp/ShowPost.asp?id=45110

http://hi.baidu.com/since2006bitlove/blog/item/81555e4cdc52c5f3d62afc71.html

http://topic.csdn.net/u/20090320/17/84ac2e8e-cdff-4ca8-908a-fe7e6854deb6.html

 

一開始,我參照:http://topic.csdn.net/u/20090320/17/84ac2e8e-cdff-4ca8-908a-fe7e6854deb6.html 在c的代碼中顯示視窗的前、後面加了這麼一段代碼:

HDESK   hdeskCurrent;
    HDESK   hdesk;
    HWINSTA hwinstaCurrent;
    HWINSTA hwinsta;

    hwinstaCurrent = GetProcessWindowStation();
    if (hwinstaCurrent == NULL)
    {
        //LogEvent(_T("get window station err"));
        return;
    }

    hdeskCurrent = GetThreadDesktop(GetCurrentThreadId());
    if (hdeskCurrent == NULL)
    {
        //LogEvent(_T("get window desktop err"));
        return;
    }

    //開啟winsta0
    hwinsta = OpenWindowStation("winsta0", FALSE,
                                WINSTA_ACCESSCLIPBOARD   |
                                WINSTA_ACCESSGLOBALATOMS |
                                WINSTA_CREATEDESKTOP     |
                                WINSTA_ENUMDESKTOPS      |
                                WINSTA_ENUMERATE         |
                                WINSTA_EXITWINDOWS       |
                                WINSTA_READATTRIBUTES    |
                                WINSTA_READSCREEN        |
                                WINSTA_WRITEATTRIBUTES);
    if (hwinsta == NULL)
    {
        //LogEvent(_T("open window station err"));

        return;
    }

    if (!SetProcessWindowStation(hwinsta))
    {
        //LogEvent(_T("Set window station err"));

        return;
    }

    //開啟desktop
    hdesk = OpenDesktop("default", 0, FALSE,
                        DESKTOP_CREATEMENU |
                        DESKTOP_CREATEWINDOW |
                        DESKTOP_ENUMERATE    |
                        DESKTOP_HOOKCONTROL  |
                        DESKTOP_JOURNALPLAYBACK |
                        DESKTOP_JOURNALRECORD |
                        DESKTOP_READOBJECTS |
                        DESKTOP_SWITCHDESKTOP |
                        DESKTOP_WRITEOBJECTS);
    if (hdesk == NULL)
    {
        //LogEvent(_T("Open desktop err"));

        return;
    }

    SetThreadDesktop(hdesk);

//到這一步,我們擷取了和使用者互動(如顯示視窗)的權利

//顯示視窗的代碼寫在這裡

.....................................

SetProcessWindowStation(hwinstaCurrent);
    SetThreadDesktop(hdeskCurrent);
    CloseWindowStation(hwinsta);
    CloseDesktop(hdesk);

編譯後,在另一台 windows 2003 sp2 上啟動服務,然後在 windows xp sp3 上,運行  mstsc /console,吊用沒有。

為什麼沒效果呢?

接著搜尋,找到一篇:

遠端桌面mstsc /console(/admin) 的運用 -> http://lcq225.blog.163.com/blog/static/16978498201171252623326/

原來:如果系統是WINXP SP3,是不支援 /console這個參數的,需要使用mstsc /admin。經測試,vista 也不支援 mstsc  /console模式,看了一下協助,是沒有/console這個參數的。

windows xp升級到sp3後,命令換成mstsc /admin即可實現winXp2中MSTSC /console的功能。

我試著使用 mstsc /admin 登入,在Java 6 環境,發現系統托盤區還是沒有顯示表徵圖。

但是,如果手動啟動服務,系統托盤就能顯示表徵圖了。

我試著使用 mstsc /admin 登入,在Java 7 環境,發現系統托盤區可以正常顯示表徵圖。

難道不成,java 6 與 java 7在系統托盤(SystemTray)方面的底層實現有所不同???

 

我接著把上面的代碼刪除,再啟動服務,系統托盤也會顯示表徵圖,看來上面的代碼是不需要了。

當然,windows服務需要與案頭互動,還是需要設定一下服務的屬性:

開啟控制台->服務,查看服務的屬性->[登入]-[允許服務與案頭互動],打上鉤後,系統托盤就能顯示在工作列。

 

至於為什麼不能顯示系統托盤的原因,看了這個介紹才明白

我們的軟體在Windows NT/2000/XP/Vista 系統中安裝了一個系統服務,這個服務負責以 SYSTEM 許可權啟動我們的主程式。我們的主程式啟動後會在系統托盤添加一個表徵圖,點擊此表徵圖可以彈出控制功能表,通過這個菜單也可以啟用配置程式喜好設定的對話方塊。在 Windows NT/2000/XP 下我們的程式都可以正常工作。哦不,當 XP 具備了快速切換使用者功能的時候我們的問題已經出現了。XP 啟動後我們以使用者 A 登入,我們的表徵圖出現在系統托盤,一切工作都正常,可當我們使用快速切換使用者,切換到使用者B後(使用者A此時也是已登入狀態,並沒有登出),雖然使用者B已經 是本地控制台會話(Session 屬性為 Console)但我們的表徵圖已經無法出現了,自然菜單和對話方塊更無從談起了。我們的程式是和本機控制台案頭相關的,這種情況無疑是個缺陷。再來看一下在 Vista 平台是怎麼樣吧,系統啟動後以使用者A登入,我們的表徵圖更本就沒有出現,查看進程管理器中的進程列表發現我們的程式已經啟動了,當我們從遠端檢查我們的服 務,發現已經正常工作,嘗試遠程登入我們的服務,Vista 會在本機控制台彈出一個訊息框,提示有互動式服務訊息,是否查看這個訊息,點擊立刻查看發現切換到另外一個案頭去了。
於是開始分析這種情況發生的原因。在 Windows NT/2000 中系統服務進程和本機控制台互動式登入的使用者都運行於Session0 中,預設使用者案頭運行於 WinSta0 視窗站,所以我們的程式由服務程式啟動時依然是和本機使用者處於同一個Session中,即使在某些情況下出現不能彈出對話方塊或者無法添加系統托盤表徵圖的情 況也只需要修改一下進程案頭到 WinSta0\Default 就可以了(可以參考 MSDN 中 OpenInputDesktop, SetThreadDesktop 等API的說明)。
XP為我們帶來了快速切換使用者,也讓我們所採用的軟體架構問題浮現出來。當我們快速切 換到使用者B的時候,使用者A仍然在會話中(Session0),而使用者B則處於新啟動的會話中(Session1或者其他),此時服務程式和本機控制台程式 就不在處於同一會話了,OpenInputDesktop,SetThreadDesktop 等API的工作範圍僅限於本Session,使用者A沒有退出,Session0也依然存在但是已經是 Disconnected 狀態,當進程所處的Session是 Disconnected 狀態的時候調用 OpenInputDesktop 會返回錯誤“無效的API”。進程及線程所屬的Session 是由他們的Token 結構中的 TokenSessionId 決定的(參見MSDN中SetTokenInformation 和 TOKEN_INFORMATION_CLASS的說明),我嘗試以微軟提供的相關API修改運行中的進程和線程的TokenSessionId 資訊從而達到修改案頭環境的目的,到目前還沒有成功過(或許可以嘗試參考RootKit 技術,不過即使修改成功到底能不能實現我們的需求也不確定)。我們的進程無法跨越Session的界限,自然無法與當前活動的另外一個Session中的 案頭互動了, 。
Vista中又是如何的一番景象呢?處於安全方面及其他因素的考慮,Vista以及將 所有的服務程式置於Session0中,而為本機第一個互動登入的使用者建立了Session1,快速切換到使用者B後則是 Session2,無論是本機登入的使用者,快速切換後的使用者,還是遠端桌面登入的使用者再也沒有誰和服務進程處於同一個Session中了,我們的程式還運 行在Session0中,自然我們的托盤表徵圖是沒有使用者能看到了。事實上這個表徵圖還是可以出現的。Session0因為不是一個互動式會話所以沒有象其他 使用者環境初始化的時候一樣啟動Explorer程式,但是我們開始可以手工啟動他,在Session0中啟動 Explorer 後工作列出現後我們還是看到了我們的表徵圖(具體啟動Explorer的方法我們不在此文中討論),菜單、對話方塊也可以使用。
既然我們的程式必須運行在Session0而我們又沒有辦法把我們的表徵圖、對話方塊一下 子就拋到隔壁Session的使用者案頭上去,只能想其他的辦法了。微軟也不提倡我們這種服務程式直接提供GUI與使用者直接互動的方式,而他們建議使用 C/S架構,Client/Server之間用Socket/Pipe/RPC等方式通訊,這樣我們只要把Client整個進程放到使用者Session去 和使用者互動,然後將配置資訊等內容通過上述途徑傳遞給Server,服務端在作出相應的響應即可。
把GUI分離出來並不是那麼困難,然後在以前直接調用的地方加上一個通過Pipe通訊的介面,這樣GUI(Client)的運行就可以靈活的掌握了。
最初我想把使用者介面程式放到 Startup(啟動)中隨使用者登入自動啟動。這樣當使用者A和B都登入後將有兩個使用者介面程式在運行,而我們的服務只是和當前活動的控制台登入使用者互動,所以這樣並不符合需求。
接下來我們需要看看如何判定當前的活動Session是哪個,然後如何在這個活動Session中啟動我們的使用者介面程式了。

 

 

2012-01-21

Windows 服務程式、視窗介面、案頭互動、與遠端桌面

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.