VBA から VBA を呼び出したかったけどできなかったから、代替案で我慢した
VBA 内で他の Excel の VBA を呼び出したかったのですが(Excel 側のセキュリティを緩めないと)ダメくさいので、代替え案でいいやと思いました。という話です。
目次
本当はこういう構成でやりたかった
もはや bat と PowerShell いらんやんけ~なのですが、要するに VBA から VBA を呼び出したかったんですね。こんなんです。
bat → PowerShell → Excel/VBA ★VBA 内でマクロ実行 → Excel/VBA ★NG, 呼び出せず
で、やってみたらこれですよ。
実行時エラー '1004': マクロ 'C:\~\aaa.xlsm!Hello' を実行できません。このブックでマクロが使用できないか、またはすべてのマクロが無効になっている可能性があります。
これを実行できるようにするには Excel のセキュリティセンターを開いて、マクロの実行レベルを緩めなければいけない模様でした。
代替え案
そんなことはしたくないので、運用(というよりは別の実現方法)でなんとかカバーできないかと、方向性を変えました。で、PowerShell からのマクロ実行は可能だったので、以下のように変えてみました。
bat → PowerShell → Excel/VBA ★PowerShellからマクロ実行、再計算させる → Excel/VBA ★PowerShellからマクロ実行、更新されたセル値を読み込む
以下ソースです。
run.bat
@echo off echo PowerShell から VBA を実行しています... powershell -NoProfile -ExecutionPolicy Unrestricted .\test.ps1 echo 処理が完了しました!... pause
test.ps1
$file1 = "C:\Users\User\~\test1.xlsm" $file2 = "C:\Users\User\~\test2.xlsm" $excel = New-Object -ComObject Excel.Application try { # 計算処理させる $book = $excel.Workbooks.Open($file1) $excel.Run("Calc", "2", "3") $book.Save() $book.Close() } finally { $excel.Quit() [System.Runtime.InteropServices.Marshal]::FinalReleaseComObject($excel) | Out-Null } $excel = New-Object -ComObject Excel.Application try { # test2.xlsm 側で、test1.xlsm を読み込み結果データの値を取得 $book = $excel.Workbooks.Open($file2) # Run は2回目はだめくさい? # $excel.Run("SetData") $result = $excel.Run("GetData") $book.Save() $book.Close() write-Host $result } finally { $excel.Quit() [System.Runtime.InteropServices.Marshal]::FinalReleaseComObject($excel) | Out-Null }
test1.xlsm
Sub Calc(ByVal i As String, ByVal j As String) Range("A1").Value = CLng(i) + CLng(j) End Sub
test2.xlsm
Function GetData() Dim bok1 As Workbook Dim sht1 As Worksheet Dim bok2 As Workbook Dim sht2 As Worksheet Dim path As String path = ThisWorkbook.path + "\test1.xlsm" Set bok1 = Workbooks.Open(path) Set sht1 = bok1.Sheets("Sheet1") path = ThisWorkbook.path + "\test2.xlsm" Set bok2 = Workbooks.Open(path) Set sht2 = bok2.Sheets("Sheet1") sht2.Range("A1").Value = sht1.Range("A1").Value ' MsgBox sht2.Range("A1").Value GetData = sht2.Range("A1").Value Set sht1 = Nothing Set bok1 = Nothing Set sht2 = Nothing Set bok2 = Nothing End Function
出力結果
PowerShell で、2 と 3 を渡して、test1.xlsm を経由して test2.xlsm に渡って、計算結果を 元の PowerShell で受け取れました!やったー!
PowerShell から VBA を実行しています... 5 処理が完了しました!... 続行するには何かキーを押してください . . .