欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

asp.net中穿透Session 0 隔离(二)

程序员文章站 2024-03-05 12:24:30
对于简单的交互,服务可以通过wtssendmessage 函数,在用户session 上显示消息窗口。对于一些复杂的ui 交互,必须调用createprocessasuse...
对于简单的交互,服务可以通过wtssendmessage 函数,在用户session 上显示消息窗口。对于一些复杂的ui 交互,必须调用createprocessasuser 或其他方法(wcf、.net远程处理等)进行跨session 通信,在桌面用户上创建一个应用程序界面。

wtssendmessage 函数
如果服务只是简单的向桌面用户session 发送消息窗口,则可以使用wtssendmessage 函数实现。首先,在上一篇下载的代码中加入一个interop.cs 类,并在类中加入如下代码:

复制代码 代码如下:

public static intptr wts_current_server_handle = intptr.zero;

public static void showmessagebox(string message, string title)
{
int resp = 0;
wtssendmessage(
wts_current_server_handle,
wtsgetactiveconsolesessionid(),
title, title.length,
message, message.length,
0, 0, out resp, false);
}

[dllimport("kernel32.dll", setlasterror = true)]
public static extern int wtsgetactiveconsolesessionid();

[dllimport("wtsapi32.dll", setlasterror = true)]
public static extern bool wtssendmessage(
intptr hserver,
int sessionid,
string ptitle,
int titlelength,
string pmessage,
int messagelength,
int style,
int timeout,
out int presponse,
bool bwait);

在showmessagebox 函数中调用了wtssendmessage 来发送信息窗口,这样我们就可以在service 的onstart 函数中使用,打开service1.cs 加入下面代码:
复制代码 代码如下:

protected override void onstart(string[] args)
{
interop.showmessagebox("this a message from alertservice.", "alertservice message");
}

编译程序后在服务管理器中重新启动alertservice 服务,从下图中可以看到消息窗口是在当前用户桌面显示的,而不是session 0 中。

asp.net中穿透Session 0 隔离(二)

createprocessasuser 函数

     如果想通过服务向桌面用户session 创建一个复杂ui 程序界面,则需要使用createprocessasuser 函数为用户创建一个新进程用来运行相应的程序。打开interop 类继续添加下面代码:

复制代码 代码如下:

public static void createprocess(string app, string path)
{
bool result;
intptr htoken = windowsidentity.getcurrent().token;
intptr hdupedtoken = intptr.zero;

process_information pi = new process_information();
security_attributes sa = new security_attributes();
sa.length = marshal.sizeof(sa);

startupinfo si = new startupinfo();
si.cb = marshal.sizeof(si);

int dwsessionid = wtsgetactiveconsolesessionid();
result = wtsqueryusertoken(dwsessionid, out htoken);

if (!result)
{
showmessagebox("wtsqueryusertoken failed", "alertservice message");
}

result = duplicatetokenex(
htoken,
generic_all_access,
ref sa,
(int)security_impersonation_level.securityidentification,
(int)token_type.tokenprimary,
ref hdupedtoken
);

if (!result)
{
showmessagebox("duplicatetokenex failed" ,"alertservice message");
}

intptr lpenvironment = intptr.zero;
result = createenvironmentblock(out lpenvironment, hdupedtoken, false);

if (!result)
{
showmessagebox("createenvironmentblock failed", "alertservice message");
}

result = createprocessasuser(
hdupedtoken,
app,
string.empty,
ref sa, ref sa,
false, 0, intptr.zero,
path, ref si, ref pi);

if (!result)
{
int error = marshal.getlastwin32error();
string message = string.format("createprocessasuser error: {0}", error);
showmessagebox(message, "alertservice message");
}

if (pi.hprocess != intptr.zero)
closehandle(pi.hprocess);
if (pi.hthread != intptr.zero)
closehandle(pi.hthread);
if (hdupedtoken != intptr.zero)
closehandle(hdupedtoken);
}

[structlayout(layoutkind.sequential)]
public struct startupinfo
{
public int32 cb;
public string lpreserved;
public string lpdesktop;
public string lptitle;
public int32 dwx;
public int32 dwy;
public int32 dwxsize;
public int32 dwxcountchars;
public int32 dwycountchars;
public int32 dwfillattribute;
public int32 dwflags;
public int16 wshowwindow;
public int16 cbreserved2;
public intptr lpreserved2;
public intptr hstdinput;
public intptr hstdoutput;
public intptr hstderror;
}

[structlayout(layoutkind.sequential)]
public struct process_information
{
public intptr hprocess;
public intptr hthread;
public int32 dwprocessid;
public int32 dwthreadid;
}

[structlayout(layoutkind.sequential)]
public struct security_attributes
{
public int32 length;
public intptr lpsecuritydescriptor;
public bool binherithandle;
}

public enum security_impersonation_level
{
securityanonymous,
securityidentification,
securityimpersonation,
securitydelegation
}

public enum token_type
{
tokenprimary = 1,
tokenimpersonation
}

public const int generic_all_access = 0x10000000;

[dllimport("kernel32.dll", setlasterror = true,
charset = charset.auto, callingconvention = callingconvention.stdcall)]
public static extern bool closehandle(intptr handle);

[dllimport("advapi32.dll", setlasterror = true,
charset = charset.ansi, callingconvention = callingconvention.stdcall)]
public static extern bool createprocessasuser(
intptr htoken,
string lpapplicationname,
string lpcommandline,
ref security_attributes lpprocessattributes,
ref security_attributes lpthreadattributes,
bool binherithandle,
int32 dwcreationflags,
intptr lpenvrionment,
string lpcurrentdirectory,
ref startupinfo lpstartupinfo,
ref process_information lpprocessinformation);

[dllimport("advapi32.dll", setlasterror = true)]
public static extern bool duplicatetokenex(
intptr hexistingtoken,
int32 dwdesiredaccess,
ref security_attributes lpthreadattributes,
int32 impersonationlevel,
int32 dwtokentype,
ref intptr phnewtoken);

[dllimport("wtsapi32.dll", setlasterror=true)]
public static extern bool wtsqueryusertoken(
int32 sessionid,
out intptr token);

[dllimport("userenv.dll", setlasterror = true)]
static extern bool createenvironmentblock(
out intptr lpenvironment,
intptr htoken,
bool binherit);

在createprocess 函数中同时也涉及到duplicatetokenex、wtsqueryusertoken、createenvironmentblock 函数的使用,有兴趣的朋友可通过msdn 进行学习。完成createprocess 函数创建后,就可以真正的通过它来调用应用程序了,回到service1.cs 修改一下onstart 我们来打开一个cmd 窗口。如下代码:
复制代码 代码如下:

protected override void onstart(string[] args)
{
interop.createprocess("cmd.exe",@"c:\windows\system32\");
}

重新编译程序,启动alertservice 服务便可看到下图界面。至此,我们已经可以通过一些简单的方法对session 0 隔离问题进行解决。大家也可以通过wcf 等技术完成一些更复杂的跨session 通信方式,实现在windows 7 及vista 系统中服务与桌面用户的交互操作。

asp.net中穿透Session 0 隔离(二)

参考资料

1. wtssendmessage function
http://msdn.microsoft.com/en-us/library/aa383842(vs.85).aspx

2. createprocessasuser function
http://msdn.microsoft.com/en-us/library/ms682429(v=vs.85).aspx

3. wtssendmessage (wtsapi32)
http://www.pinvoke.net/default.aspx/wtsapi32/wtssendmessage.html

4. wtsqueryusertoken function
http://msdn.microsoft.com/en-us/library/aa383840(vs.85).aspx

5.

代码下载 alertservice2_jb51.rar

作者:李敬然(gnie)
出处:{gnietech} (http://www.cnblogs.com/gnielee/)