LoadLibrary根据什么判断DLL已加载?

六道佩恩 2021-04-17 02:51:58
是根据名称吗?
如果程序1已加载过A.dll,此时程序2也需要加载一个A.dll,但两个DLL完全不同,那么LoadLibrary会认为这是两个相同DLL而直接将之前的DLL映射过来,还是会判定出两个DLL的不同而重新加载?
...全文
2270 28 打赏 收藏 转发到动态 举报
写回复
用AI写文章
28 条回复
切换为时间正序
请发表友善的回复…
发表回复
赵4老师 2021-04-22
  • 打赏
  • 举报
回复 1
我成了“有人”;还好没成“等”。
_mervyn 2021-04-22
  • 打赏
  • 举报
回复 1
引用 18 楼 六道佩恩 的回复:
你们都说判断DLL是根据全路径的
我可没有这么说。上面有人贴的链接里其实说的很清楚了,在正常搜索DLL之前,就有特例: 1、应用程序自己使用了DLL redirection(.loacl文件)或者使用了manifest文件控制dll载入目录 2、应用程序已经载入了一个同名dll模块,不论它的路径在哪,都不会再继续搜索dll(载入是指已在程序的虚拟空间中) 3、dll是已知dll,或者任何已知dll的依赖dll(所谓已知dll在注册表中列出:HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\KnownDLLs.) 当不满足上面的条件时,应用程序才会按照标准搜索顺序搜索dll: 搜索顺序分两种,取决于安全搜索模式是否开启(默认开启,可通过注册表关闭或通过调用 SetDllDirectory关闭)。 如果安全搜索模式开启,则顺序如下: 1、应用程序所在目录 2、系统目录. 3、16位系统目录. 4、Windows目录. 5、当前目录. 6、环境变量PATH指定的目录 如果安全搜索模式关闭,则顺序如下: 1、应用程序所在目录 2、当前目录. 3、系统目录. 4、16位系统目录. 5、Windows目录. 6、环境变量PATH指定的目录 另外还有高级搜索模式,通过使用LOAD_WITH_ALTERED_SEARCH_PATH调用 LoadLibraryEx开启,具体自己去看上面其他人发的那个链接吧。 注意!上面的规则都是以一个应用程序实例的视角来说的,不用应用程序实例是互不影响的,所以你说的:
引用 18 楼 六道佩恩 的回复:
其实最开始的问题主要是想知道,当物理内存中已经有一个同名DLL时,此时加载该名称的DLL是重新找还是直接映射到虚拟内存。
这个问题的答案,对你想知道的结果来说,没有任何意义。不管系统是否会重复载入同一个dll到物理内存,都能满足上面所说的一个应用程序实例看到的规则。 说白了,就是因为你不知道已知DLL(known DLL)的概念,导致你想的太多了。。 最后给你捋一下,对于同一个应用程序实例来说!!!
引用 18 楼 六道佩恩 的回复:
你们都说判断DLL是根据全路径的
错!! 只判断名字!!
引用 18 楼 六道佩恩 的回复:
是官方的DLL有特殊性?
对!!known DLL
Intel0011 2021-04-22
  • 打赏
  • 举报
回复
引用 18 楼 六道佩恩 的回复:
只不过,刚刚的gdi32.dll的测试并不完全符合这一行为。
Certain operating system-supplied DLLs get special treatment. These are called known DLLs. They are just like any other DLL except that the operating system always looks for them in the same directory in order to load them. Inside the registry is the following key: HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\KnownDLLs
赵4老师 2021-04-22
  • 打赏
  • 举报
回复
Process Monitor 实时监视文件系统、注册表、进程、线程和 DLL 活动。 http://www.microsoft.com/china/technet/sysinternals/utilities/processmonitor.mspx
赵4老师 2021-04-22
  • 打赏
  • 举报
回复
Process Explorer 找出进程打开了哪些文件、注册表项和其他对象,已加载哪些 DLL 等信息。这个功能异常强大的实用工具甚至可以显示每个进程的所有者。http://www.microsoft.com/china/technet/sysinternals/utilities/ProcessExplorer.mspx
六道佩恩 2021-04-22
  • 打赏
  • 举报
回复
引用 21 楼 Intel0011 的回复:
我真是羞愧,没有好好看文档,原来都写了的 真的非常感谢!
martin_lew 2022-04-27
  • 举报
回复
@六道佩恩 写了啥?我都看完了还是一脸懵。_mervyn解释了单个exe实例只会加载同一个dll一次,多个不同exe到底是怎么判断某个dll是否加载的呢(既然全路径都不行)?
六道佩恩 2021-04-22
  • 打赏
  • 举报
回复
引用 22 楼 _mervyn 的回复:
非常感谢!!! 麻烦您了!!!
forever74 2021-04-22
  • 打赏
  • 举报
回复
山,就在那里 如果你的目标是征服高山,那就做好准备,上 但如果你的目标是征服大海,那就没必要和每座路过的山较真儿
forever74 2021-04-22
  • 打赏
  • 举报
回复
嗯,我其实是打酱油的。 我的懒人哲学一直认为,不打算写操作系统的猿,就应该信任操作系统。 也就是相信系统能做到它承诺做到的那些事,然后去快乐地做我们自己的事。 操作系统里面应该有很多类似于C语言里面的所谓“未定义行为”的自行发挥的部分,闭源系统可能不希望猿们深入它的实现细节,也许它会在下一个版本替换实现细节,只留下一致性接口。 快乐来自适可而止,请相信我。 当然,天花板也来自“适可”而止,所以请不要相信我。
六道佩恩 2021-04-21
  • 打赏
  • 举报
回复
引用 17 楼 _mervyn 的回复:
所以,所谓的LoadLibrary判断dll是否已加载,针对的是虚拟地址。 这点不能搞混。
感谢您来问答 前面关于LoadLibrary那个,是我将调用LoadLibrary后直到它返回期间的行为统称为LoadLibrary的行为,其实应该也可以这样看吧,总得有代码去判断。 我说的这个判断是指对于已经加载到物理内存(加载后到未从物理内存释放期间,包含了换出到硬盘)后,如果已经加载到物理内存,判断到这一行为后,直接将其映射到进程的虚拟空间,而不是再去加载 你们都说判断DLL是根据全路径的,但我测试过程中发现一些奇怪的事 首先我要确定加载目录先于system32,除了通过微软的文档,也将两个同名不同内容的DLL放到system32和程序同目录,根据DllMain的输出可以确定,优先加载的是程序所在目录的DLL 确定了这点后,将程序所在目录的DLL命名为gdi32.dll,写如下代码

	HMODULE h0 = GetModuleHandleA( "gdi32.dll" );
	printf("h0=%p\n", h0 );
	HMODULE h1 = LoadLibrary( "gdi32.dll" );
	printf("h=%p\n", h1 );
前两行通过输出可以肯定没有加载gdi32.dll,第三行加载gdi32.dll的时候,没有输出预先设置在DllMain中的字符串,说明此时加载的是system32下的gdi32.dll,而不是程序所在目录自定义的gdi32.dll。(为确保自己的gdi32.dll有正确的输出行为,加载时指定.\\gdi32.dll,能得到预期的结果) 这里就有问题了,它并没有按我期望的加载当前目录的DLL 我推测是内存中已经加载过gdi32.dll了,因为出现同名DLL,所以直接映射过来了,这个行为看起来还是根据文件名来的 但又做了测试,结果又不同 程序A加载A.dll不退出,程序B和它是不同文件夹,它也加载一个不同内容的A.dll,根据输出来看,最终加载的是程序B同目录的A.dll 程序A的A.dll仍在内存中,说明这里又没完全根据名称来,而是确实做了搜索工作的 这么说的话,是官方的DLL有特殊性? 其实最开始的问题主要是想知道,当物理内存中已经有一个同名DLL时,此时加载该名称的DLL是重新找还是直接映射到虚拟内存。 现在根据你们的解惑,算上完整路径的话,当找到的DLL和物理内存中的DLL的完整路径相同(即同一文件),那么直接从物理内存中映射过来; 如果找到的DLL和内存中同文件名的DLL(一个或多个)的路径不同,那么还是会将其加载到物理内存,并映射到当前程序的虚拟内存中 是这样的吧?我是这样理解的。 只不过,刚刚的gdi32.dll的测试并不完全符合这一行为。
哈哈gogo 2021-04-20
  • 打赏
  • 举报
回复
模块名不是可以
_mervyn 2021-04-20
  • 打赏
  • 举报
回复
所以,所谓的LoadLibrary判断dll是否已加载,针对的是虚拟地址。 这点不能搞混。
_mervyn 2021-04-20
  • 打赏
  • 举报
回复
引用 10 楼 六道佩恩 的回复:
这是微软的一段原话 If a DLL with the same module name is already loaded in memory, the system checks only for redirection and a manifest before resolving to the loaded DLL, no matter which directory it is in. The system does not search for the DLL. 按这说的,出现同名的模块,系统不会再搜索第二个的(如果我没理解错的话)
这说的是针对同一个应用程序(exe)来说的。 针对同一个exe运行实例来说,如果它已经加载了一个A.dll,再次加载同名A.dll 是不起作用的,哪怕它们路径不同! 请不要对此有怀疑。 在这种情况下,它就是根据dll名称区别的。 在你确定上述这一点之后,再来看你说的另一种情况:
引用 4 楼 六道佩恩 的回复:
比如A程序加载的A.dll在它的当前文件夹 然后B程序也要加载一个A.dll(与之前的A.dll不一样,只是恰好名字一样),这个dll也在B程序的当前文件夹,你看,这就跟搜索顺序无关了对吧 接着,B加载A.dll的时候,系统已经将一个A.dll加载到物理内存了,那么面对B程序要加载当前文件夹的A.dll,是加载还是不加载? 加载吧,内存里已经有一个同名的DLL了,映射过来就可以了 不加载吧,可两个DLL明明不一样,B程序希望加载的可用的DLL,但系统没给它加载 是这么个问题
首先,你既然问出了“LoadLibrary根据什么判断DLL已加载” 这个问题,就说明你从某处得知LoadLibrary会判断dll是否已加载。 而这点一般情况下说的都是针对一个exe的单个运行实例来说的。我不知道你对这点是否有理解错误才提出的这个多个exe运行实例的例子(包括同名exe的多个运行实例)。 我先假设你是理解错误了,如果你是明确从某处得知的“多个exe实例或同名exe的多个运行实例加载dll也会判断是否已加载过”这个信息的。请不要听我接下来说的,并请告诉我你从哪里获取的信息。 因为关于这一点我也不是很明确,所以接下来说的是以我的经验常识推断的: 我认为多个进程间加载dll肯定是毫无影响的。这里我说的加载是指 将dll映射至进程自身的虚拟地址。 因为事实就是如此(A.exe和B.exe一定能够得到正确的A.dll),所以从事实反推,通过一个dll文件的全路径来判断是否需要将其从硬盘装进物理内存肯定是可以办到的,而只判断名称显然是不行的。 而且我认为“判断该dll是否已经装进在物理内存里了” 这件事情跟LoadLibrary没有关系,这应该是系统 ”内存管理“ 功能相关的知识,在需要的时候装入内存,在不需要的时候换出到硬盘。 另外说一句,一个dll的文件内容是否在实际的物理内存里,不仅仅依靠是否调用过LoadLibrary就能确定的,如果你LoadLibrary之后经常不用甚至完全不用该dll的内容,它很有可能被系统换出到硬盘甚至只把一部分换出到硬盘,把位置留给更需要的内容。
这不是鸭头 2021-04-20
  • 打赏
  • 举报
回复
和dll的名称没关系
灿灿在此 2021-04-19
  • 打赏
  • 举报
回复
牛逼,大佬们厉害
赵4老师 2021-04-19
  • 打赏
  • 举报
回复
Intel0011 2021-04-19
  • 打赏
  • 举报
回复
引用 10 楼 六道佩恩 的回复:
[quote=引用 6 楼 Intel0011 的回复:] 你忽略了一点,虽然两个的名称都是A.dll,但两者的全路径不同呀,系统还是能区分的
你的意思是,路径也作为了辨识DLL的一环吗? 这是微软的一段原话,你那个链接里的 If a DLL with the same module name is already loaded in memory, the system checks only for redirection and a manifest before resolving to the loaded DLL, no matter which directory it is in. The system does not search for the DLL. 按这说的,出现同名的模块,系统不会再搜索第二个的(如果我没理解错的话)[/quote] 路径也作为了辨识DLL的一环吗?--->那是当然的,如果有manifest文件的话,又会使用manifest文件中指定的版本,所以说比较复杂
GKatHere 2021-04-18
  • 打赏
  • 举报
回复
A程序与程序B不在同一个文件夹,那和A与B的当前路径就不一样,那么各自加载的当前路径下的dll全路径就不一样,所以dll就不一样。 A程序与程序B在同一个文件夹,那和A与B的当前路径就一样,那么各自加载的当前路径下的dll全路径就一样,所以dll就一样。 另外说一句: 1: 每个程序的当前路径好像是可以修改的. 2: 系统中给每个程序维护了一个dll加载链表,如果手动修改此链表,导致其它需要的行为。
forever74 2021-04-18
  • 打赏
  • 举报
回复
在这个问题上我完全是主观臆断的,想当然。
Intel0011 2021-04-18
  • 打赏
  • 举报
回复
引用 4 楼 六道佩恩 的回复:
[quote=引用 3 楼 Intel0011 的回复:][quote=引用 楼主 六道佩恩 的回复:]是根据名称吗? 如果程序1已加载过A.dll,此时程序2也需要加载一个A.dll,但两个DLL完全不同,那么LoadLibrary会认为这是两个相同DLL而直接将之前的DLL映射过来,还是会判定出两个DLL的不同而重新加载?
这个涉及到DLL的搜索路径问题,比较复杂,请参阅 https://docs.microsoft.com/en-us/windows/win32/dlls/dynamic-link-library-search-order [/quote] 搜索顺序我知道呀,我说的是另外的一个问题 比如A程序加载的A.dll在它的当前文件夹 然后B程序也要加载一个A.dll(与之前的A.dll不一样,只是恰好名字一样),这个dll也在B程序的当前文件夹,你看,这就跟搜索顺序无关了对吧 接着,B加载A.dll的时候,系统已经将一个A.dll加载到物理内存了,那么面对B程序要加载当前文件夹的A.dll,是加载还是不加载? 加载吧,内存里已经有一个同名的DLL了,映射过来就可以了 不加载吧,可两个DLL明明不一样,B程序希望加载的可用的DLL,但系统没给它加载 是这么个问题[/quote] 你忽略了一点,虽然两个的名称都是A.dll,但两者的全路径不同呀,系统还是能区分的
加载更多回复(7)

69,377

社区成员

发帖
与我相关
我的任务
社区描述
C语言相关问题讨论
社区管理员
  • C语言
  • 花神庙码农
  • 架构师李肯
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧