AutoItでエラー the requested action with this object has failed COMエラーをハンドリング

AutoIt COMエラーのハンドリング AutoIT

AutoItでRPAチックな自動化アプリを作成していると、開発PCでは出ないのにテストPCだと出る、なんてことがよく(?)あります。
で、メッセージ的には「the requested action with this object has failed」そしてアプリが落ちる。
・・・いやいや、これだと追っかけようにもどうしたらいいのかわからないでしょ・・・

スポンサーリンク

1. 出るタイミングがつかめない

同じ個所で出るのではなく、場所やタイミングが違って尚更困るという。
エクセルにループ内で書き込み(Excel UDF使用しても使用しなくても)で起きています。
COMオブジェクトを使う時にエラーが出ている模様。

AutoIt Error the requested action with this object has failed.

2. Excel UDFを見る

AutoItインストールフォルダのinclude\Excel.au3を見てみましょう。
各関数最初にエラーひっかけていますね。

 
Local $oError = ObjEvent("AutoIt.Error", "__Excel_COMErrFunc")
 

ではこの__Excel_COMErrFuncが何やってるかと、Excel.au3の一番下を見ると関数あるけど中身なしです。

Func __Excel_COMErrFunc()

EndFunc

というか、Excel UDFの関数は最初に毎回呼んでいますが・・・これいいの?って感じです。
いや、よくないからうまくエラーをハンドル出来ないんですね。

3. エラーがわかるようにしてみる ObjEvent

ObjEvent関数リファレンス(日本語)を見てみましょう。

Function ObjEvent

ObjEvent( “AutoIt.Error” [, “function name”] ) と2番目に書いてあり、
「2番目のフォーマットはCOMのエラーをハンドリングするために使用します。COMのエラーが発生すると、指定した関数が呼び出されます。
2番目のパラメータを省略すると、(存在する場合は)現在のエラーハンドリング関数を返します。」と書いています。

更にその下に COMエラーハンドリングサンプル があります。IEの例ですが、今回はExcelで。Excel UDFはやめて、自分でエクセルと接続していきましょう。
WorkSheets.Item(“存在しないシート”)でエラー出してみます。

Global $oExcel = ObjCreate("Excel.Application")
Global $g_eventerror = 0 ;COMエラーが起きたかどうかチェック用、ハンドリング後にリセット必要

Global $oMyError = 0 ;errorオブジェクト

$oMyError = ObjEvent("AutoIt.Error", "ComErrorFunc") ;COMエラーハンドラ初期化

$wb = $oExcel.Workbooks.Add
$sheet = $wb.WorkSheets.Item("存在しないシート")

Func ComErrorFunc()
  Msgbox(0, "AutoIt ComError", "COMエラーが起きています " & @CRLF & _
    "err.description is : " & @TAB & $oMyError.description & @CRLF & _
    "err.windescription:"     & @TAB & $oMyError.windescription & @CRLF & _
    "err.number is: "         & @TAB & hex($oMyError.number,8)  & @CRLF & _
    "err.lastdllerror is: "   & @TAB & $oMyError.lastdllerror   & @CRLF & _
    "err.scriptline is: "     & @TAB & $oMyError.scriptline     & @CRLF & _
    "err.source is: "         & @TAB & $oMyError.source         & @CRLF & _
    "err.helpfile is: "       & @TAB & $oMyError.helpfile       & @CRLF & _
    "err.helpcontext is: "    & @TAB & $oMyError.helpcontext _
  )
  Local $err = $oMyError.number 
  If $err = 0 Then $err = -1
  $g_eventerror = $err
EndFunc

AutoItでcomエラーをハンドルする

確かにハンドルできました。一度ObjEvent呼べばいいのにExcel UDFでは関数呼ぶ度に毎回呼んでいます。まぁ、他のUDFでCOMエラーハンドリングするからなのかもしれませんが、Excel UDFだけではExcel操作足りない事が多々出てくるので、自分でハンドリングしたいですね。

最終的にはExcel.au3を見ながら自分でエクセル操作関数作成するのが良さそうです。
筆者は_Excel_RangeWrite()内で$oExcel.Transpose($vValue)でよくエラー出ていたことがわかり、_ArrayTranspose($vValue)にするなどしました。

3.1 Excel UDFもbForceFunc=Trueで_ArrayTranspose()を使う

後日知ったのですが、$oExcel.Transpose($vRange.Value)で失敗するのは、255文字超えたセルのTransposeは未対応とのこと。各配列で255文字超えてるのチェックするなら$bForceFunc=Trueセットしたほうがいいですね。_Excel_RangeRead(),_Excel_RangeWrite()などですね。

Too many "lines" for Excel? Transpose error on a spreadsheet
Hello everyone , I have spotted a weird problem with the Excel COM API. It doesn't read a spreadsheet with a good amount of lines in a cell... Enough talk, let'...

4. 参考リンク

Function ObjEvent
COM Reference

コメント

タイトルとURLをコピーしました