【EXCEL】外部toolを呼び出し結果を取り込む

# やること
　EXCELで外部toolを呼び出し結果を取り込む際のメモをまとめておく。


# 事前確認：Qiitaでの記事
　ということで、以下の検索をしたところ、154件ヒットした。(2025/01/30時点)
[「VBAでPythonを動かす」の検索結果 - Qiita](https://qiita.com/search?q=VBA%E3%81%A7Python%E3%82%92%E5%8B%95%E3%81%8B%E3%81%99)

  以下、ご紹介。(検索結果以外を1つ含む)

## (参考)Run と Exec の違い
　いきなり検索結果以外で、Qiiraの記事ではない話。
 「Exec メソッド」。「Run メソッド」、「xlwings」辺りがでるかと想像し、以下を紹介しておきます。

[Run と Exec の違い【WSH】 | バグ取りの日々](https://www.bugbugnow.net/2018/06/wshrunexec.html)
投稿 2018/06/06　更新 2023/03/14


## Exec メソッド
[VBAでPythonを動かす #Excel - Qiita](https://qiita.com/O_LUPAN/items/1ceb5c950ff40f3558ab)
投稿日 2020年02月22日


## Run メソッド
あると思ったのですが……。

## xlwings
[VBAユーザーのためのPython入門 ～xlwingsでExcelからPythonを呼び出す～ #ExcelVBA - Qiita](https://qiita.com/k_maki/items/9efdb70f69d6f3b00f80)
最終更新日 2022年01月24日　投稿日 2020年04月28日

[xlwingsでExcel VBAからPythonを実行＆チュートリアルの補足 #ExcelVBA - Qiita](https://qiita.com/h_oki/items/1a4dc71afe4890ed1ae9)
最終更新日 2019年07月23日　投稿日 2016年06月10日

[【保存版】Excel GUIのPython実行ツールを作ろう(xlwings) #VBA - Qiita](https://qiita.com/bridgenail24/items/7c3f3ebf7f8bc7db260c)
最終更新日 2021年08月09日　投稿日 2021年08月08日

[xlwings: 複数行にまたがったレコードの値を取得する #Python - Qiita](https://qiita.com/stm32p103/items/8c3918542f5dbfd8b4bd)
投稿日 2024年04月29日

[PythonでExcelを操作する #Python - Qiita](https://qiita.com/wakasama_pcmaster/items/83422ef629a31a596db2)
最終更新日 2021年02月24日　投稿日 2021年01月28日


## その他
[Excelで使うスクリプト言語は何がいいか #ポエム - Qiita](https://qiita.com/tomgoodsun/items/49db6270f747908306d2)
投稿日 2024年11月27日

[【Python】Python経由でPowerPointにパスワードをかける方法（win32com） #自動化 - Qiita](https://qiita.com/mokonu/items/00c27e148a4ce2961ff7)
投稿日 2024年12月25日

[PythonからExcelをwin32comで操作する #Python3 - Qiita](https://qiita.com/kumarstack55/items/9ae3432446afca06497f)
最終更新日 2019年10月14日　投稿日 2019年10月14日

[しょーもない事務作業を快適にするためのツールを作りたいとき　〜セキュア意識の高い会社編〜 #Python - Qiita](https://qiita.com/ak-sasaki0919/items/e05bc3962d3540ce481f)
投稿日 2024年06月28日


# 事例
![スクリーンショット 2025-01-30 225917.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3838258/39283692-5afa-77a5-4fe9-68b9e6f738fe.jpeg)
* セルA1　起動するPythonのスクリプトの場所
* セルA2　変換元jpegファイルの場所
* セルA3　二値化する閾値
* セルA4　二値化変換後のjpegファイルの場所

(使い方)
1. 任意のB列で右クリックする
2. 右クリックしたcellの右側のセル(C列)に二値化変換後の画像が挿入される

「Run メソッド」が見つからなかったので、以下はその事例。
```vb:Excel2Python.bas 
Attribute VB_Name = "Excel2Python"
Option Explicit
'Excel2Python：EXCELから外部toolを呼び出し結果を取り込む例
' ① EXCELのA列に起動するPythonのスクリプトと引数を書く(固定)
' ② 任意のB列で右クリックする(Target As Range)
' ③ 右クリックしたcellの右側のセル(C列)に画像を挿入する
Sub test(Target As Range)
    Dim ws As Worksheet
    Set ws = Target.Parent                          'TargetのWorksheet
'        Application
'        └ Wokbook
'            └ Worksheet   ←Target.Parent
'                └ Range   ←Target
    Dim pSFPath As String
        pSFPath = ws.Range("a1").Value              'python scriptの場所
    Dim sourceJFPath As String
        sourceJFPath = ws.Range("a2").Value         '変換元jpegファイルの場所
    Dim tValue As String
        tValue = ws.Range("a3").Value               '閾値
    Dim outputJFPath As String
        outputJFPath = ws.Range("a4").Value         '2値画像のファイルパス

'   python script起動
    Dim sObj As Object
    Set sObj = CreateObject("WScript.Shell")
    sObj.Run "python " & pSFPath & " " & sourceJFPath & " " & tValue & " " & outputJFPath, 0, True
        ' 0 : コマンドプロンプトの非表示、 True : 同期(python script終了までVBAの処理を待つ)

'    Shell "python " & pSFPath & " " & sourceJFPath & " " & tValue & " " & outputJFPath, vbNormalFocus
'        '->Shellは非同期のため、ファイル作成前に画像表示に行ってしまう

'   /* pythonで画像処理 */

'   画像貼り付け
    Dim pic As Shape
    Set pic = ws.Shapes.AddPicture(outputJFPath, False, True, Left:=Target.Next.Left, Top:=Target.Top, Width:=-1, Height:=-1)
        ' Shapes.AddPicture メソッド (Microsoft.Office.Interop.Excel) | Microsoft Learn
        '  https://learn.microsoft.com/ja-jp/dotnet/api/microsoft.office.interop.excel.shapes.addpicture
End Sub
```
右クリックしたときに起動させるため、該当シートに記載。
```vb:Sheet.cls 
VERSION 1.0 CLASS
BEGIN
  MultiUse = -1  'True
END
Attribute VB_Name = "Sheet"
Attribute VB_GlobalNameSpace = False
Attribute VB_Creatable = False
Attribute VB_PredeclaredId = True
Attribute VB_Exposed = True
Option Explicit

' 右クリック押下
Private Sub Worksheet_BeforeRightClick(ByVal Target As Range, Cancel As Boolean)
    ' B列で起動
    If Target.Column = 2 Then
        Call test(Target)
    End If
End Sub
```
二値化するためのPythonスクリプト。

```python:sample.py
#ライブラリのインポート
import cv2
import sys

# 引数１が開く画像ファイル名
file_name = sys.argv[1]
# 引数２が閾値
img_thres = int(sys.argv[2])
# 引数３が保存先
file_path = sys.argv[3]


# 画像を開く
#pic=cv2.imread(file_name)
#cv2.imshow('Picture', pic)

# 画像をグレースケール化
pic_gray=cv2.imread(file_name,0)

# 閾値で二値化
ret, img_binary = cv2.threshold(pic_gray, img_thres, 255, cv2.THRESH_BINARY)

# 画像を保存
cv2.imwrite(file_path, img_binary)

# 画像を開く
cv2.imshow('Binary', img_binary)
cv2.waitKey(0)
cv2.destroyAllWindows()
```
## 補足
自分の環境では問題なかったが、環境により以下のエラーが出る場合もあるようです。
![スクリーンショット 2025-01-30 193005.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3838258/57427fd3-e4bb-666d-6133-cb35808c467c.jpeg)
NGが出る場合、もしかして、下側のようになっているのかしら……。
![スクリーンショット 2025-01-30 193645.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3838258/4fabc6f2-9ebc-639a-5421-49868005be53.jpeg)