奇怪的VB6构建问题(与nlog相关)

时间:2020-03-06 14:42:10  来源:igfitidea点击:

我认为这与我对nlog C ++ API的使用有关(我在nlog论坛上的问题在这里);我在这里提出此问题的目的是使我的问题得到更广泛的了解,也许还可以从VB6 IDE无法在我的特定方案中构建背后得到一些更一般的想法。

简而言之,我遇到的问题是我在构建VB6组件时遇到麻烦,这些组件引用了非托管C ++组件,这些组件具有对nlog的C \ C ++ API(在NLogC.DLL中定义)的调用。构建问题不是在编译时发生的,而是在构建二进制文件时发生的,这对我来说是某种链接器类型的问题?对如何产生VB6二进制文件还不够了解。生成了VB6二进制文件,但它已损坏并在调用后不久崩溃。

有没有人对VB6有类似的经历(不必与nlog或者C ++相关)?

编辑:感谢我们对这个相当晦涩的问题的所有答复。不幸的是,仍然没有进展。自发布此书以来的发现:

  • "调整"编译选项似乎对解决此问题没有帮助。
  • 从"空白" VB6项目中添加对启用了nlog的C ++组件的引用不会使它崩溃或者引起奇怪的生成问题。因此,这不是VB6的"本机"问题,可能不是nlog与各种组件以及其他引用的组件使用的第三方库之间的交互问题?
  • 至于C ++调用约定:据我所知,启用nlog的C ++组件符合这些约定,并且在不进行任何nlog API调用的情况下,当被VB6引用时,确实可以正常工作。不知道nlogc.DLL本身是否符合VB6,但我认为这并不重要,因为API调用是从C ++组件进行的;因此,请参见参考资料。 VB6不应该了解或者关心C ++组件所引用的内容(据我所知……)

edit2:我还应该注意,在构建过程中获得的错误消息是:"加载过程中的错误。有关详细信息,请参阅" xxx"。当我打开日志文件时,其中所有内容都是:"无法加载控件xxx"。有趣的是,如果我尝试再次构建,则对该特定控件的所有引用将从该特定项目中消失,从而导致编译错误。

解决方案

我将尝试调整在"项目","属性"菜单,"编译"面板中找到的一些"编译"选项,以查看它们是否对发生错误提供了其他提示。

例如,如果将可执行文件编译为p代码而不是本机代码,它在启动时仍会崩溃。

运行编译的二进制文件时,我们会收到什么错误消息?

我怀疑编译器/链接器是问题所在:VB6项目中的项目引用未链接到最终可执行文件中。 VB6中的项目引用实际上是对COM类型库的引用(它可以或者可以不嵌入.dll或者其他二进制文件类型)。项目参考主要用于两个目的:

  • IDE从引用的类型库中提取类型信息,然后将其显示在对象浏览器中(以及在Intellisense下拉列表中)
  • 在编译时,编译器提取存储在引用库中的类型信息,包括我们实例化的每个类的CLSID,并将此数据嵌入到可执行文件中。这使可执行文件可以创建所引用的库中包含的类的实例。

请注意,编译后的二进制文件不会链接到引用库中的任何代码,甚至不包含引用库的文件名。最终的可执行文件仅包含CLSID和其他类型的信息,在运行时实例化COM对象需要该信息。

问题很可能与NLog有关,或者与我们如何从代码中调用它有关,而不是在VB6编译过程中出现问题。

如果我们认为这可能是链接器问题,则应使用相同的方法使其崩溃:

  • 创建一个新的标准项目(任何形式)
  • 添加一个新模块并将"声明"语句复制到其中
  • 编译

如果它不崩溃,那是另外一回事了。

这将有助于对错误的准确描述或者正在发生的情况的屏幕截图。

要检查的一件事是在我们构建的NLogC.DLL或者C ++ DLL定义了正确的调用约定的任何地方。基本上,除了STDCALL调用约定之外,我们无法修改DLL函数名称或者使用任何其他函数。如果在创建C ++ DLL时没有考虑到这两点,那么它将无法在VB6中使用。

有关调用约定的MSDN文章。

通过使用不受管理的C ++代码中的NLog的COM接口(NLog.ComInterop.DLL)解决了该问题。做起来不像C \ C ++ API那样容易,但是至少它不会崩溃我的VB6组件。

通过与当前使用的不同版本的.ocx创建的.oca文件可能导致"无法加载控件xxx"错误。在这种情况下,删除.oca文件会有所帮助。