Note that there are some explanatory texts on larger screens.

plurals
  1. POCreateProcessWithLogonW get standard output
    primarykey
    data
    text
    <p>I found the below comment on <a href="http://msdn.microsoft.com/en-us/library/windows/desktop/ms682431%28v=vs.85%29.aspx" rel="nofollow noreferrer">Microsoft's documentation site</a>:</p> <blockquote> <p>Also, CreateProcessWithLogonW rejects STD handles (0/1/2) i.e. what GetStdHandle() returns by default, when using STARTF_USESTDHANDLES. It returns error 6, invalid handles, because 0/1/2 are not "real" handles. The only way we found to redirect the console input/output was to create custom handles (pipes) and use those instead (e.g. even just as dummy handles that you don't use). This is missing functionality from CreateProcessWithLogonW, because CreateProcess (and maybe CreateProcessAsUser, I didn't verify that) accepts STD handles.</p> </blockquote> <p>This points to creating custom pipes.</p> <p>I found <a href="https://stackoverflow.com/questions/1973376/how-to-get-standard-output-from-createprocesswithlogonw">this StackOverflow answer</a> which points to using things such as <code>"SafeFileHandle"</code>. This is apparently C++/CLI which I am not familiar with how to use. I am using Visual C++ and therefore "native" C++?</p> <p>I am looking for a simple solution of how to fix this issue. I am a newbie in C++ and the CLI thing confused me because I simply don't know how to use it, or make Visual C++ compatible with it.</p> <p>Given my normal C++ and my question, HOW EXACTLY would I create the custom pipe which will allow me to get the standard output?</p> <p>Here is my code:</p> <pre><code>#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)&amp;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( &amp;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, &amp;hToken)) DisplayError(L"LogonUser"); if (!CreateEnvironmentBlock(&amp;lpvEnv, hToken, TRUE)) DisplayError(L"CreateEnvironmentBlock"); dwSize = sizeof(szUserProfile)/sizeof(WCHAR); if (!GetUserProfileDirectory(hToken, szUserProfile, &amp;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, &amp;si, &amp;pi)) DisplayError(L"CreateProcessWithLogonW"); if (!DestroyEnvironmentBlock(lpvEnv)) DisplayError(L"DestroyEnvironmentBlock"); CloseHandle(hToken); CloseHandle(pi.hProcess); CloseHandle(pi.hThread); } </code></pre> <p>I tried this and I am getting no output on the console window. As I said, I checked the answer on StackOverflow and this whole C++/CLI thing confuses me. If someone knows a simple solution to redirecting the output using a custom pipe using Visual C++, let me know.</p> <p>And if I did anything wrong above, let me know as well.</p> <p>EDIT:</p> <p>After following the suggestions given by Remy's answer. I came up with the following code, which yields an error code 3: The system cannot find the path specified.</p> <p><code></p> <pre><code>#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)&amp;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(&amp;g_hChildStd_OUT_Rd, &amp;g_hChildStd_OUT_Wr, &amp;saAttr, 0) ) ErrorExit(TEXT("StdoutRd CreatePipe")); if ( ! SetHandleInformation(g_hChildStd_OUT_Rd, HANDLE_FLAG_INHERIT, 0) ) ErrorExit(TEXT("Stdout SetHandleInformation")); if (! CreatePipe(&amp;g_hChildStd_IN_Rd, &amp;g_hChildStd_IN_Wr, &amp;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( &amp;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, &amp;hToken)) DisplayError(L"LogonUser"); if (!CreateEnvironmentBlock(&amp;lpvEnv, hToken, TRUE)) DisplayError(L"CreateEnvironmentBlock"); dwSize = sizeof(szUserProfile)/sizeof(WCHAR); if (!GetUserProfileDirectory(hToken, szUserProfile, &amp;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, &amp;si, &amp;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-&gt;Contents of %s written to child STDIN pipe.\n", argv[1]); printf( "\n-&gt;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, &amp;dwRead, NULL); if ( ! bSuccess || dwRead == 0 ) break; bSuccess = WriteFile(g_hChildStd_IN_Wr, chBuf, dwRead, &amp;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, &amp;dwRead, NULL); if( ! bSuccess || dwRead == 0 ) break; bSuccess = WriteFile(hParentStdOut, chBuf, dwRead, &amp;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) &amp;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); } </code></pre> <p></code></p>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload