Allegro.cc - Online Community

Allegro.cc Forums » Programming Questions » Communication

Credits go to Carrus85, kazzmir, Sevalecan, and X-G for helping out!
This thread is locked; no one can reply to it. rss feed Print
Communication
ImLeftFooted
Member #3,935
October 2003
avatar

So Program A on exit has to start up Program B and pass some text-based information to it. What is the best way to do this?

The applications will be running on windows so using something windows-specific is a possibility, but if its just as easy I'd like to do it in a portable fashion.

kazzmir
Member #1,786
December 2001
avatar

Command line arguments?

X-G
Member #856
December 2000
avatar

If you only need to give it the data once at the start, command line arguments. Otherwise, look into named pipes or some other inter-process communication protocol.

--
Since 2008-Jun-18, democracy in Sweden is dead. | 悪霊退散!悪霊退散!怨霊、物の怪、困った時は ドーマン!セーマン!ドーマン!セーマン! 直ぐに呼びましょう陰陽師レッツゴー!

ImLeftFooted
Member #3,935
October 2003
avatar

Command Line would be easiest, but doesn't it have some static limit?

Sevalecan
Member #4,686
June 2004
avatar

Something like that.

Pipes would be better for binary or large amounts of data. And as far as ease goes... At least they aren't tcp sockets, which are a royal pain in the ass(of course, you could use them.... if you were masochist).

TeamTerradactyl: SevalecanDragon: I should shoot you for even CONSIDERING coding like that, but I was ROFLing too hard to stand up. I love it!
My blog about computer nonsense, etc.

X-G
Member #856
December 2000
avatar

You really should tell us what kind of data and how much you need to pass. The correct method depends on these factors.

--
Since 2008-Jun-18, democracy in Sweden is dead. | 悪霊退散!悪霊退散!怨霊、物の怪、困った時は ドーマン!セーマン!ドーマン!セーマン! 直ぐに呼びましょう陰陽師レッツゴー!

Carrus85
Member #2,633
August 2002
avatar

Quote:

So Program A on exit has to start up Program B and pass some text-based information to it. What is the best way to do this?

The applications will be running on windows so using something windows-specific is a possibility, but if its just as easy I'd like to do it in a portable fashion.

On nix, exec* works nicely. On Windows, it looks like exec exists, but I'm not sure it behaves exactly the same way as it does on nix. (exec on nix replaces the current process image with the given process image and starts execution, effectively replacing the current process with a completely separate process (that has the same Process ID as the "parent" process)) As for Program B text arguments, exec maintains the file descriptors across the two "processes", allowing you to freopen on say, stdin, for example (allowing redirection). (Once again, *nix programming, not sure of the windows equivalents (or if the windows equivalents work the same way).

ImLeftFooted
Member #3,935
October 2003
avatar

The data is going to be in this format:

"Descr"{"blah")
"descr two"{"blah":"0","blah2":"1"}

kazzmir
Member #1,786
December 2001
avatar

Write it to a file and give the file as a command line argument.

ImLeftFooted
Member #3,935
October 2003
avatar

What about concurrency issues? Also where to write the file? What if the program does not have permissions to write to a given folder.

Finding the proper folder to write stuff is a battle I'd rather not fight.. :-/

[update]
Getting a pipe to work is way too much work. There has to be an easier way to do this...

[update 2]
Nevermind, I got pipes working (via lots of copy paste from msdn). Talk about complicated code:

1#ifndef RUNNER_H
2#define RUNNER_H
3 
4#include <string>
5 
6// 'Runs' a given program with specified options.
7// You can access the programs stdin using this class.
8class Runner {
9public:
10 // Begins running the program specified in 'command'. Command-line arguments
11 // are also passed into command.
12 Runner(const std::string &command) throw(const char*);
13 
14 ~Runner() throw(const char*);
15 
16 // Writes 'message' onto the programs stdin buffer.
17 bool write(const std::string &message) throw(const char*);
18 
19 class Data {
20 public:
21 virtual bool write(const std::string &message) throw(const char*) {return false;}
22 
23 } *pData;
24};
25 
26#endif

1#include "runner.h"
2using namespace std;
3 
4#ifdef WIN32
5#include <windows.h>
6 
7class WindowsData : public Runner::Data {
8public:
9 // Opens handles, calls CreateProcess
10 WindowsData(const string &command) throw(const char*);
11 
12 // Closes the child program's input handle
13 virtual ~WindowsData() throw(const char*);
14 
15 // Writes to the program's stdin handle.
16 virtual bool write(const std::string &message) throw(const char*);
17 
18private:
19 
20 // Handles to the programs stuff.
21 HANDLE hChildStdinRd, hChildStdinWr,
22 hChildStdoutRd, hChildStdoutWr,
23 hInputFile, hStdout;
24};
25 
26WindowsData::WindowsData(const string &command) throw(const char*)
27{
28 SECURITY_ATTRIBUTES saAttr;
29
30// Set the bInheritHandle flag so pipe handles are inherited.
31
32 saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
33 saAttr.bInheritHandle = TRUE;
34 saAttr.lpSecurityDescriptor = NULL;
35 
36// Get the handle to the current STDOUT.
37
38 hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
39
40// Create a pipe for the child process's STDOUT.
41
42 if (! CreatePipe(&hChildStdoutRd, &hChildStdoutWr, &saAttr, 0))
43 throw("Stdout pipe creation failed\n");
44 
45// Ensure the read handle to the pipe for STDOUT is not inherited.
46 
47 SetHandleInformation( hChildStdoutRd, HANDLE_FLAG_INHERIT, 0);
48 
49// Create a pipe for the child process's STDIN.
50
51 if (! CreatePipe(&hChildStdinRd, &hChildStdinWr, &saAttr, 0))
52 throw("Stdin pipe creation failed\n");
53 
54// Ensure the write handle to the pipe for STDIN is not inherited.
55
56 SetHandleInformation( hChildStdinWr, HANDLE_FLAG_INHERIT, 0);
57 
58 PROCESS_INFORMATION piProcInfo;
59 STARTUPINFO siStartInfo;
60 BOOL bFuncRetn = FALSE;
61
62// Set up members of the PROCESS_INFORMATION structure.
63
64 ZeroMemory( &piProcInfo, sizeof(PROCESS_INFORMATION) );
65
66// Set up members of the STARTUPINFO structure.
67
68 ZeroMemory( &siStartInfo, sizeof(STARTUPINFO) );
69 siStartInfo.cb = sizeof(STARTUPINFO);
70 siStartInfo.hStdError = hChildStdoutWr;
71 siStartInfo.hStdOutput = hChildStdoutWr;
72 siStartInfo.hStdInput = hChildStdinRd;
73 siStartInfo.dwFlags |= STARTF_USESTDHANDLES;
74 
75 CHAR buf[command.size() + 1];
76 
77 memcpy(buf, command.c_str(), command.size() + 1);
78
79// Create the child process.
80
81 bFuncRetn = CreateProcess(NULL,
82 buf, // command line
83 NULL, // process security attributes
84 NULL, // primary thread security attributes
85 TRUE, // handles are inherited
86 0, // creation flags
87 NULL, // use parent's environment
88 NULL, // use parent's current directory
89 &siStartInfo, // STARTUPINFO pointer
90 &piProcInfo); // receives PROCESS_INFORMATION
91
92 if (bFuncRetn == 0)
93 throw("CreateProcess failed\n");
94 else
95 {
96 //CloseHandle(piProcInfo.hProcess);
97 //CloseHandle(piProcInfo.hThread);
98 }
99}
100 
101WindowsData::~WindowsData() throw(const char*)
102{
103// Close the pipe handle so the child process stops reading.
104
105 if (! CloseHandle(hChildStdinWr))
106 throw("Close pipe failed\n");
107}
108 
109bool WindowsData::write(const string &msg) throw(const char*)
110{
111 DWORD dwWritten;
112
113 if (! WriteFile(hChildStdinWr, msg.c_str(), msg.size() + 1, &dwWritten, NULL))
114 return false;
115
116 return true;
117}
118 
119#endif
120 
121Runner::Runner(const string &command) throw(const char*)
122 :
123#ifdef WIN32
124 pData(new WindowsData(command))
125#else
126 pData(0)
127#endif
128{
129 
130}
131 
132Runner::~Runner() throw(const char*)
133{
134 delete pData;
135}
136 
137bool Runner::write(const string &msg) throw(const char*)
138{
139 if(pData)
140 return pData->write(msg);
141 
142 return false;
143}

I left room for implementations on other platforms.

Thomas Fjellstrom
Member #476
June 2000
avatar

And in unix it can be as easy as "named pipes" (a special file that both processes open), or the "pipe" function which returns two file handles which correspond to each end of the pipe.

--
Thomas Fjellstrom - [website] - [email] - [Allegro Wiki] - [Allegro TODO]
"If you can't think of a better solution, don't try to make a better solution." -- weapon_S
"The less evidence we have for what we believe is certain, the more violently we defend beliefs against those who don't agree" -- https://twitter.com/neiltyson/status/592870205409353730

kazzmir
Member #1,786
December 2001
avatar

Maybe it would be easier to just open up a socket and write to that?

ImLeftFooted
Member #3,935
October 2003
avatar

Ya probably. But using a pipe like this handles concurrency in the best possible way.

So sockets would be easier but pipes would be less evil.

Go to: