Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations Mike Lewis on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

How to Add a path to system variables?

Status
Not open for further replies.

Insider1984

Technical User
Feb 15, 2002
132
US
I have a program that requires a few dll files but I'd like to stick them in a different directory and want my program to add the directory path to the system variables.

AKA C:\Windows\System;D:\MyProgram\DLL

Is there a function to do this?

Anyone use Innosetup? any chance inno can do it?

Thanks!

=====================
Insider
4 year 'on the fly' programmer
C++ Basic Java
 
Any reason why you can't just modify the PATH Environment variable on your machine and leave it as a permanent setting?
 
Thanks for the question. The problem is that this program will be running on about 200 machines across the company. The work around I have right now is to run a very large installer from CD when I only need a few binary files and the environment variable added.

So the goal would be during my smaller/faster installation or through Inno Setup script to modify the system variable when I load.

Inno Setup has a passin to overwrite the current path variable but now to append to it.

Thanks again.

=====================
Insider
4 year 'on the fly' programmer
C++ Basic Java
 
Have you tried putting all the dlls in the same directory as the executable. Can't quite remember the order in which it picks up the dlls but I think it is the working directory first, then the stuff in the path. I may be wrong as I switch between Unix and Windows quite often and get quite confused.

Alternatively (may be a bad idea), add .\ to the path. As long as the working directory is correct in the shortcut, it should work.
 
If you want to programatically do this, open and edit the HKEY_CURRENT_USER\Environment\Path. This will ensure persistency (next time you reboot, what you added will still be there).

Then you need to notify all applications that an environmental change has occured. You do so as it follows:

char lParameter[]="Environment";
BroadcastSystemMessage (BSF_POSTMESSAGE | BSF_IGNORECURRENTTASK | BSF_ALLOWSFW,NULL,WM_SETTINGCHANGE,0,(int)lParameter);

The lParameter MUST be "Environment". The other parameters of BroadcastSystemMessage are self-explanatory (or you could look it up in the MSDN).

P.S.: For an application to "see" this change in the environment, it must handle the WM_SETTINGCHANGE message, and re-read the environment variables. (Most of them do).
 
Thanks for the help but I'm more asking "how to open and edit the path variable within a MFC Dialog application.

The reason I can't stick (or don't want to stick) all the applications and dll into the same folder is because the dlls are about 400 MB and there are about 550 of them.

I appreciate your help on this.

=====================
Insider
4 year 'on the fly' programmer
C++ Basic Java
 
You can call getenv with "Path". You will get a pointer to the string. setenv will keep the value set for the lifetime of the app. I have had to use this for NLS_LANG for Oracle to support Japanese.

Do the computers need to retain the information when they are not running your application? I believe the values may be stored in the registry as well where you can make direct modifications but I am not 100% on this.

Hope this helps.
Matt
 
Yes Matt

I would like the setting to be there forever. I'm just writing a slim version of the installer and all I do is install the application dll and other files required (drivers for hardware etc) in order to run it. Right now we have it down from 5 installers down to 2. If I can correctly read in and forever modify the Path variable I'd get it down to one.

Thanks again.

=====================
Insider
4 year 'on the fly' programmer
C++ Basic Java
 
Hi there.
This C++ cmdline proggy is 4 u:

Code:
/*! This small program adds a directory to the Win32
      path variable or removes it from there.

    Copyright (c) 2004 by PHaX - all rights reserved.
    If you use this code in your software, drop me a note :)
    Ask questions by sending a mail to
      coding at helger.com

    The directory must be specified by the -p command
      line parameter.
    Example call:
      pathmod -a "-pc:\program file\PathModifier"
    Adds the path c:\program file\PathModifier to the users
      PATH variable.
    The call
      pathmod -r "-pc:\program file\PathModifier"
    removes the pathe from the users PATH

    Compiles with Visual C++ 2003
    Should work with others too!

    ANSI version:
      cl -MD pathmod.cxx

    Unicode version:
      cl -MD pathmod.cxx -D_UNICODE -DUNICODE
 */

#include <crtdbg.h>
#include <windows.h>
#include <tchar.h>

#ifdef _MSC_VER
#pragma comment (lib, "advapi32.lib")
#pragma comment (lib, "user32.lib")
#endif

int _tmain (int argc, TCHAR**argv)
{
  bool bAdd = false;
  bool bRemove = false;
  LPTSTR pPathToAdd = NULL;
  bool bChanged = false;
  HKEY hRoot = NULL;
  LPCTSTR pEnvPath = NULL;
  DWORD eType = 0;

  for (int i = 1; i < argc; ++i)
  {
    LPTSTR pArg = argv[i];
    if (*pArg == _T ('-'))
    {
      ++pArg;
      if (*pArg == _T ('a'))
        bAdd = true;
      else
      if (*pArg == _T ('r'))
        bRemove = true;
      else
      if (*pArg == _T ('p'))
      {
        pPathToAdd = new TCHAR [_tcslen (pArg + 1) + 1];
        _tcscpy (pPathToAdd, pArg + 1);
      }
      else
      if (*pArg == _T ('l'))
      {
        hRoot = HKEY_LOCAL_MACHINE;
        pEnvPath = _T ("SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Environment");
        eType = REG_EXPAND_SZ;
      }
      else
      if (*pArg == _T ('?'))
      {
        MessageBox (NULL, _T ("Parameters:\n")
                          _T ("\t-a\tadd to PATH\n")
                          _T ("\t-r\tremove from PATH\n")
                          _T ("\t-pDIR\tthe path to add\n")
                          _T ("\t-l\tapply to local machine\n"),
                          _T ("Usage"), MB_OK);
        return 1;
      }
    }
  }

  // if no directory is set, issue an error
  if (!pPathToAdd)
  {
    MessageBox (NULL, _T ("Error: No path was specified. Use -? to show the usage."), _T ("Error"), MB_OK | MB_ICONERROR);
    return 1;
  }

  // add more than one path at once is not allowed
  if (_tcschr (pPathToAdd, _T (';')) != NULL)
  {
    MessageBox (NULL, _T ("Error: Don't try to add pathes that contain a semicolon ';'. Call separately."), _T ("Error"), MB_OK | MB_ICONERROR);
    return 1;
  }

  // uppercase the path (default behaviour)
  CharUpperBuff (pPathToAdd, _tcslen (pPathToAdd));

  LONG n;

  // HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\Environment
  // HKEY_CURRENT_USER\Environment
  HKEY hKey;
  n = RegOpenKeyEx (hRoot    ? hRoot    : HKEY_CURRENT_USER,
                    pEnvPath ? pEnvPath : _T ("Environment"),
                    0,
                    KEY_QUERY_VALUE | (bAdd || bRemove ? KEY_SET_VALUE : 0),
                    &hKey);
  _ASSERTE (n == ERROR_SUCCESS);
  if (n == ERROR_SUCCESS)
  {
    // query value length
    DWORD nType, nBufSize;
    n = RegQueryValueEx (hKey, _T ("Path"), NULL, &nType, NULL, &nBufSize);
    _ASSERTE (n == ERROR_SUCCESS);
    _ASSERTE (nType == (eType ? eType : REG_SZ));

    // query value
    LPTSTR pPath = new TCHAR [nBufSize / sizeof (TCHAR)];
    n = RegQueryValueEx (hKey, _T ("Path"), NULL, &nType, (LPBYTE) pPath, &nBufSize);
    _ASSERTE (n == ERROR_SUCCESS);
    _ASSERTE ((nBufSize / sizeof (TCHAR)) == (_tcslen (pPath) + 1));

    // find position
    // make a copy in uppercase for searching
    LPTSTR pUCPath = new TCHAR [_tcslen (pPath) + 1];
    _tcscpy (pUCPath, pPath);
    CharUpperBuff (pUCPath, _tcslen (pUCPath));
    LPTSTR pPathToAddPos = _tcsstr (pUCPath, pPathToAdd);
    size_t pPathToAddIndex = pPathToAddPos ? pPathToAddPos - pUCPath : 0;
    delete [] pUCPath;

    if (bAdd)
    {
      // add path
      if (pPathToAddPos != NULL)
      {
        MessageBox (NULL, _T ("YourPath is already in the path"), _T ("Warning"), MB_OK | MB_ICONWARNING);
      }
      else
      {
        // add to path (first or append)
        LPTSTR pNewPath = new TCHAR [_tcslen (pPath) + 1 + _tcslen (pPathToAdd) + 1];
        _tcscpy (pNewPath, pPath);
        if (*pNewPath)
          _tcscat (pNewPath, _T (";"));
        _tcscat (pNewPath, pPathToAdd);

        // set new value
        n = RegSetValueEx (hKey, _T ("Path"), 0, (eType ? eType : REG_SZ), (LPBYTE) pNewPath, (_tcslen (pNewPath) + 1) * sizeof (TCHAR));
        _ASSERTE (n == ERROR_SUCCESS);
        if (n == ERROR_SUCCESS)
        {
          bChanged = true;
          MessageBox (NULL, _T ("YourPath was successfully added to the path"), _T ("Information"), MB_OK | MB_ICONINFORMATION);
        }
        else
          MessageBox (NULL, _T ("Failed to add YourPath to the path"), _T ("Error"), MB_OK | MB_ICONERROR);
        delete [] pNewPath;
      }
    }
    else
    if (bRemove)
    {
      // remove path
      if (pPathToAddPos != NULL)
      {
        // remove from path
        LPTSTR pNewPath = new TCHAR [_tcslen (pPath) + 1];
        _tcscpy (pNewPath, pPath);
        // skip the previous ';' too?
        size_t nLen = _tcslen (pPathToAdd);
        if (pPathToAddIndex > 0 && pNewPath[pPathToAddIndex - 1] == _T (';'))
        {
          // was append -> remove ';'
          --pPathToAddIndex;
          ++nLen;
        }
        else
        {
          // first element! an ';' at the back?
          if (pNewPath [pPathToAddIndex + nLen] == _T (';'))
            ++nLen;
        }
        // move everything from right to left
        memmove (pNewPath + pPathToAddIndex, pNewPath + pPathToAddIndex + nLen, (_tcslen (pNewPath + pPathToAddIndex + nLen) + 1) * sizeof (TCHAR));

        // set new value
        n = RegSetValueEx (hKey, _T ("Path"), 0, (eType ? eType : REG_SZ), (LPBYTE) pNewPath, (_tcslen (pNewPath) + 1) * sizeof (TCHAR));
        _ASSERTE (n == ERROR_SUCCESS);
        if (n == ERROR_SUCCESS)
        {
          bChanged = true;
          MessageBox (NULL, _T ("YourPath was successfully removed from the path"), _T ("Information"), MB_OK | MB_ICONINFORMATION);
        }
        else
          MessageBox (NULL, _T ("Failed to remove YourPath from the path"), _T ("Error"), MB_OK | MB_ICONERROR);
        delete [] pNewPath;
      }
      else
      {
        MessageBox (NULL, _T ("YourPath is not in the path"), _T ("Warning"), MB_OK | MB_ICONWARNING);
      }
    }
    else
    {
      // info only
      if (pPathToAddPos != NULL)
        MessageBox (NULL, _T ("YourPath is already in the path"), _T ("Information"), MB_OK | MB_ICONINFORMATION);
      else
        MessageBox (NULL, _T ("YourPath is not in the path"), _T ("Information"), MB_OK | MB_ICONINFORMATION);
    }

    delete [] pPath;

    // close again
    RegCloseKey (hKey);
  }

  delete [] pPathToAdd;

  if (bChanged)
  {
    DWORD_PTR dwReturnValue;
    LRESULT nRet = SendMessageTimeout (HWND_BROADCAST,
                                       WM_SETTINGCHANGE,
                                       0,
                                       (LPARAM) _T ("Environment"),
                                       SMTO_ABORTIFHUNG | SMTO_NOTIMEOUTIFNOTHUNG,
                                       5000,
                                       &dwReturnValue);
    _ASSERTE (nRet != 0);
  }

  return 0;
}
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top