【VBA×WindowsAPI】クリップボードにビットマップ画像をセットする

VBAを使っていてクリップボードを操作したいという場面に出くわすことがしばしばあります。
クリップボードを操作する方法はいくつか存在しますが、ここではWindows APIを使ってクリップボードに指定の画像ファイルをセットする方法を解説していきます。Windows APIを利用することで(Application.ClipboardFormatsやActiveSheet.Pasteなどのような)“Excel VBAだけ”といったアプリケーションにとらわれない処理を行うことができます

Windows APIを使ってクリップボードにビットマップ画像をセットするコードは、基本的にほとんど決まりきったものです。そのためパッと使いたい程度であればサンプルコードをコピペすればそのまま利用できます。ただし、しっかりと扱わないとVBA外にも影響の出る恐れのあるコードのため、コード解説の「終了処理」の項目だけは軽く目を通しておくことをオススメします。

 

VBAでクリップボードに画像をセットする方法

 
VBAでクリップボードに任意の画像データをセットするには下記のWindows APIを利用します。
それぞれ関数のより詳細な使い方の解説は各関数のリンクページを参照下さい。

icon-check-square OpenClipboard関数:      クリップボードを開く
icon-check-square EmptyClipboard関数:    クリップボードを空にする
icon-check-square CloseClipboard関数:      クリップボードを閉じる
icon-check-square SetClipboardData関数:  クリップボードにデータ(画像)をセットする
icon-check-square LoadImage関数:            メモリ上にビットマップをロードする
icon-check-square DeleteObject関数:         メモリ上のビットマップを削除しシステムリソースを解放する

「そもそもWindows APIって何?」という方はコチラ(メインページ)も併せて参照下さい。

 

サンプルコード

クリップボードにビットマップ画像をセットするためのサンプルコードは下記の通りです。
コード内の「”画像ファイルパス.bmp”」部分を任意のビットマップファイルのフルパスに書き換えてから実行すると、指定した画像ファイルがクリップボードにセットされます。

指定パスがビットマップでなかったり、ファイル自体が存在しなかったりしてうまく処理ができなかった場合はクリップボード内が空になります。しっかりとデータのセットができたかを確認したい場合は”Callで関数を呼び出す”のではなく戻り値での判定処理を追加する必要があります。各関数の戻り値はそれぞれの関数別ページで解説しているので合わせて参照してください。

 

コード解説

icon-edit Bmpファイルをメモリ上に読み込む

クリップボード内に画像をセットするにはまず、画像をメモリ上に読み込む必要があります。
画像をメモリ上に読み込ませるためにはLoadImage関数を使い下記のように書きます。

icon-code LoadImage関数 

hBitmap = LoadImage(0, sPathImage, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE)

LoadImage関数はアイコン、カーソル、ビットマップをメモリ上に読み込むための関数で、今回のようなビットマップ画像データを読み込む場合は第3引数に「IMAGE_BITMAP」を入力します。また、その読み込ませるビットマップ画像データとしてローカルにある画像ファイル(.bmp)を読み込ませる場合は第6引数に「LR_LOADFROMFILE」を入力します。

「IMAGE_BITMAP」「LR_LOADFROMFILE」は該当のヘッダーファイル内に定義されていますが、VBAでは関数の呼び出しを行っているだけなのでこれら定数は定義されていません。そのため「Const IMAGE_BITMAP As Long = 0」「Const LR_LOADFROMFILE As Long = &H10」というかたちでコードの初めに定義しています。(引数として直接「0」「&H10」を入力しても同じ結果となります)

上記の引数と合わせて実際にメモリ上に読み込ませるビットマップ画像のファイルパス(フルパス)を第2引数に入力することで、指定の画像ファイルをメモリ上に読み込ませることができます。戻り値の「hBitmap」にはメモリ上に読み込まれたビットマップ画像へのハンドルが返されます。
 

icon-edit クリップボードを開く & 初期化

クリップボード内のデータ操作を行う際は、OpenClipboard関数を使ってクリップボードを”開く”、つまりはプログラム(VBA)からクリップボードにアクセスできるようにする必要があります。

分岐処理の「If OpenClipboard(0) Then」は”クリップボードが正常に開かれた場合”を意味しています。基本的にOpenClipboard関数が失敗することはありませんが、VBAとは別で稼働しているアプリケーション等でクリップボード操作の処理が行なわれている場合に失敗する可能性があります。

クリップボードが正常に開けたらクリップボード内に既にあるデータをクリアして、クリップボード内を空の状態にします。クリップボード内のデータを空にするにはEmptyClipboard関数を呼び出すだけです。(※この関数は事前にOpenClipboard関数でクリップボードを開いておく必要があります)
 

icon-edit 読み込んだBmpファイルをクリップボードにセットする

クリップボードを開くことが出来たらをSetClipboardData関数を使ってメモリ上に読み込んだビットマップ画像をクリップボードにセットします。

icon-code SetClipboardData関数 

Call SetClipboardData(CF_BITMAP, hBitmap)

クリップボードにセットするデータがビットマップの場合は第1引数に「CF_BITMAP」を入力します。これもLoadImage関数の時と同様にヘッダーファイルで定義された定数で値は「2」です。

第2引数には読み込ませたビットマップ画像へのハンドル(LoadImage関数の戻り値)を入力します。これでクリップボード内に画像データをセットすることができます。サンプルコードでは正常に処理ができる前提で戻り値の受け取りはしていませんが、よりしっかりと書くのであれば戻り値を受け取って正常に処理ができているかを判定したほうがよいです。
 

icon-edit 終了処理

クリップボードの操作が終わったらCloseClipboard関数でクリップボードを閉じる必要があります。
これを行わないと外部のアプリケーションおよび手作業でのクリップボードの操作が行えなくなるので、OpenClipboard関数を使った後は必ずCloseClipboard関数でクリップボードを閉じる処理を通るようなコードにしておく必要があります。

またLoadImage関数でメモリ上に読み込ませた画像データはVBAが終わってもメモリ上に残り続けてしまいます。つまり実行すればするほどメモリ上に画像データが読み込まれ、不要なメモリが蓄積されていってしまいます。この現象をメモリリークといい、これを起こさないようにするためには使わなくなった不要な画像データをメモリ上から除去する必要があります。メモリ上の画像データを削除するにはDeleteObject関数を使います。使い方は引数に読み込ませたビットマップ画像へのハンドル(LoadImage関数の戻り値)を入力するだけです。

 

関連情報

icon-share-square VBA×WindowsAPIまとめページ

その他のWindowsAPI関数は下記ページにまとまっているので合わせて参照下さい。

icon-share-square 参考

Microsoft公式:クリップボードの使用 – Win32 apps

Excel, VBA, Windows API

Posted by Lic