引数が構造体のVBAのマクロをVB.NETから呼び出すには?

解決


yy  2012-10-23 14:33:06  No: 147907  IP: [192.*.*.*]

引数が構造体の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 )

編集 削除
魔界の仮面弁士  2012-10-23 19:49:43  No: 147908  IP: [192.*.*.*]

>「引数が構造体の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

編集 削除
yy  2012-10-24 11:43:06  No: 147909  IP: [192.*.*.*]

魔界の仮面弁士さん

>利用側のコードは元の物と殆ど変らないので、
>あえて書くまでも無いとは思いますが、一応記載。

サンプルコードが載せてありましたのでとてもよかったです。
SampleLibrary.Tの部分に気付かなくておそらく質問していたと思います。

「COMの構造体はタイプライブラリとして公開されているが、VBAのユーザー定義型は公開することができないので、その構造体を定義したVB.NETのCOMのDLL(タイプライブラリ)を別途用意しておいて、これをVB.NETとVBAの双方から参照する。」。なるほど。今回も大変参考になりました。この方法で引数が構造体のVBAのマクロをVB.NETから呼び出すことができました。

ありがとうございました。

編集 削除