CEditクラスを拡張して、読み取り専用でかつ背景色が白で、
簡単に文字列を「追加」できるCLogEditというクラスを作ってみました。
今作成中のソフトに必要があったから作ったのですが、
また将来ログを表示するためのエディットボックスが
欲しいな〜と思ったらさくっとこのクラスを使えば良いわけです。
過去を思うと毎回そのたびにクラスを作っていましたね。(なんと非効率な!)
こうやって便利なクラスを作り貯めておくのも将来の楽に繋がるかもしれません。
本当ならばActiveX等で作っておくともっと互換性が広がるのでしょうが・・・
まあこれは難しそうなので暇があったら挑戦してみたいと思います。
MFCのプロジェクトで、バージョン番号を上げたいと思った時は、次の2つの事をしなくてはなりません。
CAboutDlg を編集し、バージョンを表示するスタティックコントロールを、IDC_VERSION 、
著作権を表示するスタティックコントロールをIDC_COPYRIGHT としましょう。
|
CAboutDlg に、WM_INITDIALOG のハンドラを追加し、
そこに次のように記述します。
|
TCHAR path[MAX_PATH]; DWORD handle; ::GetModuleFileName(AfxGetInstanceHandle(), path, sizeof(path)); DWORD size = ::GetFileVersionInfoSize(path, &handle); CByteArray buf; buf.SetSize(size); ::GetFileVersionInfo(path, handle, buf.GetSize(), buf.GetData()); LPVOID item; UINT itemsize; ::VerQueryValue(buf.GetData(), _T("\\VarFileInfo\\Translation"), &item, &itemsize); CString verstr; verstr.Format("\\StringFileInfo\\%04X%04X\\", LOWORD(*((LPDWORD)item)), HIWORD(*((LPDWORD)item))); ::VerQueryValue(buf.GetData(), (LPTSTR)(LPCTSTR)(verstr + _T("FileDescription")), &item, &itemsize); CString name = (LPTSTR)item; ::VerQueryValue(buf.GetData(), (LPTSTR)(LPCTSTR)(verstr + _T("FileVersion")), &item, &itemsize); CString version = (LPTSTR)item; ::VerQueryValue(buf.GetData(), (LPTSTR)(LPCTSTR)(verstr + _T("LegalCopyright")), &item, &itemsize); CString copy = (LPTSTR)item; SetDlgItemText(IDC_VERSION, name + " ver " + version); SetDlgItemText(IDC_COPYRIGHT, copy); |
FileDescription
とFileVersion
を参照しています。
他の情報を表示したい場合は書き換えて使って下さい。
応用としては、GetModuleFileName
を使わずに、path
になんらかのファイル名を入れてこのコードを
実行すれば、そのファイルのバージョン情報が取得出来ます。バージョン関係のAPIは、他にも色々あるようですね。
でもこうやってバージョン変更を簡単にしても、私はバージョンアップの際のリソースの編集を良く忘れます。 うーーむ・・・
前回の続きになりますが、Documentにどうやってデーターを置くか?という事ですが、
最近は、データー管理用のクラスAを作り、さらにそれを継承してクラスBを作り、
クラスBに表示処理を行わせて居ます。
クラスAは、まさしくデーターの管理や計算をするだけで、
アプリケーションの種類には依存しないようにします。
クラスBは、アプリケーションにべたべたに依存して書きます。
他の環境に移植する時は、クラスAだけをそのまま移し、
そこでクラスAを継承してクラスCをつくり、クラスCに表示処理を行わせます。
データー管理はクラスAで、表示処理はそれを継承したクラスで、という事です。
クラスAで、例えば、"Hoge"
と表示したいと思った時は、
Output("Text");
と呼びます。Output
は、virtual関数で、A::Output()
は何もしません。
このクラスBやCでは、このOutput
を継承し、それぞれのアプリケーションに応じた
文字列出力処理を行います。
今の所、この方法は面倒なだけですね。この形でプログラムを書いたのは良いのですが、
まだ移植作業をやっていないのです。(^^;;;
この先、移植作業をやる事がありましたら、この構造のプログラムの移植が
簡単だったのか難解だったのかの結果が出ると思いますので、それまでお待ち下さい。
Windowsでは、リソースにデーターを含ませる事が出来ます。
BITMAPやメニュー情報を含ませる事が出来るのはもちろん、実はバイナリデーターならば
何でも出来ます。VC++ならば、メニューから挿入->リソース->カスタムで挿入できます。
このリソースは、カスタムリソースと呼ぶようです。
カスタムリソースは、リソースのタイプやIDを自分で指定します。
とりあえずリソースのタイプは"BIN"
、名前は"DATA"
とします。
もしも名前やタイプをIDで指定するならば、MAKEINTRESOURCE(ID_DATA)
というように、
MAKEINTRESOURCE
を使えば、文字列に変換できます。
では、そのカスタムリソースの読み込み方法を見てみます。
バイナリデーターなのですから、LPBYTE型のポインタにデーターの先頭アドレスが入れば
完了ですね。
HRSRC hrsrc; HGLOBAL hglobal; LPBYTE data; DWORD rsize; if ((hrsrc = ::FindResource(AfxGetInstanceHandle(), "DATA", "BIN")) == NULL || (rsize = ::SizeofResource(AfxGetInstanceHandle(), hrsrc)) == 0 || (hglobal = ::LoadResource(AfxGetInstanceHandle(), hrsrc)) == NULL || (data = (LPBYTE)::LockResource(hglobal)) == NULL){ // ●リソース読み込み失敗● }else { // ●リソース読み込み成功処理● } |
FindResource
の引数の名前とタイプの順番に注意して下さい。
私はよくこれを間違えます。
リソース読み込みに成功すれば、変数data
にデーターの先頭アドレス、
変数rsize
にデーターの大きさが入っています。
あとはご自由にアクセスして下さい。
あけましておめでとうございます。今年もよろしくお願い致します。
2001年と書こうとするといつも20001年と書いてしまいます。 2000と1年をそのまま書くと20001になるのですね。2000+1=20001なのです。 どうやら頭の中まで文字列クラスが進入してきてしまったようです。
最近開発をしていて、コードの再利用性というのが気になるようになってきました。 1度書いたコードを、2度書くことが面倒だからです。 でも再利用するために最初に面倒な思いをするのも大変ですね。 作る前は再利用するかどうか分からない時も多々ありますし。 MFCのドキュメント/ビューアーキテクチャを使っている時の コードの再利用性を上げるコツは、ずばりこれです。 Documentに直接データーを置かない! これらでは無く、データー管理用のクラスを作って、 そちらでデーターを管理するようにしましょう。 こうすると、ダイアログベースのアプリケーションに移植! という場合にも、比較的容易に行う事が出来ます。 ViewやAppクラスにはデーターを置いても良いのかというと、 これらのクラスには、そもそもデーターを置くべきではありません。 さらに、データーのみに依存する操作と、データーを表示するための操作は、 別クラスに分けたりすると効果的です。 データーのみ依存する操作は、移植しても変化はありませんが。 表示するための操作は、別の環境に移植すると大幅に変わってしまうかもしれない からです。 操作を分けるといってもどうやって分けるのか?についてはまた次回という事で。
クリティカルセクションとは、危険領域の事です。この単語は、
マルチスレッドを扱う時に使われます。
2つのスレッドが同時に実行してはならない場所。それが危険領域です。
片方のスレッドが危険領域に入っている時には、
もう片方のスレッドは、危険領域突入を待たなければなりません。
これをやってくれるのがMFCのCCriticalSection
クラスと
CSingleLock
クラスです。
危険領域部分の書き方は以下のようになります。
CCriticalSection cs; // ●それぞれのスレッドで共通の変数。● |
{ CSingleLock sl(&cs, TRUE); // ●ここに危険領域の部分のコードを書く。● // ●ここに書かれたコードは、同時に1スレッドしか実行できません。● } |
CMultiLock
を使うと良いでしょう。CMultiLock
を避ける余り、CSingleLock
でロックしている最中に、
さらにCSingleLock
でロックすると
デッドロックという非常に危険な状態を招く可能性があります。CSingleLock
のネストを行うならば、
CMultiLock
で対応した方が良いでしょう。