ExcelVBA keybd_eventの落とし穴
そこそこ時間かけて上の件を解決して、昨日の書いたとおりSendKyesで処理してたのをkeybd_eventに変える作業をしてたんですが……。
これ、使えないかも……。
ウェイトをかませても、Sleepをかませても、どうしても処理が遅れます。
たとえば……
keybd_event vbKeyDelete, 0, KEYEVENTF_EXTENDEDKEY Or 0, 0 'Delキーを押す keybd_event vbKeyDelete, 0, KEYEVENTF_EXTENDEDKEY Or KEYEVENTF_KEYUP, 0 'Delキーを離す '結局ここにウェイト入れてもSleep入れてもダメでした……orz Range("A1").Select
これを実行すると、期待する処理としては「アクティブセルをDeleteしてカーソルをA1に」という処理ですが、実際には「カーソルをA1に移動してDelete」になってしまいます。
どうやら、keybd_eventはマクロ処理がすべて終わってから実行されるようです……。
かなーりいろいろやってみた結果、上の現象の解釈としてはこんな感じかと。
1)Excelがマクロを再生しているとき、Excelは制御をOSから奪います。
2)keybd_eventはOSからExcelに飛ばされる命令なので、マクロでkeybd_event部を通ったとしても、制御がExcelに奪われている間は処理されません。
3)よって、他のマクロに記述されている命令をすべて処理したあとに、改めてOSからExcelにkeybd_eventの命令が飛ばされるまでは処理が行われません。
で、これの回避方法も見つけたには見つけました。
Excelから制御を戻すVBA関数「DoEvents」です。
たとえばさっきのであれば、
keybd_event vbKeyDelete, 0, KEYEVENTF_EXTENDEDKEY Or 0, 0 keybd_event vbKeyDelete, 0, KEYEVENTF_EXTENDEDKEY Or KEYEVENTF_KEYUP, 0 DoEvents Range("A1").Select
これで正常に動きます。
これではなにがいけないかというと……DoEventsはUndoが効かなくなる関数っぽいんですよねぇ……。
そもそもこれを使いたかった場所が、Undoを生かすためにVBA関数で処理しないでKeyEventsやkeybd_eventに頼ってたわけなので……orz
もーお手上げです。
不安定なの覚悟でKeyEvents使うか、安定させるためにUndoを諦めるか……。
前者かな……。もしくは、SendMessageでも試してみるか……。