CreateProcessWithLogonW获取标准输出

时间:2013-02-22 18:36:56

标签: c++ visual-c++

我在Microsoft's documentation site找到了以下评论:

  

此外,CreateProcessWithLogonW拒绝STD句柄(0/1/2),即使用STARTF_USESTDHANDLES时默认返回GetStdHandle()。它返回错误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 [user@domain] [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 [user@domain] [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);
}

#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 [user@domain] [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); }

1 个答案:

答案 0 :(得分:0)

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

Creating a Child Process with Redirected Input and Output