Excel VBA 逆引き集 | Excel外からVBA呼び出し

Excel VBA
スポンサーリンク
  1. ねらい:Excelの外からVBAを呼び出し、ヘッドレスで安全に実務を回す
    1. 重要ポイントの深掘り
  2. 入口の型:ヘッドレス実行に耐えるRun_XXXX
    1. 標準モジュールの公共入口と枠の整備
    2. 重要ポイントの深掘り
  3. VBScriptでCOMオートメーション:最短・定番の外部呼び出し
    1. Excelを起動し、Application.Runで入口Subを呼ぶ
    2. 重要ポイントの深掘り
  4. PowerShellでCOMオートメーション:引数や日付操作が柔軟
    1. Excelを非表示で開いてRunを呼び、最後に解放
    2. 重要ポイントの深掘り
  5. 起動イベントで自動実行:Excel起動時に走らせる
    1. Workbook_OpenやAuto_Openを使う(簡易だが運用要件に注意)
    2. 重要ポイントの深掘り
  6. タスクスケジューラ連携:時間指定で自動起動する
    1. VBS/PS1をスケジュール登録し、夜間・早朝に回す
    2. 重要ポイントの深掘り
  7. 引数と結果の受け渡し:外部→VBA→外部の往復を整える
    1. 引数は文字列で渡し、VBA側で変換・検証する
    2. 結果はファイル/セル/ログへ出す
  8. 実務の落とし穴と対策(深掘り)
    1. マクロセキュリティでブロックされる
    2. ダイアログで処理が止まる
    3. Excelが終了しない/プロセスが残る
    4. 競合・二重起動
  9. 例題の通し方と確認ポイント
    1. 入口Subを直接実行して動作を確認する
    2. VBScript/PowerShellから呼び、Excelが自動で閉じるかを見る
    3. 想定外引数・失敗時の挙動を検証する
  10. まとめ:入口の型+COM呼び出し+枠とログで「Excel外起動」を堅牢にする

ねらい:Excelの外からVBAを呼び出し、ヘッドレスで安全に実務を回す

「Excel外からVBA呼び出し」は、ユーザー操作なしに処理を起動するための基礎です。代表手段はCOMオートメーション(VBScript・PowerShell・他言語)、起動イベント(Workbook_Open/Auto_Open)、タスクスケジューラ連携です。肝は入口Subの型を整え、Excelを「開く→実行→保存→終了」まで自動で完了させ、失敗時も確実に復帰すること。初心者向けに、貼ってすぐ使えるテンプレートと、運用の勘所を丁寧に解説します。

重要ポイントの深掘り

外部起動では「Excelを正しく閉じる」「COM参照を解放する」「マクロをヘッドレスで動かす」設計が必須です。入口Subはメッセージを出さず、例外復帰・ログ記録・開始/終了枠を持たせ、引数受け取り(ファイル・日付など)をサポートすると、スクリプトからの制御が容易になります。


入口の型:ヘッドレス実行に耐えるRun_XXXX

標準モジュールの公共入口と枠の整備

外部から呼ぶ前提で、メッセージボックスや選択依存を排し、開始/終了枠・ログ・エラー復帰を備えます。Application.Runから引数を渡せるよう設計します。

' ModApp.bas(開始/終了の共通枠)
Option Explicit
Public Sub AppEnter(Optional ByVal status As String = "")
    Application.ScreenUpdating = False
    Application.EnableEvents = False
    Application.DisplayAlerts = False
    Application.Calculation = xlCalculationManual
    If Len(status) > 0 Then Application.StatusBar = status
End Sub
Public Sub AppLeave()
    Application.StatusBar = False
    Application.Calculation = xlCalculationAutomatic
    Application.DisplayAlerts = True
    Application.EnableEvents = True
    Application.ScreenUpdating = True
End Sub
VB
' ModLog.bas(簡易ログ:Logシートへ)
Option Explicit
Public Sub LogInfo(ByVal action As String, ByVal detail As String)
    Dim ws As Worksheet
    On Error Resume Next
    Set ws = ThisWorkbook.Worksheets("Log")
    If ws Is Nothing Then Set ws = ThisWorkbook.Worksheets.Add: ws.Name = "Log"
    On Error GoTo 0
    Dim r As Long: r = ws.Cells(ws.Rows.Count, 1).End(xlUp).Row + 1
    ws.Cells(r, 1).Value = Format(Now, "yyyy-mm-dd HH:NN:SS")
    ws.Cells(r, 2).Value = action
    ws.Cells(r, 3).Value = detail
End Sub
VB
' ModService.bas(外部呼び出し入口)
Option Explicit
Public Sub Run_DailyExport(ByVal inPath As String, ByVal outCsv As String, ByVal yyyymmdd As String)
    On Error GoTo EH
    AppEnter "DailyExport"
    LogInfo "Start", yyyymmdd

    Dim arr As Variant: arr = ReadCsvToArray(inPath)
    Dim out As Variant: out = NormalizeAndFilterByDate(arr, yyyymmdd)
    WriteArrayToCsv outCsv, out

    LogInfo "Finish", outCsv
    AppLeave
    Exit Sub
EH:
    LogInfo "Error", Err.Number & " - " & Err.Description
    AppLeave
End Sub
VB
' ModCsvUtil.bas(CSVユーティリティ・配列I/O)
Option Explicit
Public Sub WriteArrayToCsv(ByVal path As String, ByVal data As Variant)
    Dim st As Object: Set st = CreateObject("ADODB.Stream")
    st.Type = 2: st.Charset = "UTF-8": st.Open
    Dim r As Long, c As Long, line As String
    For r = 1 To UBound(data, 1)
        line = ""
        For c = 1 To UBound(data, 2)
            Dim s As String: s = Replace(CStr(data(r, c)), """", """""")
            line = line & IIf(c > 1, ",", "") & """" & s & """"
        Next
        st.WriteText line & vbCrLf
    Next
    st.SaveToFile path, 2
    st.Close: Set st = Nothing
End Sub

Public Function ReadCsvToArray(ByVal path As String) As Variant
    Dim st As Object: Set st = CreateObject("ADODB.Stream")
    st.Type = 2: st.Charset = "UTF-8": st.Open: st.LoadFromFile path
    Dim text As String: text = st.ReadText: st.Close: Set st = Nothing
    Dim lines() As String: lines = Split(text, vbCrLf)
    If UBound(lines) < 0 Then Exit Function
    Dim head() As String: head = ParseCsvLine(lines(0))
    Dim cols As Long: cols = UBound(head) + 1
    Dim arr() As Variant: ReDim arr(1 To UBound(lines) + 1, 1 To cols)
    Dim c As Long: For c = 1 To cols: arr(1, c) = head(c - 1): Next
    Dim r As Long
    For r = 2 To UBound(lines) + 1
        If Len(lines(r - 1)) = 0 Then Exit For
        Dim rec() As String: rec = ParseCsvLine(lines(r - 1))
        For c = 1 To cols: arr(r, c) = IIf(c - 1 <= UBound(rec), rec(c - 1), ""): Next
    Next
    ReadCsvToArray = arr
End Function

Private Function ParseCsvLine(ByVal line As String) As String()
    Dim res() As String, buf As String, i As Long, inQ As Boolean
    ReDim res(0 To 0)
    For i = 1 To Len(line)
        Dim ch As String: ch = Mid$(line, i, 1)
        If ch = """" Then
            If inQ And i < Len(line) And Mid$(line, i + 1, 1) = """" Then buf = buf & """": i = i + 1 Else inQ = Not inQ
        ElseIf ch = "," And Not inQ Then res(UBound(res)) = buf: buf = "": ReDim Preserve res(0 To UBound(res) + 1)
        Else buf = buf & ch
        End If
    Next
    res(UBound(res)) = buf
    ParseCsvLine = res
End Function
VB

重要ポイントの深掘り

外部起動では「対話」を排し、ログとステータスバーだけで進捗・結果を残します。引数は文字列で渡すのが基本で、ファイルパス・日付・フラグなどを受け取れる形にしておくとスクリプト側が柔軟に制御できます。


VBScriptでCOMオートメーション:最短・定番の外部呼び出し

Excelを起動し、Application.Runで入口Subを呼ぶ

VBScriptはWindows標準で動きます。Excelを不可視で開き、マクロを実行して保存・終了します。引数はApplication.Runで渡せます。

' run_export.vbs(ダブルクリック可/タスクスケジューラも容易)
Option Explicit
Dim xl, wb, bookPath, inPath, outCsv, yyyymmdd
bookPath = CreateObject("Scripting.FileSystemObject").GetAbsolutePathName(".") & "\Book1.xlsm"
inPath   = CreateObject("Scripting.FileSystemObject").GetAbsolutePathName(".") & "\input.csv"
outCsv   = CreateObject("Scripting.FileSystemObject").GetAbsolutePathName(".") & "\output.csv"
yyyymmdd = Year(Date) & Right("0" & Month(Date), 2) & Right("0" & Day(Date), 2)

Set xl = CreateObject("Excel.Application")
xl.Visible = False
xl.DisplayAlerts = False

Set wb = xl.Workbooks.Open(bookPath)
xl.Run "Book1.xlsm!Run_DailyExport", inPath, outCsv, yyyymmdd
wb.Close True  ' 保存して閉じる
xl.Quit

Set wb = Nothing
Set xl = Nothing
VB

重要ポイントの深掘り

「ブック修飾つきのマクロ名(Book!ModuleOrPublicSub)」で呼ぶのが安定します。Visible=Falseでヘッドレス、DisplayAlerts=Falseでダイアログ抑止。終了時にClose→Quit→参照解放まで確実に行えば、バックグラウンド実行でもリソースが残りません。


PowerShellでCOMオートメーション:引数や日付操作が柔軟

Excelを非表示で開いてRunを呼び、最後に解放

PowerShellは文字列・日時・パス操作が楽です。引数を柔軟に組み立てて渡せます。

# run_export.ps1
$bookPath = Join-Path (Get-Location) "Book1.xlsm"
$inPath   = Join-Path (Get-Location) "input.csv"
$outCsv   = Join-Path (Get-Location) "output.csv"
$yyyymmdd = (Get-Date).ToString('yyyyMMdd')

$xl = New-Object -ComObject Excel.Application
$xl.Visible = $false
$xl.DisplayAlerts = $false

$wb = $xl.Workbooks.Open($bookPath)
$xl.Run("Book1.xlsm!Run_DailyExport", $inPath, $outCsv, $yyyymmdd)
$wb.Close($true)
$xl.Quit()

[System.Runtime.Interopservices.Marshal]::ReleaseComObject($wb) | Out-Null
[System.Runtime.Interopservices.Marshal]::ReleaseComObject($xl) | Out-Null
[GC]::Collect()
[GC]::WaitForPendingFinalizers()

重要ポイントの深掘り

PowerShellはCOM解放を明示できるため、長期運用でも安定です。ReleaseComObject→GCの流れを入れるとプロセス残りを防ぎやすくなります。タスクスケジューラから直接呼べるのも利点です。


起動イベントで自動実行:Excel起動時に走らせる

Workbook_OpenやAuto_Openを使う(簡易だが運用要件に注意)

Excelを開いたタイミングで自動実行させたい場合に使います。スクリプトでブックを開くだけで処理が走ります。

' ThisWorkbook
Option Explicit
Private Sub Workbook_Open()
    On Error Resume Next
    Run_DailyExport ThisWorkbook.Path & "\input.csv", ThisWorkbook.Path & "\output.csv", Format(Date, "yyyymmdd")
    On Error GoTo 0
End Sub
VB

重要ポイントの深掘り

開いたら「必ず動く」ため、開発中や手作業と相性が悪い場面があります。業務では、起動イベントよりCOMから明示的にRunで呼ぶ方が事故が少ないです。使う場合は「フラグセル」や「引数要求」で条件付き実行にするのが安全です。


タスクスケジューラ連携:時間指定で自動起動する

VBS/PS1をスケジュール登録し、夜間・早朝に回す

WindowsタスクスケジューラにVBScriptやPowerShellを登録すれば、Excelを開かずとも自動運用できます。アカウントのログオン/最上位の特権・実行時フォルダ・ネットワークパス権限などの前提を確認し、失敗時の再試行・ログ保存パスをセットしておくと安心です。

重要ポイントの深掘り

ExcelはGUIアプリのため、完全なサーバー常駐用途には不向きです。とはいえ、単純バッチならタスクスケジューラ+COMで十分に運用可能です。出力先はローカル/権限のある共有を選び、ファイルロックや競合を避ける運用ルールを添えるとトラブルを減らせます。


引数と結果の受け渡し:外部→VBA→外部の往復を整える

引数は文字列で渡し、VBA側で変換・検証する

Application.Runは複数引数を渡せます。VBA側で型検証(IsDate/IsNumeric)を行い、誤引数ならFail Fastでログに残しつつ終了します。複雑な設定はJSON/CSV/Configシートを読むようにし、外部は「パスだけ渡す」方針が安全です。

結果はファイル/セル/ログへ出す

ヘッドレスではメッセージを使いません。結果はCSV/Excel出力、Logシート、外部ログファイル(ADODB.StreamでTXT)へ残す形にします。外部スクリプト側は終了コードの代わりに「結果ファイル存在」や「ログ末尾」を見て成功判定できます。


実務の落とし穴と対策(深掘り)

マクロセキュリティでブロックされる

信頼済みの場所にブックを置く、または署名を付けると安定します。企業環境ではITポリシーに従い、実行許可の前提を確認してください。

ダイアログで処理が止まる

DisplayAlerts=Falseにして上書き確認を抑止。自動保存が絡む処理は「SaveCopyAs」で別名保存にするなど、ダイアログ不要の設計にします。

Excelが終了しない/プロセスが残る

Close→Quit→参照解放まで必ず行い、例外時でも必ず到達するように外部スクリプト側もTry/Finally風に組むと残留を防げます。PowerShellならReleaseComObject/GCを併用します。

競合・二重起動

簡易ロック(名前定義 nm_Lock)や一時ファイルロックを入口で取得し、取れなければスキップします。時刻やユーザー名も記録して調査可能にしておくと安心です。


例題の通し方と確認ポイント

入口Subを直接実行して動作を確認する

Excel内で Run_DailyExport を手動実行し、CSVの入出力・ログ記録・枠復帰が正しく動くか確認します。対話不要で完了することが重要です。

VBScript/PowerShellから呼び、Excelが自動で閉じるかを見る

run_export.vbs/run_export.ps1 を実行し、Excelプロセスが終了するか、出力とLogシートが更新されるか確認します。タスクスケジューラに登録して時間実行も試します。

想定外引数・失敗時の挙動を検証する

意図的に不正な日付・存在しないパスで実行し、Fail Fastでログに残して終了できるかを確認します。外部スクリプト側が後片付け(Quit/解放)まで到達することもチェックします。


まとめ:入口の型+COM呼び出し+枠とログで「Excel外起動」を堅牢にする

標準モジュールのRun_XXXXをヘッドレス対応に整え、VBScript/PowerShellからCOMで開く→Run→保存→終了の流れを固定する。開始/終了枠・ログ・引数検証を徹底すれば、夜間バッチや定時取り込みが安定して回ります。

タイトルとURLをコピーしました