Excel VBA 逆引き集 | Shell拡張

Excel VBA
スポンサーリンク
  1. ねらい:VBAから「WindowsのShell」を使いこなし、外部処理を安全に操る
    1. 重要ポイントの深掘り
  2. 実行モデルと共通枠(必ず復帰させる)
    1. 開始・終了の共通枠
    2. 例外でも復帰する入口テンプレ
  3. コマンドライン実行:WScript.Shell.Runで「待つ・判定する」
    1. 非表示実行+戻り値で判定(最短で実用)
    2. 重要ポイントの深掘り
  4. 既定アプリで開く・印刷する:Shell.ApplicationのShellExecute
    1. 既定プログラムで “開く” “印刷” を指示
    2. 重要ポイントの深掘り
  5. ZIP圧縮・展開:Shell 名前空間で“使い勝手重視”
    1. フォルダをZIPに圧縮する
    2. ZIPを展開する
    3. 重要ポイントの深掘り
  6. ショートカット(.lnk)作成:WScript.Shellで“起動器”を配布
    1. デスクトップにショートカットを作る
    2. 重要ポイントの深掘り
  7. エクスプローラの操作:フォルダを開く・選択を表示する
    1. フォルダを開く/ファイルを選択表示する
    2. 重要ポイントの深掘り
  8. PowerShellブリッジ:JSON・API・高度処理は外部へ委譲
    1. PowerShellスクリプトを安全に呼ぶ
    2. 重要ポイントの深掘り
  9. ファイル・フォルダのShell拡張操作:プロパティ、リサイクル、タイムスタンプ
    1. ごみ箱へ送る(安全な削除)
    2. タイムスタンプ確認(差分検知)
    3. 重要ポイントの深掘り
  10. 例題の通し方と確認ポイント
    1. 例題シナリオ
    2. 確認ポイント
  11. 落とし穴と対策(深掘り)
    1. 待機不足による不定挙動
    2. クオート漏れによる失敗
    3. 権限・既定アプリの差
    4. UI自動化の不安定さ
  12. まとめ:Shellは「待つ・クオート・後片付け」を徹底すれば、強い相棒になる

ねらい:VBAから「WindowsのShell」を使いこなし、外部処理を安全に操る

Shell拡張は、VBAからWindowsのコマンド、エクスプローラ、既定アプリ、ZIP、ショートカットなど“OS標準の力”を呼び出す設計です。最優先は「完了待ち」「引数の正しいクオート」「後片付け(例外でも到達)」の枠を入れること。これだけで、初心者でも壊れにくく、実務で回せる外部連携が組めます。

重要ポイントの深掘り

Shellは「投げっぱなし」だと壊れます。見えない失敗を防ぐため、非表示実行+戻り値チェック+待機が基本です。ファイルパスは必ずダブルクォートで囲み、UTF-8やロケールの違いを吸収します。ShellExecuteは「既定アプリで開く/印刷/ZIP」に強く、WScript.Shellの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

例外でも復帰する入口テンプレ

' ModEntry.bas
Option Explicit
Public Sub Run_SafeShell()
    On Error GoTo EH
    AppEnter "Shell"
    ' …ここで外部処理…
    AppLeave
    Exit Sub
EH:
    AppLeave
    MsgBox "失敗: " & Err.Description, vbExclamation
End Sub
VB

コマンドライン実行:WScript.Shell.Runで「待つ・判定する」

非表示実行+戻り値で判定(最短で実用)

' ModShellExec.bas
Option Explicit

Public Function RunCmdWait(ByVal cmd As String) As Long
    Dim sh As Object: Set sh = CreateObject("WScript.Shell")
    RunCmdWait = sh.Run(cmd, 0, True) ' 0=非表示, True=完了まで待つ
End Function

Public Sub Demo_CmdEcho()
    On Error GoTo EH
    AppEnter "Cmd"
    Dim outPath As String: outPath = ThisWorkbook.Path & "\hello.txt"
    Dim cmd As String
    cmd = "cmd /c echo Hello World> """ & outPath & """"
    Dim rc As Long: rc = RunCmdWait(cmd)
    If rc <> 0 Then Err.Raise 8001, , "外部コマンドがエラー終了: " & rc
    AppLeave: MsgBox "完了: " & outPath
    Exit Sub
EH:
    AppLeave: MsgBox "失敗: " & Err.Description, vbExclamation
End Sub
VB

重要ポイントの深掘り

「待たない」Runは事故の素です。必ず True で待機し、戻り値で成否判定します。パスや引数はダブルクォートで囲み、スペースや日本語を確実に通します。cmd /c は一度きりの実行に適し、複雑系はPowerShellへ委譲すると安定します。


既定アプリで開く・印刷する:Shell.ApplicationのShellExecute

既定プログラムで “開く” “印刷” を指示

' ModShellVerb.bas
Option Explicit

Public Sub OpenWithDefault(ByVal path As String)
    Dim sh As Object: Set sh = CreateObject("Shell.Application")
    sh.ShellExecute path, "", "", "open", 1 ' 1=通常ウィンドウ
End Sub

Public Sub PrintWithDefault(ByVal path As String)
    Dim sh As Object: Set sh = CreateObject("Shell.Application")
    sh.ShellExecute path, "", "", "print", 0 ' 印刷は非表示が多い
End Sub

Public Sub Demo_Open_Print()
    OpenWithDefault ThisWorkbook.FullName
    PrintWithDefault ThisWorkbook.Path & "\report.pdf"
End Sub
VB

重要ポイントの深掘り

ShellExecuteは「関連付け」に従うため、PDFや画像、txtを“既定アプリ”で処理できます。操作は“verb(動詞)”で指定し、open/print/preview などが使えます。印刷はアプリやプリンタに依存するので、運用PCでの事前確認が必須です。


ZIP圧縮・展開:Shell 名前空間で“使い勝手重視”

フォルダをZIPに圧縮する

' ModZip.bas
Option Explicit

Public Sub ZipFolder(ByVal srcFolder As String, ByVal zipPath As String)
    On Error GoTo EH
    If Dir(zipPath, vbNormal) <> "" Then Kill zipPath
    CreateEmptyZip zipPath

    Dim sh As Object: Set sh = CreateObject("Shell.Application")
    Dim src As Object: Set src = sh.NameSpace(srcFolder)
    Dim dst As Object: Set dst = sh.NameSpace(zipPath)
    If src Is Nothing Or dst Is Nothing Then Err.Raise 8002, , "パス不正"

    dst.CopyHere src.Items, 16 ' 16=進捗なし・非表示
    Application.Wait Now + TimeValue("0:00:02") ' ざっくり待機(必要ならファイル数で待ち調整)
    MsgBox "圧縮完了: " & zipPath
    Exit Sub
EH:
    MsgBox "失敗: " & Err.Description, vbExclamation
End Sub

Private Sub CreateEmptyZip(ByVal zipPath As String)
    Dim h As Integer: h = FreeFile
    Open zipPath For Binary As #h
    Put #h, , Chr$(80) & Chr$(75) & Chr$(5) & Chr$(6) & String$(18, Chr$(0))
    Close #h
End Sub
VB

ZIPを展開する

Public Sub UnzipToFolder(ByVal zipPath As String, ByVal dstFolder As String)
    On Error GoTo EH
    Dim sh As Object: Set sh = CreateObject("Shell.Application")
    If Dir(dstFolder, vbDirectory) = "" Then MkDir dstFolder
    Dim zipNs As Object: Set zipNs = sh.NameSpace(zipPath)
    Dim dstNs As Object: Set dstNs = sh.NameSpace(dstFolder)
    If zipNs Is Nothing Or dstNs Is Nothing Then Err.Raise 8003, , "パス不正"
    dstNs.CopyHere zipNs.Items, 16
    Application.Wait Now + TimeValue("0:00:02")
    MsgBox "展開完了: " & dstFolder
    Exit Sub
EH:
    MsgBox "失敗: " & Err.Description, vbExclamation
End Sub
VB

重要ポイントの深掘り

ShellのZIPは「簡単で互換性が高い」反面、進捗や厳密な完了検知が弱いです。大容量や多数ファイルでは待機ロジックを少し厚めにし、実務では7zなど外部ツール+RunCmdWaitの組み合わせがより正確です。


ショートカット(.lnk)作成:WScript.Shellで“起動器”を配布

デスクトップにショートカットを作る

' ModShortcut.bas
Option Explicit

Public Sub CreateShortcut(ByVal targetPath As String, ByVal args As String, ByVal iconPath As String, ByVal linkName As String)
    Dim sh As Object: Set sh = CreateObject("WScript.Shell")
    Dim desk As String: desk = sh.SpecialFolders("Desktop")
    Dim lnk As Object: Set lnk = sh.CreateShortcut(desk & "\" & linkName & ".lnk")
    With lnk
        .TargetPath = targetPath
        .Arguments = args
        .IconLocation = iconPath
        .WorkingDirectory = CreateObject("Scripting.FileSystemObject").GetParentFolderName(targetPath)
        .Save
    End With
    MsgBox "ショートカット作成: " & desk & "\" & linkName & ".lnk"
End Sub

Public Sub Demo_Shortcut()
    CreateShortcut "notepad.exe", """" & ThisWorkbook.Path & "\readme.txt""", "notepad.exe", "Readmeを開く"
End Sub
VB

重要ポイントの深掘り

配布や起動導線を“固定”できるのがショートカットの利点です。Argumentsは必ずダブルクォートで囲み、作業ディレクトリを設定して相対パスの誤動作を防ぎます。アイコン設定で現場の識別性も向上します。


エクスプローラの操作:フォルダを開く・選択を表示する

フォルダを開く/ファイルを選択表示する

' ModExplorer.bas
Option Explicit

Public Sub OpenFolder(ByVal folderPath As String)
    Dim sh As Object: Set sh = CreateObject("Shell.Application")
    sh.Open folderPath
End Sub

Public Sub SelectInExplorer(ByVal filePath As String)
    Dim cmd As String
    cmd = "explorer /select,""" & filePath & """"
    Dim rc As Long: rc = RunCmdWait(cmd)
    If rc <> 0 Then MsgBox "Explorer選択失敗: " & rc, vbExclamation
End Sub
VB

重要ポイントの深掘り

ユーザーに「ここ」を見せる導線は復旧や運用効率に直結します。Openはフォルダを開くだけ、/select は対象ファイルを選択表示します。権限やネットワークパスの前提を運用で揃えると安定します。


PowerShellブリッジ:JSON・API・高度処理は外部へ委譲

PowerShellスクリプトを安全に呼ぶ

' ModPowerShellBridge.bas
Option Explicit

Public Sub RunPs1(ByVal ps1Path As String, ByVal args As String)
    Dim sh As Object: Set sh = CreateObject("WScript.Shell")
    Dim cmd As String
    cmd = "powershell -ExecutionPolicy Bypass -File """ & ps1Path & """ " & args
    Dim rc As Long: rc = sh.Run(cmd, 0, True)
    If rc <> 0 Then Err.Raise 8010, , "PowerShell失敗: " & rc
End Sub
VB

重要ポイントの深掘り

VBAはファイルI/OとExcel操作が得意、APIやJSONはPowerShellが得意。無理はせず、役割分担して“ファイルで契約”すると壊れにくく拡張しやすいです。ExecutionPolicyは運用ルールに従い、信頼済みフォルダや署名で安全性を高めます。


ファイル・フォルダのShell拡張操作:プロパティ、リサイクル、タイムスタンプ

ごみ箱へ送る(安全な削除)

' ModRecycle.bas
Option Explicit

Public Sub SendToRecycleBin(ByVal path As String)
    Dim sh As Object: Set sh = CreateObject("Shell.Application")
    Dim ns As Object: Set ns = sh.NameSpace(CreateObject("Scripting.FileSystemObject").GetParentFolderName(path))
    Dim it As Object: Set it = ns.ParseName(CreateObject("Scripting.FileSystemObject").GetFileName(path))
    If Not it Is Nothing Then it.InvokeVerb "delete" ' 既定はごみ箱へ
End Sub
VB

タイムスタンプ確認(差分検知)

' ModStamp.bas
Option Explicit
Public Function LastWrite(ByVal path As String) As Date
    Dim fso As Object: Set fso = CreateObject("Scripting.FileSystemObject")
    If fso.FileExists(path) Then LastWrite = fso.GetFile(path).DateLastModified
End Function
VB

重要ポイントの深掘り

削除は“ごみ箱送り”で事故を減らせます。ShellのInvokeVerbはエクスプローラの動詞(open, edit, delete など)を使えるため、簡単に既定の操作を呼べます。更新日時の差分監視は、外部ファイル取り込みのトリガー設計に役立ちます。


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

例題シナリオ

WordでPDF作成→エクスプローラで出力場所を開く→ZIPでまとめる→Outlookへ下書きメール作成→ショートカット配布、といった一連の流れを各テンプレで繋ぎます。

確認ポイント

完了待ちが機能しているか、戻り値で失敗を検知できているか、パスのクオート漏れがないか、外部アプリが確実に終了しているか。運用PCの権限・既定アプリ設定・ネットワークパス前提を最初に整えると、現場で安定します。


落とし穴と対策(深掘り)

待機不足による不定挙動

Runの待機(第三引数=True)と、Shell操作後の短いWaitを入れて安定化。ZIPや印刷のように“裏で続く処理”は余裕を持たせます。

クオート漏れによる失敗

すべてのパス・引数は “”” & path & “”” で囲む。日本語・スペース・記号を含む運用で必須です。

権限・既定アプリの差

企業環境ではポリシー差が出ます。既定アプリ、プリンタ、PowerShell実行ポリシーを運用ルールで固定し、事前にPCセットアップガイドを用意します。

UI自動化の不安定さ

SendKeysは最終手段。可能な限りShellExecuteやCOM、外部コマンドに置き換えます。


まとめ:Shellは「待つ・クオート・後片付け」を徹底すれば、強い相棒になる

WScript.Shell.Runで“待って判定”、ShellExecuteで“既定アプリ操作”、Shell名前空間で“ZIP・エクスプローラ”、WScript.Shellで“ショートカット”。この道具を「完了待ち」「正しいクオート」「例外でも復帰」の枠に乗せれば、VBAはExcelの外でも十分に戦えます。

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