情况:.net包装器类的多个版本,所有版本都具有相同的签名,并且具有相同的签名。我们想以wcf服务方法动态加载包装器中的1个。我计划使用每个包装器+依赖dll来设置文件夹。我们将根据用户选择的版本使用switch或if语句来运行。
我具有带有路径的Assembly.LoadFrom,并且可以创建包装器类的实例。但是在包装器中调用方法失败,并显示“无法加载或找到CTV.dll”。
如果更改计算机或用户环境路径以指向CTV.dll,它将执行该方法。但这是全局的,并且只会指向一个版本文件夹中的特定CTV.dll。我已经尝试了很多次
Environment.SetEnvironmentVariable(“ Path”,[文件夹中ctv.dll的路径],EnvironmentalVariableTarget.Process);
但是无效,会发生相同的错误。
我是否缺少某些东西。似乎会有答案。
还有另一种方法来处理此用例吗?
乍看之下,在加载托管包装程序之前先加载目标本机dll似乎是一个很好的解决方案(通过使用带有绝对路径的LoadLibrary调用)
[DllImport("kernel32", SetLastError=true, CharSet = CharSet.Ansi)]
static extern IntPtr LoadLibrary([MarshalAs(UnmanagedType.LPStr)]string lpFileName);
如果字符串指定完整路径,则该函数仅搜索模块的路径。
我也想谈一谈我成功尝试过的替代方法。
我们可以使用SetDllDirectory本机API将新路径注入LoadLibrary的搜索顺序。
使用LoadLibrary函数加载本机库,并且要加载的库具有特定的directory search order。
请参阅本节,摘自LoadLibrary函数的文档:
可以使用SetDllDirectory函数更改搜索路径。建议使用此解决方案,而不要使用SetCurrentDirectory或硬编码DLL的完整路径。
我向不存在的模块添加了符号互操作调用:
[DllImport("oguzozgul.dll")]
static extern uint InvokeOguzOzgul(IntPtr oguz, uint ozgul);
然后调用此函数并使用ProcMon监视搜索行为>
您可以清楚地看到LoadLibrary以什么顺序查找本机映像。 (在我的系统上)
然后,在对该不存在的模块进行任何调用之前,我调用了[SetDllDirectory]:
[DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)] [return: MarshalAs(UnmanagedType.Bool)] static extern bool SetDllDirectory(string lpPathName); // Calling SetDllDirectory: SetDllDirectory("c:\\temp\\");
并再次调用该方法。结果如下。
检查进程的文件夹后,LoadLibrary将立即检查注入的路径。
因此,如果您调用SetDllDirectory并将正确的目录路径添加到LoadLibrary的搜索顺序中,则在托管包装程序要求时,应从那里自动加载所需版本的本机dll。
希望这会有所帮助。