1

平台:WinXP SP2、Intel Fortran 11、Excel 2007

我在将 dll 文件与 excel 连接时遇到问题。

dll文件比较简单:

subroutine FortranCall (r1, num)
!DEC$ ATTRIBUTES DLLEXPORT, STDCALL, REFERENCE, ALIAS:"FortranCall" :: FortranCall
integer, intent(in) :: r1
character(10), intent(out) :: num
!DEC$ ATTRIBUTES REFERENCE :: num

num = ''
write (num,'(i0)') r1 * 2

return
end subroutine FortranCall

使用:ifort /nologo /dll Fcall.f90 构建,然后复制到 C 驱动器上的“temp”目录(无论如何,如何在此处写反斜杠(复制/粘贴除外)?

我在 Sheet1 中有一个 Excel 文件:

Private Sub CommandButton1_Click()
Dim r1 As Long
Dim num As String * 10

     r1 = 123
     Call FortranCall(r1, num)

     TextBox1.Text = "Answer is " & num

End Sub

在 Moduel1 中:

Declare Sub FortranCall Lib "C:\temp\Fcall.dll" (r1 As Long, ByVal num As String)

运行时报错:runtime error 53, file not found c:\temp\fcall.dll

任何人都知道可能出了什么问题?

4

6 回答 6

2

我知道这是一个非常古老的问题,但前几天我遇到了这个问题,并认为我会为后代提供一个答案。我调用 Fortran DLL 的 VBA 代码在我的计算机上运行良好,但在我老板或其他任何人的计算机上却不行。尽管在“发布”模式而不是“调试”模式下编译,问题最终还是依赖于其他 DLL。我使用Dependency Walker在无法运行的计算机上检查 DLL 中的依赖关系,找到两个所需的英特尔编译器附带的 DLL,并使用我自己编译的 DLL 分发这些。

于 2012-02-18T06:22:47.727 回答
2

我有同样的问题 - 超级令人沮丧!

我在 Excel VBA 中有类似的声明:Declare Sub FortranCall Lib "C:\temp\Fcall.dll" (r1 As Long, ByVal num As String)

它可以在我的计算机上运行,​​但它不能在我老板的计算机上运行。文件名和路径规范的所有拼写都很好。我的 DLL 是在 Microsoft Visual C++ 6.0 中编译的。问题是 - “找不到文件/运行时错误 53”的常见原因是调用应用程序无法找到相关 dll 实际依赖的 dll!我给了我的老板我在调试模式下编译的 DLL——在这种情况下,DLL 使用了许多其他调试版本的 DLL,这些在普通计算机上并不常见。当我给我的老板 RELEASE 版本的 DLL 时,它运行良好!另请参阅: http ://software.intel.com/en-us/forums/showthread.php?t=42472

于 2010-12-17T03:02:25.013 回答
1

不知道可能出了什么问题。

我无法使用 ifort 编译器,但我通过将随机 DLL 复制到指定 Declare 语句的 Temp 文件夹来尝试您的代码。运行时报错:“Can't find DLL entry point FortranCall in C:\Temp\RandomDLL.DLL”,这与使用错误的DLL一致(即找到了DLL,但是与调用代码无关)。

您可以尝试用随机的其他 DLL 替换您编译的 DLL,看看是否会遇到相同的错误。如果你这样做了,那是操作系统环境的问题,而不是编译器的问题。

这可能不是很有帮助,但可能会消除一两种可能性。

我使用的环境:Win Vista、Excel 2003

于 2009-06-10T04:26:11.730 回答
1

您可以尝试将 DLL 移动到 C:\Windows\system32 (或默认路径上的任何其他文件夹)并将Lib部分更改为"FCall.dll". 这应该消除定位实际文件的任何奇怪之处

于 2009-06-10T08:17:04.153 回答
0

我最近对 ​​ifort 14 也有同样的情况,当我编译时问题就消失了

ifort /dll /libs:static /threads

而不仅仅是

ifort /dll

当 DLL 依赖于不在系统路径上的另一个 DLL 时,通常会出现“找不到文件”的消息(例如,我使用 gfortran 和MinGW32\bin中的 DLL )。但是我这里没有发现这样的依赖,比较奇怪。

于 2014-07-02T06:18:44.770 回答
0

好吧,这可能为时已晚,但需要考虑一些问题

1)“调用约定”必须正确匹配。这有几个不同的方面,其中一些是:

a) s/r 和 Arg 名称是否大写或混合。

b) Srting 调用约定。在您的代码中,您使用了一些“混合”的东西,并且似乎缺少一些位。

例如,试试这个

subroutine FORTRANCALL (R1, NUM)        ! notice capitalisation
!DEC$ ATTRIBUTES DLLEXPORT :: FORTRANCALL   ! notice capitalisation  and default "calling convention" (this varies between compilers)
                    ! but older CVF and Intel compilers default to CDECL, which you can set in your "properties" etc.  
                    ! Its been a while but I think newer IVF have changed to a different default convention
                    ! e.g. if you were doing this, say, in GCC/gFortran, there would be a much longer discussion
integer, intent(in) :: r1
Character(Len=10), intent(out) :: num   ! you might be able to use Character(Len=*) so long as its fixed on the VBA side
!   remove this => !DEC$ ATTRIBUTES REFERENCE :: num

num = ''
write (num,'(i0)') r1 * 2

return
end subroutine FortranCall

在 VBA 方面,声明是:

Declare Sub FortranCall_XX Lib "C:\ ... your path ...\Fcall.dll.dll" _
Alias "FORTRANCALL" (R1 as Long, ByVal NUM As String, ByVal NumLen as Long)

注意 String len 的额外 Arg,这仅出现在 VBA 端,并且仅在通过 ByVal 传递 String 时出现(任何其他字符串传递,尤其是字符串数组都是一个巨大的问题......可行,但要为一些功课做好准备) .

此外,这里的字符串 len 只是在 Arg 位置之后跟随字符串。但是,如果 num 位于更早的位置,则 NumLen 的位置将位于 Arg num 之后,或者位于 Arg 列表的末尾,具体取决于调用约定。

此外,当您创建 DLL 时,编译器通常还会创建一个“Def”文件。使用 VBA/Fortran 时无需直接访问 Def 文件。但是,查看它的内部会向您显示编译器认为您的 s/r 应该被调用的确切“命名风格”。例如,使用某些调用约定,Def 文件可能会将您的 s/r 的名称显示为类似 __fortrancall@12

...无论 Def 文件说什么,您必须在 VBA 声明中使用别名“__fortrancall@12”

...这些事情需要对具有不同调用约定/编译器的一般实现进行冗长的讨论。

顺便说一句:我添加“_XX”纯粹是为了让实际的 VBA UDF 具有“明显的名称”,比如 FortranCall,或者其他什么......如果你会做很多这样的事情,尤其是使用 Functions 等,这是一个合理的习惯。 ,但在这里不太重要。

并且 VBA 子变成:

Private Sub CommandButton1_Click()
Dim r1 As Long
Dim num As String * 10
Dim numlen as Long

 numlen = 10                ' required string len, can automate via intrinsics etc

 r1 = 123
 Call FortranCall_XX(r1, num, numlen)   ' notice the extra Arg

 TextBox1.Text = "Answer is " & num     ' you may wish to add Trim() or something in case returned num does not require 10 chars

End Sub

2) 你真的需要将 num 作为字符串传递吗?在 VBA 和 DLL 之间传递字符串是一大堆蠕虫。为什么不将 num 作为 Double 或其他东西传递?

如果它必须是字符串并且如果它是 ByVal,那么您还必须在 VBA 端将字符串长度包括为 ByVal Long(因为在 Fortran 中,字符串 len 是隐藏值),如上所示。

如果您知道如何在 Fortran 端使用(Cray)指针或变体将 VBString 转换为 Fortran 字符串等,则可以通过 Ref 和带有/不带有额外的 StringLen 等... 一个很长的讨论。

3)分发/连接到dll的更通用和“确定”的方法是将XL表/模块转换为XLA ...即加载项。然后(通常)将 XLA 和 DLL 放入同一个目录中,并通过工具/插件等将插件添加到 Excel 中......它具有浏览以确保正确的路径。

然后,您还可以从任何工作簿/工作表等中调用您的 s/r,而不仅仅是一个工作簿。

于 2017-09-17T00:29:21.897 回答