Search code examples
delphidelphi-7

SetEnvironmentVariable not working


I need to set two environmental variables (when my application runs) for included 3rd party libraries.

The problem is that 'that way' it is not working, however when I run console application, set these two variables and then run the application, everything is okay ...

how to configure these two vars correctly?

i use the procedure:

function SetEnvVarValue(const VarName,
  VarValue: string): Integer;
begin
  // Simply call API function
  if SetEnvironmentVariable(PChar(VarName),
    PChar(VarValue)) then
    Result := 0
  else
    Result := GetLastError;
end;

It returns 0

Maybe the thing is, that i have the libraries being loaded on application startup. When my application stars I set then the variables and I do it too late ...?


Further information

I have included two units in dpr:

ImageMagick in 'C:\Program Files (x86)\Borland\Delphi7\Lib\Magick\magick\ImageMagick.pas', magick_wand in 'C:\Program Files (x86)\Borland\Delphi7\Lib\Magick\wand\magick_wand.pas';

And the Unit:

unit DoItFirst;

interface

uses
  Windows, Sysutils;

var
  s: string;
  error: Integer;

function _putenv_s(const lpName, lpValue: PChar): BOOL; cdecl; external 'msvcrt.dll';

implementation

function GetEnvVarValue(const VarName: string): string;
var
  BufSize: Integer;  // buffer size required for value
begin
  // Get required buffer size (inc. terminal #0)
  BufSize := GetEnvironmentVariable(PChar(VarName), nil, 0);
  if BufSize > 0 then
  begin
    // Read env var value into result string
    SetLength(Result, BufSize - 1);
    GetEnvironmentVariable(PChar(VarName),
      PChar(Result), BufSize);
  end
  else
    // No such environment variable
    Result := '';
end;  

initialization

_putenv_s(PChar('DYLD_LIBRARY_PATH'), PChar('g:\_projekty\ZBar Test\'));
_putenv_s(PChar('MAGICK_CODER_MODULE_PATH'), PChar('g:\_projekty\ZBar Test\modules\coders\'));

s := GetEnvVarValue('DYLD_LIBRARY_PATH');
s := GetEnvVarValue('MAGICK_CODER_MODULE_PATH');

end.

This unit is at the beginning of dpr file.


Solution

  • From what I can discern from your update, the third party library in question is ImageMagick. And the .pas wrappers for that library use load-time linking to the ImageMagick DLL.

    When you modify the environment variables from a command interpreter, and then start your process, the ImageMagick DLL can see those environment variables. When you modify the environment variables in your process startup code, the the ImageMagick DLL cannot see those environment variables. Presumably because it has read the variables before your code modifies them.

    What I would conclude from the above is that the ImageMagick DLL is reading the environment variables in its initialization.

    Because you are using load-time linking, the DLL initialization happens before you have any opportunity to execute your code. I can think of the following ways to work around the issue:

    1. Switch from load-time linking to run-time linking for the ImageMagick DLL. This will require you to modify the ImageMagick wrappers that you use. If you are unfamiliar with how to do this, then you might consult the JEDI source code for inspiration. Note that if you are using a modern Delphi, then you can simply modify the wrapper DLL to delay load the ImageMagick DLL. Add the delayed directive to the function declarations. This results in run time linking.
    2. Move some of your code into a DLL so that you can load it with run-time linking. I'm imagining that you move any code that uses the ImageMagick wrapper into a DLL. That would allow you to keep on using the same wrapper, but still have the ImageMagick DLL loaded at process run-time rather than process load-time. You might even move your entire code into a DLL and then have an executable that did nothing more than load that DLL, and then call a single exported main function.
    3. Use a separate launcher process. The launcher process prepares the environment, and then launches the real application.

    Of these options, the first is by far the most preferable, in my opinion.