好得很程序员自学网

<tfoot draggable='sEl'></tfoot>

Windows服务编写(Windows Service,system权限)程序显示界面与用户交互(x

1、vc2008中编写[windows服务](windows service)程序

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,并且可以与用户进行交互


当然,在本例子启动进程的地方创建一个对话框也是可以显示对话框的。

dy("nrwz");

查看更多关于Windows服务编写(Windows Service,system权限)程序显示界面与用户交互(x的详细内容...

  阅读:50次