1

I wrote a routine that allows me to make windows system calls from an application, trap the response into a buffer so the content of the buffer can be used in my application. Every command I've tried, until today, has worked without a flaw, including those with very large response buffers. The basic steps are as follows:

1) start a child cmd prompt process from application
2) write a command to it's stdin, eg:
3) "cmd.exe /c dir"  (returns listing of applications host directory)
4) capture response from stdout

for most commands, making the call and getting the response is normally as simple as:

int main(void)
{
    char *buf = {0};
    buf = calloc(100, 1);
    if(!buf)return 0;
    cmd_rsp("dir /s", &buf, 100);//cmd_rsp is fully defined in the links I provided in post.
                                 //Note: all commands are prepended with 
                                 //'cmd.exe /c ' inside the cmd_rsp function.
    printf("%s", buf);
    free(buf);

    return 0;
}

But when I send the command powershell start-sleep -m 2000, nothing is ever sent to stdout, causing application to hang.

Execution flow stops at the ReadFile function, trying to catch at least one byte of data out through the stdout pipe. ( refer to code here )

I have read (and tried the suggestions in) this link about this topic, but still have not seen results using the & to concatenate the calls. i.e., the & does work with combination calls such as:

cmd.exe /c cd c:\\devphys\\msvc\\ && dir

Just not when powershell is called.

I am hoping someone familiar with this scenario can suggest a different calling convention when using such things as powershell in the command line, Or, suggest a way to break out of ReadFile (called from within the function ReadFromPipe ) when it is clear nothing is coming to stdout.

EDIT: in the code for cmd_rsp(...) , some may have noticed that inside the function ReadFromPipe, I made an attempt at a timeout using:

//Set timeouts for stream
ct.ReadIntervalTimeout = 0;
ct.ReadTotalTimeoutMultiplier = 0;
ct.ReadTotalTimeoutConstant = 10;
ct.WriteTotalTimeoutConstant = 0;
ct.WriteTotalTimeoutMultiplier = 0;
SetCommTimeouts(g_hChildStd_OUT_Rd, &ct);

However, as detailed here and here (see comment under post). this method, as a timeout, is not compatible with an implementation using ReadFile and pipes.

ryyker
  • 22,849
  • 3
  • 43
  • 87
  • You're missing a space between `-m` and `2000` in the PowerShell command. – Bill_Stewart Oct 25 '17 at 22:21
  • Also - what PowerShell command are you using that writes to stdout that doesn't work? (`Start-Sleep -m 2000` doesn't write anything to stdout.) – Bill_Stewart Oct 25 '17 at 22:23
  • I would not expect the command `start-sleep -m 2000` to output anything to std out (note the fixed typo). try `powershell write-output "Hello"` – zdan Oct 25 '17 at 22:25
  • Your question was ambiguous on that point. – Bill_Stewart Oct 26 '17 at 00:36
  • Does `cmd /c powershell ...` work? – Bill_Stewart Oct 26 '17 at 00:43
  • @zdan - yes, I think I am discovering this. The reappearance of my command prompt (when calling from a normal desktop `cmd` prompt) i.e. `C:\>`, is just that, a `cmd` shell prompt. My code depends on getting something back from any executable I call, eg. `dir` returns content, `time` returns: `The current time is:...`. But not powershell – ryyker Oct 26 '17 at 12:37
  • @Bill_Stewart - The missing space was a typo in the question, (edited to fix) but yes, the command works on the command line when entered correctly in a `cmd` shell. For your last question, no, it does not work when prepended with `cmd /c` as other commands do. – ryyker Oct 26 '17 at 12:37
  • @Bill_Stewart - regarding your comment: Also - what PowerShell command.... Yes, this is the problem. I am asking if there is a different way to call powershell that would not result in hanging in ReadFile. Or, is there a technique for putting a timeout, or other condition on ReadFile to return after a reasonable time of no output. Also, One command I tried that did return something was `powershell -Version`. It returned a single `M`, which I assume is part of the `Missing argument...` error message – ryyker Oct 26 '17 at 12:51
  • Could the issue be that PowerShell is outputting double-byte unicode instead of single-byte ASCII? – Bill_Stewart Oct 26 '17 at 13:28
  • @Bill_Stewart - I think the problem, as noted in other comments, is that a normal response from powershell, for most commands is _nothing_. This is the essence of my problem. I am trying to find an alternative calling method for `powershell` to force output back to `stdout` so that `ReadFile` is satisfied. Eg. if powershell had an argument such as `-Verbose`, that returned content to `stdout`, the problem would be solved. Or, if a timeout could be asserted onto the `ReadFile` function. – ryyker Oct 26 '17 at 13:33
  • PowerShell _does_ write to stdout. I prove this by opening `cmd.exe` and running the command `powershell -Command Write-Output 'Hello, world' > output.txt`. File `output.txt` contains the expected string. – Bill_Stewart Oct 26 '17 at 13:40
  • @Bill_Stewart - True, but nothing is returned when attempting to use the `start-sleep -m 2000` argument, `powershell` is silent. And there are other arguments that are silent too. I assume also that if these behaviors exist with other utilities, I will run into the same issues with the posted code. I am looking for the workaround to mitigate this behavior in general. – ryyker Oct 26 '17 at 13:49
  • So your actual question is this: How do I prevent this code from hanging when the called process writes nothing to stdout? This doesn't have anything to do with PowerShell specifically. – Bill_Stewart Oct 26 '17 at 14:22
  • @Bill_Stewart - You could summarize it that way. And no, not `powershell` specifically, but it was `powershell` that first exhibited this behavior, and so essentially it provides the best illustration for me to describe what I have seen. My guess is that any utility that exhibits the same behaviour will result in the same problem. So far, most of the executables native to `Windows 7`, that I have used, do not exhibit the same behavior, and so have worked well with the `cmd_rsp()` function. – ryyker Oct 26 '17 at 15:05
  • You can test this by creating a short dummy console executable that writes nothing to stdout and then see if you get the same problem. If so, then you can remove the PowerShell tag from your question. – Bill_Stewart Oct 26 '17 at 15:06
  • @Bill_Stewart - Just tried. When a console application, that returns no output is called from a `cmd` prompt, eg: `c:\apps\bin\DelayMs 1000`, the function returns what was written to `stdout` upon return, which is an identical echo of the command sent: `c:\apps\bin\DelayMs 1000`. So evidently, there is a difference in that `cmd_rsp()` is picking up the zero returned from the C exectuable upon it return to the OS. – ryyker Oct 26 '17 at 15:16

0 Answers0