d_lemmon
06-17-2004, 05:36 PM
I am writing a book chapter on creating Fortran COM Servers, and I wish to include an example using LF Fortran for .NET. I want to demonstrate using a COM object from VBA in Excel. However, I'm having trouble with array properties. Here's a whittled-down version of my server module code:
!====================================
module EmExpSrvr
use System%Runtime%InteropServices ! needed to create COM interface
implicit none
! class prototype
type :: EmExpObj
!
! field and enum definitions
!
real(kind=kind(0.d0)), private, pointer, dimension(:) :: y_int
real(kind=kind(0.d0)), private :: pi_int
integer, private :: iter_int
contains
!
! method, property, and constructor declarations
!
property, pass :: y => set_y, get_y
property, pass :: pi => set_pi, get_pi
property, pass :: iter => get_iter
end type EmExpObj
! Instruct framework to generate an COM automation
! interface for the EmExpObj class
!.nca (EmExpObj, add=ClassInterfaceAttribute(ClassInterfaceType%Aut oDual))
contains
! Property y
subroutine set_y(this, y_in)
type( EmExpObj ) :: this
real(kind=kind(0.d0)), dimension(:) :: y_in
if( associated(this%y_int) ) deallocate(this%y_int)
allocate( this%y_int( size(y_in,1) ) )
this%y_int = y_in
end subroutine set_y
function get_y(this) result(y_out)
type( EmExpObj ) :: this
real(kind=kind(0.d0)), dimension(size(this%y_int,1)) :: y_out
y_out = this%y_int
end function get_y
! Property pi
subroutine set_pi(this, pi_in)
type( EmExpObj ) :: this
real(kind=kind(0.d0)) :: pi_in
this%pi_int = pi_in
end subroutine set_pi
function get_pi(this) result(pi_out)
type( EmExpObj ) :: this
real(kind=kind(0.d0)) :: pi_out
pi_out = this%pi_int
end function get_pi
! Property iter (read-only)
function get_iter(this) result(iter_out)
type( EmExpObj ) :: this
integer :: iter_out
iter_out = this%iter_int
end function get_iter
end module EmExpSrvr
!====================================
I register this using "regasm EmExpSrvr.dll /tlb". Then I place a copy of EmExpSrvr.dll in the same directory as Excel.exe.
I then create an Excel macro using VBA. I create a reference to EmExpSrvr. Then I enter the following code in VBA:
'----------------------------------------
Sub run()
Dim a As EmExpSrvr.EmExpObj
Dim y(10) As Double
Set a = New EmExpSrvr.EmExpObj
y(1) = 5.6
y(2) = 0.7
y(3) = 2.4
y(4) = 2.2
y(5) = 4.5
y(6) = 0.6
y(7) = 2.3
y(8) = 3.1
y(9) = 1.6
y(10) = 2.2
a.y = y
a.Pi = 0.465
MsgBox ("a.pi = " & a.Pi)
End Sub
'----------------------------------------
I get an error, "Invalid use of property", on the line with a.y in it. When I comment out that line it works. The non-array property 'a.pi' work fine. There also seem to be these auxillary properties that are created during registration: y_2 and y_3. I've tried these as well, but they don't work either. I know there has to be a way to get this working, involving a deeper understanding of COM interop, but I'd like to see if you have any insight.
Thanks!
!====================================
module EmExpSrvr
use System%Runtime%InteropServices ! needed to create COM interface
implicit none
! class prototype
type :: EmExpObj
!
! field and enum definitions
!
real(kind=kind(0.d0)), private, pointer, dimension(:) :: y_int
real(kind=kind(0.d0)), private :: pi_int
integer, private :: iter_int
contains
!
! method, property, and constructor declarations
!
property, pass :: y => set_y, get_y
property, pass :: pi => set_pi, get_pi
property, pass :: iter => get_iter
end type EmExpObj
! Instruct framework to generate an COM automation
! interface for the EmExpObj class
!.nca (EmExpObj, add=ClassInterfaceAttribute(ClassInterfaceType%Aut oDual))
contains
! Property y
subroutine set_y(this, y_in)
type( EmExpObj ) :: this
real(kind=kind(0.d0)), dimension(:) :: y_in
if( associated(this%y_int) ) deallocate(this%y_int)
allocate( this%y_int( size(y_in,1) ) )
this%y_int = y_in
end subroutine set_y
function get_y(this) result(y_out)
type( EmExpObj ) :: this
real(kind=kind(0.d0)), dimension(size(this%y_int,1)) :: y_out
y_out = this%y_int
end function get_y
! Property pi
subroutine set_pi(this, pi_in)
type( EmExpObj ) :: this
real(kind=kind(0.d0)) :: pi_in
this%pi_int = pi_in
end subroutine set_pi
function get_pi(this) result(pi_out)
type( EmExpObj ) :: this
real(kind=kind(0.d0)) :: pi_out
pi_out = this%pi_int
end function get_pi
! Property iter (read-only)
function get_iter(this) result(iter_out)
type( EmExpObj ) :: this
integer :: iter_out
iter_out = this%iter_int
end function get_iter
end module EmExpSrvr
!====================================
I register this using "regasm EmExpSrvr.dll /tlb". Then I place a copy of EmExpSrvr.dll in the same directory as Excel.exe.
I then create an Excel macro using VBA. I create a reference to EmExpSrvr. Then I enter the following code in VBA:
'----------------------------------------
Sub run()
Dim a As EmExpSrvr.EmExpObj
Dim y(10) As Double
Set a = New EmExpSrvr.EmExpObj
y(1) = 5.6
y(2) = 0.7
y(3) = 2.4
y(4) = 2.2
y(5) = 4.5
y(6) = 0.6
y(7) = 2.3
y(8) = 3.1
y(9) = 1.6
y(10) = 2.2
a.y = y
a.Pi = 0.465
MsgBox ("a.pi = " & a.Pi)
End Sub
'----------------------------------------
I get an error, "Invalid use of property", on the line with a.y in it. When I comment out that line it works. The non-array property 'a.pi' work fine. There also seem to be these auxillary properties that are created during registration: y_2 and y_3. I've tried these as well, but they don't work either. I know there has to be a way to get this working, involving a deeper understanding of COM interop, but I'd like to see if you have any insight.
Thanks!