DELPHI盒子
!实时搜索: 盒子论坛 | 注册用户 | 修改信息 | 退出
检举帖 | 全文检索 | 关闭广告 | 捐赠
技术论坛
 用户名
 密  码
自动登陆(30天有效)
忘了密码
≡技术区≡
DELPHI技术
lazarus/fpc/Free Pascal
移动应用开发
Web应用开发
数据库专区
报表专区
网络通讯
开源项目
论坛精华贴
≡发布区≡
发布代码
发布控件
文档资料
经典工具
≡事务区≡
网站意见
盒子之家
招聘应聘
信息交换
论坛信息
最新加入: webb123
今日帖子: 1
在线用户: 3
导航: 论坛 -> DELPHI技术 斑竹:liumazi,sephil  
作者:
男 dbyoung (dbyoung) ★☆☆☆☆ -
普通会员
2022/9/27 15:05:17
标题:
请教:Dll 路径问题 浏览:1675
加入我的收藏
楼主: 三个厂家的 SDK,每个 SDK 都有一堆 Dll。
我不希望将这些 Dll 都放在程序根目录下。
所以我将:
  A 厂家的 SDK 放在 01 子目录下。并将 Dll 的函数声明路径修改为 ‘.\01\A.DLL’。
  B 厂家的 SDK 放在 02 子目录下。并将 Dll 的函数声明路径修改为 ‘.\02\B.DLL’。
就可以正常使用了。

但 C 厂家的 SDK 不知为何,不能放在子目录中,必须要放在程序根目录下。
否则提示找不到 Dll。不知道是啥原因?修改了函数声明路径也不起作用。

有谁碰到过这样的问题,指点一二。谢谢。

(三个 SDK,Dll 函数都是静态声明)
----------------------------------------------
武汉天气不好
作者:
男 lsuper (lsuper) ★☆☆☆☆ -
盒子活跃会员
2022/9/27 15:25:19
1楼: x86/64 混用?或者 dll 还有其他依赖导致加载失败;可以用 depends 看看
----------------------------------------------
-
作者:
男 dbyoung (dbyoung) ★☆☆☆☆ -
普通会员
2022/9/27 15:38:19
2楼: 没有,都是 x86 的。

关键是放在程序根目录下就可以(程序根目录下原本没有任何 Dll)。
----------------------------------------------
武汉天气不好
作者:
男 zhoutler (苦行僧) ★☆☆☆☆ -
普通会员
2022/9/27 21:27:45
3楼: 具体报错的errorcode是什么,可以再看看阿
----------------------------------------------
-
作者:
男 wr960204 (武稀松) ★☆☆☆☆ -
盒子活跃会员
2022/9/28 15:22:35
4楼: 也许C厂的一堆DLL中有些DLL会动态加载其他的DLL,而加载路径写的是EXE的路径。
----------------------------------------------
武稀松http://www.raysoftware.cn
作者:
男 ddrfan (若苗瞬) ▲▲▲▲▲ -
普通会员
2022/9/28 17:14:48
7楼: 所以是【test02.dll】调用【test01.dll】找不到库。

主程序调用一次后,它就找得到了。
如果将test01.dll放主程序目录,则它也找得到(子目录下)的。

难道是找库和调用不是一次完成的?

我不太明白。

不过我把【test02.dll】项目里面也加上目录后:
function MyAdd1(const i, j: Integer): Integer; stdcall; external '.\01\test01.dll';

就可以主程序仅调用步骤02了:
  //Caption := Format('%d', [MyAdd1(4, 3)]); // 001
  Caption := Format('%d', [MyAdd2(4, 3)]); // 002
----------------------------------------------
Bye bye DDRFAN...
作者:
男 ddrfan (若苗瞬) ▲▲▲▲▲ -
普通会员
2022/9/28 17:16:05
8楼: 呃,LZ楼上的帖子不见了……
----------------------------------------------
Bye bye DDRFAN...
作者:
男 dbyoung (dbyoung) ★☆☆☆☆ -
普通会员
2022/9/28 20:36:03
9楼: 结论有点问题。所以删除了。
测试不仔细。我在测试测试。
此帖子包含附件:dbyoung_2022928213459.zip 大小:1.66M
----------------------------------------------
武汉天气不好
作者:
男 newbuyer (newbuyer) ★☆☆☆☆ -
普通会员
2022/9/29 0:48:28
10楼: 支持4楼看法,

实在想搞清楚, 应该可以单独写个动态装载C厂DLL的程序, 断点在CPU LoadLibrary(Ex)上, 看有哪些调用过来.

不过这种事情个人觉得也不必要较真, 属于屠龙之技, 知道也没啥用, 能工作WorkAround就行了.
----------------------------------------------
-
作者:
男 emailx45 (emailx45) ▲▲▲▲△ -
普通会员
2022/9/29 8:57:14
11楼: implementation

{$R *.dfm}

//
// HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\KnownDLLs
//
{
  this can change the searches:

  1) If a DLL with the same module name is already loaded in memory, the system will only check the redirection and a manifest before resolving to the loaded DLL,
  ... regardless of which directory it is in. The system does not search the DLL.

  2) If the DLL is in the list of known DLLs for the version of Windows the application is running on, the system will use its copy of the known DLL
  ...  (and the DLLs dependent on the known DLL, if any) instead of looking up the DLL. For a list of known DLLs on the current system,
  ...  see the following registry key: HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\KnownDLLs.

  3) If a DLL has dependencies, the system will look for the dependent DLLs as if they were loaded with just their module names.
  ...  This is true even if the first DLL was loaded specifying a full path.

  search order:
  // ----------
  // 0) On memory if already loaded!!!
  // 1) Manifest executable, dll dependences
  // 2) Registry key: "HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\KnownDLLs" registered DLLs
  // 3) Folder executable
  // 4) System folders
  // ----------
}
//
type
  TMyFunc = function: integer;

const
  MyDLLOneName: string = 'myDLL_One.dll';
  MyDLLTwoName: string = 'myDLL_Two.dll';
  MyFuncName: string   = 'MyStaticValue';

var
  MyDLLPath: string = 'D:\RADRX112Tests\VCL_DLL_search_order_if_not_in_the_same_folder_than_executable\MyDLL\Win32\Debug';

procedure TForm1.Button1Click(Sender: TObject);
var
  MyHndDLL          : NativeUInt;
  MyFunc          : TMyFunc;
  MyBuffer          : string;
  MyBufferReturnSize: cardinal;
begin
  Memo1.Text := 'Now: ' + DateTimeToStr(now);
  //
  Memo1.Lines.Add('Exe path: ' + ParamStr(0) + sLineBreak);
  //
  SetLength(MyBuffer, MAX_PATH);
  //
  MyBufferReturnSize := GetDllDirectory(MAX_PATH, PWideChar(MyBuffer));
  //
  // ... waiting SetDllDirecotry() usage!!!
  Memo1.Lines.Add(sLineBreak + 'GetDllDirectory: (before SetDllDirectory) ' + sLineBreak + MyBufferReturnSize.ToString + ', ' + MyBuffer);
  //
  // new folder to search the DLL file....
  //
  if SetDllDirectory(PWideChar(MyDLLPath)) then
    begin
      MyBufferReturnSize := GetDllDirectory(MAX_PATH, PWideChar(MyBuffer));
      //
      Memo1.Lines.Add('GetDllDirectory: (after SetDllDirectory) ' + sLineBreak + MyBufferReturnSize.ToString + ', ' + MyBuffer);
      //
      MyHndDLL := LoadLibrary(PWideChar(MyDLLOneName)); // no path used for tests...
      try
        if (MyHndDLL > 0) then
          begin
          MyFunc := GetProcAddress(MyHndDLL, PWideChar(MyFuncName));
          //
          if not(@MyFunc = nil) then
          Memo1.Lines.Add(sLineBreak + 'MyFunc result: ' + MyFunc.ToString);
          end
        else
          Memo1.Lines.Add(sLineBreak + 'MyHndDll(1) = ' + MyHndDLL.ToString);
      finally
        FreeLibrary(MyHndDLL);
      end;
    end
  else
    Memo1.Lines.Add(sLineBreak + 'SetDLLDirectory(1) = false');
  //
  // **********//
  //
  Memo1.Lines.Add('');
  //
  MyDLLPath := ExtractFilePath(ParamStr(0));
  //
  if SetDllDirectory(PWideChar(MyDLLPath)) then
    begin
      MyBufferReturnSize := GetDllDirectory(MAX_PATH, PWideChar(MyBuffer));
      //
      Memo1.Lines.Add('GetDllDirectory: (after SetDllDirectory) ' + sLineBreak + MyBufferReturnSize.ToString + ', ' + MyBuffer);
      //
      MyHndDLL := LoadLibrary(PWideChar(MyDLLTwoName)); // no path used for tests...
      try
        if (MyHndDLL > 0) then
          begin
          MyFunc := GetProcAddress(MyHndDLL, PWideChar(MyFuncName));
          //
          if not(@MyFunc = nil) then
          Memo1.Lines.Add(sLineBreak + 'MyFunc result: ' + MyFunc.ToString);
          end
        else
          Memo1.Lines.Add(sLineBreak + 'MyHndDll(2) = ' + MyHndDLL.ToString);
      finally
        FreeLibrary(MyHndDLL);
      end;
    end
  else
    Memo1.Lines.Add(sLineBreak + 'SetDLLDirectory(2) = false');
end;

end.
此帖子包含附件:
PNG 图像
大小:153.7K
----------------------------------------------
The higher the degree, the greater the respect given to the humblest!RAD 11.3
作者:
男 emailx45 (emailx45) ▲▲▲▲△ -
普通会员
2022/9/29 9:09:31
12楼: scrennshot 2
此帖子包含附件:
PNG 图像
大小:26.7K
----------------------------------------------
The higher the degree, the greater the respect given to the humblest!RAD 11.3
作者:
男 dbyoung (dbyoung) ★☆☆☆☆ -
普通会员
2022/9/29 9:45:21
13楼: 我测试下来,
  SetDllDirectory 只能针对动态调用的 Dll 函数。
  静态声明的 Dll 函数,SetDllDirectory 没有效果。
  你即使添加一个单元,放在工程第一的位置,在初始化里面调用 SetDllDirectory,也是不行的。


I tested:
  SetDllDirectory can only be used for dynamically called Dll functions.
  For statically declared Dll functions, SetDllDirectory has no effect.
  Even if you add a unit, put it in the first place of the project, 
  and call SetDllDirectory in initialization, it will not work.
----------------------------------------------
武汉天气不好
作者:
男 emailx45 (emailx45) ▲▲▲▲△ -
普通会员
2022/9/29 10:03:14
14楼: The directory to be added to the search path. 
If this parameter is an empty string (""), the call removes the current directory from the default DLL search order.
If this parameter is NULL, the function restores the default search order.

The SetDllDirectory function affects all subsequent calls to the LoadLibrary and LoadLibraryEx functions. 

It also effectively disables safe DLL search mode while the specified directory is in the search path.

For Win32 processes that are not running a packaged or protected process, calling this function will also affect the DLL search order of the children processes started from the process that has called the function.


//----------//


if need more paths, you can use "AddDllDirector(...)"

An absolute path to the directory to add to the search path. For example, to add the directory Dir2 to the process DLL search path, specify \Dir2. For more information about paths, see Naming Files, Paths, and Namespaces.
----------------------------------------------
The higher the degree, the greater the respect given to the humblest!RAD 11.3
作者:
男 emailx45 (emailx45) ▲▲▲▲△ -
普通会员
2022/9/29 10:06:09
15楼: unfortunatelly, if you define the DLL call on exe-main (statically), SetDllDirectory can not changes this path!!!

basically, because the "DLL" reside in the same space than Exe!
understandood like a "Child"- from "Exe"
----------------------------------------------
The higher the degree, the greater the respect given to the humblest!RAD 11.3
作者:
男 ddrfan (若苗瞬) ▲▲▲▲▲ -
普通会员
2022/9/29 11:30:01
16楼: 能不能干脆都放Windows/System32(Syswow64)目录,这样exe目录也显得不乱。
问题也就绕过了:)
----------------------------------------------
Bye bye DDRFAN...
作者:
男 kentty (kentty) ★☆☆☆☆ -
普通会员
2022/9/29 12:57:16
17楼: demo里面Test02.dll载入test01.dll时,
搜索目标是 exe当前目录+test01.dll
对于自己写的test02.dll,可以在载入test01.dll时
通过GetModuleFileName获取自身所在目录
再在这个目录里寻找Test01.dll

对于外部提供的dll,
可以试试在载入Test02.dll时临时变更一下当前目录
相当于改变Test02.dll载入的上下文环境,
载入完成后再恢复到原来的,
不知道有没有效果
----------------------------------------------
-
信息
登陆以后才能回复
Copyright © 2CCC.Com 盒子论坛 v3.0.1 版权所有 页面执行138.1836毫秒 RSS