我正在尝试从我的Fortran应用程序中使用COM。我做COMINITIALIZE
后跟COMCreateObjectByProgID
。这两个似乎都成功并返回零状态。但是,当我尝试使用COM对象时,我得到:
Unhandled exception at 0x00000000 in FortranProg01.exe: 0xC0000005: Access violation.
我意识到这个错误几乎可以意味着什么,但有没有人得到一些COM常见问题的建议产生这个问题?我的程序代码:
program FortranProg01
use myolepg
implicit none
integer*4 comInitStatus
integer:: comCreateStatus
INTEGER(INT_PTR_KIND()) $OBJECT
INTEGER(4) funcResult
REAL(8) pkgVersion
call COMINITIALIZE(comInitStatus)
print *, comInitStatus
call COMCreateObjectByProgID('MyOlePg.MyOlePkg', $OBJECT, comCreateStatus)
print *, comCreateStatus
funcResult = IMyOlePkg_GetPackageVersion($OBJECT, pkgVersion)
print *, funcResult
call COMUNINITIALIZE()
end program FortranProg01
向导生成的界面代码:
INTERFACE
!property PackageVersion
INTEGER(4) FUNCTION IMyOlePkg_GetPackageVersion($OBJECT, pVal)
INTEGER(INT_PTR_KIND()), INTENT(IN) :: $OBJECT ! Object Pointer
!DEC$ ATTRIBUTES VALUE :: $OBJECT
REAL(8), INTENT(OUT) :: pVal
!DEC$ ATTRIBUTES REFERENCE :: pVal
!DEC$ ATTRIBUTES STDCALL :: IMyOlePkg_GetPackageVersion
END FUNCTION IMyOlePkg_GetPackageVersion
END INTERFACE
非常感谢任何帮助!
答案 0 :(得分:1)
好吧,看起来这是特定于包的问题。更准确地说,这是我对包或当前Fortran约定的误解。据我所知,包中的几乎所有方法都定义了两次,一次使用常规名称,一次使用$
前言。
因此,如果我使用$IMyOlePkg_GetPackageVersion
调用而不是IMyOlePkg_GetPackageVersion
调用,我会收到构建警告:
ipo: warning #11077: ...: locally defined symbol ... imported
但它有效!特别有趣的是,$
方法只是添加偏移量然后调用non-$
方法。
现在我并不喜欢这个警告,如果有人能解释警告和两个不同的电话,我会很高兴,我有它的工作,如果我从来没有得到满意的解释,我可能会学会与之共处。
答案 1 :(得分:1)
非装饰接口成员只是函数名称,但它们的地址在编译时是未知的(由于它们是从COM动态导入的,因此无法知道)。链接器将其值设置为0x00000000
,这就是您收到此错误的原因,类似于在C中取消引用NULL
指针时发生的情况。
正如它在Compaq Visual Fortran用户指南中所写:
COM成员函数的接口看起来非常类似于接口 一个动态链接库函数,有一个主要的例外。与DLL函数不同, 在程序链接时永远不知道COM成员函数的地址。 您必须在运行时获取指向对象接口的指针,以及a的地址 特定成员函数由此计算。
这正是装饰版本的功能。它们取$OBJECT
实际上是指向对象接口的指针,而对象接口又是实现接口(vtable)的实际对象方法的地址表。然后,修饰函数在实际方法的vtable中添加偏移量,并通过指针分配结果地址,然后 调用未装饰的地址(不再是一个NULL
指针)。
请参阅第541页(调用模块生成的例程 Compaq Visual Fortran用户指南的向导)可用here。有一个带注释的示例,说明究竟生成了什么以及为什么生成。注意接口定义的注释6(声明指向非装饰接口成员的指针)和装饰函数的注释4。
警告#11077
与Microsoft的链接器中的warning LNK4217相同。忽略它可能是安全的。