我读了很多关于这个话题的内容,但我无法理解。我有一个SSCCE,其服务使用CreateProcessAsUser创建子进程。此子进程仅用于从其标准输入读取;父进程写的是什么,但是我从父母那里得不到任何东西。
家长服务代码:
public static unsafe int WriteToHandle(byte[] buffer, int index, int count, IntPtr hStdOut)
{
int n = 0;
bool cont = true;
fixed (byte* p = buffer)
{
cont = WriteFile(hStdOut, p + index, count, &n, 0);
}
return n;
}
public static bool StartProcessAsCurrentUser()
{
var hUserToken = IntPtr.Zero;
var sInfo = new STARTUPINFO();
var procInfo = new PROCESS_INFORMATION();
var pEnv = IntPtr.Zero;
int iResultOfCreateProcessAsUser;
string cmdLine = "ClientFormApp.exe";
sInfo.cb = Marshal.SizeOf(typeof(STARTUPINFO));
byte[] buffer = new byte[BUFSIZE];
bool result = false;
const int STARTF_USESTDHANDLES = 0x00000100;
const int STARTF_USESHOWWINDOW = 0x00000001;
const int WAIT_TIMEOUT = 0x102;
const int ERROR_SUCCESS = 0x0;
const int HANDLE_FLAG_INHERIT = 1;
try
{
var tSecurity = new SECURITY_ATTRIBUTES();
tSecurity.nLength = Marshal.SizeOf(tSecurity);
var pSecurity = new SECURITY_ATTRIBUTES();
pSecurity.nLength = Marshal.SizeOf(pSecurity);
pSecurity.bInheritHandle = true;
IntPtr pointer = Marshal.AllocHGlobal(Marshal.SizeOf(pSecurity));
Marshal.StructureToPtr(pSecurity, pointer, true);
if (!CreatePipe(out hReadOut, out hWriteOut, pointer, 0)) // hReadOut -> read data from output | hWriteOut -> send data to output
return result = false;
if (!CreatePipe(out hReadIn, out hWriteIn, pointer, 0)) // hReadOut -> read data from output | hWriteOut -> send data to output
return result = false;
if (!SetHandleInformation(hWriteOut, HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT))
return result = false;
if (!SetHandleInformation(hReadOut, HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT))
return result = false;
if (!SetHandleInformation(hWriteIn, HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT))
return result = false;
if (!SetHandleInformation(hReadIn, HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT))
return result = false;
sInfo.hStdOutput = hWriteOut;
sInfo.hStdInput = hReadIn;
sInfo.hStdError = hWriteOut;
if (!GetSessionUserToken(ref hUserToken))
{
throw new Exception("StartProcessAsCurrentUser: GetSessionUserToken failed.");
}
uint dwCreationFlags = CREATE_UNICODE_ENVIRONMENT | (uint)CREATE_NEW_CONSOLE;
sInfo.wShowWindow = (short)SW.SW_SHOW;
sInfo.lpDesktop = "winsta0\\default";
if (!CreateEnvironmentBlock(ref pEnv, hUserToken, false))
{
throw new Exception("StartProcessAsCurrentUser: CreateEnvironmentBlock failed.");
}
if (!CreateProcessAsUser(hUserToken,
null, // Application Name
cmdLine, // Command Line
IntPtr.Zero,
IntPtr.Zero,
true,
dwCreationFlags,
pEnv,
null, // Working directory
ref sInfo,
out procInfo))
{
throw new Exception("StartProcessAsCurrentUser: CreateProcessAsUser failed.\n");
}
iResultOfCreateProcessAsUser = Marshal.GetLastWin32Error();
string message = "Message";
byte[] messageByte = System.Text.Encoding.Unicode.GetBytes(message);
int bytesWrited = WriteToHandle(messageByte, 0, messageByte.Length, hWriteIn);
}
finally
{
//Clossing handles
}
return true;
}
}
我已经验证bytesWrited不是0.
关注this example,这是我的子流程:
public static unsafe int ReadFromHandle(byte[] buffer, int index, int count, IntPtr hStdOut)
{
int n = 0;
try
{
fixed (byte* p = buffer)
{
if (!ReadFile(hStdOut, p + index, count, &n, 0)) //Nothing to read from handle
return 0;
}
return n;
}
catch (Exception e)
{
return 0;
}
}
private void OnNewStep()
{
byte[] buffer = new byte[BUFSIZE];
const int STD_OUTPUT_HANDLE = -11;
const int STD_INPUT_HANDLE = -10;
const int STD_ERROR_HANDLE = -12;
string content = "";
hStdin = GetStdHandle(STD_INPUT_HANDLE);
do
{
bytesReadOutput = ReadFromHandle(buffer, 0, buffer.Length, hStdin);
content = content + System.Text.Encoding.Unicode.GetString(buffer, 0, bytesReadOutput);
}
}
但bytesReadOutput
始终为0.我并不真正理解第hStdin = GetStdHandle(STD_INPUT_HANDLE)
行的目的。如果我没有错,当我在服务流程中创建子流程时,我在子流程中设置重定向的标准输入sInfo.hStdInput = hReadIn;
和hStdin = GetStdHandle(STD_INPUT_HANDLE)
会得到{{1}服务句柄。但是我检查了它,hReadIn
总是0。
我做错了什么?提前谢谢。