Solved:
Workable solution: sbi's answer
Explanation for what really happens: Hans's answer
Explanation for why OpenFile doesn't pass through "DELETE PENDING": Benjamin's answer
The Problem:
Our software is in large part an interpreter engine for a proprietary scripting language. That scripting language has the ability to create a file, process it, and then delete the file. These are all separate operations, and no file handles are kept open in between these operations.
(I.e. during the file creation, a handle is created, used for writing, then closed. During the file processing portion, a separate file handle opens the file, reads from it, and is closed at EOF. And finally, delete uses ::DeleteFile which only has use of a filename, not a file handle at all).
Recently we've come to realize that a particular macro (script) fails sometimes to be able to create the file at some random subsequent time (i.e. it succeeds during the first hundred iterations of "create, process, delete", but when it comes back to creating it a hundred and first time, Windows replies "Access Denied").
Looking deeper into the issue, I have written a very simple program that loops over something like this:
while (true) {
HANDLE hFile = CreateFileA(pszFilename, FILE_ALL_ACCESS, FILE_SHARE_READ,
NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL);
if (hFile == INVALID_HANDLE_VALUE)
return OpenFailed;
const DWORD dwWrite = strlen(pszFilename);
DWORD dwWritten;
if (!WriteFile(hFile, pszFilename, dwWrite, &dwWritten, NULL) || dwWritten != dwWrite)
return WriteFailed;
if (!CloseHandle(hFile))
return CloseFailed;
if (!DeleteFileA(pszFilename))
return DeleteFailed;
}
As you can see, this is direct to the Win32 API and is pretty darn simple. I create a file, write to it, close the handle, delete it, rinse, repeat...
But somewhere along the line, I'll get an Access Denied (5) error during the CreateFile() call. Looking at sysinternal's ProcessMonitor, I can see that the underlying issue is that there is a pending delete on the file while I'm trying to create it again.
Questions:
Is there a way to wait for the delete to complete?
Is there a way to detect that a file is pending deletion?
We have tried the first option, by simply WaitForSingleObject() on the HFILE. But the HFILE is always closed before the WaitForSingleObject executes, and so WaitForSingleObject always returns WAIT_FAILED. Clearly, trying to wait for the closed handle doesn't work.
I could wait on a change notification for the folder that the file exists in. However, that seems like an extremely overhead-intensive kludge to what is a problem only occasionally (to wit: in my tests on my Windows 7 x64 E6600 PC it typically fails on iteration 12000+ -- on other machines, it can happen as soon as iteration 7 or 15 or 56 or never).
I have been unable to discern any CreateFile() arguments that would explicitly allow for this ether. No matter what arguments CreateFile has, it really is not okay with opening a file for any access when the file is pending deletion.
And since I can see this behavior on both an Windows XP box and on an x64 Windows 7 box, I am quite certain that this is core NTFS behavior "as intended" by Microsoft. So I need a solution that allows the OS to complete the delete before I attempt to proceed, preferably without tying up CPU cycles needlessly, and without the extreme overhead of watching the folder that this file is in (if possible).
1 Yes, this loop returns on a failure to write or a failure to close which leaks, but since this is a simple console test application, the application itself exits, and Windows guarantees that all handles are closed by the OS when a process completes. So no leaks exist here.
bool DeleteFileNowA(const char * pszFilename)
{
// Determine the path in which to store the temp filename
char szPath[MAX_PATH];
strcpy(szPath, pszFilename);
PathRemoveFileSpecA(szPath);
// Generate a guaranteed to be unique temporary filename to house the pending delete
char szTempName[MAX_PATH];
if (!GetTempFileNameA(szPath, ".xX", 0, szTempName))
return false;
// Move the real file to the dummy filename
if (!MoveFileExA(pszFilename, szTempName, MOVEFILE_REPLACE_EXISTING))
return false;
// Queue the deletion (the OS will delete it when all handles (ours or other processes) close)
if (!DeleteFileA(szTempName))
return false;
return true;
}
There are other processes in Windows that want a piece of that file. The search indexer is an obvious candidate. Or a virus scanner. They'll open the file for full sharing, including FILE_SHARE_DELETE, so that other processes aren't heavily affected by them opening the file.
That usually works out well, unless you create/write/delete at a high rate. The delete will succeed but the file cannot disappear from the file system until the last handle to it got closed. The handle held by, say, the search indexer. Any program that tries to open that pending-delete file will be slapped by error 5.
This is otherwise a generic problem on a multitasking operating system, you cannot know what other process might want to mess with your files. Your usage pattern seems unusual, review that first. A workaround would be to catch the error, sleep and try again. Or moving the file into the recycle bin with SHFileOperation().
First rename the file to be deleted, and then delete it.
Use GetTempFileName() to obtain a unique name, and then use MoveFile() to rename the file. Then delete the renamed file. If the actual deletion is indeed asynchronous and might conflict with the creation of the same file (as your tests seems to indicate), this should solve the problem.
Of course, if your analysis is right and file operations happen somewhat asynchronous, this might introduce the problem that you attempt to delete the file before the renaming is done. But then you could always keep trying to delete in a background thread.
If Hans is right (and I'm inclined to believe his analysis), then moving might not really help, because you might not be able to actually rename a file that's open by another process. (But then you might, I don't know this.) If that's indeed the case, the only other way I can come up with is "keep trying". You would have to wait for a few milliseconds and retry. Keep a timeout to give up when this doesn't help.
Silly suggestion - since it fails so infrequently, simply wait some milliseconds on failure and try again.
Or, if latency is important, switch to another file name, leaving the old file to be deleted later.
This is maybe not your particular issue, but it's possible so I suggest you get out Process Monitor (Sysinternals) and see.
I had exactly the same problem and discovered that Comodo Internet Security (cmdagent.exe) was contributing to the problem. Previously I had a dual-core machine, but when I upgraded to an Intel i7 suddenly my working software (jam.exe by Perfore software) no longer worked because it had the same pattern (a delete then create, but no check). After debugging the problem I found GetLastError() was returning access denied, but Process Monitor reveals a 'delete pending'. Here is the trace:
10:39:10.1738151 AM jam.exe 5032 CreateFile C:\Users\Dad\AppData\Local\Temp\jam5032t1.bat SUCCESS Desired Access: Read Attributes, Delete, Disposition: Open, Options: Non-Directory File, Open Reparse Point, Attributes: n/a, ShareMode: Read, Write, Delete, AllocationSize: n/a, OpenResult: Opened
10:39:10.1738581 AM jam.exe 5032 QueryAttributeTagFile C:\Users\Dad\AppData\Local\Temp\jam5032t1.bat SUCCESS Attributes: ANCI, ReparseTag: 0x0
10:39:10.1738830 AM jam.exe 5032 SetDispositionInformationFile C:\Users\Dad\AppData\Local\Temp\jam5032t1.bat SUCCESS Delete: True
10:39:10.1739216 AM jam.exe 5032 CloseFile C:\Users\Dad\AppData\Local\Temp\jam5032t1.bat SUCCESS
10:39:10.1739438 AM jam.exe 5032 IRP_MJ_CLOSE C:\Users\Dad\AppData\Local\Temp\jam5032t1.bat SUCCESS
10:39:10.1744837 AM jam.exe 5032 CreateFile C:\Users\Dad\AppData\Local\Temp\jam5032t1.bat DELETE PENDING Desired Access: Generic Write, Read Attributes, Disposition: OverwriteIf, Options: Synchronous IO Non-Alert, Non-Directory File, Attributes: N, ShareMode: Read, Write, AllocationSize: 0
10:39:10.1788811 AM jam.exe 5032 CreateFile C:\Users\Dad\AppData\Local\Temp\jam5032t1.bat DELETE PENDING Desired Access: Generic Write, Read Attributes, Disposition: OverwriteIf, Options: Synchronous IO Non-Alert, Non-Directory File, Attributes: N, ShareMode: Read, Write, AllocationSize: 0
10:39:10.1838276 AM jam.exe 5032 CreateFile C:\Users\Dad\AppData\Local\Temp\jam5032t1.bat DELETE PENDING Desired Access: Generic Write, Read Attributes, Disposition: OverwriteIf, Options: Synchronous IO Non-Alert, Non-Directory File, Attributes: N, ShareMode: Read, Write, AllocationSize: 0
10:39:10.1888407 AM jam.exe 5032 CreateFile C:\Users\Dad\AppData\Local\Temp\jam5032t1.bat DELETE PENDING Desired Access: Generic Write, Read Attributes, Disposition: OverwriteIf, Options: Synchronous IO Non-Alert, Non-Directory File, Attributes: N, ShareMode: Read, Write, AllocationSize: 0
10:39:10.1936323 AM System 4 FASTIO_ACQUIRE_FOR_SECTION_SYNCHRONIZATION C:\Users\Dad\AppData\Local\Temp\jam5032t1.bat SUCCESS SyncType: SyncTypeOther
10:39:10.1936531 AM System 4 FASTIO_RELEASE_FOR_SECTION_SYNCHRONIZATION C:\Users\Dad\AppData\Local\Temp\jam5032t1.bat SUCCESS
10:39:10.1936647 AM System 4 IRP_MJ_CLOSE C:\Users\Dad\AppData\Local\Temp\jam5032t1.bat SUCCESS
10:39:10.1939064 AM jam.exe 5032 CreateFile C:\Users\Dad\AppData\Local\Temp\jam5032t1.bat DELETE PENDING Desired Access: Generic Write, Read Attributes, Disposition: OverwriteIf, Options: Synchronous IO Non-Alert, Non-Directory File, Attributes: N, ShareMode: Read, Write, AllocationSize: 0
10:39:10.1945733 AM cmdagent.exe 1188 CloseFile C:\Users\Dad\AppData\Local\Temp\jam5032t1.bat SUCCESS
10:39:10.1946532 AM cmdagent.exe 1188 IRP_MJ_CLOSE C:\Users\Dad\AppData\Local\Temp\jam5032t1.bat SUCCESS
10:39:10.1947020 AM cmdagent.exe 1188 IRP_MJ_CLOSE C:\Users\Dad\AppData\Local\Temp\jam5032t1.bat SUCCESS
10:39:10.1948945 AM cfp.exe 1832 QueryOpen C:\Users\Dad\AppData\Local\Temp\jam5032t1.bat FAST IO DISALLOWED
10:39:10.1949781 AM cfp.exe 1832 CreateFile C:\Users\Dad\AppData\Local\Temp\jam5032t1.bat NAME NOT FOUND Desired Access: Read Attributes, Disposition: Open, Options: Open Reparse Point, Attributes: n/a, ShareMode: Read, Write, Delete, AllocationSize: n/a
10:39:10.1989720 AM jam.exe 5032 CreateFile C:\Users\Dad\AppData\Local\Temp\jam5032t1.bat SUCCESS Desired Access: Generic Write, Read Attributes, Disposition: OverwriteIf, Options: Synchronous IO Non-Alert, Non-Directory File, Attributes: N, ShareMode: Read, Write, AllocationSize: 0, OpenResult: Created
As you can see, there is a request to delete followed by several attempts to open the file again by jam.exe (it's an fopen in a loop). You can see cmdagent.exe presumably had the file open as it closes its handle and then suddenly jam.exe is able to now open the file.
Of course, the suggested solution to wait and try again, and it works just fine.
Is there a way to detect that a file is pending deletion?
Use the GetFileInformationByHandleEx function with the FILE_STANDARD_INFO structure.
But the function can't solve your problem. sbi's solution neither.
Since you're creating a new file, processing it, then deleting it, it sounds like you don't really care about what the file name is. If that's truly the case, you should consider always creating a temporary file. That way, each time through the process, you don't have to care that the file didn't yet get deleted.
I actually had the same issue while using the LoadLibrary(path). I couldn't delete the file in path.
The solution was to "close the handle" or use the FreeLibrary(path) method.
NOTE: Please read the "Remarks" on MSDN regarding the FreeLibrary().
On Windows Vista/Windows 7 there is DeleteFileTransacted which deletes a file using transactions which ensures they are deleted (flushes file buffers, etc.). For Windows XP compatibility this is not an option though.
Another idea how this might be done is use OpenFile() with the flag OF_CREATE which sets the length to zero if the file exists or creates it if it doesn't and then to call FlushFileBuffers on the file handle to wait for this operation (making the file zero length) to complete. On completion, the file is of size 0 and then simply call DeleteFile.
You can later test if the file exists or if it has zero-length to treat it the same way.
According to [1], you could use NtDeleteFile to avoid the asynchronous nature of DeleteFile. Also [1] gives some details on how DeleteFile works.
Unfortunately the official documentation on NtDeleteFile [2] doesn't mention any particular details on this issue.
[1] Undocumented functions of NTDLL
[2] ZwDeleteFile function
The best answer was given by sbi, but in the interest of completeness, some people might also want to know about a new way now available from Windows 10 RS1/1603.
It involves calling the SetFileInformationByHandle API with class FileDispositionInfoEx, and setting flags FILE_DISPOSITION_DELETE | FILE_DISPOSITION_POSIX_SEMANTICS. See the full answer by RbMm.
If CreateFile returns INVALID_HANDLE_VALUE then you should determine what GetLastError returns in your particular situation (pending delete) and loop back to CreateFile based on that error code only.
The FILE_FLAG_DELETE_ON_CLOSE flag might buy you something.
I just had this exact issue and took TWO steps to address it; I stopped using C/C++ stdlib apis and ::DeleteFile(..), and switched to:
::MoveFileEx(src,dest,MOVEFILE_WRITE_THROUGH);. See: MOVEFILE_WRITE_THROUGH
h = ::CreateFile(DELETE | SYNCHRONIZE,OPEN_EXISTING,FILE_FLAG_DELETE_ON_CLOSE | FILE_FLAG_OPEN_REPARSE_POINT); ::CloseHandle(h);
The above are pseudo calls showing the relevant flags, specifically note that there is NO sharing on the CreateFile call used to achieve delete.
Together they gave me better precision on the rename and delete semantics. They are working in my code now and have improved the precision and control from other threads/processes (watching the file-system for changes) interjecting actions on the file due to latencies [or sharing] in the other rename and/or delete APIs. Without that control, a file set to delete when its last kernel-handle was closed might actually languish open until the system was rebooted, and you might not know.
Hopefully those feedback snippets might prove useful to others.
Addendum: I happen to use hardlinks for a portion of the work I do. It turns out that although you can create hardlinks on a file that is OPEN, you cannot delete ANY of them until all handles to ANY of the underlying data-stream(s) to that NTFS file are closed. That is weird since:
the OS tracks by them using a single ID in what is effectively an INode (ntfs uid).
https://learn.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-openfilebyid
https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-getfinalpathnamebyhandlew
https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-findfirstfilenamew
https://learn.microsoft.com/en-us/windows/win32/api/winbase/ns-winbase-file_id_info
you can create hardlinks while it is open, just not delete them
hardlinks are actually alias-names in the attributes (XATTRs) in NTFS
you can rename them while it is open
so changing the name doesn't matter
Which would lead you to think that only the last hardlink should be non-deletable while the kernel has one or more open-file handles referring to the hardlinked NTFS File's MFT-Entry/ATTRs. anyway, just another thing to know.
I think this is just by poor design in the file system. I have seen the same problem when I worked with communication ports, opening/closing them.
Unfortunately I think the simplest solution would be to just retry to create the file a number of times if you get an INVALID_HANDLE_VALUE. GetLastError() might also give you a better way of detecting this particular INVALID_HANDLE_VALUE.
I would have preferred overlapped I/O, but their CloseHandle() and DeleteFile() don't handle overlapped operations :(
First, yes this is related to this stack overflow question, but I'm having a slightly different set of circumstances and my post there is not getting an answer.
So, on my Dell desktop workstation, Ubuntu 10.04 32 bit, I have developed a server program that is designed to offer a Unix-Domain socket to a PHP "program" run by Apache. (note: umask = 0022) I named the socket file /home/wmiller/ACT/web_socket_file. (ACT is a reference to the product name). /home/wmiller/ACT has permissions of 777. /home/wmiller/ACT/web_socket_file gets created with permissions of 777.
Now, I copy the program to my test platform, a Q7 format Intel processor board, which also has Ubuntu 10.04 32 bit and umask = 0022. Same directories, same 777 permission on the dir. However, now when i run the code /home/wmiller/ACT/web_socket_file comes up with 755 permissions and Apache/PHP can't open the Unix Domain socket because it gets r-x permissions instead of rw- or rwx. Apache is running in uid = www-data.
sockaddr_un webServAddr;
remove( g_webSocketFileName.c_str() ); // to erase any lingering file from last time
memset(&webServAddr, 0, sizeof(webServAddr));
webServAddr.sun_family = AF_UNIX;
snprintf( webServAddr.sun_path, UNIX_PATH_MAX, "%s", g_webSocketFileName.c_str() );
if (( g_webServerSock = socket(AF_UNIX, SOCK_STREAM, 0)) < 0 )
{
PLOG( ERROR ) << "Failed to acquire the web Server socket: "; // uses google glog tool
return -1;
}
So I tried both of these and neither worked.
chmod( g_webSocketFileName.c_str(), S_IRWXU | S_IRWXG | S_IRWXO );
and
char temp[100];
sprintf( temp , "chmod o+w %s\n", g_webSocketFileName.c_str() );
system( temp );
Tried permissions of 777 and o+w.
I even tried adding a
unlink( g_webSocketFileName.c_str() );
But no help there.
Anyone have suggestions on why ir works on one machine and not on another almost identical machine?
Would I be better off to put the socket file elsewhere? Is there a standard place-where-socket-files-go?
On Linux, you need to call fchmod() on the Unix domain socket file descriptor before bind(). In this way the bind() call will create the filesystem object with the specified permissions. Calling fchmod() on an already bound socket is not effective.
Using chmod() could lead to TOCTTOU race condition. If possible, use fchmod() instead.
This is a Linux-specific hack. On most BSD systems, fchmod() will fail on a socket fd and set EINVAL.
Edit. I found this system-dependent behavior difference by tinkering. Perhaps the best "source" for this should be the kernel source code itself.
On FreeBSD, it appears that fchmod() on a Unix domain socket is defined as a no-op that sets EINVAL (Ref1)
On Linux, it appears that a Unix domain socket fd is created just like an inode, along with file modes (but with S_IFSOCK bitwise-or'ed in). (Ref2) Linux's fchmod() implementation will then happily apply changes to such an object. When binding a Unix domain socket to an address, the file modes are used in creating the filesystem-object. (Ref3) According to man 2 stat, S_IFSOCK is present in POSIX.1-2001.
If I read the sources wrong, please feel free to correct me.
As Cong Ma said, under Linux you should look at using fchmod() before the bind(). However, the umask() is still going to be applied. So the correct sequence goes like this:
// create the socket
int s = socket();
// restrict permissions
#ifdef __linux__
fchmod(s, S_IRUSR | S_IWUSR);
#endif
// bind the socket now
bind(s, &u, sizeof(u));
// finally, fix the permissions to your liking
chmod(u.sun_path, 0666); // <- change 0666 to what your permissions
Important Note: the code here does not show the error handling which is required to make sure things work as expected. See complete example here.
What is the problem with fchmod()?
If you try to set the exact mode that you need in fchmod(), the file gets created by bind() and at that point the umask gets applied. That means with a umask such as 022, you still do not get the write permissions for the group and other users (i.e. you would get 0644 instead of 0666).
One way to use fchmod() and skip on the chmod() after the bind() is to change umask with:
umask(0);
bind(...);
However, if like many of us you are running in a multithreaded application, changing the umask is probably not an option. The solution above works without having to use umask(0) which long term is a better way of doing things.
I know, that there's the is_open() function in C++, but I want one program to check if a file hasn't been opened by another application. Is there any way to do it using standard library?
EDIT - Clarified in the answers that this is for a Linux application.
Not only the standard library does not have this funcionality, it's not even possible in general. You could (on linux) check /proc/*/fd — but it is possible that your program does not have permission to do it on processes from other users (this is the default in Ubuntu, for instance).
No, the standard library has no such functionality.
If you control the other process (have source code), the best plan is to use advisory locks in both processes. This locking is defined in POSIX, and will be portable across operating systems.
In Linux, you can use the utility lsof to see what files are opened by other processes.
This is limited to what you have permissions for - you have to do the check as a privileged user, or you'll only get results for files opened by the same user as the one doing the check.
I only know of the command line utility, not of any system call you can use directly from C code.
In Linux, it's also possible to turn on mandatory locking for a given filesystem (mount -o mand), and set special flags on the file (chmod g-x,g+s). Then when your process attempts to acquire a write lock, it will fail if another process has the file open. This is hardly ever used, but if you completely control the system in question, it may be an option.
The following code may work.
int main(int argc, char ** argv)
{
int fd = open(argv[1], O_RDONLY);
if (fd < 0) {
perror("open");
return 1;
}
if (fcntl(fd, F_SETLEASE, F_WRLCK) && EAGAIN == errno) {
puts("file has been opened");
}
else {
fcntl(fd, F_SETLEASE, F_UNLCK);
puts("file has not been opened");
}
close(fd);
return 0;
}
Perhaps you could just try and get a full write lock? It'll fail if anyone else has it open for reading or writing.
fopen("myfile.txt", "r+")
If it's not cross platform and is Win32, then you can request even more fine-grained set of locks.
See here
and look at dwShareMode, value of 0, as well as the other parameters.
Nope. Unless other application uses advisory locks.
See http://docs.sun.com/app/docs/doc/816-0213/6m6ne37v5?a=view
Non-natively, you could call out to Sysinternals' handle.exe as a last resort...
As #Neil Butterworth says, the standard library doesnt.
In unix you can use fcntl to use file locks.
You could write a wrapper for your open function, that checks for a lock (and locks if none exists) a file if its open by no one else. You shold write a wrapper for close as well, that releases that lock on file close.
Seeing you have tagged linux -> there's a command-line too and API that have been added to the Linux kernel and do just that: inotify.
Here's the man page.
In Windows this little and dirty trick will work (if the file exists and you have the right permissions)
if ( 0 != rename("c:/foo.txt", "c:/foo.txt") ) {
printf("already opened\n");
}
It's likely to work also in Linux.
How do I launch an app and capture the output via stdout and maybe stderr?
I am writing an automated build system and I need to capture the output to analyze. I'd like to update the svn repo and grab the revision number so I can move the files in autobuild/revNumber/ if successful. I also would like to build using make and upload the compile text to my server for everyone to see the warnings and errors on a failed build.
I can't find the system() function, but I found the CreateProcess() function on MSDN. I am able to launch what I need but I have no idea how to capture the stderr and stdout. I notice the process launches separately unless I set a breakpoint and keep my app exiting which it then will keep all the text in my app console window. I would also want to wait until all processes are finished and then scan the data it produced to do any additional operations I need. How do I do any of this?
In real shells (meaning, not sea shells - I mean, not in C Shell or its derivatives), then:
program arg1 arg2 >/tmp/log.file 2>&1
This runs program with the given arguments, and redirects the stdout to /tmp/log.file; the notation (hieroglyph) '2>&1' at the end sends stderr (file descriptor 2) to the same place that stdout (file descriptor 1) is going. Note that the sequence of operations is important; if you reverse them, then standard error will go to where standard output was going, and then standard output (but not standard error) will be redirected to the file.
The choice of file name shown is abysmal for numerous reasons - you should allow the user to choose the directory, and probably should include the process ID or time stamp in the file name.
LOG=${TMPDIR:-/tmp}/log.$$.$(date +%Y%m%d-%H%M%S)
program arg1 arg2 >$LOG 2>&1
In C++, you can use the system() function (inherited from C) to run processes. If you need to know the file name in the C++ program (plausible), then generate the name in the program (strftime() is your friend) and create the command string with that file name.
(Strictly, you also need getenv() to get $TMPDIR, and the POSIX function getpid() to get the process ID, and then you can simulate the two-line shell script (though the PID used would be of the C++ program, not the launched shell).
You could instead use the POSIX popen() function; you'd have to include the '2>&1' notation in the command string that you create to send the standard error of the command to the same place as standard output goes, but you would not need a temporary file:
FILE *pp = popen("program arg1 arg2 2>&1", "r");
You can then read off the file stream. I'm not sure whether there's a clean way to map a C file stream into a C++ istream; there probably is.
You need to fill up the STARTUP_INFO structure, which has hStdInput, hStdOutput and hStdError. Remember to inherit handles when you CreateProcess.
/* Assume you open a file handle or pipe called myoutput */
STARTUP_INFO si_startinfo;
ZeroMemory(&si_startinfo, sizeof(STARTUP_INFO));
si_startinfo.cb = sizeof(STARTUP_INFO);
si_startinfo.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
si_startinfo.hStdOutput = myoutput;
si_startinfo.hStdError = myoutput;
si_startifno.dwFlags != STARTF_USEHANDLES;
PROCESS_INFORMATION pi_procinfo;
ZeroMemory(&pi_procinfo, sizeof(PROCESS_INFORMATION);
CreateProcess(NULL, cmdline, NULL, NULL, true, 0, NULL, pathname, &si_startinfo, &pi_procinfo);
I have not shown the error handling aspects, which you will need to do. The 5th argument is set to true to inherit the handles. Others have explained how to create pipes so I won't repeat it here.
Microsoft's CRTs and the MSDN library do include the system function and the _popen function.