平台:WinXP SP2,英特尔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 / dllbuild立Fcall.f90 ,然后拷贝到C盘的“temp”目录下(这里怎么写一个反斜杠,除了复制/粘贴)?
我有一个Excel文件,在Sheet1中:
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)
运行时报告错误:运行时错误53,找不到文件c:\ temp \ fcall.dll
任何人有任何线索可能是错误的?
我知道这是一个非常古老的问题,但是前些天我遇到了这个问题,并认为我会为后代作出回答。 我的VBA代码调用Fortran DLL在我的电脑上工作正常,但在我的老板或其他任何人的电脑上都没有问题。 该问题最终依赖于其他DLL,尽管编译在“释放”模式,而不是“调试”。 我使用Dependency Walker来检查DLL中的依赖关系,它不会工作,找到两个与intel编译器一起使用的DLL,并使用我自己编译的DLL分发这些DLL。
不知道什么可能是错的。
我无法使用ifort编译器,但是我通过将一个随机DLL复制到指定了Declare语句的Temp文件夹来尝试执行代码。 当我运行它时,我得到的错误是:“无法找到C:\ Temp \ RandomDLL.DLL中的DLL入口点FortranCall”,这是与使用错误的DLL一致(即,找到该DLL,但它不与调用代码一起)。
您可以尝试用随机的其他DLL替换您编译的DLL,并查看是否得到相同的错误。 如果这样做,这是OS环境的问题,而不是编译器。
这可能不是很有帮助,但可能会消除一两个可能性。
我使用的环境:Win Vista,Excel 2003
您可以尝试将您的DLL移动到C:\ Windows \ system32(或其他位于默认路径上的文件夹),并将Lib
部分更改为"FCall.dll"
。 这应该消除定位实际文件的任何古怪
我有同样的问题 – 超级沮丧!
我在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! 我给了我的老板我以DEBUG模式编译的DLL – 在这种情况下,DLL使用了很多在普通计算机上不常见的DLL的其他调试版本。 当我给我的老板RELEASE版本的DLL,它工作的很好! 另见: http : //software.intel.com/zh-cn/forums/showthread.php?t=42472
那么这可能太晚了,但是需要考虑一些问题
1)“调用约定”必须正确匹配。 这有几个不同的方面,其中一些是:
a)s / r和Arg名称的大小写。
b)停顿调用约定。 在你的代码中,你使用了一些“混合”的东西,似乎缺少一些位。
例如,试试这个
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 ! eg 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)
注意为字符串len额外的Arg,这只出现在VBA一侧,只有当字符串通过ByVal(任何其他字符串传递,尤其是字符串数组是一个巨大的问题…可行,但准备一些作业) 。
此外,这里的字符串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,或者其他什么…一个合理的习惯,如果你会做很多这样的事情,特别是与函数等。 ,但这里并不重要。
和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(通常)放在相同的目录中,并通过工具/ Addins等将Addin添加到Excel中…浏览以确保正确的路径。
然后,您也可以从任何工作簿/表单中调用您的s / r,而不仅仅是一个工作簿。
我最近和ifort 14一样,当我编译时,问题就消失了
ifort /dll /libs:static /threads
而不是仅仅
ifort /dll
当DLL不依赖于系统路径上的另一个DLL(例如gfortran和MinGW32 \ bin中的一个DLL)时,通常会出现消息“找不到文件”。 但是我没有在这里找到这样的依赖,很奇怪。