excel/fortran dll 连接中的文件位置问题

发布于 2024-07-24 08:20:58 字数 1012 浏览 5 评论 0原文

平台: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”目录(这里如何写反斜杠,无论如何(复制/粘贴除外)?

并且我有一个 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

有人知道可能出了什么问题吗?

Platform: WinXP SP2, Intel Fortran 11, Excel 2007

I'm having trouble connecting a dll file with excel.

The dll file is relatively simple:

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

build with: ifort /nologo /dll Fcall.f90, and after that copied to "temp" directory on C drive (how does one write a backslash in here, anyway (except copy/pasting) ?)

and I have an Excel file with, in 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

and in Moduel1:

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

When ran it reports an error: runtime error 53, file not found c:\temp\fcall.dll

Anyone has any clue what could be wrong ?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

黯然#的苍凉 2024-07-31 08:20:58

我遇到了同样的问题 - 超级令人沮丧!

我在 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

I had the same problem - super frustrating!

I had the similar kind of declaration in Excel VBA:
Declare Sub FortranCall Lib "C:\temp\Fcall.dll" (r1 As Long, ByVal num As String)

It worked on my computer but it did not work on my boss's computer. All the spelling of the file name and the path specification were fine. My DLL was compiled in Microsoft Visual C++ 6.0. The problem was - A common cause for "File not found/Runtime error 53" is that the calling application cannot find dll's on which the dll in question actually depends!!! I gave my boss the DLL that I compiled in DEBUG mode - in this case DLL uses lots of other debug versions of DLL which not commonly found on regular computers. When I gave my boss RELEASE version of DLL it worked fine!
See also:
http://software.intel.com/en-us/forums/showthread.php?t=42472

会发光的星星闪亮亮i 2024-07-31 08:20:58

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

I know this is a very old question, but I came across this issue the other day and thought I'd put an answer up for posterity. My VBA code calling a Fortran DLL worked fine on my computer, but not on my boss's or anyone else's computer. The problem ended up being dependency on other DLLs, despite compiling in "release" mode instead of "debug". I used Dependency Walker to check the dependencies in the DLL on a computer where it wouldn't work, found two DLLs which come with the intel compiler that were needed, and distributed these with my own compiled DLL.

再见回来 2024-07-31 08:20:58

不确定可能出了什么问题。

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

您可以尝试用随机的其他 DLL 替换您编译的 DLL,看看是否出现相同的错误。 如果出现这种情况,则是操作系统环境的问题,而不是编译器的问题。

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

我使用的环境:
赢得维斯塔,
Excel 2003

Not sure what could be wrong.

I couldn't get my hands on an ifort compiler, but I tried your code by copying a random DLL to the Temp folder specified the Declare statement. When I run it, the error I get is: "Can't find DLL entry point FortranCall in C:\Temp\RandomDLL.DLL", which is consistent with using the wrong DLL (that is, the DLL was found, but it doesn't jive with the calling code).

You could try to replace the DLL you compiled with a random other DLL and see if you get the same error. If you do, it is a problem with the OS environment, not the compiler.

This is probably not very helpful, but may eliminate one or two possibilities.

Environment I used:
Win Vista,
Excel 2003

盗琴音 2024-07-31 08:20:58

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

You could try moving your DLL to C:\Windows\system32 (or any other folder that's on the default path) and changing the Lib part to just "FCall.dll". That should eliminate any oddities with locating the actual file

心安伴我暖 2024-07-31 08:20:58

好吧,这可能已经太晚了,但是需要考虑一些问题

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

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

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

例如,尝试这个

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 端,并且仅当 String 传递 ByVal 时(任何其他字符串传递,尤其是字符串数组是一个巨大的问题......可行,但要做好一些功课的准备)。

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

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

... 无论 Def 文件说什么,您都必须在 VBA 声明中使用 Alias "__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(通常)放入同一个目录中,并且通过工具/插件等将插件添加到 Excel 中......它已浏览以确保正确的路径。

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

Well this may be way too late, but a number of issues to consider

1) The "calling convention" must match correctly. This has several different aspects, some of which are:

a) The capitalisation or not or mix of s/r and Arg names.

b) Srting calling conventions. In your code you have used some "mix" of things, and seem to be missing some bits.

For example, try this

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

On the VBA-side, the declaration is:

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

NOTICE the extra Arg for the String len, this only appears on the VBA side, and ONLY when String is passed ByVal (any other string passing and especially arrays of strings is a giant issue ... doable, but be prepared for some homework).

Also, the string len here simply follows the string in terms of Arg position. However, if num was located earlier on, the the location of NumLen would be either just following the Arg num, or at the end of Arg list, depending on the calling convention.

Also, when you create a DLL, the compiler often also creates a "Def" file. You don't need to access the Def file directly when using VBA/Fortran. However, looking inside it will show you the exact "naming style" of what the compiler thinks your s/r should be called. For example, with some calling conventions, the Def file might show the name of your s/r as something like
__fortrancall@12

... whatever the Def files says, is what you must use in the VBA declaration Alias "__fortrancall@12"

... these things require a lengthy discussion for general implementation with different calling conventions/compilers.

BTW: I added the "_XX" purely to allow the actual VBA UDF to have the "obvious name", say FortranCall, or whatever ... a reasonable habit if you will be doing a lot of this, and especially with Functions etc., but not too important here.

and the VBA sub becomes:

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) Do you really need to pass num as a string? Passing strings between VBA and DLL's is a big can of worms. Why not pass num as a Double or something?

If it must be a string and if it's ByVal, then you must also include the string length as ByVal Long on the VBA-side (since in Fortran the string len is a hidden value) as shown above.

You can pass by Ref and with/without the extra StringLen if you know how use (Cray) Pointers or Variants on the Fortran side to convert the VBString to a Fortran string etc. ... a long long discussion.

3) A more general and "certain" way to distribute/connect to a dll is to convert the XL sheet/module to an XLA ... i.e. an Add-In. Then the XLA and DLL are (usually) put into the same Dir, and the Addin is Added to Excel via Tools/Addins etc ... which has browse to ensure the correct path.

Then, you can also call your s/r's from any workbook/sheet etc., not just the one workbook.

凌乱心跳 2024-07-31 08:20:58

编译时,问题就消失了

ifort /dll /libs:static /threads

我最近在 ifort 14 上也遇到了同样的问题,当我使用而不是仅仅

ifort /dll

当 DLL 依赖于另一个不在系统路径上的 DLL 时,经常会出现消息“文件未找到”(我用 gfortran 进行了此操作) ,以及 MinGW32\bin 中的 DLL,例如)。 但我这里并没有发现这样的依赖,比较奇怪。

I had the same recently with ifort 14, and the problem disappears when I compile with

ifort /dll /libs:static /threads

Instead of just

ifort /dll

The message "file not found" often arise when the DLL has a dependency on another DLL which is not on system path (I had this with gfortran, and a DLL in MinGW32\bin, for instance). But I didn't find such a dependency here, rather strange.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文