【问题标题】:SetEnvironmentVariable not workingSetEnvironmentVariable 不起作用
【发布时间】:2014-07-25 07:34:47
【问题描述】:

我需要为包含的第 3 方库设置两个环境变量(当我的应用程序运行时)。

问题是“那样”它不起作用,但是 当我运行控制台应用程序时,设置这两个变量,然后运行应用程序,一切正常...

如何正确配置这两个变量?

我使用程序:

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;

返回 0

也许事情是,我在应用程序启动时加载了库。 当我的应用程序启动时,我设置了变量,但我做得太晚了......?


更多信息

我在 dpr 中包含了两个单元:

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

还有单位:

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.

这个单元在 dpr 文件的开头。

【问题讨论】:

  • SetEnvironmentVariable 在失败时返回 Windows 错误代码,您可以通过 GetLastError 获得该错误代码。你得到了什么价值?
  • 返回时返回 0
  • @John,听起来是退货的最佳时机,退货时:-)
  • 您的代码中有第三方库吗?在您更改环境变量之前,您是否考虑过他们已经读取环境变量的可能性?
  • 见鬼,这可能是问题所在......

标签: delphi delphi-7


【解决方案1】:

从您的更新中我可以看出,有问题的第三方库是 ImageMagick。该库的 .pas 包装器使用加载时链接到 ImageMagick DLL。

当您从命令解释器修改环境变量,然后启动您的进程时,ImageMagick DLL 可以看到这些环境变量。当您在进程启动代码中修改环境变量时,ImageMagick DLL 无法看到这些环境变量。大概是因为它在您的代码修改变量之前已经读取了变量。

我从上面得出的结论是 ImageMagick DLL 在其初始化时正在读取环境变量。

因为您使用的是加载时链接,所以 DLL 初始化发生在您有机会执行代码之前。我可以想出以下方法来解决这个问题:

  1. ImageMagick DLL 从加载时链接切换到运行时链接。这将要求您修改您使用的 ImageMagick 包装器。如果您不熟悉如何执行此操作,则可以查阅 JEDI 源代码以获取灵感。请注意,如果您使用的是现代 Delphi,那么您可以简单地修改包装 DLL 以延迟加载 ImageMagick DLL。将delayed 指令添加到函数声明中。这会导致运行时链接。
  2. 将一些代码移动到 DLL 中,以便您可以通过运行时链接加载它。我想象您将任何使用 ImageMagick 包装器的代码移动到 DLL 中。这将允许您继续使用相同的包装器,但仍然在进程运行时而不是进程加载时加载 ImageMagick DLL。您甚至可以将整个代码移动到一个 DLL 中,然后创建一个可执行文件,该可执行文件只是加载该 DLL,然后调用单个导出的 main 函数。
  3. 使用单独的启动程序进程。启动器进程准备环境,然后启动真正的应用程序。

在我看来,在这些选项中,第一个是迄今为止最可取的。

【讨论】:

  • 谢谢。我明白你的意思。我假设我可以这样做:设置变量、加载库和调用方法。但是我很好奇为什么,当这些库被调用时,我不能更早地设置变量......
  • 您需要了解加载时链接和运行时链接之间的区别。在 MSDN 上阅读它。关键是加载时链接 DLL 的 DllMain 函数在您的任何可执行代码之前执行。
  • @DavidHeffernan 值得补充的是,任何使用 Delphi 2010 或更高版本阅读本文的人都可以选择将延迟关键字添加到 dll API 声明中,这将自动延迟 dll 加载,直到第一个 dll API 调用修复没有任何重大返工的问题。它显然与当前的海报无关,因为我们可以看到正在使用 Delphi 2007
  • @Kanitatlan 是的,我会这样做的
【解决方案2】:

您可能正在更改环境变量它们已被第三方库读取。

首先,您应该像游览程序所做的第一件事一样设置环境变量。

即便如此,第三方库也可能在初始化函数中读取该信息,甚至可能在您的代码开始运行之前。

如果是这种情况,我认为初始化顺序是确定性的(请参阅here),具体取决于您在dpr(项目文件)中的单元顺序。

如果您希望在第三方库查看它们之前设置这些变量,您可以创建一个DoMeFirst 单元并在该单元的初始化代码中执行此操作。然后确保这是项目文件中的第一个。

如果这不起作用,另一种选择可能是编写一个更改环境的程序,然后然后将您当前的程序作为子程序调用。

【讨论】:

  • 是否可以在应用程序加载外部库之前在应用程序的某处运行代码?我尝试在 dpr 项目开始后运行代码,但没有运气
  • 不幸的是它不起作用。我按照你的提议做了。它在一开始就设置了这两个变量,但是该库仍然存在问题:/
  • 那么您最好的选择可能是联系这些库的作者。顺便说一句,您确定 DPR 文件中的顺序正确吗?
  • 我发现了这样的东西:stackoverflow.com/questions/4788398/… 也许这就是问题所在?
猜你喜欢
  • 2018-05-30
  • 2020-02-01
  • 1970-01-01
  • 1970-01-01
  • 2011-10-30
  • 2022-10-20
  • 1970-01-01
  • 1970-01-01
  • 2016-03-13
相关资源
最近更新 更多