Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/127.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ C+无法解释的行为+;excelvba中DLL的位置_C++_Excel_Vba_Dll - Fatal编程技术网

C++ C+无法解释的行为+;excelvba中DLL的位置

C++ C+无法解释的行为+;excelvba中DLL的位置,c++,excel,vba,dll,C++,Excel,Vba,Dll,我最初将此作为一个答案发布,因为问题似乎类似。但由于这是一个老问题,引用FORTRAN,我决定发布一个新的问题,因为我认为更多的人会在C++中有这种体验(抱歉,第一次发布这样的文章,请耐心等待)。 当VBA调用C++第二方语言,引用第二个C++ DLL时,问题就出现了。我这样做的原因是因为我正在处理不同的dll项目,这些项目共享一些类似的功能,所以我希望有一个实用程序dll,它们都可以引用。我的设置是: Visual Studio Express 2013 V12.0 Excel 2010 V1

我最初将此作为一个答案发布,因为问题似乎类似。但由于这是一个老问题,引用FORTRAN,我决定发布一个新的问题,因为我认为更多的人会在C++中有这种体验(抱歉,第一次发布这样的文章,请耐心等待)。 当VBA调用C++第二方语言,引用第二个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\”中创建的位置,测试子系统可以很好地输入它。然后,我向解决方案中添加了第二个名为“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”项目属性中,我在附加Include目录下指定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,不知何故,这似乎足以促使它再次找到a

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


虽然让我感到困惑,但这并不麻烦,因为我正在开发DLL,并且不必在每次编译后都复制它们。另一个解决方案是将Excel工作簿保存在输出DLL所在的VS文件夹中,以便CurDir自动包含它们。以上所有内容都适用于VS是否在调试或发布模式下编译。我得到了来自的帮助,但是我想了解这种看似不一致的行为,而不仅仅是有一个解决办法。谢谢作为开发者,我想我们大多数人都曾经历过这种奇怪的错误。调试此类问题的一个很好的工具是系统内部工具包


它可以捕获进程的文件加载/卸载活动,从它的日志中,您可以看到进程是如何搜索DLL的。因此,您将获得两个日志,用于这两种情况,并对它们进行比较,以找出问题所在;这不是一件容易的事,因为日志文件可能很大。我曾使用此工具获取客户端的进程监视日志,以调试无法重现的错误,它帮助我找出其中一些错误。

此处给出了Windows查找DLL的搜索路径:。在检查特殊情况和加载的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的版本以及windows的设置方式

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


在我写这篇文章时,Visual Studio文档页面(即使是当前的VS2015页面)要短得多,不完整得多,而且已经过时,只会重复有关旧版本Windows的旧信息。

这是正常的,操作系统不会在同一目录中查找相关DLL。Excel没有太多好的选项,将DLL复制到Office目录是非常实用的。帮助你摆脱那丑陋的硬编码路径。啊,好的,这是有意义的。仔细检查,test2在第一行直接调用时运行的是新版本的b.dll,但在第二行作为依赖dll从a.dll中调用时运行的是旧版本的b.dll。谢谢你的帮助