6

I need to create a new process with redirected standard error stream to some file. The code from which child process is being created has no console available, so there are cases when GetStdHandle(any) will return 0. Child process will try to duplicate all of its standard IO handles for some reason (source code for child process is unavailable) so all of it's handles should be valid.

So I need to run that process in the same manner as it's can be ran from the console with:

someproc <nul >nul 2>err

I see some ways for this: 1. Create two pair of pipes. This is possibly good solution, but it will be too complex for me. 2. Open "nul" file with CreateFile("nul", ...) function call. No file is being created by this call, but this looks weird too me. 3. Use INVALID_HANDLE_VALUE. This works too, but I think there can be different problems with another child processes.

I believe there are better ways.

Ben Voigt
  • 277,958
  • 43
  • 419
  • 720
okutane
  • 13,754
  • 10
  • 59
  • 67

4 Answers4

6

As originally phrased, you have already answered your own question. To open a "nul" file, you simply specify "nul" when you call CreateFile. It only looks weird because hardly anyone ever uses that file name. (I don't see it used nearly as often as I see /dev/null.) It's perfectly valid, though.

But if you've found that Invalid_Handle_Value works, too, then go ahead and use that instead. It's certainly easiest. I wouldn't have expected it to work, initially, since I wouldn't expect it to be duplicable.

Rob Kennedy
  • 161,384
  • 21
  • 275
  • 467
3

Yes, "nul" is doing what you think. If you move to unix, it will be "/dev/null". The funky name is a holdover from DOS days, along with "prn" and "com1", etc.

Mark Harrison
  • 297,451
  • 125
  • 333
  • 465
1

Using INVALID_HANDLE_VALUE with DuplicateHandle is improper: the documentation states that you need PROCESS_DUP_HANDLE access right on the handle. You don't have that righton INVALID_HANDLE_VALUE. Device NUL (symbolic link to /device/null) will work fine, though.

MSalters
  • 173,980
  • 10
  • 155
  • 350
0

This is old, but for reference, this one worked for me:

BOOL CreateAndWait(LPCTSTR file /*command line*/, DWORD* ret /*return value*/, bool printToStdout/*print to current stdout? (or rather to NUL)*/) {
    STARTUPINFO         si;
    PROCESS_INFORMATION pi;
    if(ret)
    { *ret=0xFFFFFFFF; }
    ::ZeroMemory(&si, sizeof(STARTUPINFO));
    si.cb=sizeof(STARTUPINFO);
    si.dwFlags=0;

    if(!printToStdout) {
        SECURITY_ATTRIBUTES secattr;
        secattr.nLength = sizeof secattr;
        secattr.lpSecurityDescriptor = NULL;
        secattr.bInheritHandle = TRUE;
        HANDLE hNULL = CreateFile(_T("NUL"), GENERIC_ALL, 0, &secattr, OPEN_EXISTING, 0, NULL);
        HANDLE hTHIS = GetCurrentProcess();

        if(!SetHandleInformation(hNULL, HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT)) {
            printToStdout = true;
            return FALSE;
        } else {
            si.dwFlags|=STARTF_USESTDHANDLES;

            HANDLE dupIN, dupOUT, dupERR;
            DuplicateHandle(hTHIS, hNULL,
                            hTHIS, &dupIN, 0, TRUE, DUPLICATE_SAME_ACCESS);
            DuplicateHandle(hTHIS, hNULL,
                            hTHIS, &dupOUT, 0, TRUE, DUPLICATE_SAME_ACCESS);
            DuplicateHandle(hTHIS, hNULL,
                            hTHIS, &dupERR, 0, TRUE, DUPLICATE_SAME_ACCESS);
            CloseHandle(hTHIS);
            CloseHandle(hNULL);

            si.hStdOutput = dupOUT;
            si.hStdError = dupERR;
            si.hStdInput = dupIN;
        }
    }


    TCHAR* fstr = new TCHAR[_tcslen(file)+1];
    _tcscpy(fstr, file);

    BOOL rv=TRUE;
    if(::CreateProcess(NULL, fstr, NULL, NULL, printToStdout?FALSE:TRUE, NORMAL_PRIORITY_CLASS, NULL, NULL, &si, &pi)) {
        ::CloseHandle(pi.hThread);
        ::WaitForSingleObject(pi.hProcess, INFINITE);
        DWORD dwCode = STILL_ACTIVE;
        ::GetExitCodeProcess(pi.hProcess, &dwCode);
        if(ret) { *ret = dwCode; }
        ::CloseHandle(pi.hProcess);
    } else
    { rv = FALSE; }
    delete[] fstr;

    if(!printToStdout) {
        ::CloseHandle(si.hStdOutput);
        ::CloseHandle(si.hStdInput);
        ::CloseHandle(si.hStdError);
    }

    return rv;
}
KungPhoo
  • 516
  • 4
  • 18