• 締切済み

VB.NETからVBAマクロ(引数)を呼び出す方法

  VB.NETから参照型引数付きのFunctionのVBAマクロを呼び出す方法 Excel2003のVBEの標準モジュールModule1にあるFunctionのマクロtest(引数)をVB.NETから呼び出して、引数に設定した値をVBA側で加工して、加工された値をVB.NETで取り出したいのですが、VB.NET側でどのように記述してよいのかがよく分かりません。 具体的には、以下のVBAをVB.NETから呼び出すにはどのように記述すればよいのでしょうか。できましたらそのままVB.NETのConsoleApplicationのModule1のSub Main()の中にコピーペーストして動くコードと参照設定を教えていただけると助かります。 ---Excel2003のVBA(C:\test\Book1.xls)---------- Function test(ByRef data As Long) As Long  If data = 0 Then   test = 0   data = 0  Else   test = 1   data = 100 / data  End If End Function ---------------------------------------------- よろしくお願いします(WindowsXP,VisualStudio2010,Excel2003VBE)  

みんなの回答

  • angel_Z
  • ベストアンサー率66% (12/18)
回答No.6

こんにちは。 >参照型の引数として呼び出すことは原理的にできないのでしょうか。 そうですね。。。 できないと思われます。 戻り値は取れるんですけどね。 ただ値を取得するのであれば、すでに解答したので対応出ると思いますが、 細かい事は、実際のソースを見て判断しないと何とも言えません。 いろいろ考えてみましたが、Excelのバージョンを考えると、 作り変えた方が早いのではないでしょうか。 私はそういう場合、クラスに作り変えたりします。 時間が経てば、そのうちひらめく場合もありますけど(^o^) 今はお役に立てなくてごめんなさい。 逆にひらめいたら、教えて下さい(*・∇-)

yam2012
質問者

お礼

こんにちは。 参照型の引数として呼び出すことができないということが分かっただけでも質問してよかったです。 そのほかにもいろいろな回避策を教えていただきまして大変参考になりました。 ありがとうございました。

  • angel_Z
  • ベストアンサー率66% (12/18)
回答No.5

こんにちは。 こんなのはどうでしょう? クリップボードに値をコピーさせてみては。 タイプライブラリは無かった事に。。。 Microsoft Forms 2.0 Object Library VBAと.NETの参照設定に追加します。 VBAの参照設定に無い場合は、FM20.DLLを参照から追加して下さい。 参考URLを付けておきます。 ------VBA------------------------------------ Function test(ByRef data As Long) As Long Dim CB As DataObject Set CB = New DataObject If data = 0 Then test = 0 data = 0 Else test = 1 data = 100 / data End If 'クリップボードのクリア Application.CutCopyMode = False 'クリップボードに値をセット CB.SetText data 'コピーの実行(これを実行しないとクリップボードにコピーされません。) CB.PutInClipboard End Function ---------.NET------------------ Imports Excel = Microsoft.Office.Interop.Excel Module Module1 Sub Main() Try Dim oExcel As New Excel.Application Dim oBook As Excel.Workbook Dim oBooks As Excel.Workbooks = oExcel.Workbooks Dim strPath As String Dim Result As Long Dim data As Long 'C:\test\Book1.xlsを実行ファイルに指定する。 strPath = "C:\test\Book1.xls" 'Excelオブジェクトの設定 oExcel.Visible = False oBook = oBooks.Open(strPath) data = 1 'Excel側のFunctionを実行する Result = oExcel.Run("'" & oBook.Name & "'!test", data) 'クリップボードに保存された値を取得 If Clipboard.ContainsText() Then MsgBox(Clipboard.GetText()) End If '解放 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 Catch ex As Exception MsgBox(ex.Message) End Try End Sub End Module プログラムの実行でクリップボードにコピーの動作がないようでしたら、 こちらで対応できそうなのですが…

参考URL:
http://officetanaka.net/excel/vba/tips/tips20.htm
yam2012
質問者

補足

angel_Zさん こんにちは。 いろいろ提案をしていただきましてありがとうございます。 教えていただきました戻り値経由による方法、および今回のクリップボード経由による方法を確認しました。呼び出し先で変更された結果を呼び出し元で得ることができたのですが1つ問題があります。 すでにあるVABのマクロをVB.NETからそのまま呼び出して利用したいのですが、これらのマクロの引数は、サンプル例のように整数型の変数が1個だけではなく、複数の引数を持っています。型も整数型だけではなく他の型も混在していたり、ユーザー定義型もあります。クリップボードでこれらの引数の値のすべてを返すことは可能でしょうか。できたとしても処理が複雑になるような気がしているのですが。。。 マクロ自体も複数あり、各マクロ内部の処理も大掛かりな処理をしていてVBへの移植が大変なので、少しの修正程度で、できれば何も手を加えずそのまま呼び出したかったのですが、参照型の引数として呼び出すことは原理的にできないのでしょうか。 よろしくお願いします。

  • angel_Z
  • ベストアンサー率66% (12/18)
回答No.4

こんにちは。 相談ですが、 エクセル側のFunction testを修正する事が可能ですか? 可能でしたら、 Function test(ByRef data As Long, Optional fg As Integer = 0) As Long 'fg 0:VBAより 1:.NETより   If data = 0 Then     test = 0     data = 0   Else     If fg = 0 Then       test = 1       data = 100 / data     Else       test = 100 / data     End If   End If End Function に修正して、.NET側のマクロの呼び出しで、   'Excel側のFunctionを実行する   Result = oExcel.Run("'" & oBook.Name & "'!test", data,1) にすると、100が帰ってきます。 VBA側は、fgはデフォルト0で省略可能なので、 変更しなくてOKなのですが。 こちらが一番簡単な変更なのかと考え方を変えてみたのですが、 いかがでしょうか? 変更できない場合は、 自作のDLL作成で両方の参照設定や、 API使用などありそうですが、 ややこしいです。。。

yam2012
質問者

補足

angel_Zさん 返答ありがとうございます。 >エクセル側のFunction testを修正する事が可能ですか? 少しの修正は可能ですが、引数には反映されず、結果が戻り値で返るのは、ちょっと問題があります。引数として返されるのであれば上記のコードの程度の修正はOKです。 >変更できない場合は、 >自作のDLL作成で両方の参照設定や、 >API使用などありそうですが、 >ややこしいです。。。 かなりややこしそうで苦戦しております。ANo.3 で教えていただきましたリンク先のサンプルで確認していますがもう少し時間がかかりそうです。結果は ANo.3 のところにご報告致します。 よろしくお願いします。

  • angel_Z
  • ベストアンサー率66% (12/18)
回答No.3

こんにちは。 参照渡しでしたね。 この辺りが参考になりそうですが、 http://hpcgi1.nifty.com/MADIA/vbnet/wwwlng.cgi?print+201210/12100013.txt タイプライブラリを用意して、 両方に参照設定の必要がありますね。

yam2012
質問者

補足

  angel_Zさん 返答ありがとうございます。 分からないことだらけでいろいろ確認していて返答が遅くなってしまいました。 > この辺りが参考になりそうですが、 > http://hpcgi1.nifty.com/MADIA/vbnet/wwwlng.cgi?print+201210/12100013.txt > タイプライブラリを用意して、 > 両方に参照設定の必要がありますね。 > 変更できない場合は、 > 自作のDLL作成で両方の参照設定や、 > API使用などありそうですが、 > ややこしいです。。。 ややこしくても、このようにすることで問題が解決するのであれば、やってみる価値はあると思いましたので、リンク先のサンプルを参考にして確認してみました。どこかが間違っているのかもしれませんが、下記のMsgBox(t_o.data)の結果は100にはならず1のままでした。 ---Excel2003のVBA(C:\test\Book1.xls)---------- Option Explicit Function test(ByRef t_o As ClassLibrary1.T) As Long If t_o.data = 0 Then test = 0 t_o.data = 0 Else test = 1 t_o.data = 100 / t_o.data End If End Function ---VB.NET(ConsoleApplication)------------- Imports Excel = Microsoft.Office.Interop.Excel Module Module1 Sub Main() Try Dim oExcel As New Excel.Application Dim oBook As Excel.Workbook Dim oBooks As Excel.Workbooks = oExcel.Workbooks Dim strPath As String Dim Result As Long 'Dim data As Long Dim t_o As New ClassLibrary1.T ' <--変更 'C:\test\Book1.xlsを実行ファイルに指定する。 strPath = "C:\test\Book1.xls" 'Excelオブジェクトの設定 oExcel.Visible = False oBook = oBooks.Open(strPath) 'data = 1 t_o.data = 1 ' <--変更 'Excel側のFunctionを実行する 'Result = oExcel.Run("'" & oBook.Name & "'!test", data) Result = oExcel.Run("'" & oBook.Name & "'!test", t_o) ' <--変更 '確認用 MsgBox(Result) 'MsgBox(data) MsgBox(t_o.data) ' <--変更 '解放 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 Catch ex As Exception MsgBox(ex.Message) End Try End Sub End Module ---VB.NET(ClassLibrary1)----------------------- Public Structure T 'Public data As Long 'Longではエラーに? Public data As Integer End Structure ------------------------------------------------   もし、angel_Zさんの意図されている方法と異なっていましたらご指摘ください。 よろしくお願いします。  

  • angel_Z
  • ベストアンサー率66% (12/18)
回答No.2

こんにちは。 これではどうですか? '参照設定の追加 COM 'Microsoft Excel xx.0 Object Libraryを追加 Imports Excel = Microsoft.Office.Interop.Excel Sub Main()  Try   Dim oExcel As New Excel.Application   Dim oBook As Excel.Workbook   Dim oBooks As Excel.Workbooks = oExcel.Workbooks   Dim strPath As String   Dim Result As Long   'C:\test\Book1.xlsを実行ファイルに指定する。   strPath = "C:\test\Book1.xls"   'Excelオブジェクトの設定   oExcel.Visible = False   oBook = oBooks.Open(strPath)   'Excel側のFunctionを実行する   Result = oExcel.Run("'" & oBook.Name & "'!test", 引数)   '確認用   Msgbox(Result)   '解放   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  Catch ex As Exception   MsgBox(ex.Message)  End Try End Sub

yam2012
質問者

補足

angel_Zさん。こんにちは。 返答ありがとうございます。 教えていただきましたコードで確認してみました。 エラーは出ず実行して正常に終了するのですが VBA側で変更した引数の値が VB.NETの引数には反映されてこないようです。 -------------------- (省略) Dim data As Long '<-----追加 data = 1 '<-----追加 'Excel側のFunctionを実行する Result = oExcel.Run("'" & oBook.Name & "'!test", data) ' <-----修正 '確認用 MsgBox(Result) MsgBox(data) '<-----追加 (省略) -------------------- MsgBox(data)のdataの期待値は100ですが実際は1のままです。 よろしくお願いします。

  • yamaj_biz
  • ベストアンサー率71% (10/14)
回答No.1

http://dobon.net/vb/dotnet/programing/eval.html」の「CSharpCodeProviderを使用した方法」が参考になるのではないでしょうか。

参考URL:
http://dobon.net/vb/dotnet/programing/eval.html
yam2012
質問者

補足

yamaj_bizさん 返答ありがとうございます。 すでにあるVABのマクロの処理をVBでも処理したいのですが、そのマクロはサンプル例のように単純ではなく、かなり大掛かりな処理をしています。それでVBへの移植が大変なので、そのままVABのマクロを呼び出せないのかを検討しています。 よろしくお願いします。

関連するQ&A

  • VBAのマクロをシート内の式で使いたい

    VBAで、マクロの関数をエクセルの式で使うことは可能でしょうか? 引数や戻り値の制約も知りたいです。 引数はExcel側ではセル値B1とかになりますが、VBA側では何か対策でもあるのでしょうか? 'VBA public function test(byval a as integer, byval b as integer) as integer test = a + b end function 'エクセル側 C1セルに以下の式 =test(A1, B1)

  • Excelマクロを引数付で起動

    VB.NET2002を使用しています。 VBよりEXCELマクロを実行できるとこまでは出来たのですが、 excel.Application.Run("Module1!test") VBで処理した値をExcelに渡すことはできないのでしょうか? Run("マクロ名",引数1,引数2,・・・)のように宣言すれば良さそうなのですが、 型のエラーが出てしまいます。 VB上の吹き出しには「As Object」とあるのですが、実際には文字列(string)や数字(long)です。 そのままRun("test",moji,suuji)のようには無理でしょうか。 ちなみにExcelの受け側ですが、 test(byval moji as string,byval num as integer) のようにすれば…と思っていたのですが。 ご存知の方がいらっしゃいましたら教えてください。 お願いいたします。

  • VB6とVBAのマクロのアクセス方法を教えてください。

    VB6とVBAのマクロのアクセス方法を教えてください。 用途は、 (1)VB6からVBAマクロを起動する。 (2)VBAマクロの途中経過をVB6のオブジェクトへ通知する。 VBAはPC外部接続機器をコントロールします。 VB6での実装サンプルが用意されていない為、VBAを使用しております。) (3)VB6は通知結果を、拾って別ルーチンの処理を実行する。 (1)では、下記の様な方法にてマクロ実行を考えていたのですが、 マクロが終了するまで、次コードへ移らない為、 シェル関数の様な形でマクロをキックしたい。 xlApp.run ("VBA_TEST(" & Chr(&H22) & strarg & Chr(&H22) & " )") (2)では、VBAとVB6と平行に実行したい為、フラグをやり取りするのに、 VB6のオブジェクトを使用したい。

  • VBAで呼び出したVBのDLLのデバッグ方法

    VB2010で、COM相互運用機能を使って作成したDLLを VBAから呼び出すことはできるのですが この状態でこのDLLをデバッグすることはできないでしょうか。 本来ならば、DLLをデバッグするテストプログラムを VB2010のVB.NETのWindowsフォームアプリケーションか ConsoleApplication1で作成して、 同じソリューションの中に DLLとテストプログラムのプロジェクトを配置して 参照の追加でDLLを参照設定して 両者をデバッグをすると思われますが、 テストプログラムを作るのがかなり大変なのと、 今回作成したDLLは、元々はVBAの中のひとつのプロシージャ―で、 事情があって、このプロシージャ―だけをVBのDLLにしたものです。 このプロシージャ―は元々はVBAの中で正しく動作していたものです。 VBに書き直した時に何らかの不具合が起きていると思われます。 テストプログラムを作らずに、既存のVBAから呼び出して、 DLLの部分の動作だけを(できればVB2010で)デバッグできないでしょうか。 よろしくお願いします。 (WindowsXP SP3 , Excel2003のVBA , Visual Studio 2010)

  • vb.netでCreateEventの引数

    vb.netでCreateEventの引数 CreateEventを実行後、OpenEventをすると失敗してしまいます。 CreateEventの第一引数に問題があるような気がするのですが、vb.Netでのサンプルが少なく悩んでいます。 CreateEventの第一引数のSECURITY_ATTRIBUTESにはなにを指定してあげればよいでしょうか。 Structure SECURITY_ATTRIBUTES nLength As Integer lpSecurityDescriptor As Integer bInheritHandle As Integer End Structure lpSecurityDescriptor ってなにものでしょうか。

  • VBA DLLワークシート関数配列引数について

    こんばんわ Cで書かれたDLLをワークシートで呼んで計算に使用しているのですが 配列を引数に取る関数にワークシートの値(B1:B5みたいな感じ)を渡したいのですが渡せなくて困っています。 VBAのFunctionから呼んでデバックをかけてみたら、たとえば「B1:B5」を渡すとRangeオブジェクトとして渡されているみたいなんですがこれをなんとか配列として渡したいです。 ↓DLLの関数例です __declspec(dllexport) LONG __stdcall SumTest(LONG *p, LONG psize) { LONG i = 0; LONG Rtn = 0; for(i = 0; i < psize; i++) { Rtn = Rtn + p{i]; } return Rtn; } こんな感じのをセルA1に「=SumTest(B1:B5,5)」にすると「#Value」と表示されています。 ↓デバックに使用したVBAのFunction Function Test(p As Variant, ByVal psize As Long) As Long Test = SumTest(p, psize) End Function 配列を引数に取らないものは、正常に呼べるので問題ないです。

  • Excel 2003のVBAマクロデータをExcel 2007で見たい

    Excel 2003のVBAマクロデータをExcel 2007で見たい。 Excel 2003でVBAマクロを登録したExcelファイルがありますが、今回、Excel 2007をインストールして、該当ファイルを開いたところ、「マクロデータを削除しました。」とメッセージが出て、VBEを起動してもマクロが見えなくなりました。OSはWindowsXP SP3です。Excel 2003で登録したVBAマクロをExcel 2007で削除されないで、次の2点について、可能にするにはどうすればよいか、ご教示願います。 (1)マクロデータを残す方法。 (2)マクロ起動する方法。

  • ACCESS2003 VBAよりVB.NETを使った方がいい?

    ACCESS2003 VBAよりVB.NETを使った方がいい? プログラマーでもないのですが、仕事でAccess2003でVBAを書いています。フォームにテーブルから引っ張てきたデータを表示させてデータを閲覧したり、データを加工してExcelにデータを吐き出したりしています。テーブルには10万件程度のデータがあります。 特に私は便利に使っているのですが、上司がVB.netとMYSQLでプログラム書いた方が楽じゃない?VB.NETよかったら買ってあげるよと言われました。買ってくれるのは嬉しいのですが、.netなんてやったこともないですし、DAOしか使ったことがなくADOなんて全くわかりません。 何かACCESS VBAよりVB.net+MYSQLのメリットって何かありますでしょうか?ちなみに業務で使うためのものなので、家からアクセスして何かするというのは考えていません。あくまで社内で使う時にメリットはあるでしょうか?

  • VBA・VB6.0・VB.NETの文字列型

     失礼します。  Excel97/2000のVBAの文字列型変数は、アスキーコード129-159/224-252のデータを保持できないみたいですが、これはVB6.0/VB.NETなどでもそうなのですか?  つまり、VBAでは、 Sub main()  Dim s as String  s = Chr$(130)  Sheet1.Cells(1, 1) = Asc(s) End Sub  とすると、シートのA1に「0」が表示されてしまうということです。  というのも、私はVB6.0/VB.NETを持っていないのですが、ちょっとVB2.0時代のコードを使う必要が生じたので、VBAで実行してみたところ、以上のような仕様の違いに気付いたのです。  これがVBAだけの特性なのか、最近のVBはこういう仕様になってしまったのかが知りたいのです。

  • 関数の引数

    こんにちわ。 ご存知の方、ご教授してもらえないでしょうか? VB.net2005を使っているのですが 関数の引数に変数をセットして、別関数で 引数に対してデータをセットすることは可能でしょうか? C言語でいうところのポインタを引数に渡し ポインタアドレスに書き込むような処理はVB.netでは 可能なんでしょうか? 下記のような事は試したのですが、うまく出来ませんでした(。。; public sub test1() dim mojiretu as string test2( mojiretu ) msgbox(mojiretu) end sub public sub test2( str as string) str = "文字列" end sub

専門家に質問してみよう