引数が構造体のVBAのマクロをVB.NETから呼び出すにはどのように記述すればよいのでしょうか。
例えば、下記のコードでは、ビルドは問題ないのですが、実行時に、oExcel.Run("'" & oBook.Name & "'!TEST", t_o)のt_oの箇所で、「ArgumentExceptionはハンドルされませんでした。値が有効な範囲にありません。」というエラーになります。前回、「引数が構造体のVBのDLLの関数をVBAから呼び出す方法」について教えていただきましたが、ユーザー定義型でString型をBSTR型にマーシャリングしてみましたがうまくいきませんでした。どのように記述すれば、VB.NETからVBAのマクロに構造体の引数を渡すことができるのでしょうか。
---VB.NET---
Imports Microsoft.Office.Interop
Imports System.Runtime.InteropServices
Public Structure T
<MarshalAs(UnmanagedType.BStr)> Public x As String
Public y As Integer
End Structure
Module Module1
Sub Main()
Dim oExcel As New Excel.Application
Dim oBook As Excel.Workbook
Dim oBooks As Excel.Workbooks = oExcel.Workbooks
Dim strPath As String
Dim t_o As T
t_o.x = "ABC"
t_o.y = 123
strPath = "C:\temp\test\Book1.xls"
oExcel.Visible = False
oBook = oBooks.Open(strPath)
oExcel.Run("'" & oBook.Name & "'!TEST", t_o)
oBook.Close(False)
System.Runtime.InteropServices.Marshal.ReleaseComObject(oBook)
oBook = Nothing
System.Runtime.InteropServices.Marshal.ReleaseComObject(oBooks)
oBooks = Nothing
oExcel.Quit()
System.Runtime.InteropServices.Marshal.ReleaseComObject(oExcel)
oExcel = Nothing
End Sub
End Module
---VBA側---
Option Explicit
Public Type T
x As String
y As Integer
End Type
Sub test(ByRef t_o As T)
MsgBox t_o.x
MsgBox t_o.y
End Sub
-------------
よろしくお願いします。
( WindowsXP , Excel2003_VBA , VisualStudio2010 )
>「引数が構造体のVBのDLLの関数をVBAから呼び出す方法」について教えていただきましたが
下記のスレッドですね。
http://madia.world.coocan.jp/cgi-bin/vbnet/wwwlng.cgi?print+201210/12100006.txt
http://okwave.jp/qa/q7721398.html
> どのように記述すれば、VB.NETからVBAのマクロに構造体の引数を渡すことができるのでしょうか。
COM の構造体は、タイプライブラリとして公開された型であり、
VBA のユーザー定義型とは別の物です。
VB6 のユーザー定義型や VB.NET の構造体であれば、COM として公開できますが、
VBA の場合は、その構造体を定義したタイプライブラリを参照設定して使う事になります。
今回の場合は、T 型を定義したタイプライブラリを用意しておき、
それをVB.NET と VBA の双方から参照するのが手っ取り早いでしょう。
タイプライブラリは ODL/IDL 等で書いたものでも良いですし、
VB.NET で COM 公開した DLL を利用しても構いません。
利用側のコードは元の物と殆ど変らないので、
あえて書くまでも無いとは思いますが、一応記載。
'-------------------------------
Option Explicit
Sub test(ByRef t_o As SampleLibrary.T)
'Sub test(ByVal t_o As Variant)
MsgBox t_o.x
MsgBox t_o.y
MsgBox TypeName(t_o)
End Sub
'-------------------------------
Imports Microsoft.Office.Interop
Imports System.Runtime.InteropServices
Module Module1
Sub Main()
Dim oExcel As New Excel.Application
Dim oBook As Excel.Workbook
Dim oBooks As Excel.Workbooks = oExcel.Workbooks
Dim strPath As String
Dim t_o As SampleLibrary.T
t_o.x = "ABC"
t_o.y = 123
strPath = "C:\temp\test\Book1.xls"
oExcel.Visible = True
oBook = oBooks.Open(strPath)
oExcel.Run("'" & oBook.Name & "'!TEST", t_o)
oBook.Close(False)
System.Runtime.InteropServices.Marshal.ReleaseComObject(oBook)
oBook = Nothing
System.Runtime.InteropServices.Marshal.ReleaseComObject(oBooks)
oBooks = Nothing
oExcel.Quit()
System.Runtime.InteropServices.Marshal.ReleaseComObject(oExcel)
oExcel = Nothing
End Sub
End Module
魔界の仮面弁士さん
>利用側のコードは元の物と殆ど変らないので、
>あえて書くまでも無いとは思いますが、一応記載。
サンプルコードが載せてありましたのでとてもよかったです。
SampleLibrary.Tの部分に気付かなくておそらく質問していたと思います。
「COMの構造体はタイプライブラリとして公開されているが、VBAのユーザー定義型は公開することができないので、その構造体を定義したVB.NETのCOMのDLL(タイプライブラリ)を別途用意しておいて、これをVB.NETとVBAの双方から参照する。」。なるほど。今回も大変参考になりました。この方法で引数が構造体のVBAのマクロをVB.NETから呼び出すことができました。
ありがとうございました。
ツイート | ![]() |