エクセルを別プロセスで開くVBAツールの作成

##エクセルを別プロセスで開きたい
　日々の業務の中で、何個もエクセルを開いて作業をしている方は多いのではないでしょうか。
 
 私も日次の集計・分析作業があり10個以上のエクセルを開いて業務をしています。

　効率よく作業を行うために考えたのが、**エクセルが開く仕組み**を知ることでした。
どういうことかというと、エクセルは普通に何個も開くと同じプロセス内で開かれています。

A,B,Cのエクセルを開いているとしてAで重たいマクロを実行しているとAのマクロが終わらない限りはB,Cの操作ができません。

分かりやすく例えると、船が一隻あります。
その中に乗組員が4名いるとします。全員男性としましょう。**`船の中にはトイレが1個しかありません`**。
たまたま全員が同じタイミングで用を足したくなりました。さあどうしますか。全員が一斉にトイレでするという荒業はさておき、順番に並んで前の人が終わったら次の人というような流れになりますよね。

もし、**`トイレが4つあればすべて解決です`**。

そう、私たちが日々エクセルで並行して作業する場合は作業分トイレを用意すればよいのです（違う）

##別プロセスってどんな感じ？？

　試しに何個かエクセルを開いた後に、タスクマネージャーを開いて確認してみてください。

こんな感じになっているかと思います。

※図1
![image.png](https://qiita-image-store.s3.amazonaws.com/0/257191/d0da26d9-9889-c43d-00a7-9416830769a7.png)

黄色く（汚くてすみません）ハイライトしたように(4)となっています。これは4つのエクセルが同じプロセスで開いていることになります。

ではどうなればよいのか。

以下のようになれば別プロセスで開いていることになります。

※図2
![image.png](https://qiita-image-store.s3.amazonaws.com/0/257191/c97a95df-8518-0709-bb01-52a914975f91.png)

いかがでしょうか。図1ではタスクの終了をすると開かれているエクセルが全部閉じてしまいます。
図2の場合は複数のエクセルが独立しています。

この状態になれば、並行して作業をしても問題ありません。
先ほどのトイレが4つあるので待つ必要はない状態と同じです。

##エクセルを作業する分一気に開きたい。

そんなマクロを作成してみます。

完成形はこんな感じです。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/257191/84b929d1-537c-e369-54a6-5d7fda0b9ab5.png)

|A列              |B列       |C列      |D列      |E列   |
|:----------------|---------|-------  |----------|------:|
|ディレクトリのパス|ファイル名|開く対象  |結果       |備考   |

このようになっています。
あらかじめA列B列C列を入れておき、ボタンを押下して実行する。
完了やエラーはD列に表示する。　E列は備考なのでVBAのマクロにはなりません。

まずはこれらのサンプルコードをいかに貼ります。
`リファクタリング要素は多いのでご了承ください。。。`
別プロセスで開く点に集中して解説したいと思います。

```vb
Public mySheet As Worksheet

'ファイルパスの読み取り開始行
Const COUNT_START_ROW = 5                        '開始セル行
'グレー色にしているセルには数式が入っています。 3行目は変更禁止
Const IN_FUNCTION_ROW = 3                        '対象を数える数式が入っているセル（行数）
Const IN_FUNCTION_COUNT_OPEN_CHECK_COLUMN = 3    '対象を数える数式が入っているセル（列数）
Const IN_FUNCTIION_READ_ONLY_CHECK_COLUMN = 1    '読み取り専用で開くかどうかを確認する式が入っている列数
Const IN_FILE_PATH_COLUMN = 1                    'ファイルのパスが入っているセルの列数
Const IN_FILE_NAME_COLUMN = 2                    'ファイル名が入っているセルの列数
Const OPEN_CHECK_COLUMN = 3                      'ファイルを開く対象を判別する■が入っている列数
Const RESULT_MSG_COLUMN = 4                      '結果を表示する列数

Public Sub init()
    Set mySheet = ActiveSheet
End Sub

Sub OpenSepProSample()

    Call init
    Call resultMsgClear
    
    Application.ScreenUpdating = False
    Application.Calculation = xlCalculationManual
    
    
    Dim filePath As String
    Dim myApp As Excel.Application
    Dim yesNo As Integer
    Dim openCheck As String
    Dim readOnlyCheck As String
    
    Dim inFunctionRow As Integer
    inFunctionRow = IN_FUNCTION_ROW
    
    
    
    'ファイルを読み取りで開くかどうかのチェック
    
    Dim inFunctionReadOnlyCol As Integer
    inFunctionReadOnlyCol = IN_FUNCTIION_READ_ONLY_CHECK_COLUMN
    
    'Trueかfalseの文字列を格納
    readOnlyCheck = mySheet.Cells(inFunctionRow, inFunctionReadOnlyCol).Value
    
    '実行の確認
    Dim inFunctionCheckOpenCol As Integer
    inFunctionCheckOpenCol = IN_FUNCTION_COUNT_OPEN_CHECK_COLUMN
    mySheet.Cells(inFunctionRow, inFunctionCheckOpenCol).Formula = "=COUNTA(C5:C1048576)"
    If mySheet.Cells(inFunctionRow, inFunctionCheckOpenCol) = 0 Then
        MsgBox "対象ファイルを１つ以上選択してください。"
        Exit Sub
    Else
        yesNo = MsgBox("対象のファイルをすべて開きますか。", vbYesNo + vbQuestion, "実行の確認")
        If yesNo = vbYes Then
        
            'ファイルを開く処理
            'セルA5から一覧記載　ループ処理
            Dim targetSearchRow As Integer
            Dim filePathColumn As Integer
            Dim fileNameColumn As Integer
            Dim openCheckCoumn As Integer
            Dim resultMsgColumn As Integer
            
            targetSearchRow = COUNT_START_ROW    '検索開始行
            filePathColumn = IN_FILE_PATH_COLUMN
            fileNameColumn = IN_FILE_NAME_COLUMN
            openCheckCoumn = OPEN_CHECK_COLUMN
            resultMsgColumn = RESULT_MSG_COLUMN
            
            Dim openCheckCountNum As Integer
            Dim loopNum As Integer
            openCheckCountNum = 0
            loopNum = mySheet.Cells(inFunctionRow, inFunctionCheckOpenCol)
            
            'Do While Cells(targetSearchRow, filePathColumn) <> ""
            Do While (openCheckCountNum < loopNum)
                Set myApp = CreateObject("Excel.Application")
                filePath = mySheet.Cells(targetSearchRow, filePathColumn).Value
                Filename = mySheet.Cells(targetSearchRow, fileNameColumn).Value
                fileFull = filePath & "\" & Filename
                'Debug.Print fileFull
        
                openCheck = mySheet.Cells(targetSearchRow, openCheckCoumn).Value 'B列
                
                'B列に■が入っているファイルを開く
                If openCheck = "■" Then
                    openCheckCountNum = openCheckCountNum + 1
                    'パスが見つからない場合は①のエラー分へ文岐する。
                    
                    If filePath <> "" Then
                        If Filename <> "" Then
                            If Dir(fileFull) <> "" Then
                                myApp.Workbooks.Open fileFull, ReadOnly:=readOnlyCheck
                                myApp.Visible = True
                                mySheet.Cells(targetSearchRow, resultMsgColumn).Value = "完了"
                                Set myApp = Nothing
                            Else
                                'ファイルパス＋ファイル名で検索できなかった場合のエラー処理
                                mySheet.Cells(targetSearchRow, resultMsgColumn).Value = "ファイルパスが不正です。"
                            End If
                        Else
                            'ファイル名のセルが空だった場合のエラー処理
                            mySheet.Cells(targetSearchRow, resultMsgColumn).Value = "ファイル名の指定がありません。"
                        End If
                    Else
                        'ファイルパスのセルが空だった場合のエラー処理
                        mySheet.Cells(targetSearchRow, resultMsgColumn).Value = "パスの指定がありません。"
                    End If
                End If
                '■が入っていないセルは飛ばし下のセルへ移動する。
                targetSearchRow = targetSearchRow + 1
            Loop
            'ループの終了
            'MsgBox "ファイルをすべて開きました。"
        Else
            'マクロ起動時のYes／NoボタンのNoが押された場合の処理
            MsgBox "終了します。"
        End If
    End If
End Sub

Public Sub resultMsgClear()
    
    ActiveSheet.Range("D5:D3000").ClearContents
    
End Sub

```

ざっとこれです。
コピペで使えると思います。

今回の記事のメインであるエクセル別プロセスのコードは以下です。

```vb
'CreateObject("Excel.Application")を宣言し変数を作成します。
Set myApp = CreateObject("Excel.Application")
'以下のコードがエクセルを別プロセスで開くための肝になる点です。
myApp.Workbooks.Open "開く対象のファイルのフルパス"　'※オプション指定も可能
```

作業用エクセルの一覧があると効率も上がると思いますので
ぜひ活用してみてください！