0

Not sure if it's something in my code or how I'm handling launching the process but in the code below, if I turn on the boolean outputToFile TRUE, the program will happily output the standard output from UWFMGR to the out.log file and it is readable and looks as it does when executed from the cmd line.

If I turn that boolean off and try to use the standard output I read from the pipe it is garbage... Something like "U A n yzna...a/". buf, csTemp, and m_csOutput all have the off characters. If I run the same program with other programs like ipconfig, netsh, ect instead of uwfmgr it works perfectly. I have even used this code in the past with ewfmgr and it worked fine. I'm not sure what's different with uwfmgr but it breaks this code. The other odd thing that must be a clue is the WaitForSingleObject works fine with everything but uwfmgr, when I am running uwfmgr that WaitForSingleObject will never return and waits forever.

Another thing to note is the call to uwfmgr works correctly, for example "uwfmgr filter enable" will enable the filter on system reboot even though the std output is unreadable.

Any ideas? Thanks!

String csExecute;
csExecute = "uwfmgr get-config";
bool outputToFile = FALSE;

SECURITY_ATTRIBUTES secattr;
ZeroMemory(&secattr, sizeof(secattr));
secattr.nLength = sizeof(secattr);
secattr.bInheritHandle = TRUE;
secattr.lpSecurityDescriptor = NULL;

HANDLE rPipe = NULL;
HANDLE wPipe = NULL;

//For test use....File works and captures output correctly
HANDLE h = CreateFile(_T("out.log"),
    FILE_APPEND_DATA,
    FILE_SHARE_WRITE | FILE_SHARE_READ,
    &secattr,
    OPEN_ALWAYS,
    FILE_ATTRIBUTE_NORMAL,
    NULL );

// Create pipes to write and read data
//if(outputToFile)
//{
//   CreatePipe(&rPipe, &h, &secattr, 0);
//}else
//{
   CreatePipe(&rPipe, &wPipe, &secattr, 0);
//}

STARTUPINFOW sInfo;
PROCESS_INFORMATION pInfo;

ZeroMemory(&sInfo, sizeof(STARTUPINFOW));
ZeroMemory(&pInfo, sizeof(PROCESS_INFORMATION));

sInfo.cb = sizeof(STARTUPINFOW);


sInfo.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
sInfo.wShowWindow = SW_HIDE;
sInfo.hStdInput = NULL;

if(outputToFile)
{
   sInfo.hStdOutput = h;
   sInfo.hStdError = h;
}else
{
   sInfo.hStdOutput = wPipe;
   sInfo.hStdError = wPipe;
}

char command[1024];

wcstombs(command, csExecute.c_str(), sizeof(command));
ShowMessage(csExecute);

CreateProcessWithLogonW(L"username", L"PCDOMAIN", L"password",
    LOGON_NETCREDENTIALS_ONLY, NULL, csExecute.w_str(),
    NORMAL_PRIORITY_CLASS | CREATE_NO_WINDOW, NULL, NULL,
    &sInfo, &pInfo);

//Never returns with UWFMGR, works fine on other processes like ipconfig, netsh, ect
//WaitForSingleObject(pInfo.hThread, Infinite);


if(outputToFile)
{
   CloseHandle(h);
}else
{
   CloseHandle(wPipe);
}

//returns 0 and works fine (actual call to uwfmgr succeeded, for example uwfmgr filter enable turns the filter on even though the output is garbage unless outputted to a file
ShowMessage(GetLastError());

// now read the output pipe here.
#define BUFSIZE 100
BOOL res = FALSE;
String m_csOutput = "";

for(;;)
{
    char buf[BUFSIZE+1] = "";
    DWORD reDword;

    if(!::ReadFile(rPipe, buf, BUFSIZE, &reDword, 0))
    {
        DWORD error = ::GetLastError();
        ShowMessage("Error #....");
        ShowMessage(error);
        break;
    }
    if(reDword == 0)
    {
        break;
    }
    buf[reDword] = '\0';
    ShowMessage(buf);
    String csTemp = buf;
    ShowMessage(csTemp);
    m_csOutput += csTemp;//.SubString(1, reDword);
    ShowMessage(m_csOutput);
}
martinarcher
  • 137
  • 2
  • 9
  • You are fooling yourself somehow, probably looking at the stale contents in the file written by some prior attempts. In the code shown, the value of `outputToFile` makes absolutely no difference. `CreatePipe(&rPipe, &h, &secattr, 0);` does not redirect the pipe to the file - it just creates a pipe and stores its handle in `h`, overwriting the file handle. Then there's no difference between `h` with the flag set to `TRUE`, and `wPipe` with the flag set to `FALSE`. – Igor Tandetnik Apr 18 '20 at 16:10
  • Sorry, that was a failed attempt to direct the file to a pipe, I edited and commented out the first if statement you were looking at. The other two remaining uses of the boolean outputToFile work fine. I delete the file before running the program and when it is set to true, it creates the file and has proper output in it. If the boolean is false, the output from my pipe is garbage. Thanks for the help and sorry for the confusion. – martinarcher Apr 18 '20 at 16:23
  • 1
    I wonder if it outputs wide text (UTF-16) to the standard stream. In this case, every other byte tends to be zero, and your `ShowMessage` probably only shows the first character of each buffer-ful. Whereas the text editor you use to view the output file detects the encoding and renders the correct text. Examine the file in a hex editor. – Igor Tandetnik Apr 18 '20 at 16:32
  • 1
    FYI, `CREATE_NO_WINDOW` is ignored by `CreateProcessWithLogonW` because it implicitly uses `CREATE_NEW_CONSOLE`. When waiting, it would almost always be on the process object, `pInfo.hProcess`; waiting for the initial thread to exit is unreliable. Also, never wait on an active process in your reader thread while the program is writing to a pipe. The default buffer size for the pipe in the kernel is 4 KiB, and if it fills, you cause a deadlock. Also, setting a `BUFSIZE` constant and allocating `BUFSIZE+1` is confusing. Instead you should read up to `BUFSIZE - 1` bytes. – Eryk Sun Apr 18 '20 at 16:42
  • Thanks guys. I'll take a look at the file in an editor. – martinarcher Apr 18 '20 at 16:55
  • The file is over 4K so it sounds like that is exactly why I'm seeing the deadloack. Thanks for that info - I wasn't aware of that. – martinarcher Apr 18 '20 at 16:55
  • Igor was right on the money. Every other byte in the file is zero which is why the ShowMessage and other String tools think it's a single character output, therefore only showing the first character of the 100 character buffer. Thanks Microsoft. – martinarcher Apr 18 '20 at 17:01
  • You guys know any tools/functions to change the UTF-16 output to a standard stream? – martinarcher Apr 18 '20 at 17:02
  • I put a little loop together to remove the zeros from the even indexes in the char buf and it works like a champ. I'm sure there's better tools ways to test of it is UTF-16 and remove them. I'd love to hear suggestions but my method works for now. Thanks Igor....much appreciated for steering me in the right direction. – martinarcher Apr 18 '20 at 17:37
  • Your code already uses a function that does that: `wcstombs` or WINAPI `WideCharToMultiByte`. But really, if you have a wide-character string, which is the native string format of Windows, then you should pass it to a version of `ShowMessage` (wherever that's from) that accepts a wide-character string. – Eryk Sun Apr 18 '20 at 17:42

0 Answers0