RCIE-ジャンクのコード屋

主に自分のためにコーディングのTIPSを蓄積しています。

VBA マウスポインタの形状を取得する GetCursorInfo / LoadCursor

やりたいこと

VBAで、マウスポインタが矢印カーソルなのか、待機カーソルなのか知りたい。
待機カーソルになったらVBAの処理を中断、というプログラムを作ろう。

方針

VBAには、Application.Cursor でカーソルの状態を取得することができる。
しかし、これは残念なことに、Excel の外にマウスカーソルが出ると全く機能しない。
Excel の外のマウスポインタの形状を知るには、Win32 API を使う必要がある。

  • マウスカーソルの形状や位置を得るための APIGetCursorInfo
  • 待機カーソルの番号を得るための APILoadCursor


コード(64bit版)

'取得するカーソル情報を保持する構造体
Type CURSORINFO
	nSize As Long '構造体の大きさ(=24)
	nFlag As Long '表示・非表示フラグ
	hCursor As LongPtr 'カーソル画像を表す数値
	x As Long 'X座標
	y As Long 'Y座標
End Type

Const IDC_WAIT = 32514 '待機カーソルのID

'カーソル情報を取得する Win32API 関数
Declare PtrSafe Function GetCursorInfo Lib "user32" (p As CURSORINFO) As Long

'カーソル画像を表す数値を取得する Win32API 関数
Declare PtrSafe Function LoadCursor Lib "user32" Alias "LoadCursorA" ( _
	ByVal hInst As LongPtr, _
	ByVal idc As Long _
) As LongPtr

'処理を一時停止する Win32API 関数
Declare PtrSafe Sub Sleep Lib "kernel32" (ByVal nミリ秒 As Long)

Public Sub 今回の処理()
	Dim h待機カーソル As LongPtr
	h待機カーソル = LoadCursor(0, IDC_WAIT) '待機カーソル画像を表す数値を取得
	
	Dim i As Long
	For i = 1 To 100000 'しばらくループする
		Dim カーソル As CURSORINFO
		カーソル.nSize = LenB(カーソル) '構造体の大きさをセット
		GetCursorInfo カーソル 'カーソル情報を取得する
		
		'カーソルの形状が待機になったら、メッセージを表示して終了
		If カーソル.hCursor = h待機カーソル Then
			MsgBox "待機カーソルになりました"
			Exit Sub
		End If
		
		DoEvents 'OSに処理をゆずる
		Sleep(1) '0.001秒待機
	Next
End Sub

補足説明

待機カーソルのIDは 32514 だが、他のカーソルのIDも記載しておく。
参照元
LoadCursorA function (winuser.h) - Win32 apps | Microsoft Docs

意味
IDC_APPSTARTING 32650 標準的な矢印と小さな砂時計
IDC_ARROW 32512 標準的な矢印
IDC_CROSS 32515 十字
IDC_HAND 32649
IDC_HELP 32651 矢印とはてなマーク
IDC_IBEAM 32513 Iの字
IDC_NO 32648 🚫マーク
IDC_SIZEALL 32646 十字矢印
IDC_SIZENESW 32643 /の向きの両矢印
IDC_SIZENS 32645 │の向きの両矢印
IDC_SIZENWSE 32642 \の向きの両矢印
IDC_SIZEWE 32644 ─の向きの両矢印
IDC_UPARROW 32516
IDC_WAIT 32514 砂時計

具体的にどのような形状なのかは、以下のリンクが参考になる。
Windowsアプリケーション上のマウス・カーソルを変更するには?[C#、VB] - @IT