Windows 服務預設運行於非互動式工作階段,無法直接存取使用者桌面顯示視窗。要實現服務程式彈出對話框與使用者互動,必須明確開啟 WinSta0 視窗站與 Default 桌面物件。
BOOL CServiceModule::ShowMsgDlg(void)
{
HDESK hdeskCurrent, hdesk;
HWINSTA hwinstaCurrent, hwinsta;
// 保存當前環境
hwinstaCurrent = GetProcessWindowStation();
hdeskCurrent = GetThreadDesktop(GetCurrentThreadId());
// 開啟 WinSta0 視窗站
hwinsta = OpenWindowStation(_T("winsta0"), FALSE,
WINSTA_ACCESSCLIPBOARD | WINSTA_ACCESSGLOBALATOMS |
WINSTA_CREATEDESKTOP | WINSTA_ENUMDESKTOPS |
WINSTA_ENUMERATE | WINSTA_EXITWINDOWS |
WINSTA_READATTRIBUTES | WINSTA_READSCREEN |
WINSTA_WRITEATTRIBUTES);
if (!hwinsta || !SetProcessWindowStation(hwinsta)) return FALSE;
// 開啟 Default 桌面
hdesk = OpenDesktop(_T("default"), 0, FALSE,
DESKTOP_CREATEMENU | DESKTOP_CREATEWINDOW |
DESKTOP_ENUMERATE | DESKTOP_HOOKCONTROL |
DESKTOP_JOURNALPLAYBACK | DESKTOP_JOURNALRECORD |
DESKTOP_READOBJECTS | DESKTOP_SWITCHDESKTOP |
DESKTOP_WRITEOBJECTS);
if (!hdesk || !SetThreadDesktop(hdesk)) return FALSE;
// 此處已具備互動權限,可顯示對話框
CMsgDlg dlgMsg;
dlgMsg.DoModal();
// 還原環境並清理資源
SetProcessWindowStation(hwinstaCurrent);
SetThreadDesktop(hdeskCurrent);
CloseWindowStation(hwinsta);
CloseDesktop(hdesk);
return TRUE;
}
OpenWindowStation 和 OpenDesktop 必須請求完整存取權限旗標,否則後續視窗操作會失敗SetProcessWindowStation 和 SetThreadDesktop 將呼叫執行緒關聯到互動式桌面DoModal() 會阻塞服務執行緒,生產環境建議改用非模態視窗或獨立 UI 執行緒驗證環境:Windows 2000 Professional + VC6.0 + SP5 + Platform SDK 2001.8。若編譯失敗請更新至最新 Platform SDK。編譯生成 guiser.exe,以 guiser /service 註冊服務,再從控制台服務管理工具啟動即可看到對話框彈出。