使用C ++在Windows中更新PATH环境变量

时间:2014-01-20 17:45:50

标签: c++ windows winapi process

我正在尝试从当前进程启动一个新进程。我正在使用CreateProcess()来启动它。问题是我需要在PATH中拥有某些目录才能成功完成。这是我当前的实现,但它不起作用。我做错了什么?

// Environment variables
char *env = new char[2048];
char *ptr = env;

char temp[MAX_PATH] = "PATH=";
strcpy(ptr, strcat(temp, plugin_path));
ptr += strlen(ptr) + 1;

char  temp2[MAX_PATH] = "PATH=";
strcpy(ptr, strcat(temp, lib_path));
ptr += strlen(ptr) + 1;
*ptr = '\0';

 // Execute
STARTUPINFO si;
PROCESS_INFORMATION pi;

ZeroMemory(&si, sizeof(si));
si.cb = sizeof(si);
ZeroMemory(&pi, sizeof(pi));

// error checking required
if(!CreateProcess(
    NULL,             // application name
    command_path,   // app.exe
    NULL,
    NULL,
    TRUE,
    0,
    env,           // environment
    NULL,
    &si,
    &pi)) {
    std::cout << GetLastError();
    return 1;
}

WaitForSingleObject(pi.hProcess, INFINITE);
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
std::cout << "Process Started!";

如果需要其他任何内容,请告诉我。

编辑:有人在下面提到我需要更具体一点。它在环境变量未被传递的意义上不起作用。它失败,因为库路径不在PATH中。 createProcess实际上确实启动了它。

EDIT2:这是更新后的代码。同样的问题。此外,CreateProcess抛出错误1087,这似乎在文档中不存在。

// Environment variables
char env[2048];
char *ptr = env;
char *path_path = getenv("PATH");

// copy original path
memcpy(ptr, path_path, strlen(path_path));
ptr += strlen(ptr) + 1;
memcpy(ptr, ";", 1);
ptr++;

// copy plugin path
memcpy(ptr, plugin_path, strlen(plugin_path));
ptr += strlen(plugin_path) + 1;
memcpy(ptr, ";", 1);
ptr++;

// copy libpath
memcpy(ptr, lib_path, strlen(lib_path));
ptr += strlen(lib_path) + 1;
memcpy(ptr, ";", 1);
ptr++;

// double null terminated
memcpy(ptr, "\0\0", 2);

std::cout << "ENV : " << env << std::endl;

// error checking required
if(!CreateProcess(
    NULL,             // application name
    command_path,   // app.exe
    NULL,
    NULL,
    TRUE,
    0,
    env,           // environment
    NULL,
    &si,
    &pi)) {
    std::cout << GetLastError();
    return 1;
}

WaitForSingleObject(pi.hProcess, INFINITE);
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
std::cout << "Process Started!";

2 个答案:

答案 0 :(得分:3)

PATH变量是单个变量。该变量中列出了不同的目录,以分号分隔。但是你试图两次定义变量。这是错误的。

代码应该是这样的(假设你想扩展现有的路径):

char *env = new char[2048]; // fingers crossed this is enough
strcpy(env, "PATH=");
strcat(env, getenv("PATH"));
strcat(env, ";");
strcat(env, plugin_path);
strcat(env, ";");
strcat(env, lib_path);
env[strlen(env)+1] = '\0';

虽然这段代码(问题中你的代码是)只是要求缓冲区溢出。

如果使用C ++工具来构建字符串会更容易。例如:

std::stringstream ss;
ss << "PATH=" << getenv("PATH");
ss << ";" << plugin_path;
ss << ";" << lib_path;
ss << '\0';
std::string env = ss.str();

然后将env.c_str()传递给CreateProcess

这不仅使代码更易于阅读和验证,而且您知道不会超出任何缓冲区。

我还注意到您传递的环境中只定义了一个变量,即PATH。如果从调用进程的环境开始,将额外的目录添加到PATH,然后将其作为新进程的环境传递,则可能会更好。

答案 1 :(得分:0)

#include <iostream>
#include <windows.h>
#include <cstring>
#include "tchar.h"


void SetUserVariablePath(){
    HKEY hkey;
    long regOpenResult;
    const char key_name[] = "Environment";
    const char path[]="D:/custom_command";                                               //new_value path need to update 
    regOpenResult = RegOpenKeyEx(HKEY_CURRENT_USER,key_name, 0, KEY_ALL_ACCESS, &hkey);
    LPCSTR stuff = "VVS_LOGGING_PATH";                                                   //Variable Name 
    RegSetValueEx(hkey,stuff,0,REG_SZ,(BYTE*) path, strlen(path));
    RegCloseKey(hkey);
}



void GetUserVariablePath(){
    static const char path[] = "VVS_LOGGING_PATH" ;                                      //Variable Name 
    static BYTE buffer1[1000000] ;
    DWORD buffsz1 = sizeof(buffer1) ;
    {
        //HKEY_CURRENT_USER\Environment
        const char key_name[] = "Environment";
        HKEY key ;

        if( RegOpenKeyExA( HKEY_CURRENT_USER, key_name, 0, KEY_QUERY_VALUE, std::addressof(key) ) == 0 &&
            RegQueryValueExA( key, path, nullptr, nullptr, buffer1, std::addressof(buffsz1) ) == 0 )
        {
            std::cout << "The updated value of the user variable is :  " << reinterpret_cast<const char*>(buffer1) << '\n' ;
        }
    }
}

int main()
{   
    SetUserVariablePath();
    GetUserVariablePath();
    return 0;
}