2013-02-22 123 views
0

我发现下面的评论Microsoft's documentation siteCreateProcessWithLogonW得到标准输出

此外,CreateProcessWithLogonW拒绝STD手柄(0/1/2)即什么GetStdHandle()默认返回,用时STARTF_USESTDHANDLES。它返回错误6,无效句柄,因为0/1/2不是“真正的”句柄。我们发现重定向控制台输入的唯一途径/输出是创建自定义手柄(管道),并使用这些替代(例如,甚至就像你不使用虚拟手柄)。这是失踪CreateProcessWithLogonW功能,因为CreateProcess的(也许CreateProcessAsUser,我没有验证)接受STD处理。

这指向创建自定义管道。

我发现this StackOverflow answer指向使用的东西,如"SafeFileHandle"。这显然是C++/CLI,我不熟悉如何使用。我正在使用Visual C++,因此“本机”C++?

我寻找的是如何解决这个问题的简单解决方案。我是C++的新手,CLI让我感到困惑,因为我不知道如何使用它,或使Visual C++与它兼容。

考虑到我正常的C++和我的问题,我究竟会创建自定义的管道,将让我得到标准的输出?

这里是我的代码:

#include "stdafx.h" 

void DisplayError(LPWSTR pszAPI) 
{ 
    LPVOID lpvMessageBuffer; 

    FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | 
     FORMAT_MESSAGE_FROM_SYSTEM, 
     NULL, GetLastError(), 
     MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), 
     (LPWSTR)&lpvMessageBuffer, 0, NULL); 

    // 
    //... now display this string 
    // 
    wprintf(L"ERROR: API  = %s.\n", pszAPI); 
    wprintf(L"  error code = %d.\n", GetLastError()); 
    wprintf(L"  message = %s.\n", (LPWSTR)lpvMessageBuffer); 

    // 
    // Free the buffer allocated by the system 
    // 
    LocalFree(lpvMessageBuffer); 

    ExitProcess(GetLastError()); 
} 

void _tmain(int argc, WCHAR *argv[]) 
{ 
    STARTUPINFO si; 
    ZeroMemory(&si, sizeof(STARTUPINFO)); 
    si.cb = sizeof(STARTUPINFO); 

    HANDLE pipe1 = CreateNamedPipe(L"\\\\.\\pipe\\pipe1", PIPE_ACCESS_DUPLEX, 
       PIPE_WAIT, 1024, 1024, 1024, 60, NULL); 
    HANDLE pipe2 = CreateNamedPipe(L"\\\\.\\pipe\\pipe2", PIPE_ACCESS_DUPLEX, 
       PIPE_WAIT, 1024, 1024, 1024, 60, NULL); 
    si.dwFlags |= STARTF_USESHOWWINDOW; 
    si.dwFlags = STARTF_USESTDHANDLES; 
    si.hStdOutput = pipe1; 
    si.hStdError = pipe2; 

    DWORD  dwSize; 
    HANDLE hToken; 
    LPVOID lpvEnv; 
    PROCESS_INFORMATION pi = {0}; 
    WCHAR    szUserProfile[256] = L""; 

    si.cb = sizeof(STARTUPINFO); 

    if (argc != 4) 
    { 
     wprintf(L"Usage: %s [[email protected]] [password] [cmd]", argv[0]); 
     wprintf(L"\n\n"); 
     return; 
    } 

    // 
    // TO DO: change NULL to '.' to use local account database 
    // 
    if (!LogonUser(argv[1], NULL, argv[2], LOGON32_LOGON_INTERACTIVE, 
      LOGON32_PROVIDER_DEFAULT, &hToken)) 
     DisplayError(L"LogonUser"); 

    if (!CreateEnvironmentBlock(&lpvEnv, hToken, TRUE)) 
     DisplayError(L"CreateEnvironmentBlock"); 

    dwSize = sizeof(szUserProfile)/sizeof(WCHAR); 

    if (!GetUserProfileDirectory(hToken, szUserProfile, &dwSize)) 
     DisplayError(L"GetUserProfileDirectory"); 

    // 
    // TO DO: change NULL to '.' to use local account database 
    // 
    if (!CreateProcessWithLogonW(argv[1], NULL, argv[2], 
      LOGON_WITH_PROFILE, NULL, argv[3], 
      CREATE_UNICODE_ENVIRONMENT, lpvEnv, szUserProfile, 
      &si, &pi)) 
     DisplayError(L"CreateProcessWithLogonW"); 

    if (!DestroyEnvironmentBlock(lpvEnv)) 
     DisplayError(L"DestroyEnvironmentBlock"); 

    CloseHandle(hToken); 
    CloseHandle(pi.hProcess); 
    CloseHandle(pi.hThread); 
} 

我尝试这样做,我得到的控制台窗口无输出。正如我所说的,我检查了StackOverflow上的答案,而这整个C++/CLI的事情让我感到困惑。如果有人知道使用Visual C++使用自定义管道重定向输出的简单解决方案,请告诉我。

如果我在上面做了任何错误,请让我知道。

编辑:

在按照雷米的答案给出的建议后。我想出了下面的代码,它产生了一个错误代码3:系统找不到指定的路径。

#include "stdafx.h" 


HANDLE g_hChildStd_IN_Rd = NULL; 
HANDLE g_hChildStd_IN_Wr = NULL; 
HANDLE g_hChildStd_OUT_Rd = NULL; 
HANDLE g_hChildStd_OUT_Wr = NULL; 

HANDLE g_hInputFile = NULL; 


int BUFSIZE = 1064; 
void CreateChildProcess(void); 
void WriteToPipe(void); 
void ReadFromPipe(void); 
void ErrorExit(PTSTR); 

void DisplayError(LPWSTR pszAPI) 
{ 
    LPVOID lpvMessageBuffer; 

    FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | 
     FORMAT_MESSAGE_FROM_SYSTEM, 
     NULL, GetLastError(), 
     MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), 
     (LPWSTR)&lpvMessageBuffer, 0, NULL); 

    // 
    //... now display this string 
    // 
    wprintf(L"ERROR: API  = %s.\n", pszAPI); 
    wprintf(L"  error code = %d.\n", GetLastError()); 
    wprintf(L"  message = %s.\n", (LPWSTR)lpvMessageBuffer); 

    // 
    // Free the buffer allocated by the system 
    // 
    LocalFree(lpvMessageBuffer); 

    ExitProcess(GetLastError()); 
} 





void _tmain(int argc, WCHAR *argv[]) 
{ 

SECURITY_ATTRIBUTES saAttr; 
    saAttr.nLength = sizeof(SECURITY_ATTRIBUTES); 
    saAttr.bInheritHandle = TRUE; 
    saAttr.lpSecurityDescriptor = NULL; 

    if (! CreatePipe(&g_hChildStd_OUT_Rd, &g_hChildStd_OUT_Wr, &saAttr, 0)) 
     ErrorExit(TEXT("StdoutRd CreatePipe")); 

    if (! SetHandleInformation(g_hChildStd_OUT_Rd, HANDLE_FLAG_INHERIT, 0)) 
     ErrorExit(TEXT("Stdout SetHandleInformation")); 

    if (! CreatePipe(&g_hChildStd_IN_Rd, &g_hChildStd_IN_Wr, &saAttr, 0)) 
     ErrorExit(TEXT("Stdin CreatePipe")); 

    if (! SetHandleInformation(g_hChildStd_IN_Wr, HANDLE_FLAG_INHERIT, 0)) 
     ErrorExit(TEXT("Stdin SetHandleInformation")); 

    /////////////////////////////Start CreateChildProcess//////// 



    STARTUPINFO si; 
    ZeroMemory(&si, sizeof(STARTUPINFO)); 
    si.cb = sizeof(STARTUPINFO); 

    si.dwFlags |= STARTF_USESHOWWINDOW; 
    si.dwFlags |= STARTF_USESTDHANDLES; 
    si.hStdError = g_hChildStd_OUT_Wr; 
    si.hStdOutput = g_hChildStd_OUT_Wr; 
    si.hStdInput = g_hChildStd_IN_Rd; 

    DWORD  dwSize; 
    HANDLE hToken; 
    LPVOID lpvEnv; 
    PROCESS_INFORMATION pi = {0}; 
    WCHAR    szUserProfile[256] = L""; 

    si.cb = sizeof(STARTUPINFO); 

    if (argc != 4) 
    { 
     wprintf(L"Usage: %s [[email protected]] [password] [cmd]", argv[0]); 
     wprintf(L"\n\n"); 
     return; 
    } 

    // 
    // TO DO: change NULL to '.' to use local account database 
    // 
    if (!LogonUser(argv[1], NULL, argv[2], LOGON32_LOGON_INTERACTIVE, 
      LOGON32_PROVIDER_DEFAULT, &hToken)) 
     DisplayError(L"LogonUser"); 

    if (!CreateEnvironmentBlock(&lpvEnv, hToken, TRUE)) 
     DisplayError(L"CreateEnvironmentBlock"); 

    dwSize = sizeof(szUserProfile)/sizeof(WCHAR); 

    if (!GetUserProfileDirectory(hToken, szUserProfile, &dwSize)) 
     DisplayError(L"GetUserProfileDirectory"); 

    // 
    // TO DO: change NULL to '.' to use local account database 
    // 
    if (!CreateProcessWithLogonW(argv[1], NULL, argv[2], 
      LOGON_WITH_PROFILE, NULL, argv[3], 
      CREATE_UNICODE_ENVIRONMENT, lpvEnv, szUserProfile, 
      &si, &pi)) 
     DisplayError(L"CreateProcessWithLogonW"); 

    if (!DestroyEnvironmentBlock(lpvEnv)) 
     DisplayError(L"DestroyEnvironmentBlock"); 

    CloseHandle(hToken); 
    CloseHandle(pi.hProcess); 
    CloseHandle(pi.hThread); 



    /////////////////////////////End CreateChildProcess/////////// 

    if (argc == 1) 
     ErrorExit(TEXT("Please specify an input file.\n")); 

    g_hInputFile = CreateFile(
     argv[3], 
     GENERIC_READ, 
     0, 
     NULL, 
     OPEN_EXISTING, 
     FILE_ATTRIBUTE_READONLY, 
     NULL); 

    if (g_hInputFile == INVALID_HANDLE_VALUE) 
     ErrorExit(TEXT("CreateFile")); 

    WriteToPipe(); 
    printf("\n->Contents of %s written to child STDIN pipe.\n", argv[1]); 


     printf("\n->Contents of child process STDOUT:\n\n", argv[1]); 
    ReadFromPipe(); 

} 

void WriteToPipe(void) 

// Read from a file and write its contents to the pipe for the child's STDIN. 
// Stop when there is no more data. 
{ 
    DWORD dwRead, dwWritten; 
    CHAR chBuf[4096]; 
    BOOL bSuccess = FALSE; 

    for (;;) 
    { 
     bSuccess = ReadFile(g_hInputFile, chBuf, BUFSIZE, &dwRead, NULL); 
     if (! bSuccess || dwRead == 0) break; 

     bSuccess = WriteFile(g_hChildStd_IN_Wr, chBuf, dwRead, &dwWritten, NULL); 
     if (! bSuccess) break; 
    } 

// Close the pipe handle so the child process stops reading. 

    if (! CloseHandle(g_hChildStd_IN_Wr)) 
     ErrorExit(TEXT("StdInWr CloseHandle")); 
} 

void ReadFromPipe(void) 

// Read output from the child process's pipe for STDOUT 
// and write to the parent process's pipe for STDOUT. 
// Stop when there is no more data. 
{ 
    DWORD dwRead, dwWritten; 
    CHAR chBuf[4096]; 
    BOOL bSuccess = FALSE; 
    HANDLE hParentStdOut = GetStdHandle(STD_OUTPUT_HANDLE); 

    for (;;) 
    { 
     bSuccess = ReadFile(g_hChildStd_OUT_Rd, chBuf, BUFSIZE, &dwRead, NULL); 
     if(! bSuccess || dwRead == 0) break; 

     bSuccess = WriteFile(hParentStdOut, chBuf, 
          dwRead, &dwWritten, NULL); 
     if (! bSuccess) break; 
    } 
} 

void ErrorExit(PTSTR lpszFunction) 

// Format a readable error message, display a message box, 
// and exit from the application. 
{ 
    LPVOID lpMsgBuf; 
    LPVOID lpDisplayBuf; 
    DWORD dw = GetLastError(); 

    FormatMessage(
     FORMAT_MESSAGE_ALLOCATE_BUFFER | 
     FORMAT_MESSAGE_FROM_SYSTEM | 
     FORMAT_MESSAGE_IGNORE_INSERTS, 
     NULL, 
     dw, 
     MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), 
     (LPTSTR) &lpMsgBuf, 
     0, NULL); 

    lpDisplayBuf = (LPVOID)LocalAlloc(LMEM_ZEROINIT, 
     (lstrlen((LPCTSTR)lpMsgBuf)+lstrlen((LPCTSTR)lpszFunction)+40)*sizeof(TCHAR)); 
    StringCchPrintf((LPTSTR)lpDisplayBuf, 
     LocalSize(lpDisplayBuf)/sizeof(TCHAR), 
     TEXT("%s failed with error %d: %s"), 
     lpszFunction, dw, lpMsgBuf); 
    MessageBox(NULL, (LPCTSTR)lpDisplayBuf, TEXT("Error"), MB_OK); 

    LocalFree(lpMsgBuf); 
    LocalFree(lpDisplayBuf); 
    ExitProcess(1); 
} 

回答

0

使用通过CreatePipe()匿名管道,而不是通过CreateNamedPipe()命名管道。请参阅MSDN中的示例:

Creating a Child Process with Redirected Input and Output

+0

我得到一个“的CreateFile失败,错误代码2:系统找不到指定的文件”时,我用你给我的例子运行它。这似乎是在正确的轨道上。你有什么想法,为什么它会给我这样一个错误?或者如何解决它? – ThePrince 2013-02-22 23:11:01

+0

我的CreateFile线是这样的:g_hInputFile =的CreateFile( 的argv [1], GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_READONLY, NULL); – ThePrince 2013-02-22 23:12:50

+0

'argv [1]'是你的应用的'user @ domain'命令行参数。改用'argv [3]'。 – 2013-02-22 23:55:55