GetLastError()の間違った使い方…。

先日リクエストを頂いた、GetLastError()の件ですが、忘れないうちに説明しておきたいと思います。
まずは、とあるEAにあったGetLastError()の間違った使い方のサンプルから。

#include  // ←エラーコードをメッセージとして表示するErrorDescription を使う時必要になる。
//
void subCheckError(int ticket, string Type)
{
    if(ticket>0) 
    {
      if(OrderSelect(ticket,SELECT_BY_TICKET,MODE_TRADES)) Print(Type + " order opened : ",OrderOpenPrice());
    }
    else Print("Error opening " + Type + " order : (",GetLastError(),") ", ErrorDescription(GetLastError()));
}

OrderSend後に、ticket が取れていなかったら、subCheckError関数でエラーメッセージを表示しようとしているのですが、この中にバグを見つけられますか?








以前の記事を読まれている人ならすぐ分かると思うのですが、

    else Print("Error opening " + Type + " order : (",GetLastError(),") ", ErrorDescription(GetLastError()));

この行で、GetLastError() を2度呼び出しているのが間違いです。
GetLastError()は、オンラインヘルプに書かれている通り、1度呼び出すと、エラーコードを格納しているlast_error変数をゼロにリセットします。
そのため、2度目の呼び出しでは、ゼロが返ってくることになり、本来エラーが発生しているにもかかわらず、"no error" というメッセージが表示されてしまうのです。


正しく書き直すとしたら、

#include // 

//
void subCheckError(int ticket, string Type)
{
    err=GetLastError();←1度だけの呼び出しにした
    if(ticket>0) 
    {
      if(OrderSelect(ticket,SELECT_BY_TICKET,MODE_TRADES)) Print(Type + " order opened : ",OrderOpenPrice());
    }
    else Print("Error opening " + Type + " order : (",err,") ", ErrorDescription(err));
}

とすれば、2度呼び出しのバグは解決できそうです。オンラインヘルプの参考コードも同様の書き方になっていると思います。




実際は、このEA の場合、別の関数内で

ticket=OrderSend(Symbol(),OP_BUY,Lots,Ask,Slippage,aStopLoss,aTakeProfit,TicketComment,MagicNumber,0,Green);
err=GetLastError();

と書かれていて、OrderSend 直後に既に GetLastError が呼ばれているので、subCheckError の中身をいくら書き換えても解決しませんでした....orz




GetLastError() のような一度しか呼べない関数は、エラーの起きる可能性のある命令の直後に呼んで err のような変数に保持しておくのが良いと思います。遠く離れた場所で呼び出そうとすると、うっかりミスをすることが多いです。