Naknet blog

Nothing to believe, nothing else to believe.

M$のプログラム教室

Microsoftのプログラム講座。セキュリティ関連も初心者にわかりやすくまとめてあったりして、M$と言えども侮れないところがあったり。

学生の人は、「Visual Studio .NET 2003 theSpoke Premium」買いましょうw
税込み5kでProfessional相当の環境が手に入ります。

# C/C++だけなら Visual C++ Toolkit なんてのもありますがね……
comments (0) | trackbacks (0)

VS.NETのデフォルト拡張子を変更

Visual Studio .NET 2003で、新規作成ファイルのデフォルト拡張子を変更する方法を発見。

1.<install_dir>\Vc7\vcprojectitemsの中で、変えたい種類のファイルの拡張子を変更。
2.VCProjectItems.vsdir(テキストファイル)の中の該当エントリを修正
3.IDEを再起動

<例>
新しいヘッダファイルの拡張子を、デフォルトの .h から .hpp にしたい。
1.<install_dir>\Vc7\vcprojectitems\hfile.hをhfile.hppにリネーム
2.<install_dir>\Vc7\vcprojectitems\VCProjectItems.vsdir l.12の
"HFile.h|{1B027A40- ..."

"HFile.hpp|{1B027A40- ..."
と変更。(ファイル名をリネーム後のものにする)
3.IDEを再起動

これでいけます。

ただ、UIの表示は変わりません。
文字数が減る(.cpp -> .ccなど)ならリソースは簡単に変えられますが、増える場合は参照元のアドレスをいじらなくちゃいけないので大変。

まぁ、参考程度にどうぞ。

(この記事の内容は無保証です)
続きを読む>>
comments (0) | trackbacks (0)

message handling考察

何かいいmessage handlingの方法はないかとずっと考えていたんですが、今ふと思いついたので忘れないうちにメモっときます。

-----

CMessageMapper< TypeList handlers >
  • message mapper class with static dispatch


CMessageTranslateAdapter< UINT Msg, class ConcreateHandler >
  • CMessageHandlerHelper と ConcreateHandler の間に入って, messageを翻訳する

  • 全てのWM_*についてspecialize.

  • method : bool is( const MSG & )
    message parameterをHandlerに渡し, 処理対象ならtrueを返す

  • method : LRESULT handle( const MSG & )
    message handling. translateしたmessageを引数としてConcreateHandler::handle()をコール


Handler
  • concrete handler class


こんなクラス群を用意して、WindowProc()の中から,
return CMessageMapper< ... >::handle( hWnd, uMsg, wParam, lParam );

MFCみたいにWindow handleを隠蔽するクラスは作らない。
<- HWNDは十分にカプセル化されているから。

Windowを使うときは, HWNDと, CStaticCallback<>からCMessageMapper< ... >::handle()を呼ぶようにした薄いwrapperを作って使う。
  • operator HWND &()を定義

  • CreateDialog()なwindowとCreateWindow()なwindowは既定の戻り値が違う -> CMessageMapper< ... >にDefault値を管理するclassを渡す

  • ここを変えたversionを, CModalDialog, CDialogWindow ...として定義
続きを読む>>
comments (0) | trackbacks (0)

policy classes

今、policy classesを使ったwindow systemの設計をしてました。
policyというと、Modern C++ Designのあれです。
あの場合、policyをまとめるclassは、各policyを

template < template < class > class SomePolicy >
という感じで受けていました。
確かに、普通に使用する分には何の問題もないのですが、静的にpolicyをカスタマイズしようとすると突然、この手法には問題があることが見えてきます。

詳しい事情などは省きますが、要するに、policy classに T 以外のtemplate引数を追加したいということです。

そこで、policyを以下

template < /* additional parameters */ >
class PolicyName
{
public:
	template < /* basic parameters */ >
	class PolicyType
	{
		/* ... */
	};
};
のように定義し、受け側classでは普通に

template < class SomePolicy >
と受け、例えば継承するのであれば、以下

template < typename GenericParam, class SomePolicy >
class DerivedClass : public SomePolicy::PolicyType< GenericParam >
{
	/* ... */
};
のように使います。

こうすれば、policyをより細かくカスタマイズでき、結果的に柔軟性が増すことになります。

# これは、MCDを読んでSmartPtrを自作している時に編み出した(?)手法です。
# 「車輪の再発明はするな」と言いますが、遠回りは必ずしもマイナスとはならないようです。
comments (0) | trackbacks (0)

謎の例外

ちょいとwindowを作ってて気づいたんですが、プログラム終了時に謎の例外が出ているようです。

-----

win32_test2.exe の 0x77cfe062 で初回の例外が発生しました : 0xC0000005: 場所 0x25a07404 を読み込み中にアクセス違反が発生しました。 。
プログラム '[956] win32_test2.exe: ネイティブ' はコード 0 (0x0) で終了しました。

-----

こんな感じ。
Accesss Violationですね。Module一覧からAddressを調べてみると、どうやらuser32.dll内で発生しているようです。

ここで(多分)重要なことがあって、Windowsを散々批判している方もいらっしゃるようですが、殆どの場合においてWindowsそのものは無実です。
Me, 9xはともかくとしてXPのシステムファイルはそう簡単に壊れたりしません。上手く動かないことがあっても大抵はハードウェアかサードパーティ製のアプリケーションが原因です。
M$社だって、テストはしているでしょうが世の中全てのプログラムやハードウェアの全ての組み合わせについてなんて無理な話です。

ですから、ここでuser32.dllには問題がないと仮定します。そこで、それ以外にロードされているDLLを調べてみると……

C:\Program Files\Messenger Plus! 3\MsgPlusH.dll

………………
………


氏ね。
# 今更か?

恐らく、global hook procedure内でエンバグしているのでしょう。
ちゃんとテストしろよ……。global hookはかなり危険なんだから…………。

というわけで、global hookをinstallする時は注意しましょう。ていうかきちんとデバッグしましょう。例外投げられるなんて普通じゃない。
comments (0) | trackbacks (0)

OOPは分かってきてからが面白い

作りたいプログラムがあります。
初心者の人は、いきなりコーディングにかかったりすることもあるでしょう。
上級者でも、ちょっとしたutilityならさくっと書いてしまうこともあります。

しかし、ある程度規模の大きいプログラムを作ろうとすると、そのスタイルは突然、破綻します。
ここら辺は実際にやってしまった経験のある人も多いのではないでしょうか。

そこで「設計」というものが重要になるのですが、設計屋の人ならともかく、個人レベルで(外注の業務などの場合は除く)そこまでやる人は少ないのではないでしょうか。

しかし、きちんとした「設計図」を書かなくても、自分がやろうとしていること、プログラムにやらせたいことを分析し、責任を適切に分割するだけで、相当楽になるのではないでしょうか。

最近実際にあった例を挙げます。
チェスをするプログラムを作りたいとします。
ある人が作った例では、一応動きはするものの、流れを捉えず、処理をひたすら追加するスタイルの中でコピペを多用し、バグが出た際の修正に四苦八苦していました。
彼はまだ始めたばかりだから仕方ないです。むしろ、きちんと動くものを作れたことには敬意を表すべきです。

ただ、次のステップに進むためにはやはり、プログラムを作るにあたっての「何か」を習得しなくてはならないのではないかと思います。

バグという観点から見ても、コードが冗長でなければ修正も楽だしバグそのものが入り込む余地も減ります。

それだけでなく、例えば彼がそのプログラムを、CUIからGUIへ移行したいとしたらどうでしょうか。
また1から全て書き直す。これは果たして正しいといえるのか。
CUIだろうがGUIだろうがチェスのルールは共通のはずです。必要なのは表示部分を差し替えるだけであり、表示に関する詳細な実装をルールを司る部分が知っている必要はありません。文字の色や駒を動かすアニメーションのことなんて知らなくていいのです。

それ以外に、一つの関数なりクラスが担当する範囲を広げすぎてしまうと、これまた管理のしにくいものになってしまいます。
例えば、stackのpop関数は、複数の機能を搭載すると例外に対して完全に安全ではなくなります。
# この辺りは「Exceptional C++」に詳しいです

なので、重要だと思うことを書いておきます:

  • そのプログラムに「何をさせたいか」を正確に把握する

  • プログラムを適切に分割する。ある事柄の責任の所在をはっきりさせる

  • 上と関連して、一つの単位には一つの責任しか担当させないようにする。管理外のことは適切な他の単位に委譲する


こんなもんでしょうか。

OOPとは殆ど別の話になってしまいましたが、この辺で閉めさせていただきます。
OOPについてはいつか書くかもしれません。
comments (0) | trackbacks (0)

Compile Time Checker

Loki の STATIC_CHECK を使おうと思ったら、どうやら Reference のものは VC++ では使えないようです。
なので、 Loki では VC 用のものは、マクロを以下:

#define STATIC_CHECK(expr, msg) \
typedef char ERROR_##msg[1][(expr)]

のようにしていましたが、これだと「添字がありません」のエラー(ERROR_ ## msg が表示される-> Static check によるエラーだと分かる)が二番目に来てしまい、 template 引数をたくさん持つクラスのメンバ関数のローカルクラスの……なんて場所で使ってると、パッと見ではこれが Static check に引っかかったかどうかは分かりにくいです。

なので、以下のようにしました:

template < bool >
struct CompileTimeChecker
{
typedef int result;
};

template <>
struct CompileTimeChecker< false >
{
typedef int &result; // It makes 'pointer-to-reference'. So, it causes C2528.
};

#define Static_Check( expr, msg ) \
typedef CompileTimeChecker< ( expr ) != 0 >::result *Error_ ## msg;

参照へのポインタを typedef することによって、エラーを出しています。
これだと、関数内だけでなくクラス内(宣言部分)でも使えます。

ただ一つ問題があって、同じエラー文字列に対して複数 check すると、引っかかってなくてもエラーが出ます(識別子の定義が複数ある)。
なので、複数の expr について check するときは、全てを && で繋いでください。

どうでしょうか?

# 他の処理系でどんなエラーが出るのか気になりますね。
続きを読む>>
comments (0) | trackbacks (0)

template meta programmingでwindow manipulation

例えば、何かチェックボックスがあって、それをOnにすると横のエディットボックスに入力できるようになるダイアログがあったとします。

その操作は以下:

::EnableWindow( ::GetDlgItem( hwnd, IDC_EDIT ), ::IsDlgButtonChecked( hwnd, IDC_CHECK ) == BST_CHECKED ? TRUE : FALSE );

のように記述できるわけです。

で、複数の control を操作したい場合はこれを複数記述するわけですが、タイプ量が多くてたるいので普通はこれを inline 関数(マクロ)にします。

しかしですね……。

考えてみてください。今我々は、コントロール ID で示されるコントロールの状態を変更したいわけです。で、その ID はコンパイル時定数です。

……はい、もうお分かりですね。これを template を使ってごにょごにょしてみます。

今扱うのはintなので、 typelist ならぬ intlist を定義します:

// container
template < int _N >
struct int_container
{
enum { value = _N, };
};

#define intlist_1( I1 ) typelist< int_container< I1 > >
#define intlist_2( I1, I2 ) typelist< int_container< I1 >, intlist_1( I2 ) >
#define intlist_3( I1, I2, I3 ) typelist< int_container< I1 >, intlist_2( I2, I3 ) >
...

で、本題ですが、以下:

template < class _IDList >
class EnableControls
{
Static_Check( 0, _IDList_is_not_typelist );
};

template < typename _First, typename _Second >
class EnableControls< typelist< _First, _Second > >
{
private:
template < typename _IDList >
struct withCheckBoxImpl
{
Static_Check( 0, _IDList_is_not_intlist );
};

// generic
template < int _N, typename _Second >
struct withCheckBoxImpl< typelist< int_container< _N >, Second > >
{
static inline void change( HWND hParent, BOOL state )
{
::EnableWindow( ::GetDlgItem( hParent, _N ), state );
withCheckBoxImpl< _Second >::change( hParent, state );
}
};

// end of the list
template <>
struct withCheckBoxImpl< NullType >
{
static inline void change( HWND, BOOL ) {}
};
public:
static void withCheckBox( HWND hParent, int chk )
{
BOOL state = ::IsDlgButtonChecked( hParent, chk ) == BST_CHECKED ? TRUE : FALSE;
withCheckBoxImpl< typelist< _First, _Second > >::change( hParent, state );
}
};

のようにして、使う時は

EnableControls< intlist_3( IDC_CONTROL1, IDC_CONTROL2, IDC_CONTROL3 ) >::withCheckBox( hWnd, IDC_CHECK );

のようにします。

あーーーーーー。
キモいですねw
何がキモいって、これ inline 関数にしてるので、上のコードは

BOOL state = ::IsDlgButtonChecked( hWnd, IDC_CHECK ) == BST_CHECKED ? TRUE : FALSE;
::EnableWindow( ::GetDlgItem( hWnd, IDC_CONTROL1 ), state );
::EnableWindow( ::GetDlgItem( hWnd, IDC_CONTROL2 ), state );
::EnableWindow( ::GetDlgItem( hWnd, IDC_CONTROL3 ), state );

と書くのと同じになるんですね……。
(上手く展開されればですが)

そんな感じで、 template meta programming の凄まじさを思い知った出来事でした。
comments (0) | trackbacks (0)

student day

今年で二回目でしたっけ。
今回は、物理部として団体参加することになりました。

現場の人の話が聞ければいいと思ってます。
後は同年代のすごい人たちを見たりね。
やっぱり何かが違うんでしょうねぇ、我々とは。
その辺を盗むべく、明日に望みたいと思っています。
comments (0) | trackbacks (0)

The Student Day

というわけで行ってきました。
O田とかS飽は時間ぎりぎりに来てんじゃねーよと。
集合するときはもうちょっと余裕を持ちましょう。お互いにな。

中身はまぁ結構楽しめました。
つまり、programmingは目的ではなくて手段であると。
うーん。まぁ確かにそうですよね。アイディアが何かあって、それを実現するための手段に過ぎないって言うのも分かります。というかそれが本来の姿。
ただ、そう言われて気づいたのは、自分はその手段と目的が入れ違っているんじゃないかなということ。
programmingは面白いんですよねぇ。設計通りにクラスが繋がって、魔法のようなイディオムでコードがいとも簡単に記述できて、それでそういったもの全てがうまく繋がってプログラムが動く感動。私の中ではそっちの方が感動の比率が高いわけです。

つまりこういうことです。例えばprogramによって日常生活が楽になります。普通はその成果物なり結果なりが求められるのに対して、自分はその動作原理とか製作過程での工夫とかの方に、どちらかといえば興味があるということです。

うーん。
アイディアはあるけどノウハウ、スキルがない。
スキルもノウハウもあって、プログラムは作れるのにアイディアがない。
二者が手を取り合ってチームを組めば、きっと素晴しい世界が開けるのでしょうなぁ。
comments (0) | trackbacks (0)
1/3 >>