首页 文章

Excel VBA中C DLL位置的无法解释的行为

提问于
浏览
3

我最初发布这个作为Trouble with file location in excel/fortran dll connection的答案,因为问题似乎相似 . 但由于这是一个引用fortran的旧问题,我决定发布一个新问题,因为我认为更多的人会在c中有这方面的经验(对不起,第一次在SO上发帖所以请耐心等待我) .

当从VBA调用一个引用第二个c dll的c dll时出现问题 . 我这样做的原因是因为我正在处理不同的dll项目,这些项目共享一些类似的功能,所以我希望有一个单独的实用程序DLL,他们都可以参考 . 我的设置是:

Visual Studio Express 2013 V12.0

Excel 2010 V14.0(64位),VBA V7.0

当只有一个DLL项目时,一切正常 . 在最简化的形式中,我有一个名为'a'的解决方案,其中包含一个名为'a'的项目,其中包含以下两个文件:

// a.cpp
void __stdcall a() {}

// a.def
EXPORTS
    a

我在项目属性页面中的链接器输入下指定a.def作为模块定义文件,然后编译生成a.dll文件 . 在VBA中,我有:

Declare PtrSafe Sub a Lib "C:\ ... \a.dll" ()

Sub test()
  a
End Sub

a.dll位于“C:\ ... \ Visual Studio 2013 \ Projects \ a \ x64 \ Debug \”中创建的位置,测试Sub输入正常 . 然后我向解决方案添加一个名为'b'的第二个dll项目,其中包含以下三个文件:

// b.h
void __stdcall b();

// b.cpp
#include "b.h"
void __stdcall b() {}

// b.def
EXPORTS
    b

我将a.cpp定义更改为:

// a.cpp
#include "b.h"

void __stdcall a() {
  b();
}

在'a'项目属性中,我在其他包含目录下指定b.h的路径,并在公共属性下添加对b的引用 . 一切都很好 . 回到VBA我添加:

Declare PtrSafe Sub b Lib "C:\ ... \b.dll" ()

Sub test1()
  a
  b
End Sub

test1产生运行时错误'53':文件未找到“C:\ ... \ a.dll”,尽管我可以看到它位于之前的同一位置 . 但奇怪的是,如果我在sub中更改了a和b的调用顺序,那么它确实有效:

Sub test2()
  b
  a
End Sub

所以VBA可以找到b,不知怎的,这似乎足以促使它再次找到它 .

无论如何,解决方案是在Excel / VBA当前工作目录CurDir()中放置a.dll和b.dll的副本 . 奇怪的是,我实际上不必将Declare语句中的Lib路径更改为CurDir(尽管我可以) . 我可以告诉它真的是原始VS文件夹中的dll正在运行,因为如果我对a.cpp和b.cpp进行可检测的更改并重新编译而不将新dll重新复制到CurDir,VBA肯定会运行新的dll在VS文件夹中不是CurDir中的旧副本 . 不知何故,仅仅存在CurDir中的副本就足以提示VBA在VS文件夹中找到指定的dll . 也许其他人可以对这种行为有所了解......

虽然对我来说很神秘,但由于我正在开发dll并且不必在每次编译后都不断复制它,因此并不是很不方便 . 另一种解决方案是将Excel工作簿保存在VS文件夹中,其中输出dll是这样,CurDir会自动包含它们 . 以上所有内容都表明VS是否符合Debug或Release模式 . 我得到了http://communities.bentley.com/products/microstation/f/273/t/12979.aspx的帮助,但是我想了解这种看似不一致的行为,而不仅仅是有一个解决方法 . 谢谢

2 回答

  • 0

    作为开发人员,我认为我们大多数人在某个时候经历过这种奇怪的错误 . 调试此类问题的一个很好的工具是系统内部工具包中的process monitor .

    它可以捕获进程的文件加载/卸载活动,从其日志中,您可以看到进程如何搜索dll . 所以你得到两个案例的两个日志并比较它们以找出错误;这不是一件容易的事,因为日志文件可能很大 . 我曾经使用这个工具来获取客户端的进程监控日志,以便调试我们无法重现的错误,并帮助我弄清楚其中的一些 .

  • 1

    此处给出了Windows找到DLL的搜索路径:https://msdn.microsoft.com/en-us/library/windows/desktop/ms682586%28v=vs.85%29.aspx . 检查特殊情况并加载DLL之后,它就是

    # The directory from which the application loaded.
    # The system directory. Use the GetSystemDirectory function to get the path of this directory.
    # The 16-bit system directory. There is no function that obtains the path of this directory, but it is searched.
    # The Windows directory. Use the GetWindowsDirectory function to get the path of this directory.
    # The current directory.
    # The directories that are listed in the PATH environment variable.
    

    我说“搜索路径”因为它确实依赖于哪个版本的Windows,以及如何设置窗口 .

    请注意,“已经加载了其他DLL的目录”不是搜索路径的一部分,并且“甚至已加载的dll”在它开始搜索之前出现 .

    在我写这篇文章时,Visual Studio文档页面(甚至是当前的VS2015页面)更短,更不完整,并且过时,只重复有关旧版Windows的旧信息 .

相关问题