LoginSignup
3
4

More than 5 years have passed since last update.

c++ builder > Windows 8.1 English だけ abnormal program terminationが起きる > static const TDateTime kDt = StrToDateTime(L"2000/1/1 00:00:01"); はだめ > 代替案: static const TDateTime kDt = VarToDateTime("2000/1/1 00:00:01"); / リモートデバッグ

Last updated at Posted at 2015-09-18
ビルド環境
C++ builder XE4

ビルドした.exeファイルを実行した時、なぜか以下の違いが出た。

  • Windows 7Pro (32bit, 日本語版) : OK
  • Windows 8.1Pro (64bit, 日本語版) : OK
  • Windows 8.1Pro (64bit, English) : Abnormal program termination

下記を参考にリモートデバッグでチェック
http://www.gesource.jp/weblog/?p=4889

(なおXE4では以下のファイルをコピー)

bccide.dll
bordbk180.dll
bordbk180N.dll
comp32x.dll
dcc32180.dll
rmtdbg180.exe

実行 > プロセスの読込み において「プログラムエントリポイントまで実行する(E)」をチェックしてもAbnormal program terminationが起きる。

このため、リモートデバッグはあきらめた。

以下、調査した

自動生成フォームの変更 (結果:x)

  1. オプション > フォーム において、「自動生成フォーム」にリストアップされているものすべてを「使用可能フォーム」に移す。
  2. 一番シンプルなフォームだけ「自動生成フォーム」にして、かつ「メインフォーム」にする。

結果、ダメだった。

cppとhをプロジェクトから順次削除 (原因特定できた)

複雑なcppとhを順次プロジェクトから削除して、エラーが出なくなる地点を見つける。

実際、一番シンプルなフォームだけ残してビルドしたらエラーが出なくなったので、この方法でなんらかの結果が出るだろう。

  1. Mxxx.cpp, MxxxIxxxs.cpp をプロジェクトから削除 >> ダメ
  2. OpxxxxLxxxSxxx.cpp をプロジェクトから削除 > ダメ
  3. CxxxdOxxx.cpp をプロジェクトから削除 > ダメ
  4. IxxxOxxxx.cpp, LoxxxRxxOxxx.cppを削除 > ダメ
  5. ThxxxMxxx.cpp, MxPxxxUxxx.cpp, MxxDxx.cppを削除 > 動いた

5番目の手順で削除したファイルが関係あるのだろうか。

5番目で削除したファイルを順次戻して、エラーが発生するファイルは MxPxxxUxxx.cpp であることがわかった。

あとは、このファイルの何が問題か見つけないといけない。

エラーコード

MxPxxxUxxx.cpp に定義していた以下のコードが Abnormal Program Terminationを発生するということが特定できた。

static const TDateTime kReturnInError_TDateTime = StrToDateTime(L"2000/1/1 00:00:01");

以下は問題ない。

static const TDateTime kReturnInError_TDateTime = (TDateTime)0;

日時の解釈が英語圏でちょっと違うのかもしれない。

以下もOKなので、constで日時を指定したい場合は、StrToDateTime()でなく以下のようにしておいたほうが英語OS対応にもいいのかもしれない。

static const TDateTime kReturnInError_TDateTime = EncodeDate(2000, 1, 1) + EncodeTime(0, 0, 1, 0);

調査完了。
結構、はまってしまった。

エラーの詳細

ButtonClickにてTDateTime dt = StrToDateTime(L"2000/1/1 00:00:01");を実行すると「日付または時刻ではありません。」のエラーがでる。

該当の英語版WindowsのControl Panel > Regionを見たときに、日付表記がM/d/yyyyのようになっているので、上記のフォーマットではだめになるのだろう。

こういうことがあるということは、安易にStrToDateTime()を使っていると、英語OS上で問題が起きてしまうのかもしれない。

対策

StrToDateTime()でなくVarToDateTime()を使えば上記の問題は回避できるようだ。

参考1: http://www2.big.or.jp/~osamu/Delphi/Tips/key.cgi?key=42

文字通り StrToDateTime という関数もあるんですが、これは yyyy/mm/dd などの形式にしか対応していません。ちょっとひねって VarToDateTime を使えば、ほぼどんな形式でもうまく変換できます。string -> Variant は自動で変換されるので、そのまま文字列を渡すだけで使えます。

参考2: SO

If you want to convert some special DateTime-Formats you should better use VarToDateTime instead of StrToDateTime.

以下を試した。

    TDateTime dt1 = VarToDateTime(L"2000/1/1 00:00:01");
    ShowMessage(dt1.FormatString(L"yyyy/mm/dd hh:nn:ss"));

    TDateTime dt2 = StrToDateTime(L"2000/1/1 00:00:01");
    ShowMessage(dt2.FormatString(L"yyyy/mm/dd hh:nn:ss"));

上記のコードでdt1の結果は英語版Windowsにおいて意図通りの日時として認識された。

VarToDateTime()を使う時の注意点はよくわからないが、とりあえずはStrToDateTime()よりはよさそう。


VarToDateTimeのエラー

(2015/10/05 追記)

    TDateTime dt1 = VarToDateTime(L"2000/1/1 00:00:01");

    TDateTime dt1 = VarToDateTime("2000/1/1 00:00:01");

のようにLプリフィックスなしでないとエラーがでるかもしれない。

3
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
4