I am trying to launch a process using CreateProcess() I have to modify the Path environment variable as well as add some environment variables of my own. What I am doing is I get the parent's environment block using GetEnvironmentStrings(). I basically copy the parent env block and only modify the Path variable. I then use my new environment block in CreateProcess.

NOTE: I have tried Unicode and ANSI version of env block and it works when I pass it with Path unmodified or if I only add new environment variables to the environment block (e.g. ALEX=TRUE). However any attempts to modify Path results in error 87. Below is my code. Is there any restrictions in modifying Path environment variable during process creation? I can't seem to find any documentation that says so. At first I thought it was the env block or env var size but it they are within the limit. Maximum size for my env block is only 4000. Coding for Windows2003.

Below is ANSI version.

int main(int argc, char* argv[])
{	
	int retval=0;

	LPTSTR lpszEnvEntryBuff = NULL;	/* Buffer for reading the parent environment block */
	LPTSTR lpszPrevEnvEntry = NULL;	/* Pointer to the previous read entry of parent env block */
	LPTSTR lpszNextEnvEntry = NULL;	/* Pointer to next environment entry to be added */
	LPTCH lpvEnv	 = NULL;		/* Parent environment block	*/
	LPTCH lpvNewEnv = NULL;			/* New environment block with altshell entries added	  */
	LPTCH lpvTmpEnv = NULL;			/* Placeholder for reallocating the new environment block */

	int iEnvEntryBuffLen = 0;	/* Length of current environment entry being parsed	*/
	int iCurrNewEnvSize  = 0;	/* Current size of the new environment block		*/
	int iPrevNewEnvSize  = 0;	/* Previous size of the new environment block		*/

	char szNewPathBuff[BUFFSIZE];
	LPTSTR lpszNewPathBuff = NULL;
	int iNewPathSize	= 0; 

	char szShellPath[BUFFSIZE];
	char szTMP[BUFFSIZE];

	/* Load Config File entries */
	GetShellEnvVars(szShellPath, szTMP);

	/* Get a pointer to the environment block. */
	lpvEnv = GetEnvironmentStrings();

	/* If the returned pointer is NULL, exit. */
	if (lpvEnv != NULL)
	{ 
		/* Variable strings are separated by NULL byte, and the block is 
		   terminated by a NULL byte. Copy parent environment as the environment 
		   returned by GetEnvironmentStrings()is readonly */

		lpszEnvEntryBuff = (LPTSTR) lpvEnv;

		while (*lpszEnvEntryBuff)
		{
			/* Check for PATH, TEMP, TMP. Modify according to New Shell Environment Vars */
			if (Similar("PATH=", lpszEnvEntryBuff, 5))
			{
				lpszPrevEnvEntry = lpszEnvEntryBuff; /* Store current pos of buffer in parent env  block */

				NullFld(szNewPathBuff, BUFFSIZE); /* Clean the buffer */

				iNewPathSize = strlen(lpszEnvEntryBuff) + strlen(szShellPath);
				sprintf(szNewPathBuff, "PATH=%s;%s", szShellPath, lpszEnvEntryBuff + 5);

				lpszEnvEntryBuff = szNewPathBuff;
			}
			
			iEnvEntryBuffLen = strlen(lpszEnvEntryBuff);
			iCurrNewEnvSize  = iCurrNewEnvSize + iEnvEntryBuffLen + 1;

			/* Reallocate space for lpvNewEnv per additional environment entry */
			lpvTmpEnv = (LPTCH)realloc(lpvNewEnv, iCurrNewEnvSize);

			if (!lpvTmpEnv)
			{
				return -1;
			}
			lpvNewEnv = lpvTmpEnv;
			
			/* Copy current Enviroment Entry to new Environment Block then */
			/* go to end of new Environment Block and add a NULL byte      */

			lpszNextEnvEntry = lpvNewEnv + iPrevNewEnvSize;
			MemCopy(lpszEnvEntryBuff, lpszNextEnvEntry, iEnvEntryBuffLen);
			lpszNextEnvEntry = lpszNextEnvEntry + iEnvEntryBuffLen;
			*lpszNextEnvEntry = '\0';

			iPrevNewEnvSize = iCurrNewEnvSize;

			if (lpszPrevEnvEntry)
			{
				lpszEnvEntryBuff = lpszPrevEnvEntry; /* restore to saved position before incrementing*/
				lpszPrevEnvEntry = NULL;
			}

			lpszEnvEntryBuff = lpszEnvEntryBuff + iEnvEntryBuffLen + 1;
		}
		FreeEnvironmentStrings(lpvEnv); 

		/* Add terminating NULL character */
		lpvTmpEnv = (LPTCH)realloc(lpvNewEnv, iCurrNewEnvSize + 1);

		if (!lpvTmpEnv)
		{
			return -1;
		}
		lpvNewEnv = lpvTmpEnv;

		lpszNextEnvEntry = lpvNewEnv + iCurrNewEnvSize;
		*lpszNextEnvEntry = '\0';

		lpszEnvEntryBuff = (LPTSTR) lpvNewEnv;

		while (*lpszEnvEntryBuff)
		{
			iEnvEntryBuffLen = strlen(lpszEnvEntryBuff);
			lpszEnvEntryBuff += iEnvEntryBuffLen + 1;
		}
	}

	/*Create Child*/
	STARTUPINFO StartupInfo;
    PROCESS_INFORMATION ProcessInfo;

    GetStartupInfo(&StartupInfo);
	StartupInfo.hStdInput  = GetStdHandle(STD_INPUT_HANDLE);
	StartupInfo.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
	StartupInfo.hStdError  = GetStdHandle(STD_ERROR_HANDLE);
	StartupInfo.dwFlags    = STARTF_USESTDHANDLES;
	StartupInfo.lpDesktop  = NULL;

    ZeroMemory(&ProcessInfo, sizeof(ProcessInfo));

	if( !CreateProcess( NULL,   // No module name (use command line)
        "run.exe D:\\dev\\obj\\FORM.gnt APPS",        // Command line
        NULL,           // Process handle 
        NULL,           // Thread handle 
        TRUE,          // handle inheritance
        NULL,              //  creation flags
        lpvNewEnv,           // environment block
        NULL,           // Use parent's starting directory 
        &StartupInfo,   // Pointer to STARTUPINFO structure
        &ProcessInfo )  // Pointer to PROCESS_INFORMATION structure
    ) 
    {
        return -1;
    }

    // Wait until child process exits.
    WaitForSingleObject(ProcessInfo.hProcess, INFINITE);

    // Close process and thread handles. 
    CloseHandle(ProcessInfo.hProcess);
    CloseHandle(ProcessInfo.hThread);

	free(lpvNewEnv);

	return retval;
}

Recommended Answers

All 2 Replies

You calculate the position of the new environment variable (line 81) based on the length of the current one. It is OK as long as you use the original length. In case of PATH it is not so.

You calculate the position of the new environment variable (line 81) based on the length of the current one. It is OK as long as you use the original length. In case of PATH it is not so.

Finally figured it out. Its not the code. Its the path. Anything you add in Path must exist. Had a missing folder in the path I added. When I created a blank folder with the name of the path it worked. :)

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.