Reputation: 420
Dear my stack overflow comrades. I have a question. I cannot find the answer via google. Thus I have no other alternative.
But first, once upon a time I was a GUI dunce, until I met upon fam trinli videos on game making in SFML. Through his source code I discovered and ventured deep into the Win32 universe and discovered CreateProcess. Since then CreateProcess has been a pain in the neck!
Fast forward to today. I am still married to Cpp, and thus obliged to use CreateProcess for my latest work which is connecting to MariaDb Server.
I thought I could solve my problem, with my little function wrapper around CreateProcess, but was a struck problem. ReadFile deadlocks, and stuff. I decided to just make a Process class and abstract away every functionality of CreateProcess. Have a look...
class Process
{
public:
enum { INVALID_EXIT_CODE = -1, };
enum { AUTO_KILL=1, WAIT=2, DEBUG=4, };
struct Builder
{
//to allow easy building of sorted environmment strings
using EnvList = std::map <std::string,std::istringstream>;
istringstream cmd;
EnvList env_list;
Jav::cstring app_name;
Jav::cstring current_dir;
STARTUPINFOA si;
};
public:
Process(const char *cmd=NULL,const char *current_dir=NULL,const char *app_name=NULL);
~Process ();
public:
bool launch();
int stop();
int wait(uint time=INFINITE);
size_t read (void*,size_t);
size_t readError(void*,size_t);
size_t write(const void*,size_t);
size_t write(const char*);
size_t read_async(void*,size_t);
size_t readError_async(void*,size_t);
size_t write_async(const void*,size_t);
size_t write_async(const char*);
void setAppName(const char*);
void setCurrentDir(const char*);
void addArg(const char*);
void addEnv(const char *var,const char *val);
void setConsoleTitle(const char*);
void setConsoleWidth(int);
void setConsoleHeight(int);
void setConsoleTextAndFillColor(int);
void setWindowVisibility(int);
void setWindowXpos(int);
void setWindowYpos(int);
void setWindowWidth(int);
void setWindowHeight(int);
void setWaitTime(uint);
void setParentMode(uint);
void addParentMode(uint);
void removeParentMode(uint);
Jav::cstring toString();
Jav::cstring getError() { return error; }
private:
Jav::cstring buildEnvironment();
private:
PROCESS_INFORMATION info = {};
Jav::rFile m_read_end;
Jav::rFile m_error_end;
Jav::wFile m_write_end;
OVERLAPPED async_struct;
uint flags = 0;
uint waitTime = INFINITE;
Builder *builder;
Jav::Error error = "";
};
Jav::cstring getEnvVar(const char *name);
Jav::cstring findExecutableAssociatedWithFileName(const char*);
Jav::cstring findExecutableAssociatedWithFileExtension(const char*);
I have implemented all functions except the asynchronous since I now understand how to use synchronous read and write. Basically you must know what the child function you are trying to connect to does. If you try to read the child process and it never ever writes to std out or std error, your parent process wont have anything to read and will deadlock.
I also now have a firm understanding of Pipes. A pipe is made up of two handles. one handle for writing and one handle for reading. By using the function CreatePipe, it will auto setup the writing handle and the reading handle. Registering these two handles as one pipe. A system buffer is created to store written data and is decremented when the reading handle reads. This is also how binders work in android.
THE REAL PROBLEM
All was going well until I put my Process class to the test and tried to run notepad. I added two path strings to its environment. By not passing a Null environment, the process doesnt inherit the system environment variables; and in the case of notepad it lead to note pad returning a error code, 0xc0150004.Obviously notepad requires certain System Environment variables.
How the heck do I allow the child process to inherit all System Variables and append my user environment strings to that?
Upvotes: 1
Views: 1480
Reputation: 598134
How the heck do I allow the child process to inherit all System Variables and append my user environment strings to that?
The environment block you pass to CreateProcess()
is what the new process receives, no more, no less. The new process inherits the existing environment block only when the lpEnvironment
parameter is NULL
.
MSDN demonstrates how to use (Get|Set)EnvironmentVariable()
to let the new process inherit an environment block containing modified variables (but not appended variables):
Changing Environment Variables
So, to do what you are asking, you will have to retrieve the calling process' existing environment block with GetEnvironmentStrings()
, make a copy of it, append your custom variables to the copy as needed, pass the copy to CreateProcess()
, and then free the copy.
Upvotes: 2