asp.net 에서 세 션 0 격 리 관통(2)

간단 한 상호작용 에 대해 서 비 스 는 WTSSendMessage 함 수 를 통 해 사용자 Session 에 메시지 창 을 표시 할 수 있 습 니 다.일부 복잡 한 UI 상호작용 에 대해 서 는 CreateProcessAsUser 나 다른 방법(WCF,.NET 원 격 처리 등)을 호출 하여 세 션 간 통신 을 하고 데스크 톱 사용자 에 게 응용 프로그램 인터페이스 를 만들어 야 합 니 다.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);
ShowMessage Box 함수 에서 WTSSendMessage 를 호출 하여 정보 창 을 보 냅 니 다.그러면 우 리 는 Service 의 OnStart 함수 에서 사용 할 수 있 습 니 다.Service1.cs 를 열 고 다음 코드 를 추가 합 니 다.4.567913.컴 파일 러 를 사용 한 후 서비스 관리자 에서 AlertService 서 비 스 를 다시 시작 합 니 다.다음 그림 에서 메시지 창 은 현재 사용자 데스크 톱 에 표 시 됩 니 다.Session 0 이 아 닙 니 다.
CreateProcessAsUser 함수
     서 비 스 를 통 해 데스크 톱 사용자 Session 에 복잡 한 UI 프로그램 인 터 페 이 스 를 만 들 려 면 CreateProcessAsUser 함 수 를 사용 하여 프로그램 을 실행 할 새 프로 세 스 를 만들어 야 합 니 다.Interop 클래스 를 열 고 다음 코드 를 계속 추가 합 니 다
 
protected override void OnStart(string[] args)
{
Interop.ShowMessageBox("This a message from AlertService.", "AlertService Message");
}
Create Process 함수 에서 Duplicate TokenEx,WTSQuery UserToken,Create Environment Block 함수 의 사용 과 관련 되 며 관심 이 있 는 친 구 는 MSDN 을 통 해 배 울 수 있 습 니 다.CreateProcess 함수 생 성 을 완료 하면 프로그램 을 호출 할 수 있 습 니 다.Service1.cs 로 돌아 가서 OnStart 를 수정 하고 CMD 창 을 엽 니 다.다음 코드:
 
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);
재 컴 파일 러,AlertService 서 비 스 를 시작 하면 다음 화면 을 볼 수 있 습 니 다.이로써 우 리 는 세 션 0 격 리 문 제 를 간단 한 방법 으로 해결 할 수 있 게 됐다.여러분 도 WCF 등 기술 을 통 해 더욱 복잡 한 세 션 간 통신 방식 을 완성 하여 Windows 7 및 Vista 시스템 에서 서비스 와 데스크 톱 사용자 의 상호작용 을 실현 할 수 있 습 니 다.

참고 자료 1.WTSSendMessage Functionhttp://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. http://www.pinvoke.net/
작성 자:이경 연(Gnie)출처:{GnieTech}(http://www.cnblogs.com/gnielee/)

좋은 웹페이지 즐겨찾기