Windows辦事編寫(Windows Service,system權限)法式顯示界面與用戶交互(xp,win7通用)。本站提示廣大學習愛好者:(Windows辦事編寫(Windows Service,system權限)法式顯示界面與用戶交互(xp,win7通用))文章只能為提供參考,不一定能成為您想要的結果。以下是Windows辦事編寫(Windows Service,system權限)法式顯示界面與用戶交互(xp,win7通用)正文
1、VC2008中編寫“Windows辦事”(Windows Service)法式
源碼資本下載:/201604/yuanma/TestService_jb51.rar
vc2008下新建一個 ATL 項目-》 選擇創立一個“辦事”類型的ATL 項目TestService,將生成以下代碼,
class CTestServiceModule : public CAtlServiceModuleT< CTestServiceModule, IDS_SERVICENAME > { public : DECLARE_LIBID(LIBID_TestServiceLib ) DECLARE_REGISTRY_APPID_RESOURCEID (IDR_TESTSERVICE, "{1FF78006-B225-4CC0-A7DE-E0C9D31C9937}" ) HRESULT InitializeSecurity () throw() { // TODO : 挪用CoInitializeSecurity 並為辦事供給恰當的 // 平安設置 // 建議- PKT 級其余身份驗證、 // RPC_C_IMP_LEVEL_IDENTIFY 的模仿級別 // 和恰當的非NULL 平安解釋符。 return S_OK ; } //重寫這個函數來啟動義務啦 HRESULT Run (int nShowCmd = SW_HIDE ) throw() { HRESULT hr = S_OK; hr = __super ::PreMessageLoop( nShowCmd); if (hr == S_OK) { if (m_bService ) { //須要界說#define _ATL_NO_COM_SUPPORT能力啟動辦事時走到這裡 //可以在這裡啟動線程,或許甚麼其他器械來做本身的任務的啦 //這裡是甚麼都沒有做了,只輸入一條信息 LogEvent(_T ("widebright 的辦事啟動咯,呵呵 ")); SetServiceStatus(SERVICE_RUNNING ); } //進入新聞輪回,一直的處置新聞,能夠最初分發到 Handler行止理,挪用了OnShutdown等函數的。 __super::RunMessageLoop (); } if (SUCCEEDED (hr)) { hr = __super ::PostMessageLoop(); } //可以在恰當的時刻挪用Uninstall函數來卸載失落辦事 //__super::Uninstall(); return hr ; } //重寫,辦事加入處置 void OnShutdown () throw() { LogEvent(_T ("TestService 的辦事加入咯,一點都欠好玩呵呵 ")); } }; CTestServiceModule _AtlModule; // extern "C" int WINAPI _tWinMain (HINSTANCE , HINSTANCE , LPTSTR , int nShowCmd) { return _AtlModule .WinMain( nShowCmd); }
2、我只需依據須要重寫響應的函數來完成本身想要的功效就好了
好比你想創立的“辦事”隨體系啟動,可以重寫CAtlServiceModuleT 的Install函數,把外面的CreateService函數的參數修正一下,例如添加與用戶交互可使用 SERVICE_INTERACTIVE_PROCESS,詳細可以去MSDN上查找CreateService這個API的解釋。
假如想處置辦事 停滯和啟動的舉措,可以參考CAtlServiceModuleT 的源代碼重寫OnStop ()等函數。我下面簡略到重寫了Run函數,輸入一條“事宜”其實詳細 任務是可以放到這裡來完成的吧。
編譯,生成法式以後便可以測試了,
履行“TestService -/Service” 便可以把辦事注冊到體系了,敕令行參數實際上是在CAtlServiceModuleT::ParseCommandLine 這個函數外面處置,可以去看一下,需要的話重寫也是可以的,加上挪用 UnInstall來刪除辦事的代碼也很不錯的吧。
注冊後,就看用“sc start” 或許“net start” 等敕令來把持辦事了。在“辦事”掌握器外面掌握與可以:如圖
3、這時候候在Run函數中啟動一個Notepad.exe,此時沒有界面顯示,在xp下可使用上面的辦法完成notepad與用戶的交互:
//for xp system DWORD _stdcall LaunchAppIntoSession0( LPTSTR lpCommand ) { ////////////////////////////////////////////system show dlg//////////////////// HDESK hdeskCurrent ; HDESK hdesk ; HWINSTA hwinstaCurrent ; HWINSTA hwinsta ; hwinstaCurrent = GetProcessWindowStation (); if (hwinstaCurrent == NULL) { return FALSE ; } hdeskCurrent = GetThreadDesktop (GetCurrentThreadId()); if (hdeskCurrent == NULL){ return FALSE ; } //翻開winsta0 //翻開winsta0 hwinsta = OpenWindowStation (L"Winsta0" , FALSE, WINSTA_ALL_ACCESS); // WINSTA_ACCESSCLIPBOARD| // WINSTA_ACCESSGLOBALATOMS | // WINSTA_ENUMDESKTOPS | // WINSTA_CREATEDESKTOP | // WINSTA_CREATEDESKTOP | // WINSTA_ENUMERATE | // WINSTA_EXITWINDOWS | // WINSTA_READATTRIBUTES | // WINSTA_READSCREEN | // WINSTA_WRITEATTRIBUTES); if (hwinsta == NULL){ return FALSE ; } if (!SetProcessWindowStation (hwinsta)) { return FALSE ; } //翻開desktop hdesk = OpenDesktop (L"default" , 0, FALSE, DESKTOP_CREATEMENU | DESKTOP_CREATEWINDOW | DESKTOP_ENUMERATE| DESKTOP_HOOKCONTROL| DESKTOP_JOURNALPLAYBACK | DESKTOP_JOURNALRECORD | DESKTOP_READOBJECTS | DESKTOP_SWITCHDESKTOP | DESKTOP_WRITEOBJECTS); if (hdesk == NULL){ return FALSE ; } SetThreadDesktop(hdesk ); ////////////////////////////////////////////end of system show dlg//////////////////// STARTUPINFO si = { sizeof( si) }; SECURITY_ATTRIBUTES saProcess , saThread; PROCESS_INFORMATION piProcessB , piProcessC; // Prepare to spawn Process B from Process A. // The handle identifying the new process // object should be inheritable. saProcess.nLength = sizeof( saProcess); saProcess.lpSecurityDescriptor = NULL; saProcess.bInheritHandle = TRUE; // The handle identifying the new thread // object should NOT be inheritable. saThread.nLength = sizeof( saThread); saThread.lpSecurityDescriptor = NULL; saThread.bInheritHandle = FALSE; CreateProcess(NULL , lpCommand, & saProcess, &saThread , FALSE, 0, NULL , NULL, & si, &piProcessB ); if (!SetProcessWindowStation (hwinstaCurrent)) return FALSE ; if (!SetThreadDesktop (hdeskCurrent)) return FALSE ; if (!CloseWindowStation (hwinsta)) return FALSE ; if (!CloseDesktop (hdesk)) return FALSE ; return TRUE ; }
這類辦法的症結是OpenWindowStation、SetProcessWindowStation、OpenDesktop和SetThreadDesktop這四個函數。這類辦法的思緒是:以後過程所處於的Session必需有界面交互才能,如許能力顯示出對話框。因為第一個交互式用戶會登錄到具有WinSta0的Session 0,所以,強迫性地把辦事地點的過程與WinSta0聯系關系起來,而且翻開以後的桌面,把任務線程掛到該桌面上,便可以顯示出對話框。
4、這類辦法在WinXP和Windows2003下任務得不錯,很遺憾,在Vista和Windows2008下,一旦履行到OpenWindowStation,試圖代開WinSta0任務站時,法式就會出異常。
起首懂得一下法式要具有如何的前提能力與界面交互。Windows供給了三類對象:用戶界面臨象(User Interface)、GDI對象和內查對象。內查對象有平安性,而前二者沒有。為了對前二者供給平安性,經由過程任務站對象(Window station)和桌面臨象(Desktop)來治理用戶界面臨象,由於任務站對象和桌面臨象有平安特征。簡略說來,任務站是一個帶有平安特征的對象,它與過程相干聯,包括了一個或多個桌面臨象。當任務站對象被創立時,它被聯系關系到挪用過程上,而且被賦給以後Session。交互式任務站WinSta0,是獨一一個可以顯示用戶界面,接收用戶輸出的任務站。它被賦給交互式用戶的登錄Session,包括了鍵盤、鼠標和顯示裝備。一切其他任務站都長短交互式的,這就意味著它們不克不及顯示用戶界面,不克不及接收用戶的輸出。當用戶登錄到一台啟用了終端辦事的盤算機上時,每一個用戶都邑啟動一個Session。每一個Session都邑與本身的交互式任務站相接洽。桌面是一個帶有平安特征的對象,被包括在一個窗口任務站對象中。一個桌面臨象有一個邏輯的顯示區域,包括了諸如窗口、菜單、鉤子等等如許的用戶界面臨象。
在Vista之前,之所以可以經由過程翻開Winsta0和缺省桌面顯示對話框,是由於不論是辦事照樣第一個登錄的交互式用戶,都是登錄到Session 0中。是以,辦事法式可以經由過程強迫翻開WinSta0和桌面來取得交互才能。
但是,在Vista和Windows2008中,Session 0公用於辦事和其他不與用戶交互的運用法式。第一個登錄出去,可以停止交互式操作的用戶被連到Session 1上。第二個登錄停止的用戶被分派給Session 2,以此類推。Session 0完整不支撐要與用戶交互的過程。假如采用在辦事過程中啟動子過程來顯示對話框,子對話框將沒法顯示;假如采用用OpenWindowStation體系API翻開WinSta0的辦法,函數挪用會掉敗。總之,Vista和Windows2008曾經堵上了在Session 0中發生界面交互的路。這就是緣由地點。
那末,能否真的沒法在辦事中彈出對話框了呢?關於辦事過程本身來講,確切如斯,操作體系曾經把這條路堵上了。然則,我們想要的其實不是“在辦事過程中彈出對話框”,我們想要的不外是“當辦事湧現某些狀態的時刻,在桌面上彈出對話框”。既然在Session 0中沒法彈出對話框,而我們看到的桌面是Session X,並不是Session 0,很天然的一個設法主意是:能不克不及讓Session 0告訴其他的Session,讓以後桌面正顯示著的Session彈一個對話框呢?
榮幸的是,還真可以如許做。
//for win7 DWORD _stdcall LaunchAppIntoDifferentSession( LPTSTR lpCommand ) { DWORD dwRet = 0; PROCESS_INFORMATION pi ; STARTUPINFO si ; DWORD dwSessionId ; HANDLE hUserToken = NULL; HANDLE hUserTokenDup = NULL; HANDLE hPToken = NULL; HANDLE hProcess = NULL; DWORD dwCreationFlags ; HMODULE hInstKernel32 = NULL; typedef DWORD (WINAPI * WTSGetActiveConsoleSessionIdPROC)(); WTSGetActiveConsoleSessionIdPROC WTSGetActiveConsoleSessionId = NULL; hInstKernel32 = LoadLibrary (L"Kernel32.dll" ); if (!hInstKernel32 ) { return FALSE ; } OutputDebugString(L "LaunchAppIntoDifferentSession 1\n" ); WTSGetActiveConsoleSessionId = (WTSGetActiveConsoleSessionIdPROC )GetProcAddress( hInstKernel32,"WTSGetActiveConsoleSessionId" ); // Log the client on to the local computer. dwSessionId = WTSGetActiveConsoleSessionId (); do { WTSQueryUserToken( dwSessionId ,&hUserToken ); dwCreationFlags = NORMAL_PRIORITY_CLASS | CREATE_NEW_CONSOLE; ZeroMemory( &si , sizeof( STARTUPINFO ) ); si.cb = sizeof( STARTUPINFO ); si.lpDesktop = L"winsta0\\default" ; ZeroMemory( &pi , sizeof( pi) ); TOKEN_PRIVILEGES tp ; LUID luid ; if( !::OpenProcessToken ( GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY | TOKEN_DUPLICATE | TOKEN_ASSIGN_PRIMARY | TOKEN_ADJUST_SESSIONID | TOKEN_READ | TOKEN_WRITE , &hPToken ) ) { dwRet = GetLastError (); break; } else; if ( !LookupPrivilegeValue ( NULL, SE_DEBUG_NAME, &luid ) ) { dwRet = GetLastError (); break; } else; tp.PrivilegeCount =1; tp.Privileges [0].Luid = luid; tp.Privileges [0].Attributes = SE_PRIVILEGE_ENABLED; if( !DuplicateTokenEx ( hPToken, MAXIMUM_ALLOWED, NULL , SecurityIdentification , TokenPrimary, & hUserTokenDup ) ) { dwRet = GetLastError (); break; } else; //Adjust Token privilege if( !SetTokenInformation ( hUserTokenDup,TokenSessionId ,(void*)& dwSessionId,sizeof (DWORD) ) ) { dwRet = GetLastError (); break; } else; if( !AdjustTokenPrivileges ( hUserTokenDup, FALSE, &tp , sizeof(TOKEN_PRIVILEGES ), (PTOKEN_PRIVILEGES) NULL, NULL ) ) { dwRet = GetLastError (); break; } else; LPVOID pEnv =NULL; if( CreateEnvironmentBlock ( &pEnv, hUserTokenDup, TRUE ) ) { dwCreationFlags|=CREATE_UNICODE_ENVIRONMENT ; } else pEnv =NULL; // Launch the process in the client's logon session. if( CreateProcessAsUser ( hUserTokenDup, // client's access token NULL, // file to execute lpCommand, // command line NULL, // pointer to process SECURITY_ATTRIBUTES NULL, // pointer to thread SECURITY_ATTRIBUTES FALSE, // handles are not inheritable dwCreationFlags,// creation flags pEnv, // pointer to new environment block NULL, // name of current directory & si, // pointer to STARTUPINFO structure & pi // receives information about new process ) ) { } else { dwRet = GetLastError (); break; } } while( 0 ); //Perform All the Close Handles task if( NULL != hUserToken ) { CloseHandle( hUserToken ); } else; if( NULL != hUserTokenDup) { CloseHandle( hUserTokenDup ); } else; if( NULL != hPToken ) { CloseHandle( hPToken ); } else; return dwRet ; }
5、啟動辦事後顯示了system權限的Notepad.exe,而且可以與用戶停止交互
固然,在本例子啟動過程的處所創立一個對話框也是可以顯示對話框的。