MSDNのリニューアル?された学習動画サイトですが、これによってMFCについて、たくさん学んだことがあったので、ここで、記事にしておきます。
ほかにも、便利機能とかあったら教えてくださいね。ちょっとしたことでも俺知らないことがあるともいますから。
1,SafeIntクラス
0での除算や、int型においてのバッファオーバーフローが予防できるクラスのようです。
OEでのランタイムでは、ユーザーがこちらの予期せぬデータを入力する可能性を考えると、大いに活用したいと思います。
ヘッダ |
safeint.h |
名前空間 |
msl::utilities |
とりあえず、safeint.hをインクルードして、名前空間をいちいち打つのめんどいんで、using namespace msl::utilities
としておきます。
使用方法はこんな感じのようです。
SafeInt <unsigned int> x(1234567);
なるほど、unsignedなど、型もつけられるんですね。こりゃあいい。
符号なし整数のほうが機能が活躍するらしいので、できる限りunsigned intにしておきましょう。
このまま、大きい数で計算をすると、バッファオーバーフローをおこし、デバッガが起動されます。
気づきにくかったエラーも一目瞭然。と言うわけですか。
ですが、これ以上に目玉は、try~~catch構文で囲めることです。
スローされる例外は、SafeIntExceptionのようです。
try{
エラーの発生の可能性のある、SafeIntの処理
}catch(SafeIntException e){
エラーった場合の処理。
}
これで、エラーが発生したときにメッセージボックスを発生させる処理を組めますね。
ですが、これSafeIntを使うたびに呼び出さないといけないのでめちゃくちゃめんどくさいです。
しかしちゃんとそこが対応されているのがMFCですね。
class SafeIntCustomException:public SafeIntException{
}
このように、クラスを継承して、自分なりのカスタムエラー処理を書くことができるようです。
中身でオーバーライドできる関数は以下の通りです。
static void SafeIntOnOverflow() |
その名の通り、バッファオーバーフローを起こしたときに呼び出されるメソッドのようです。 |
static void SafeIntOnDivZero() |
その名の通り、0で割った場合に呼び出されるメソッドのようです。 |
動画中の注釈によると、CMFCExceptionではないようなので、注意したほうがよさそうです。
さて、SafeInt側で、独自に用意したクラスを用意するには以下のようにする必要性があるようです。
#include <safeint.h>の前に、
#define _SAFEINT_DEFAULT_ERROR_POLICY SafeIntCustomException
#defineの後に_SAFEINT_DEFAULT_ERROR_POLICYを書いて、そのあとに自分で定義したクラス名を書きます。
しかも、こうやって指定した場合、try/catchが要らないようなのです。
独自エラー処理クラスの中に、メッセージボックスを表示するようにして、アプリケーションを終了するようにすれば安全でしょう。
さらに、このエラー処理クラスですが、変数の宣言時に分けることも可能なようです。
先ほど、Safeint<unsigned int> x(1234567);
としたところで、
SafeInt<unsigned int,カスタムエラー処理クラス名> y(1234567);
とすることによって、そのクラスがエラー処理に使われることになります。
さて、以上がSafeIntでした。VS2010、MFCの期待の戦力だと語っていました。
.Netに最近押されてきた気がするMFCですが、まだまだ新機能を出してきてほしいものです。
さて、続いて、解説が少ないドキュメントテンプレートについてです。
2,ドキュメントテンプレート
知っての通り、MFCプロジェクトを作成すると、CxxxAppクラス、CxxxViewクラス、CxxxDocクラスなどが自動で生成されます。
また、3番で解説しようと思う、再起動マネージャについても、ここが基礎知識となります。
さて、MFCはゲームなどの開発よりも、実用ソフトに適していると言われます。
これは、このドキュメントテンプレートの強力な機能を見るとよく理解できます。
ドキュメントテンプレートについては僕自身最近理解したもので、不備があったら報告お願いします。
さて、CxxxDocクラス。これがアプリケーションで開く、ドキュメントのテンプレート?になるようです。
そしてCxxxViewクラスにおいて、CxxxDocクラスを読み取ってウィンドウに表示する機能を有します。
まず、CxxxDoc上において、自分のアプリケーションで操作する変数などを扱います。
従ってここにメンバ変数などを宣言します。
そして、CxxxView上のOnDrawメソッドをオーバーライドし、その上においてドキュメント情報を読み解き、画面に表示する機能を実装します。
(余談ですが、OEでは、CDCを使用せず、DirectXにゆだねています。ただし、DirectXをMFC用に使いやすくクラスにしたもので、こうしないと相当長くなります。)
さてまず一番大事なのは、CxxxDocのメンバ変数情報を、CxxxViewで取得することです。
その方法は以下です。
CxxxDoc* pDoc=GetDocument();
これによって、CxxxDocへのポインタができますので、メンバ変数を取得できますね。
あとは、View内にハンドラなどを追加して描画すればいいです。
あとは、これをCxxx.cpp内のCxxxAppクラスでドキュメントテンプレートを使用します。
OEの場合ですが、こんな感じです。
CMultiDocTemplate* pDocTemplate;
pDocTemplate = new CMultiDocTemplate(IDR_OEFPSTYPE,
RUNTIME_CLASS(COnLineGameEditerDoc),
RUNTIME_CLASS(CChildFrame), // カスタム MDI 子フレーム
RUNTIME_CLASS(COnLineGameEditerView));
また、CMultiDocTemplateクラスについてはいろいろな機能がありますので、この後にその設定処理を書きます。
また、ファイルを開く処理ですが、生成されたものでは、
ON_COMMAND(ID_FILE_OPEN, &CWinAppEx::OnFileOpen)
となっていました。CWinAppExとなると、CxxxAppクラスの基本クラスですね。
ここは実験していない+調べていないのですが、予想で失礼しますが、
CxxxDoc内のSerializeメソッドを呼び出し、ドキュメントロード。
と言う流れであると予想しています。
さて、書きこみ、読み込みをつかさどるSerializeですが
void COnLineGameEditerDoc::Serialize(CArchive& ar)
{
if (ar.IsStoring())
{
// TODO: 格納するコードをここに追加してください。
}
else
{
// TODO: 読み込むコードをここに追加してください。
}
// 基本クラスCOleServerDocEx を呼び出すことによってコンテナー ドキュメントの
// COleClientItem オブジェクトのシリアライゼーションが可能になります。
COleServerDocEx::Serialize(ar);
}
つまり、上のスコープには、読み込み処理を、下のスコープには書きこみ処理を描けばいいという事ですね。
また、ar<<書きこみたいもの
これで書き込みができるようです。
iostreamみたいですね
3,再起動マネージャ
SafeIntやドキュメントテンプレートでわかりましたね?
SafeIntは賞用ソフトなどにおいてのバッファオーバーフローなどによるフリーズを抑止するためにあり、ドキュメントテンプレートには、プロジェクトファイルを書きだすための便利な機能があります。
さて、ここでさらに、僕たちにはうれしい機能が、この再起動マネージャです。
再起動マネージャ・・・と聞いて、PC自体を再起動するかと思われるでしょうか?違います
もし万が一ソフトがフリーズした場合において、ソフトを再起動させ、エラーを解決するためにあります。
イマイチよくわかりませんね。
つまり、一時ファイルを用意し、直前の作業をフリーズしても復元できるのです。
そうExcelにありましたね。だってMFCつかわれてますもんねOfficeは。
まず、再起動させる壊すものを作ります。
*(int*)0=0;
動画ではこれを利用しておりました。とりあえずこれで行きましょう。
さてCxxxAppのコンストラクタに // 再起動マネージャーをサポートします
m_dwRestartManagerSupportFlags = AFX_RESTART_MANAGER_SUPPORT_ALL_ASPECTS;
と言う一文がありました。
無ければ追加することでサポートされるようです。
次に一時ファイルの自動保存間隔です。これによって、ドキュメントが復元できるようです。
動画で
Jonathan Wood氏はデフォルトでは5分で設定されているが、これが一番望ましいと語っています。
ですが、これを変更する方法も語っていました。
m_nAutosaveInterval=150000;
このようにすることで保存間隔(インターバル)を設定できるようです。
また、オーバーライドされていると思われる
BOOL CxxxApp::InitInstance()において、CWinAppEx::InitInstance();
を呼び出さなければいけないとも語っています。
これで、再起動マネージャはサポートされました。
IDEの中だと、デバッグされてしまうので、外で実験することによってそれが実証されます。
以上でした。
次回も続いて自分の知っている知識を皆さんに公開したいと思います。
[1回]