ファイルのフルパスを簡単に取得する

はじめに

メール自動作成マクロ(その1その2その3その4)では、添付ファイルをセットするために表の中に添付ファイルのフルパスを入力しておく必要があった。

しかし、「添付ファイルのフルパスの入力なんてめんどくせーよな!」と誰しも思う。だから、簡単に入力できる方法が必要だ。

そこで、今回は、

セルをダブルクリックしたらファイル選択ダイアログが出てきて、そこで選んだファイルのフルパスがセルに入力される

という方針でやってみよう。

f:id:akashi_keirin:20170311114734j:plain

f:id:akashi_keirin:20170311114741j:plain

f:id:akashi_keirin:20170311114749j:plain

今回も、おなじみのこの表を使う。この表のU列~AD列のセルにファイルのフルパスを書き込むためのマクロ、ということ。

「セルをダブルクリックしたら」なので、Worksheetオブジェクトのイベントプロシージャ・「Worksheet_BeforeDoubleClick」を使う。

コードの作成

f:id:akashi_keirin:20170312205644j:plain

イベントプロシージャを書くときは、プロジェクトエクスプローラで、対象のオブジェクト名をダブルクリックしたらいい。今回は、「Sheet1」のところをダブルクリック。

f:id:akashi_keirin:20170312205647j:plain

「Sheet1」モジュールのコードウインドウが表示されるので、上の2つの窓でそれぞれ「Worksheet」(左)と「BeforeDoubleClick」を選択すると、

Private Sub Worksheet_BeforeDoubleClick(ByVal Target As Range, Cancel As Boolean)

End Sub

ってのが自動的に生成されるので、真ん中のところにコードを書いていきゃいい。

シートモジュールのコード

Option Explicit

Const PROMPT As String = "添付するファイルを指定してください。"

Private Sub Worksheet_BeforeDoubleClick(ByVal Target As Range, Cancel As Boolean)
On Error Resume Next
  Err.Clear
  Application.EnableEvents = False                                        '……(1)
  Set flp = New FilePicker                                                '……(2)
  With Target
    If .Column < colNum.att01 Or .Column > colNum.att10 Or .Row = 1 Then  '……(3)
      Application.EnableEvents = True                                     '……(4)
      Exit Sub
    Else                                                                  '……(5)
      '添付ファイルが歯抜け状態で入力されないようにするための措置
      If .Column > colNum.att01 And .Offset(0, -1).Value = "" Then
        MsgBox "添付ファイルは左詰めになるように設定せよ。" & vbCrLf & "やり直すがよい。"
        Cancel = True                                                     '……(6)
        Application.EnableEvents = True
        Exit Sub
      End If
      flp.showFilePicker PROMPT                                           '……(7)
      If flp.isCancelled = True Then                                      '……(8)
        Cancel = True
        Application.EnableEvents = True
        Exit Sub
      End If
      If LenB(flp.gotFileFullPath) > 220 Then                             '……(9)
        MsgBox "添付ファイルのフルパスのサイズが220バイトを超えています。" & vbCrLf & _
        "添付ファイルをデスクトップに貼り付けるなど、フルパスを短くしてください。"
        Cancel = True
        Application.EnableEvents = True
        Exit Sub
      Else
        .Value = flp.gotFileFullPath                                      '……(10)
        Cancel = True
      End If
    End If
  End With
  Application.EnableEvents = True                                         '……(11)                                    
  If Err.Number > 0 Then
    If Err.Number = 1004 Then
      MsgBox "指定したファイル名(フルパス)が長すぎます。" & vbCrLf & _
             "フルパスが短くなるようにして、やり直してください。" & vbCrLf & _
             "【例】添付ファイルをデスクトップに貼り付けるなど"
    End If
    Call errorCatch("WorkSheets(""Main"")のWorksheet_BeforeDoubleClickプロシージャ", Err.Number, Err.Description)
  End If
  Application.EnableEvents = True
End Sub

コードの説明

このブログでイベントマクロを紹介するのは初めてだと思うので、自分の復習も兼ねてちょっとこってり書いておこう。

  • (1)で一旦イベントの発生を抑える。実は、今回のこのマクロだけだったらこれは必要ないんだけど、このシートではもう一つ「Worksheet_Change」というイベントマクロも書いているので、イベントの連鎖を防ぐためにこうしている。いきなり分かりにくくてすまん。
  • (2)では自作クラスFilePickerをインスタンス化。FilePickerのコードはコチラをどうぞ。
  • (3)では、ダブルクリックされた場所を判定。添付ファイル入力欄以外なら(4)に進む。
    ちなみに、列番号の指定はおなじみ列挙体を使用しています。(コチラを参考にどうぞ。)
  • (4)に処理が移るということは、添付ファイル入力欄ではないということだから、イベントの発生抑止を解除して処理を終了する。処理を終了するときに「Application.EnableEvents」をTrueにしておかないと、いろいろおかしなことになるから注意。
    ※ダブルクリックしたのに何も起こらない、とか。
  • (5)に処理が移ってくるということは、添付ファイル入力欄上でダブルクリックされた、ということ。
  • ただし、ダブルクリックされたセルが添付ファイル2~10までのセルなのに、左隣のセルが空白だったら、歯抜け状態になっているとみなしてメッセージを表示して終了する。
  • (6)の「Cancel = True」というのは「ダブルクリック」というイベントをキャンセルする、ということ。ふつうセルでダブルクリックしたら、編集モードに移るんだけど、それをキャンセルするので何も起こらない。要するに直接入力もさせない、ということだ。
  • ここまでの条件をクリアしてきたら、それは、「ダブルクリックされたセルが添付ファイルのフルパスを入力しても良いセル」ということになる。そこで、(7)、FilePickerクラスのshowFilePickerメソッドの出番だ。ファイル選択ダイアログのタイトル欄に表示する文字列を引数として渡して実行する。
  • (8)。ファイル選択ダイアログで[キャンセル]が選ばれたりしてファイルパスが取得できていなければ、isCancelledプロパティがTrueになっているので、処理を終了する。
  • (9)は、取得したファイルフルパスのバイト数でふるいにかけている。添付ファイルのフルパスが長いと添付できないことがあるから。ここではそのバイト数を220にしているけど、これは目分量みたいなもん。正確なところが分からないので、知っている人がいたら教えてください。
  • ここまで、数々の苦難を乗り越えて(10)まで来たら、やっとここで取得したファイルのフルパスをダブルクリックしたセルに書き込んでいる。
  • 最後に(11)のようにイベント発生を復活させておくのを忘れないように。

イベントマクロって、便利なんですけど、思いもかけないタイミングで発動することがあるので、慣れないうちは試行錯誤が必要ですね。ダブルクリックイベントなんかの場合、単独ではイベントの無限連鎖にはならないんだけど、他のイベントマクロとの合わせ技で無限連鎖が起こってしまうことがあるのでやっかいです。

【参考】クラスモジュールFilePickerのコード

Option Explicit

'フィールド
Private gotFileFullPath_ As String
Private isCancelled_ As Boolean
'アクセサ
Public Property Get gotFileFullPath() As String
  gotFileFullPath = gotFileFullPath_
End Property
Public Property Get gotFileName() As String
  gotFileName = Right(gotFileFullPath_, _
                     (Len(gotFileFullPath) - InStrRev(gotFileFullPath, "\")))
End Property
Public Property Get isCancelled() As Boolean
  isCancelled = isCancelled_
End Property
'コンストラクタ
Private Sub Class_Initialize()
  isCancelled_ = False
End Sub
'メソッド
Public Sub showFilePicker(ByVal titleStr As String)
  Dim fileFullPath As Variant
  fileFullPath = Application.GetOpenFilename(Title:=titleStr)
  If fileFullPath = False Then
    isCancelled_ = True
    gotFileFullPath_ = ""
  Else
    isCancelled_ = False
    gotFileFullPath_ = fileFullPath
  End If
End Sub

【参考】標準モジュールのコード

'列挙体(列名を表すのに使用)
Public Enum colNum
  isSent = 1
  numOf
  sendTo
  mailTo
  CC
  BCC
  mailSubj
  belongsTo
  jobTitle
  personName
  p01
  p02
  p03
  p04
  p05
  p06
  p07
  p08
  p09
  p10
  att01
  att02
  att03
  att04
  att05
  att06
  att07
  att08
  att09
  att10
  returnReceipt
End Enum
'クラス変数
Public flp As FilePicker

おわりに

ここまで来ると、かなり便利なツールになってきます。

@akashi_keirin on Twitter