程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> C# >> C#入門知識 >> Windows辦事編寫(Windows Service,system權限)法式顯示界面與用戶交互(xp,win7通用)

Windows辦事編寫(Windows Service,system權限)法式顯示界面與用戶交互(xp,win7通用)

編輯:C#入門知識

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,而且可以與用戶停止交互


固然,在本例子啟動過程的處所創立一個對話框也是可以顯示對話框的。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved