不要'要在同一文件夹中引用dll和exe。

已加入
2020年4月29日
留言内容
16
编程经验
1-3
你好
我编写了一个非常简单的客户端,将数据发送到OPC UA服务器。我正在使用VS2017 Comm,Win10 x64,OPCLabs的官方Dll库-已通过许可购买。
OpcLabs.EasyOpcUA,版本= 5.57.1​​25.1,文化=中性,PublicKeyToken = 6faddca41dacb409,processorArchitecture = MSIL"

现在,一切工作正常-我即时引用dll / copy本地。客户,创造价值。价值在服务器上,超级。

但是,如果我不想将dll与exe文件放在同一文件夹中,该怎么办?假设dll始终位于c:/test/lib.dll ...如何告诉程序从非baseir之外的其他位置加载库?
像exe.config之类的东西,但不仅是subdir,而且在任何地方。
exe.config适用于...用于子目录。
我在玩Assembly.Load / LoadFile / LoadFrom,但是没有运气。
我正在使用嵌入式资源运行AssemblyResolver,但没有运气。
我是C#的新手。
在此先感谢您的建议。
1588148753963.png


1588148679840.png
 

跳伞

工作人员
已加入
2019年4月6日
留言内容
2,500
地点
弗吉尼亚州切萨皮克
编程经验
10+
我在玩Assembly.Load / LoadFile / LoadFrom,但是没有运气。
你到底是什么意思"no luck"?

Are you getting an exception from calling LoadFrom()? If so what exception are you getting? From the screenshot above, it looks like it is succeeding. If you are not getting an exception, what problem are you running into?

如果绝对要加载程序集,但该程序集不能与您的.EXE位于同一目录中,为什么程序集不能位于该目录中。 广汽集团 ? 广汽集团 与您的可执行文件所在的位置不同吗?在上面的该程序集名称上看到一个公共密钥令牌,它看起来像是强命名的,因此它可以存在于GAC中。

出于好奇,为什么程序集不能与可执行文件位于同一目录中?您的许可证上面是否仅用于个人使用,您没有重新分配的权利?因此,现在您在强迫其他使用程序的人(通过钩子或弯曲)获取他们自己的程序集副本,一旦他们告诉您在哪里找到它,就将其加载。

我质疑您是否希望将参考程序集放在其他位置的原因是,Microsoft专门设计了.NET Framework的默认值,以在应用程序安装的子目录中进行搜索,以最大程度地减少DLL Hell。当Windows用户抱怨Windows早期版本中的DLL Hell时,Microsoft倾听了客户的声音。最小化它的一种方法是让应用程序在安装时随身携带所需的程序集,特别是将其安装在相对于应用程序的位置,这样就不会存在覆盖其他地方现有副本的危险。
 
Last edited:
已加入
2020年4月29日
留言内容
16
编程经验
1-3
你好
我的意思是由于(在我看来)缺少库的一部分,因此无法实例化客户端:
1588582394949.png

1588582468443.png
1588582716760.png
1588582513115.png

1588583394575.png

Gacutil似乎可以工作,但是在VS中出现相同的错误,我确实认为这只是我的一个错误,因为我说我对此很陌生。

.dll在.exe之外的原因是纯粹的美学考虑。我可能会放弃它,并将它们放在EXE的子目录中,但我想学习一些新知识。
也许是愚蠢的问题,您是否有一些dll,我可以用它进行测试-找出我做错了什么还是仅在dll中。我会使用一些系统dll,但不知道如何调用它。
 

附件

  • 1588582279963.png
    1588582279963.png
    100.2 KB · Views: 10
已加入
2020年4月29日
留言内容
16
编程经验
1-3
收回Gacutil的工作原理-当我将程序集加载到GAC中并且不使用Resolver时,它就会工作。足够了。但是,您是否有一些实用的dll来尝试AssemblyResolver?
 

跳伞

工作人员
已加入
2019年4月6日
留言内容
2,500
地点
弗吉尼亚州切萨皮克
编程经验
10+
Look closely at the path you are passing to LoadFrom() in your resolver. Why the double forward slashes?
Also, did you check the ResolverEventArgs to make sure you are trying to load the right assembly? 什么 if the framework is trying to load a dependency of the main assembly, but you are still returning the main assembly again?
 

跳伞

工作人员
已加入
2019年4月6日
留言内容
2,500
地点
弗吉尼亚州切萨皮克
编程经验
10+
另外,您可以制作自己的程序集。为什么您需要其他人来进行测试?所有.NET Framework可执行二进制文件(.exe和.dll)都是程序集。碰巧,Microsoft的DevDiv中的某些程序管理器决定在Visual Studio中启动项目时应调用.exe。"applications"和.dll被称为"class libraries"。在此之后,MS外部的那些不愿阅读文档的人认为程序集是.dll,而别无其他,因为用于加载程序集的最常见示例代码显示了加载.dll。
 

跳伞

工作人员
已加入
2019年4月6日
留言内容
2,500
地点
弗吉尼亚州切萨皮克
编程经验
10+
args.Name
看你的截图。请求的程序集是"OpcLabs.EasyOpcForms,...",但您正在加载程序集"OpcLabs.EasyOpcUA..."

花时间阅读文档:

特别要注意 事件处理程序不应该做什么:
处理 AssemblyResolve 事件是您不应该尝试返回不认识的程序集。编写处理程序时,应该知道哪些程序集可能导致引发事件。您的处理程序应为其他程序集返回null。
 
已加入
2020年4月29日
留言内容
16
编程经验
1-3
args.Name
看你的截图。请求的程序集是"OpcLabs.EasyOpcForms,...",但您正在加载程序集"OpcLabs.EasyOpcUA..."

花时间阅读文档:

特别要注意 事件处理程序不应该做什么:



正如我所说的“新手错误”,感谢Skydiver先生。我将错误的dll推入解析器。现在可以正常工作:


C#:
 private static Assembly OpcAssRes(object sender, ResolveEventArgs args)
        {
            string OpcAsmPath = Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles) + "\\OPC Labs QuickOPC 2020.1\\Assemblies\\net47";
            foreach (string FAssName in Directory.GetFiles(OpcAsmPath, "*.dll"))
            {
                string ReqAss = args.Name.Substring(0, args.Name.IndexOf(","));
                if (Path.GetFileNameWithoutExtension(FAssName) == ReqAss)
                {
                    var DLL = Assembly.LoadFrom(FAssName);
                    return DLL;
                }
            }
            return null;
        }
 

跳伞

工作人员
已加入
2019年4月6日
留言内容
2,500
地点
弗吉尼亚州切萨皮克
编程经验
10+
Line 6 can move outside of the loop since args.Name never changes.

As as alternative to parsing the args.Name yourself, you could use the AssemblyName 类。就像是:
C#:
var requestedName = new AssemblyName(args.Name).Name;

As a quick aside about your naming convention: The .NET Framework highly recommends using Camel casing for local variables and parameters. Furthermore, they recommend using full words instead of abbreviations and acronyms (unless the acronyms are well-known or commonly used). So for example your FAssName should be something like fileAssemblyName. Personally, I would just use fileName.

还有这个:
C#:
string OpcAsmPath = Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles) + "\\OPC Labs QuickOPC 2020.1\\Assemblies\\net47";
应该是这样的:
C#:
var programFiles = Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles);
var opcAssembliesPath = Path.Combine(programFiles, "OPC Labs QuickOPC 2020.1", "Assemblies", "net47");
它避免了丢失或多余的反斜杠的可能性,并且可以在将来使用其他正反斜杠而不是反斜杠的OS证明您的代码。
 
已加入
2020年4月29日
留言内容
16
编程经验
1-3
你好
我可以仅针对一个问题重新打开它吗?
当程序集位于Debug文件夹中时,两种版本的代码,一种有效,另一种无效:
NOTWork:代码启动后立即弹出异常,即使尝试调试也是如此。就像它只是跳过解析器。
 

附件

  • REFNotWork.png
    REFNotWork.png
    61.8 KB · Views: 17
  • REFWorks.png
    REFWorks.png
    101.4 KB · Views: 16

跳伞

工作人员
已加入
2019年4月6日
留言内容
2,500
地点
弗吉尼亚州切萨皮克
编程经验
10+
在解析器中设置一个断点,并确定它是否真的被跳过了。我希望他们两个都能工作。
 
已加入
2020年4月29日
留言内容
16
编程经验
1-3
即使我睡着了,它也会跳过-它不会立即消失。这种行为可能与不良的网络框架有关吗?我最新的是4.8。 DLL文档说必须安装4.7.1、4.7.2或4.8之一...
 

附件

  • break1.png
    break1.png
    212.1 KB · Views: 16
  • break2.png
    break2.png
    200.1 KB · Views: 15
已加入
2020年4月29日
留言内容
16
编程经验
1-3
即使我睡着了,它也会跳过-它不会立即消失。这种行为可能与不良的网络框架有关吗?我最新的是4.8。 DLL文档说必须安装4.7.1、4.7.2或4.8之一...

我在其他计算机上尝试了相同的结果,因此不在Framework中。但是,它仍然无法正常工作。 VS中是否有某种更深入的调试?在哪里可以看到我在玩游戏时初始化了什么,或者下一步是VS等待什么-我可以看到解析器已跳过。就像VS检查正在使用的库,当它们不在文件夹中时,它会发出尖叫声。
 

跳伞

工作人员
已加入
2019年4月6日
留言内容
2,500
地点
弗吉尼亚州切萨皮克
编程经验
10+
查看生成的IL。查看JIT生成的汇编代码。

如果我不得不猜测,我会怀疑程序集已在GAC中注册,因此不需要解析程序集的位置。我记得,GAC胜过一切。
 

跳伞

工作人员
已加入
2019年4月6日
留言内容
2,500
地点
弗吉尼亚州切萨皮克
编程经验
10+
好问题。

IL ==中级语言。这是一种汇编语言,C#编译器将C#代码编译到其中。稍后,当您运行代码时,JIT(即时)编译器将获取该IL,并将其转换为将在您的处理器上运行的机器代码。

如果您正在使用GAC,并且加载了问题,则需要运行 fuslogvw 缩小原因。想到这一点,fuslogvw.exe也许还可以告诉您为什么即使它不在GAC中也无法加载程序集。

不幸的是,fuslogvw.exe可能无法告诉您的原因是为什么在一种情况下调用了解析器,而在另一种情况下却没有。
 

金西尼

C#论坛主持人
工作人员
已加入
2011年4月23日
留言内容
3,501
地点
悉尼,澳大利亚
编程经验
10+
供将来参考,尽管一张图片可能值一千个单词,但单词仍然很有价值。如果您已将那行代码从Main方法移至静态构造函数,则只需说一遍。

至于说明,如果在这两个方法上设置断点,则将看到构造函数在Main方法之前执行。如果您的应用程序在构造函数中使用该行而不在Main方法中使用该行,那么显然在执行这些方法之间需要一段时间。如果该方法正在解析程序集的路径,那么显然可以在执行Main方法之前完成。
 

跳伞

工作人员
已加入
2019年4月6日
留言内容
2,500
地点
弗吉尼亚州切萨皮克
编程经验
10+
因此,这意味着他较早的帖子(不幸的是,他还使用了屏幕截图)在该位置添加了设置事件处理程序和实例化对象之间的睡眠。如果我记得睡眠时间约为1秒钟,但现在无法检查手机。屏幕截图很难在小型设备上阅读,这也正是我们在显示代码时不鼓励使用屏幕截图的原因。
 
最佳 底部