KQUEUE only works for folder path? - c++

I am use the code (actually copy from hereFSEvents C++ Example)as following, but it can only work for a path, can not work for a file.
I just want to monitor a specific file. How can I do that? thanks
#include <fcntl.h> // for O_RDONLY
#include <stdio.h> // for fprintf()
#include <stdlib.h> // for EXIT_SUCCESS
#include <string.h> // for strerror()
#include <sys/event.h> // for kqueue() etc.
#include <unistd.h> // for close()
int main (int argc, const char *argv[])
{
int kq = kqueue ();
// dir name is in argv[1], NO checks for errors here
int dirfd = open (argv[1], O_RDONLY);
struct kevent direvent;
EV_SET (&direvent, dirfd, EVFILT_VNODE, EV_ADD | EV_CLEAR | EV_ENABLE,
NOTE_WRITE, 0, (void *)argv[1]);
kevent(kq, &direvent, 1, NULL, 0, NULL);
// Register interest in SIGINT with the queue. The user data
// is NULL, which is how we'll differentiate between
// a directory-modification event and a SIGINT-received event.
struct kevent sigevent;
EV_SET (&sigevent, SIGINT, EVFILT_SIGNAL, EV_ADD | EV_ENABLE, 0, 0, NULL);
// kqueue event handling happens after the legacy API, so make
// sure it doesn eat the signal before the kqueue can see it.
signal (SIGINT, SIG_IGN);
// Register the signal event.
kevent(kq, &sigevent, 1, NULL, 0, NULL);
while (1) {
// camp on kevent() until something interesting happens
struct kevent change;
if (kevent(kq, NULL, 0, &change, 1, NULL) == -1) { exit(1); }
// The signal event has NULL in the user data. Check for that first.
if (change.udata == NULL) {
break;
} else {
// udata is non-null, so it's the name of the directory
printf ("%s\n", (char*)change.udata);
}
}
close (kq);
return 0;
}

What operations on the file are being performed that you're missing?
Note that many things that write files don't open the existing file and write to it; they unlink the existing file and replace it with a new one. Because of that, kqueue() won't report that the file that you have open has been written to. You can add NOTE_DELETE to the fflags to try to catch that.

Related

Win32 GUI C(++) app redirect both stdout and stderr to the same file on disk

I'm creating a Windows service, which cannot have an associated console. Therefore I want to redirect stdout and stderr to a (the same) file. Here is what I discovered so far:
Redirecting cout and cerr in C++ can be done by changing the buffers, but this does not affect C I/O like puts or Windows I/O handles.
Hence we can use freopen to reopen stdout or stderr as a file like here, but we cannot specify the same file twice.
To still use the same file for both we can redirect stderr to stdout using dup2 like here.
So far so good, and when we run this code with /SUBSYSTEM:CONSOLE (project properties → Linker → System) everything works fine:
#include <Windows.h>
#include <io.h>
#include <fcntl.h>
#include <cstdio>
#include <iostream>
void doit()
{
FILE *stream;
if (_wfreopen_s(&stream, L"log.log", L"w", stdout)) __debugbreak();
// Also works as service when uncommenting this line: if (_wfreopen_s(&stream, L"log2.log", L"w", stderr)) __debugbreak();
if (_dup2(_fileno(stdout), _fileno(stderr)))
{
const auto err /*EBADF if service; hover over in debugger*/ = errno;
__debugbreak();
}
// Seemingly can be left out for console applications
if (!SetStdHandle(STD_OUTPUT_HANDLE, reinterpret_cast<HANDLE>(_get_osfhandle(_fileno(stdout))))) __debugbreak();
if (!SetStdHandle(STD_ERROR_HANDLE, reinterpret_cast<HANDLE>(_get_osfhandle(_fileno(stderr))))) __debugbreak();
if (_setmode(_fileno(stdout), _O_WTEXT) == -1) __debugbreak();
if (_setmode(_fileno(stderr), _O_WTEXT) == -1) __debugbreak();
std::wcout << L"1☺a" << std::endl;
std::wcerr << L"1☺b" << std::endl;
_putws(L"2☺a");
fflush(stdout);
fputws(L"2☺b\n", stderr);
fflush(stderr);
const std::wstring a3(L"3☺a\n"), b3(L"3☺b\n");
if (!WriteFile(GetStdHandle(STD_OUTPUT_HANDLE), a3.c_str(), a3.size() * sizeof(wchar_t), nullptr, nullptr))
__debugbreak();
if (!WriteFile(GetStdHandle(STD_ERROR_HANDLE), b3.c_str(), b3.size() * sizeof(wchar_t), nullptr, nullptr))
__debugbreak();
}
int main() { doit(); }
int WINAPI wWinMain(HINSTANCE, HINSTANCE, PWSTR, int) { return doit(), 0; }
This nicely writes the following text to log.log:
1☺a
1☺b
2☺a
2☺b
3☺a
3☺b
(Of course we want emoji, so we need some sort of unicode. In this case we use wide characters, which means we need to use setmode or else everything will mess up. You may also need to save the cpp file in an encoding that MSVC understands, e.g. UTF-8 with signature.)
But now back to the original problem: doing this as a service without console, or, equivalent but easier to debug, a GUI app (/SUBSYSTEM:WINDOWS).
The problem is that in this case dup2 fails because fileno(stderr) is not a valid file descriptor, because the app initially has no associated streams. As mentioned here, fileno(stderr) == -2 in this case.
Note that when we first open stderr as another file using freopen, everything works fine, but we created a dummy empty file.
So now my question is: what is the best way to redirect both stdout and stderr to the same file in an application which initially has no streams?
Just to recap: the problem is that when stdout or stderr is not associated with an output stream, fileno returns -2, so we cannot pass it to dup2.
(I do not want to change the code used for the actual printing, because that might mean that some output produced by external functions will not be redirected.)
Here's an example of a program that creates a file for writing and then uses CreateProcess and setting stdout and stderr for the process to the HANDLE of the created file. This example just starts itself with a dummy argument to make it write a lot of things to stdout and stderr that will be written to output.txt.
// RedirectStd.cpp
#include <iostream>
#include <string_view>
#include <vector>
#include <Windows.h>
struct SecAttrs_t : public SECURITY_ATTRIBUTES {
SecAttrs_t() : SECURITY_ATTRIBUTES{ 0 } {
nLength = sizeof(SECURITY_ATTRIBUTES);
bInheritHandle = TRUE;
}
operator SECURITY_ATTRIBUTES* () { return this; }
};
struct StartupInfo_t : public STARTUPINFO {
StartupInfo_t(HANDLE output) : STARTUPINFO{ 0 } {
cb = sizeof(STARTUPINFO);
dwFlags = STARTF_USESTDHANDLES;
hStdOutput = output;
hStdError = output;
}
operator STARTUPINFO* () { return this; }
};
int cppmain(const std::string_view program, std::vector<std::string_view> args) {
if (args.size() == 0) {
// no arguments, create a file and start a new process
SecAttrs_t sa;
HANDLE hFile = CreateFile(L"output.txt",
GENERIC_WRITE,
FILE_SHARE_READ,
sa, // lpSecurityAttributes
CREATE_ALWAYS, // dwCreationDisposition
FILE_ATTRIBUTE_NORMAL, // dwFlagsAndAttributes
NULL // dwFlagsAndAttributesparameter
);
if (hFile == INVALID_HANDLE_VALUE) return 1;
StartupInfo_t su(hFile); // set output handles to hFile
PROCESS_INFORMATION pi;
std::wstring commandline = L"RedirectStd.exe dummy";
BOOL bCreated = CreateProcess(
NULL,
commandline.data(),
NULL, // lpProcessAttributes
NULL, // lpThreadAttributes
TRUE, // bInheritHandles
0, // dwCreationFlags
NULL, // lpEnvironment
NULL, // lpCurrentDirectory
su, // lpStartupInfo
&pi
);
if (bCreated == 0) return 2;
CloseHandle(pi.hThread); // no need for this
WaitForSingleObject(pi.hProcess, INFINITE); // wait for the process to finish
CloseHandle(pi.hProcess);
CloseHandle(hFile);
}
else {
// called with an argument, output stuff to stdout and stderr
for (int i = 0; i < 1024; ++i) {
std::cout << "stdout\n";
std::cerr << "stderr\n";
}
}
return 0;
}
int main(int argc, char* argv[]) {
return cppmain(argv[0], { argv + 1, argv + argc });
}
I found a solution that works and does not create a temporary file log2.log. Instead of this file, we can open NUL (Windows's /dev/null), so the code becomes:
FILE *stream;
if (_wfreopen_s(&stream, L"log.log", L"w", stdout)) __debugbreak();
if (freopen_s(&stream, "NUL", "w", stderr)) __debugbreak();
if (_dup2(_fileno(stdout), _fileno(stderr))) __debugbreak();
if (!SetStdHandle(STD_OUTPUT_HANDLE, reinterpret_cast<HANDLE>(_get_osfhandle(_fileno(stdout))))) __debugbreak();
if (!SetStdHandle(STD_ERROR_HANDLE, reinterpret_cast<HANDLE>(_get_osfhandle(_fileno(stderr))))) __debugbreak();
if (_setmode(_fileno(stdout), _O_WTEXT) == -1) __debugbreak();
if (_setmode(_fileno(stderr), _O_WTEXT) == -1) __debugbreak();
This makes sure that _fileno(stderr) is not -2 anymore so we can use dup2.
There might be a more elegant solution (not sure), but this works and does not create a dummy empty file (also not one named NUL).

Using ptrace from multithreaded applications

I want to use ptrace to check what system calls a program spawned by my program makes. I started out from this tutorial as it was explained in an answer to my previous question. I modified the code by adapting it to the platform I'm using (SLES 11 64 bit), and put together the following test code that prints out every system call the spawned process makes:
#include <sys/ptrace.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <stdio.h>
#include <sys/reg.h>
#include <sys/syscall.h> /* For SYS_write etc */
pid_t child;
void run()
{
long orig_eax;
int status;
while(1) {
int pid = wait(&status);
if (pid == -1) {
perror("wait");
kill(child, SIGKILL);
return;
}
printf("Got event from %d.\n", pid);
if(WIFEXITED(status))
break;
orig_eax = ptrace(PTRACE_PEEKUSER,
pid, 8 * ORIG_RAX, NULL);
if (orig_eax == -1) {
perror("ptrace");
kill(child, SIGKILL);
return;
} else {
printf("Syscall %ld called.\n", orig_eax);
}
ptrace(PTRACE_SYSCALL,
pid, NULL, NULL);
}
}
int main(int /*argc*/, char* argv[])
{
child = fork();
if(child == 0) {
ptrace(PTRACE_TRACEME, 0, NULL, NULL);
execl(argv[1], argv[1], NULL);
}
else {
printf("Child process id = %d.\n", child);
run();
}
return 0;
}
It works pretty well: it prints the id of the system calls made by the program (actually it prints each one twice, once at entry and once for exit, but that doesn't matter now). However, my program needs to do other things to do other than checking the system calls, so I decided to move the checking to a separate thread (I'm more comfortable with C++ than C, so I did it the C++ way, but I don't think that matters). Of course in this thest program, I only start the thread and then join it.
#include <sys/ptrace.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <stdio.h>
#include <sys/reg.h>
#include <sys/syscall.h> /* For SYS_write etc */
#include <boost/thread.hpp>
pid_t child;
void run()
{
long orig_eax;
int status;
while(1) {
int pid = wait(&status);
if (pid == -1) {
perror("wait");
kill(child, SIGKILL);
return;
}
printf("Got event from %d.\n", pid);
if(WIFEXITED(status))
break;
orig_eax = ptrace(PTRACE_PEEKUSER,
pid, 8 * ORIG_RAX, NULL);
if (orig_eax == -1) {
perror("ptrace");
kill(child, SIGKILL);
return;
} else {
printf("Syscall %ld called.\n", orig_eax);
}
ptrace(PTRACE_SYSCALL,
pid, NULL, NULL);
}
}
int main(int /*argc*/, char* argv[])
{
child = fork();
if(child == 0) {
ptrace(PTRACE_TRACEME, 0, NULL, NULL);
execl(argv[1], argv[1], NULL);
}
else {
printf("Child process id = %d.\n", child);
boost::thread t(run);
t.join();
}
return 0;
}
This time I get an error message:
Child process id = 24682.
Got event from 24682.
ptrace: No such process
Why is this? I tried searching for an answer but found nothing like this. I found that ptrace won't trace threads started by the child process, but that's another thing needs to be dealed with later. Is that even possible to check the child process from a different therad?
The other strange thing is that in my real application I do basically the same thing (but from a much more complicated context: classes, mutexes etc.), and I get a different kind of error. Instead of ptrace returning with an error, wait doesn't even return for system calls on the child process (and the child process doesn't even stop). On the other hand, wait works as expected when the child process exits.
As far as I can tell, ptrace allows just one tracer per process. This means that if you try to attach, which you can try and force it with PTRACE_ATTACH, you will receive an error, telling that ptrace was not able to attach to the specified process.
Thus, your error appears because your thread is not attached to the child process, and this way, when you try to ptrace it, it fails, sending a -ESRCH code.
Furthermore, you can have a look at this post here, it might answer some other questions you might have apart from this one.

FSEvents C++ Example

I need to create FSEvents watcher for a Folder in Mac. I'm comfortable with C++ and is there a way to get FSEvents notifications in C++ code, rather than Objective-C. Is there some example code to start with and any libraries i need to include ..?
I'm already on this page.
http://developer.apple.com/library/mac/#featuredarticles/FileSystemEvents/_index.html
But there seems to be only Objective C, can i have CPP version of it
Yes, it is possible in C. You should look for Kernel Queues.
Here's a small sample to watch the directory:
#include <errno.h> // for errno
#include <fcntl.h> // for O_RDONLY
#include <stdio.h> // for fprintf()
#include <stdlib.h> // for EXIT_SUCCESS
#include <string.h> // for strerror()
#include <sys/event.h> // for kqueue() etc.
#include <unistd.h> // for close()
int main (int argc, const char *argv[])
{
int kq = kqueue ();
// dir name is in argv[1], NO checks for errors here
int dirfd = open (argv[1], O_RDONLY);
struct kevent direvent;
EV_SET (&direvent, dirfd, EVFILT_VNODE, EV_ADD | EV_CLEAR | EV_ENABLE,
NOTE_WRITE, 0, (void *)dirname);
kevent(kq, &direvent, 1, NULL, 0, NULL);
// Register interest in SIGINT with the queue. The user data
// is NULL, which is how we'll differentiate between
// a directory-modification event and a SIGINT-received event.
struct kevent sigevent;
EV_SET (&sigevent, SIGINT, EVFILT_SIGNAL, EV_ADD | EV_ENABLE, 0, 0, NULL);
// kqueue event handling happens after the legacy API, so make
// sure it doesn eat the signal before the kqueue can see it.
signal (SIGINT, SIG_IGN);
// Register the signal event.
kevent(kq, &sigevent, 1, NULL, 0, NULL);
while (1) {
// camp on kevent() until something interesting happens
struct kevent change;
if (kevent(kq, NULL, 0, &change, 1, NULL) == -1) { exit(1); }
// The signal event has NULL in the user data. Check for that first.
if (change.udata == NULL) {
break;
} else {
// udata is non-null, so it's the name of the directory
printf ("%s\n", (char*)change.udata);
}
}
close (kq);
return 0;
}
The details can be found in ch. 16 (kqueues and FSEvents) of "Advanced Mac OSX Programming" by Mark Dalrymple. The additional info may be found in *BSD documentation for kqueues.
Or use this API from FSEvents (it's mostly C-based).
FSEventStreamRef FSEventStreamCreate (CFAllocatorRef allocator,
FSEventStreamCallback callback,
FSEventStreamContext *context,
CFArrayRef pathsToWatch,
FSEventStreamEventId sinceWhen,
CFTimeInterval latency,
FSEventStreamCreateFlags flags);
to create the FSEvents event stream with pure-C callback.
Then attach this event stream to your runloop using the
void FSEventStreamScheduleWithRunLoop (FSEventStreamRef streamRef,
CFRunLoopRef runLoop,
CFStringRef runLoopMode);
Yes, here you probably should use a line of Obj-C to get the RunLoop handle: get the CFRunLoop from an NSRunLoop by using -getCFRunLoop
CFRunLoop* loopRef = [[NSRunLoop currentRunLoop] getCFRunLoop];
or use the pure C call
CFRunLoop* loopRef = CFRunLoopGetCurrent();
Start the event stream with
Boolean FSEventStreamStart (FSEventStreamRef streamRef);
Stop the event stream with
void FSEventStreamStop (FSEventStreamRef streamRef);
And then unschedule it from the runloop with this:
void FSEventStreamUnscheduleFromRunLoop (FSEventStreamRef streamRef,
CFRunLoopRef runLoop,
CFStringRef runLoopMode);
Invalidate the stream (cleanup):
void FSEventStreamInvalidate (FSEventStreamRef streamRef);
Hope this will get you started.

I've managed to port some code from msdn to MinGW to capture stdout from child app, but it won't exit, what wrong here?

The code, sory it is abit too long but I've managed it to shorten it only to such size, the key issue is (I think) with this strange for loop at the end. No, I don't know why the loop header is empty, microsoft want's it that way.
The problem is that the code waits to eternity for yet more data from child app.
The page with full algorighm: http://msdn.microsoft.com/en-us/library/ms682499(VS.85).aspx
(Yes, I know it's a mess, but it is self sustained mess at least.)
#include <iostream>
#include <stdio.h>
#include <windows.h>
using namespace std;
#define BUFSIZE 4096
int main() {
SECURITY_ATTRIBUTES saAttr;
printf("\n->Start of parent execution.\n");
// Set the bInheritHandle flag so pipe handles are inherited.
saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
saAttr.bInheritHandle = TRUE;
saAttr.lpSecurityDescriptor = NULL;
// Create a pipe for the child process's STDOUT.
HANDLE g_hChildStd_OUT_Rd = NULL;
HANDLE g_hChildStd_OUT_Wr = NULL;
CreatePipe(&g_hChildStd_OUT_Rd, &g_hChildStd_OUT_Wr, &saAttr, 0);
// Ensure the read handle to the pipe for STDOUT is not inherited.
SetHandleInformation(g_hChildStd_OUT_Rd, HANDLE_FLAG_INHERIT, 0);
// Create a pipe for the child process's STDIN.
HANDLE g_hChildStd_IN_Rd = NULL;
HANDLE g_hChildStd_IN_Wr = NULL;
CreatePipe(&g_hChildStd_IN_Rd, &g_hChildStd_IN_Wr, &saAttr, 0);
// Ensure the write handle to the pipe for STDIN is not inherited.
SetHandleInformation(g_hChildStd_IN_Wr, HANDLE_FLAG_INHERIT, 0);
// Create the child process.
// Create a child process that uses the previously created pipes for STDIN and STDOUT.
char szCmdline[]="cmd /c dir";
PROCESS_INFORMATION piProcInfo;
STARTUPINFO siStartInfo;
BOOL bCreateSuccess = FALSE;
// Set up members of the PROCESS_INFORMATION structure.
ZeroMemory( &piProcInfo, sizeof(PROCESS_INFORMATION) );
// Set up members of the STARTUPINFO structure.
// This structure specifies the STDIN and STDOUT handles for redirection.
ZeroMemory( &siStartInfo, sizeof(STARTUPINFO) );
siStartInfo.cb = sizeof(STARTUPINFO);
siStartInfo.hStdError = g_hChildStd_OUT_Wr;
siStartInfo.hStdOutput = g_hChildStd_OUT_Wr;
siStartInfo.hStdInput = g_hChildStd_IN_Rd;
siStartInfo.dwFlags |= STARTF_USESTDHANDLES;
// Create the child process.
bCreateSuccess = CreateProcess(NULL,
szCmdline, // command line
NULL, // process security attributes
NULL, // primary thread security attributes
TRUE, // handles are inherited
0, // creation flags
NULL, // use parent's environment
NULL, // use parent's current directory
&siStartInfo, // STARTUPINFO pointer
&piProcInfo); // receives PROCESS_INFORMATION
DWORD dwRead, dwWritten;
CHAR chBuf[BUFSIZE];
BOOL bWriteSuccess = FALSE;
BOOL bReadSuccess = FALSE;
HANDLE hParentStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
for (;;) {
bReadSuccess = ReadFile( g_hChildStd_OUT_Rd, chBuf, BUFSIZE, &dwRead, NULL);
if( ! bReadSuccess || dwRead == 0 ) break;
bReadSuccess = WriteFile(hParentStdOut, chBuf, dwRead, &dwWritten, NULL);
if (! bReadSuccess ) break;
}
printf("\n->End of parent execution.\n");
return 0;
}
From the looks of things, you've forgotten to close the parent's handles to the write-end of the pipes you're passing to the child process. Since there's still a valid write handle to the pipe, the system can't detect that writing to the pipe is no longer possible, and you'll wait infinitely for the child to finish.
If you only need to capture the child's standard output, _popen may be a lot easier way to do it.
Edit: Okay, some ancient code to spawn a child process with all three of its standard streams directed to pipes that connect to the parent. This is a lot longer than it should be for such a simple task, but such is life with the Windows API. To be fair, it probably could be shorter, but it's 20 years old (or so). Neither the API nor the way I wrote code then is quite what it is now (though some might not consider my newer code any improvement).
#define STRICT
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <stdio.h>
#include <ctype.h>
#include <io.h>
#include <fcntl.h>
#include <stdlib.h>
#include "spawn.h"
static void system_error(char const *name) {
// A function to retrieve, format, and print out a message from the
// last error. The `name' that's passed should be in the form of a
// present tense noun (phrase) such as "opening file".
//
char *ptr = NULL;
FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM,
0,
GetLastError(),
0,
(char *)&ptr,
1024,
NULL);
fprintf(stderr, "%s\n", ptr);
LocalFree(ptr);
}
static void InitializeInheritableSA(SECURITY_ATTRIBUTES *sa) {
sa->nLength = sizeof *sa;
sa->bInheritHandle = TRUE;
sa->lpSecurityDescriptor = NULL;
}
static HANDLE OpenInheritableFile(char const *name) {
SECURITY_ATTRIBUTES sa;
HANDLE retval;
InitializeInheritableSA(&sa);
retval = CreateFile(
name,
GENERIC_READ,
FILE_SHARE_READ | FILE_SHARE_WRITE,
&sa,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
0);
if (INVALID_HANDLE_VALUE == retval) {
char buffer[100];
sprintf(buffer, "opening file %s", name);
system_error(buffer);
return retval;
}
}
static HANDLE CreateInheritableFile(char const *name, int mode) {
SECURITY_ATTRIBUTES sa;
HANDLE retval;
DWORD FSmode = mode ? OPEN_ALWAYS : CREATE_NEW;
InitializeInheritableSA(&sa);
retval = CreateFile(
name,
GENERIC_WRITE,
FILE_SHARE_READ,
&sa,
FSmode,
FILE_ATTRIBUTE_NORMAL,
0);
if (INVALID_HANDLE_VALUE == retval) {
char buffer[100];
sprintf(buffer, "creating file %s", name);
system_error(buffer);
return retval;
}
if ( mode == APPEND )
SetFilePointer(retval, 0, 0, FILE_END);
}
enum inheritance { inherit_read = 1, inherit_write = 2 };
static BOOL CreateInheritablePipe(HANDLE *read, HANDLE *write, int inheritance) {
SECURITY_ATTRIBUTES sa;
InitializeInheritableSA(&sa);
if ( !CreatePipe(read, write, &sa, 0)) {
system_error("Creating pipe");
return FALSE;
}
if (!inheritance & inherit_read)
DuplicateHandle(
GetCurrentProcess(),
*read,
GetCurrentProcess(),
NULL,
0,
FALSE,
DUPLICATE_SAME_ACCESS);
if (!inheritance & inherit_write)
DuplicateHandle(
GetCurrentProcess(),
*write,
GetCurrentProcess(),
NULL,
0,
FALSE,
DUPLICATE_SAME_ACCESS);
return TRUE;
}
static BOOL find_image(char const *name, char *buffer) {
// Try to find an image file named by the user.
// First search for the exact file name in the current
// directory. If that's found, look for same base name
// with ".com", ".exe" and ".bat" appended, in that order.
// If we can't find it in the current directory, repeat
// the entire process on directories specified in the
// PATH environment variable.
//
#define elements(array) (sizeof(array)/sizeof(array[0]))
static char *extensions[] = {".com", ".exe", ".bat", ".cmd"};
int i;
char temp[FILENAME_MAX];
if (-1 != access(name, 0)) {
strcpy(buffer, name);
return TRUE;
}
for (i=0; i<elements(extensions); i++) {
strcpy(temp, name);
strcat(temp, extensions[i]);
if ( -1 != access(temp, 0)) {
strcpy(buffer, temp);
return TRUE;
}
}
_searchenv(name, "PATH", buffer);
if ( buffer[0] != '\0')
return TRUE;
for ( i=0; i<elements(extensions); i++) {
strcpy(temp, name);
strcat(temp, extensions[i]);
_searchenv(temp, "PATH", buffer);
if ( buffer[0] != '\0')
return TRUE;
}
return FALSE;
}
static HANDLE DetachProcess(char const *name, HANDLE const *streams) {
STARTUPINFO s;
PROCESS_INFORMATION p;
char buffer[FILENAME_MAX];
memset(&s, 0, sizeof s);
s.cb = sizeof(s);
s.dwFlags = STARTF_USESTDHANDLES;
s.hStdInput = streams[0];
s.hStdOutput = streams[1];
s.hStdError = streams[2];
if ( !find_image(name, buffer)) {
system_error("Finding Image file");
return INVALID_HANDLE_VALUE;
}
// Since we've redirected the standard input, output and error handles
// of the child process, we create it without a console of its own.
// (That's the `DETACHED_PROCESS' part of the call.) Other
// possibilities include passing 0 so the child inherits our console,
// or passing CREATE_NEW_CONSOLE so the child gets a console of its
// own.
//
if (!CreateProcess(
NULL,
buffer, NULL, NULL,
TRUE,
DETACHED_PROCESS,
NULL, NULL,
&s,
&p))
{
system_error("Spawning program");
return INVALID_HANDLE_VALUE;
}
// Since we don't need the handle to the child's thread, close it to
// save some resources.
CloseHandle(p.hThread);
return p.hProcess;
}
static HANDLE StartStreamHandler(ThrdProc proc, HANDLE stream) {
DWORD ignore;
return CreateThread(
NULL,
0,
proc,
(void *)stream,
0,
&ignore);
}
HANDLE CreateDetachedProcess(char const *name, stream_info *streams) {
// This Creates a detached process.
// First parameter: name of process to start.
// Second parameter: names of files to redirect the standard input, output and error
// streams of the child to (in that order.) Any file name that is NULL will be
// redirected to an anonymous pipe connected to the parent.
// Third Parameter: handles of the anonymous pipe(s) for the standard input, output
// and/or error streams of the new child process.
//
// Return value: a handle to the newly created process.
//
HANDLE child_handles[3];
HANDLE process;
int i;
// First handle the child's standard input. This is separate from the
// standard output and standard error because it's going the opposite
// direction. Basically, we create either a handle to a file the child
// will use, or else a pipe so the child can communicate with us.
//
if ( streams[0].filename != NULL ) {
streams[0].handle = NULL;
child_handles[0] = OpenInheritableFile(streams[0].filename);
}
else
CreateInheritablePipe(child_handles, &(streams[0].handle), inherit_read);
// Now handle the child's standard output and standard error streams. These
// are separate from the code above simply because they go in the opposite
// direction.
//
for ( i=1; i<3; i++)
if ( streams[i].filename != NULL) {
streams[i].handle = NULL;
child_handles[i] = CreateInheritableFile(streams[i].filename, APPEND);
}
else
CreateInheritablePipe(&(streams[i].handle), child_handles+i, inherit_write);
// Now that we've set up the pipes and/or files the child's going to use,
// we're ready to actually start up the child process:
process = DetachProcess(name, child_handles);
if (INVALID_HANDLE_VALUE == process)
return process;
// Now that we've started the child, we close our handles to its ends of the pipes.
// If one or more of these happens to a handle to a file instead, it doesn't really
// need to be closed, but it doesn't hurt either. However, with the child's standard
// output and standard error streams, it's CRUCIAL to close our handles if either is a
// handle to a pipe. The system detects the end of data on a pipe when ALL handles to
// the write end of the pipe are closed -- if we still have an open handle to the
// write end of one of these pipes, we won't be able to detect when the child is done
// writing to the pipe.
//
for ( i=0; i<3; i++) {
CloseHandle(child_handles[i]);
if ( streams[i].handler )
streams[i].handle =
StartStreamHandler(streams[i].handler, streams[i].handle);
}
return process;
}
#ifdef TEST
#define buf_size 256
unsigned long __stdcall handle_error(void *pipe) {
// The control (and only) function for a thread handling the standard
// error from the child process. We'll handle it by displaying a
// message box each time we receive data on the standard error stream.
//
char buffer[buf_size];
HANDLE child_error_rd = (HANDLE)pipe;
unsigned bytes;
while (ERROR_BROKEN_PIPE != GetLastError() &&
ReadFile(child_error_rd, buffer, 256, &bytes, NULL))
{
buffer[bytes+1] = '\0';
MessageBox(NULL, buffer, "Error", MB_OK);
}
return 0;
}
unsigned long __stdcall handle_output(void *pipe) {
// A similar thread function to handle standard output from the child
// process. Nothing special is done with the output - it's simply
// displayed in our console. However, just for fun it opens a C high-
// level FILE * for the handle, and uses fgets to read it. As
// expected, fgets detects the broken pipe as the end of the file.
//
char buffer[buf_size];
int handle;
FILE *file;
handle = _open_osfhandle((long)pipe, _O_RDONLY | _O_BINARY);
file = _fdopen(handle, "r");
if ( NULL == file )
return 1;
while ( fgets(buffer, buf_size, file))
printf("%s", buffer);
return 0;
}
int main(int argc, char **argv) {
stream_info streams[3];
HANDLE handles[3];
int i;
if ( argc < 3 ) {
fputs("Usage: spawn prog datafile"
"\nwhich will spawn `prog' with its standard input set to"
"\nread from `datafile'. Then `prog's standard output"
"\nwill be captured and printed. If `prog' writes to its"
"\nstandard error, that output will be displayed in a"
"\nMessageBox.\n",
stderr);
return 1;
}
memset(streams, 0, sizeof(streams));
streams[0].filename = argv[2];
streams[1].handler = handle_output;
streams[2].handler = handle_error;
handles[0] = CreateDetachedProcess(argv[1], streams);
handles[1] = streams[1].handle;
handles[2] = streams[2].handle;
WaitForMultipleObjects(3, handles, TRUE, INFINITE);
for ( i=0; i<3; i++)
CloseHandle(handles[i]);
return 0;
}
#endif

How can i create graphical tools with command line interface?

I am building a tool that can be both graphical or purely with a command line interface.
It's up to the user to decide with a command line option "--command_line_only". My IDE is Visual Studio 2008.
I can't seem to find the right project property to make sure
standard output prints are displayed when using the command line interface mode
no command line box is opened when using the tool in its graphical mode
Is there a way to do that ? Visual Studio's devenv seems to behave like this, so i am pretty sure it can be done !
EDIT: I seem to have answered your title, but on re reading your question I am not sure this is what you are asking. I leave the answer here as it might be useful to someone searching your title
Yes you can do this but in general visual studies doesn't make it very easy to separate code from gui (particuly from the hello world examples that are very bound). If you want to mix input then you really want to make sure this is done very well from the beginning.
My advice is to start with the command line options. If you are allowed to use boost (for lisencing reasons) then use boost::program_options.
Then once you have got that going you can add the gui on top. Also, I would recommonend using a gui library such as gtk++ as it is cross platform .
This is not an easy thing to do, IIRC. The problem is that on Windows the executable itself has a flag whether it is a GUI application or console application and e.g. cmd.exe behaves differently when executing one or the other. I suggest that you split the core functionality of your application into a library and build separate CLI and GUI front ends.
EDIT: If you really insist, this goes a long way towards the goal. The goto is there for historical reasons, it could be replaced by the if now:
static
bool
usable_handle (HANDLE h)
{
return h && h != INVALID_HANDLE_VALUE;
}
static
bool
try_reopen_std_handle (int dest_handle, DWORD os_handle_num, HANDLE os_handle,
int flags)
{
if (! usable_handle (os_handle))
return false;
int ret = SetStdHandle (os_handle_num, os_handle);
assert (ret);
if (! ret)
return false;
int base_flags = 0;
#if defined (UNICODE)
//base_flags = _O_WTEXT;
#endif
int opened_handle = _open_osfhandle (reinterpret_cast<intptr_t>(os_handle),
flags | base_flags);
assert (opened_handle != -1 && "_open_osfhandle");
if (opened_handle == -1)
return false;
int dupd_handle = _dup2 (opened_handle, dest_handle);
assert (dupd_handle != -1 && "_dup2");
return dupd_handle == 0;
}
static
bool
try_fdopen (FILE * f, int handle, char const * mode)
{
FILE * tmp = _fdopen (handle, mode);
if (tmp && f)
*f = *tmp;
return !! tmp;
}
static
HANDLE
try_dup_os_handle (HANDLE src)
{
if (! usable_handle (src))
return INVALID_HANDLE_VALUE;
HANDLE dest = INVALID_HANDLE_VALUE;
HANDLE const process = GetCurrentProcess ();
if (DuplicateHandle (process, src, process, &dest, 0, TRUE,
DUPLICATE_SAME_ACCESS))
return dest;
else
return INVALID_HANDLE_VALUE;
}
static
void
init_std_io ()
{
// Retrieve inherited standard handles. AttachConsole() will close
// the existing standard handles, so we duplicate them here first
// to keep them alive.
HANDLE os_stdin = try_dup_os_handle (GetStdHandle (STD_INPUT_HANDLE));
HANDLE os_stdout = try_dup_os_handle (GetStdHandle (STD_OUTPUT_HANDLE));
HANDLE os_stderr = try_dup_os_handle (GetStdHandle (STD_ERROR_HANDLE));
// Attach existing console or allocate a new one.
int ret = AttachConsole (ATTACH_PARENT_PROCESS);
if (ret)
OutputDebugString (_T("Attached existing console.\n"));
else
{
ret = AllocConsole ();
if (ret)
OutputDebugString (_T("Allocated new console.\n"));
else
OutputDebugString (_T("Failed to allocate new console.\n"));
assert (ret);
}
// Open a "POSIX" handle for each OS handle and then fdopen() a C stream
// for each such "POSIX" handle.
//
// Only use the standard handle provided by AttachConsole() if the standard
// handle from before AttachConsole() is not usable.
//
// Finally, re-open standard C stream.
if (! usable_handle (os_stdin))
os_stdin = GetStdHandle (STD_INPUT_HANDLE);
ret = try_reopen_std_handle (0, STD_INPUT_HANDLE, os_stdin, _O_RDONLY);
if (! ret)
goto do_stdout;
try_fdopen (stdin, 0, "r");
do_stdout:
if (! usable_handle (os_stdout))
os_stdout = GetStdHandle (STD_OUTPUT_HANDLE);
ret = try_reopen_std_handle (1, STD_OUTPUT_HANDLE, os_stdout, _O_WRONLY);
if (! ret)
goto do_stderr;
try_fdopen (stdout, 1, "w");
do_stderr:
if (! usable_handle (os_stderr))
os_stderr = GetStdHandle (STD_ERROR_HANDLE);
ret = try_reopen_std_handle (2, STD_ERROR_HANDLE, os_stderr, _O_WRONLY);
if (! ret)
goto done_stderr;
try_fdopen (stderr, 2, "w");
done_stderr:;
}
Build the application as a Win32 application (not a console application), and examine the parameters to decide whether or not to use the console window.
The following code is based on this.
To use a console; create a class called CConsoleAttacher. Use it as follows, basically if there are arguments then open a console which will connect to the CMD window if you started from that. Obviously with Win32 applications when you launch the main windows it detaches from the console so this needs to be handled early on before creating app windows (which is what you want to do anyway...)
CConsoleAttacher ca;
if (ca.hasArguments())
{
ca.ConnectToConsole();
}
printf ("Test output \n");
Create a class called CConsoleAttacher.
CConsoleAttacher.cpp
#include "StdAfx.h"
#include <windows.h>
#include <stdio.h>
#include <fcntl.h>
#include <io.h>
#include <iostream>
#include <fstream>
#include "ConsoleAttacher.h"
#ifndef _USE_OLD_IOSTREAMS
using namespace std;
#endif
static const WORD MAX_CONSOLE_LINES = 500;
CConsoleAttacher::CConsoleAttacher(void)
{
argv = CommandLineToArgvW(GetCommandLineW(), &argc);
}
CConsoleAttacher::~CConsoleAttacher(void)
{
LocalFree(argv);
}
int CConsoleAttacher::getArgumentCount(void)
{
return argc;
}
CString CConsoleAttacher::getArgument(int id)
{
CString arg ;
if (id < argc)
{
arg = argv[id];
}
return arg;
}
bool CConsoleAttacher::hasArguments(void)
{
return argc > 1;
}
void CConsoleAttacher::ConnectToConsole(void)
{
int hConHandle;
HANDLE lStdHandle;
CONSOLE_SCREEN_BUFFER_INFO coninfo;
FILE *fp;
// allocate a console for this app
if (!AttachConsole(ATTACH_PARENT_PROCESS))
{
if (!AllocConsole())
return;
}
// set the screen buffer to be big enough to let us scroll text
GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE),&coninfo);
coninfo.dwSize.Y = MAX_CONSOLE_LINES;
SetConsoleScreenBufferSize(GetStdHandle(STD_OUTPUT_HANDLE),coninfo.dwSize);
// redirect unbuffered STDOUT to the console
lStdHandle = GetStdHandle(STD_OUTPUT_HANDLE);
hConHandle = _open_osfhandle((intptr_t)lStdHandle, _O_TEXT);
fp = _fdopen( hConHandle, "w" );
*stdout = *fp;
setvbuf( stdout, NULL, _IONBF, 0 );
// redirect unbuffered STDIN to the console
lStdHandle = GetStdHandle(STD_INPUT_HANDLE);
hConHandle = _open_osfhandle((intptr_t)lStdHandle, _O_TEXT);
fp = _fdopen( hConHandle, "r" );
*stdin = *fp;
setvbuf( stdin, NULL, _IONBF, 0 );
// redirect unbuffered STDERR to the console
lStdHandle = GetStdHandle(STD_ERROR_HANDLE);
hConHandle = _open_osfhandle((intptr_t)lStdHandle, _O_TEXT);
fp = _fdopen( hConHandle, "w" );
*stderr = *fp;
setvbuf( stderr, NULL, _IONBF, 0 );
// make cout, wcout, cin, wcin, wcerr, cerr, wclog and clog
// point to console as well
ios::sync_with_stdio();
}
CConsoleAttacher.h
#pragma once
class CConsoleAttacher
{
private:
int argc;
wchar_t** argv;
public:
CConsoleAttacher(void);
~CConsoleAttacher(void);
int getArgumentCount(void);
CString CConsoleAttacher::getArgument(int id);
void ConnectToConsole(void);
bool hasArguments(void);
};