鏑矢の憂鬱2000年11月後半
透明1ドットイメージ
 
2000/11/16 (Thu)
・今日もお便り紹介〜。まずひとつめ。
 
透明1ドットイメージ
透明1ドットイメージ
 どうも、尺八郎です
 ああ、c_str()だと書き込めないけど参照できるのはstringに何か書き込むまでですよね〜(自信がない)
 書き込む場合はstring[]なりイテレータで・・・
 わからん
 とりあえずconst無しのcharに書き込むのは特に文字列の長さが変わってしまう場合は絶対だめですよね
 やっぱり、混沌としている・・・
透明1ドットイメージ
透明1ドットイメージ
 
・そうですよねー、まー混沌としてるのは C++ のせいだけど(爆)。 C++ には文字列型付けてもいいと思うんだけどね。まーその答が std::string なのかなー。なんか次期 VC で .NET で楽々〜とか思ってたら VC + .NET や C# じゃ .Exe は作れないって話だし、なんかプログラミング世界混沌へと突き進むって感じがそこはかとなくしてるんですけど。 BCC に特化した VS IDE があったら売れるって絶対!
 
・ふたつめのお便り!
 
透明1ドットイメージ
透明1ドットイメージ
> 「 operator*() 」で取得って std::string::iterator から * 1文字
> 取得して & でアドレス取得ってことなんかな。
 
 すいません。説明がまずかったですね。
 std::string::iteratorを使ってcharを取得できるのは、std::string::iterator::operator*()を使った時だけであって、::operator*()を使った場合の保証はないということです。
#そもそも、std::stringに対してchar*を取得しようとする考えが間違っているわけで。
 
> で、 std::string で char * を取得したいときには結局どうしたら
> いいんでしょうねぇ(汗)。 API とかに渡したいし。
> それともそれはしちゃダメっていう設計思想なのかなぁ……。
 
 そういう設計なんでしょう。
 Effective C++ P.143の「内部データのハンドルを返すのはやめよう」と同じ発想だと思います。
 APIに渡すためのバッファとしては、std::auto_ptr<>の配列版(auto_array<>)を自作するのが簡単ですね。
こんなの ↓
 
template <class T> class auto_array
{
public:
	auto_array(void) throw() : m_pt(NULL) {}
	explicit auto_array(size_t u) throw(std::bad_alloc)
		 : m_pt(new T[u]) {}
	explicit auto_array(T* pt) throw() : m_pt(pt) {}
	auto_array(auto_array& r) throw() : m_pt(r.release()) {}
	~auto_array() throw() {reset();}
	auto_array& operator=(T* pt) throw() 
	{reset(pt); return *this;}
	auto_array& operator=(auto_array& r) throw()
	 {reset(r.release()); return *this;}
	const T& operator[](size_t u) const throw() 
	{return m_pt[u];}
	T& operator[](size_t u) throw() {return m_pt[u];}
	T* get(void) const throw() {return m_pt;}
	void reset(T* pt = NULL) throw() {if(pt != m_pt) 
	{delete [] m_pt; m_pt = pt;}}
	T* release(void) throw() 
	{T* pt = m_pt; m_pt = NULL; return pt;}
	bool operator!(void) const throw() {return !m_pt;}
private:
	T*	m_pt;
};

template <class T> static inline T* 
operator+(const auto_array<T>& pt, ptrdiff_t i) throw() 
{return pt.get() + i;}
template <class T> static inline T* 
operator+(ptrdiff_t i, const auto_array<T>& pt) throw() 
{return pt.get() + i;}
	
透明1ドットイメージ
透明1ドットイメージ
 
・やっぱそういうクッションが必要になっちゃいますねー。それじゃ文字列型としてのかっこよさが(泣)。やっぱ簡単に渡して受け取れるってのが理想かなーと。なんでどの文字列クラスもクセがあるんだろう。あー、考えてみたら「勝手にサイズが変わらない可変長配列」があればいいのかもしんない。でも文字列って普通に使うから、可読性考えると自分独自のもの使うのもどうかとは思うんだよね。っつーか、皆さんは API に char * 渡さなきゃいけないときってどーしてるんでしょ?
 
・でわまたっ!
透明1ドットイメージ
 
2000/11/17 (Fri)
・とーとつですが、12月はプログラミング強化月間にします。理由は日記の方で<だからなぜこっちで書かない!(爆) いやね、プログラミングの話っつーよか、ホームページ全体の話なんで。
 
・ではお便り紹介。まずひとつめ。
 
透明1ドットイメージ
透明1ドットイメージ
 string::operator[]()はstring::referenceを返すのでこんなふうにできませんか?
 
const char* const src = "あああ";
string s;
s.resize(strlen(src) + 1);
strcpy(&s[0], src);
s.resize(s.size() - 1); // \0を削除
	
透明1ドットイメージ
透明1ドットイメージ
 
・そーっ、それは……確かに動くけど、それは一応「1文字への参照」だからなー、 std::string の実装に依存しちゃうんで……。実際問題はそこなんだよねー、今ある std::string の実装を見れば、色々して char * を取り出しても比較的問題ないんだけど、それは C++ 規格としては保証されてないから将来動かないかもしんない、ってとこが難点なんだよねー。結局は std::string 使えない〜ってことになってしまうんかなぁ。
 
・もひとつお便り。
 
透明1ドットイメージ
透明1ドットイメージ
 以前「選択されたアイコン」の表示について質問した者です。ご教授いただいた方法で無事解決できました。
 どうもありがとうございます。
 
 そしてまたもや質問です。
 
 SHGetFileInfoのuFlagにSHGFI_ICONLOCATIONを指定するとpszPathで指定したファイルのアイコンを持っているファイルのパスを得られる、と思ったのですが
 
SHFILEINFO shfi;
SHGetFileInfo(pszPath, 0 , &shfi, 
	sizeof(SHFILEINFO), SHGFI_ICONLOCATION);
MessageBox(hWnd, shfi.szDisplayName, "Icon Location", MB_OK);
	
 
 とかやってみても全然だめでした。pszPathがexeファイルでもtxtファイルでもまったくだめです。
 なんか根本的に間違っているのでしょうか?
透明1ドットイメージ
透明1ドットイメージ
 
・わ、分かんなかった……(汗)。サイト検索しても、いろんなフラグを試してみても、 ITEMIDLIST で渡してみても、うまくいかなかった……ってゆーか、うまくいく場合もあったりするのがやっかい(爆)。 CD-ROM ドライブやフォルダはうまくいくんです。違うアイコンを割り当てたフォルダは、ちゃんとそのアイコンのファイルを返したです。戻り値も 1 が返ってきてるから成功はしてるんだよねー。
 
・次善策になっちゃうけど、ドライブやフォルダはこれで取得して、普通のファイルは拡張子を元にレジストリから取得って形になるかなー。 Exe はそのファイルから ExtractIcon( hInst, pchFilePath, 0 )で取得することになるかなー。 それか、もしかしたらなんかそういう機能のある API があるのかも。どうなんだろう……。
 
・でわまたっ!
透明1ドットイメージ
 
2000/11/18 (Sat)
・今日はお休みにゃにょ。
透明1ドットイメージ
 
2000/11/19 (Sun)
・今日もお休み〜。
透明1ドットイメージ
 
2000/11/20 (Mon)
・今日も休みだっ!
透明1ドットイメージ
 
2000/11/21 (Tue)
・今日は、昨日のCマガに書いてあった Kylix の話。まーわては今のところウィンドウズ専門なんだけど、将来は他の OS のアプリも作っていきたいなと思ってたりするんで。で、他の OS の API を知らないんだけど、ウィンドウズでいうところの「ダイアログテンプレート」はどうやってるんでしょう。
 
・わての知る限りでは、コントロール作成用 API を呼び出す時に直接サイズや位置を決定してるみたいなんだけど。もしそうだとしたら、リソース使ってダイアログの設計するよりもかなり生産性悪くなっちゃうよねぇ。 Kylix はダイアログエディタがまず表示されるわけで、この仕組みが、ダイアログテンプレートみたいなのを使ってるのか、それともクラスウィザードみたいにコード生成を行うものなのか、って部分がちょっと知りたかったです。
 
・あーでも、別にダイアログテンプレートがいいってわけでもないんだけどね。たとえば、リソース記述言語の問題。 VC と BCC とでは違うみたいでこれは結構辛いです。それに、これをコンパイルして Exe や DLL に埋め込むってのも面倒そう。わて的には、 XUL とかの統一された言語で記述されてて、どのライブラリでも使えるようになってくれるといいと思うんだけどねー。
 
・でわまたっ!
透明1ドットイメージ
 
2000/11/22 (Wed)
・昨日の夜中に、就職前研修(CD−ROM)をやってました。CD−ROMの中身は「設計重視」みたいな感じで、それほど悪くなかったかな。でもあれ読んで実際にプログラムに反映させるのは不可能でしょう(爆)。プログラムがある程度組めるようになってから改めて読まないと。あーでもそれはそれで手遅れかもしんない(爆)。
 
・このCD−ROMの返却時に提出するプログラムも作成。 C 言語オンリーなのが結構辛かったです(汗)。プログラムは、たとえば「数値を入力させて平均を出力する」とかゆー感じのを5つほど作成するのとか。このプログラムで求められてることは分かってるんで、もちろんエラー処理とかはせず(爆)。し始めるとキリないし。
 
・もひとつ、元々のプログラムの穴埋めをするって課題も。なーんで数式関係のプログラムってのは m だの n だのっつー分かりにくい変数名使うんかな(汗)。会社ではこーゆーの作らずに済むことを祈ろう。 C++ や Java で普通に組みたいなぁ。でも CASE で関係図作ってあとはインプリメントーみたいなのもちょっとイヤ<わがままやね(汗)。やっぱプログラミングって趣味でするもんかもしんない……。
 
・でわまたっ!
透明1ドットイメージ
 
2000/11/24 (Fri)
・今日は就職前研修(出向)の最終日。 UNIX でシェルスクリプトとか組んできました。これはプログラミングに近い感じだからそれなりに面白かったかも。でも、スクリプトの中に、テンポラリファイルを作って一度結果を保存しなきゃいけないものとか出てきたり。ううっ、同期処理せんと(汗)。一番「入りやすい」プログラミングだけど、一番「自由度が高い」って点で、一番「最初に触れちゃいけない」プログラミングかもしんない……。
 
・でわまたっ!
透明1ドットイメージ
 
2000/11/25 (Sat)
・今日はお休みよん。
透明1ドットイメージ
 
2000/11/26 (Sun)
・……なんかあんま意味ない話なんだけどさ、なぜか23日木曜日の分が消えちゃってる(汗)。表紙に「今日はお休み〜」とか書くわけだから書き忘れってことはないと思うんで、たぶん間違えて消しちゃったんだと思うです。誰か、何書いてたか憶えてる?(爆) 一応、その日は就職前研修(出向)・ UNIX の前半で、その内容は日記で〜みたいなことは書いてたと思うんだけど……。
 
・えーっと、色々な呪縛から解かれたことで、フツーのプログラミングをしようかなと思ってます。その一環として WTL を使ってみようと思ってます。 WTL は、 VC 付属のテンプレートライブラリ ATL を補完するためのライブラリ。もともと ATL はコンポーネントを作るためのもんなんで、 Exe を作るのには向いてないわけです。 MFC と共存させるのが難しいし。でも、 ATL 自体はかなり出来のいいライブラリなんで、軽い Exe を作るのに良さそう、ということで。
 
・あーなんかこう書くと誤解受けそうだけど、 WTL はマイクロソフトが作ったのね(爆)。ダウンロード方法は、前も書いたけどもう一度。米マイクロソフトダウンロードで Platform SDK 選んでもいっちょ選んで最初のリンクを飛んで Platform SDK Dawnload の Step2 でインストーラーをアップデートしてから Step3 の Download the Platform SDK Setup (x86) now. でセットアップ用アプリをダウンロード。これを実行すれば WTL が解凍されます。つっても、 ATL はもちろん必要だからね。
 
・解凍した中身は、 WTL が入ったヘッダーファイル群(テンプレートライブラリだからね)、サンプルコード、 AppWizard ファイルの AtlApp60.Awx 。この AtlApp60.Awx を C:\Program Files\Microsoft Visual Studio\Common\MSDev98\Bin\IDE にコピーすれば、プロジェクトの新規作成で「 ATL/WTL AppWizard 」が表れるんで、これを選んで OK 。
 
・すると、 SDI や MDI 、ダイアログとか選べるんで、とりあえずモーダルダイアログを選んで進めると、ダイアログテンプレートが作られてダイアログクラスが作られてその他必要なファイルとコードが生成されます。その辺はまた明日(爆)。
 
・でわまたっ!
透明1ドットイメージ
 
2000/11/27 (Mon)
・今日は WTL の続き。 AppWizard を使ってモーダルダイアログをメインウィンドウにするプロジェクトを作ると、次のようなファイルが自動的に生成されます。
 
・ プロジェクト名.cpp 。まずこのファイルでは CAppModule 型のグローバル変数 _Module を宣言してます。 CAppModule は WTL に含まれるクラスで、 MFC の CWinApp に近い存在です。でもどっちかってゆーと CWinThread の方が近いかもしんない。プロセスの管理ってゆーより、スレッドの管理がメイン。スレッド ID をメンバ変数として持って、メッセージループの管理をします。
 
・この _Module 変数、実は変数名を変えられません(爆)。 ATL/WTL で直にアクセスするから(汗)。 ATL からもアクセスしてるのは CAppModule が ATL の CComModule から継承されてて、 ATL のみの場合にはこの CComModule のグローバル変数が作られることになってます。この辺はちょっと困った部分ですな。
 
・さて、このファイルにはあと _tWinMain() があります(爆)。この中で、 CoInitialize() や InitCommonControlsEx() 、 _Module.Init() を呼び出して初期化して、 CMainDlg 型変数を作って CMainDlg::DoModal() 呼び出してダイアログ表示、 _Module.Term() や CoUninitialize() を呼び出して後処理、んで終わり。 MFC と違ってこー見えてるとなんかすっきりしていいねぇ(爆)。で、処理の中心は CMainDlg へと移ります。これは明日(爆)。
 
・でわまたっ!
透明1ドットイメージ
 
2000/11/28 (Tue)
・今日も WTL について。モーダルダイアログのプロジェクトを作ると、 maindlg.h というファイルが生成されます。この中にダイアログクラス CMainDlg が作られています。ちなみに maindlg.cpp はありません。そう、 CMainDlg のメンバ関数は全部 CMainDlg の宣言内に書かれてるんです(汗)。そりゃ ATL/WTL はテンプレートライブラリだからそういう書き方かもしんないけど、普通のアプリなんだからー。
 
・ CMainDlg は CDialogImpl から継承されてます。この CDialogImpl は ATL のクラステンプレートだから MSDN 見れば解説が載ってます。メッセージマップを使ってメッセージの振り分けをする仕組みは MFC に近いですな。ちなみにウィンドウプロシージャまわりはインラインアセンブラを使ったなんかアヤシイ方法でディスパッチされてます(汗)。なんか怖い……。
 
・ CMainDlg にはあらかじめ OnInitDialog() や OnOK() が備わってます。これらは CDialogImpl にはないんでオーバーライドされてるわけではないです。 OnOK() や OnCancel() は仮想化されてるデフォルトの関数があったら便利なんだけどなー。あと、引数も MFC のものとは違います。 ATL だとメッセージハンドラ関数はどれも同じシグネイチャーじゃないとまずいんで。ただ WTL にその辺をもちっと簡略化するものがあったんでそれを使うのもいいかもしんない。
 
・ちなみに、 OnInitDialog() の実装部では、 API の LoadImage() とか呼んでアイコンのセットをしてます(爆)。 LoadImage() は API 、 SetIcon() は CWindow のメンバ、なんか不思議。でもこの方が、 ATL/WTL はサポートクラス、って感じでいいかもしんない。明日はダイアログコントロールを使ってみましょう!!
 
・では今日のお便り。
 
透明1ドットイメージ
透明1ドットイメージ
 こんにちは。質問です。よろしくお願いします。
 
 動かなくなったアプリケーションをタスクマネージャで見ると「応答なし」になっていますが、あるプロセスが「応答なし」になっているかどうか、というのはどうやって判定するのでしょうか ?
透明1ドットイメージ
透明1ドットイメージ
 
・実は、タスクマネージャは WM_CLOSE を送ってるだけだったりします(汗)。 Alt + Ctrl + Delete で出る「プログラムの強制終了」ダイアログで「終了」を選ぶと、選んだプロセスのメインウィンドウに WM_CLOSE を PostMessage() します。10秒間待ったあとにプロセスを確認して、まだ残ってたら強制終了するか尋ねるダイアログが出る、という仕組みです。 Spy++ で調べてみるとわかるよん。
 
・まーこれは閉じることが目的なんで WM_CLOSE 送ってるけど、単に「応答するかどうか」を調べるんなら WM_CLOSE じゃまずいかもしんない。そういうときは、新たにスレッドを立ち上げて、その中で SendMessage() でなんかメッセージを送って、 SendMessage() から返ってくれば応答してる、一定時間中に返ってこなかったら止まってる、みたいな感じにすればいいかな。
 
・もひとつお便り〜。
 
透明1ドットイメージ
透明1ドットイメージ
 システムフックに関して質問させてください。まず本ページの解説を読んでフックのことがよく理解できました。ありがとうございます。
 私がやりたいことはWM_DEVICECHANGEメッセージをフックしたいということなのですが、本ページのサンプルのようにキー入力のフックはうまくいくもののWM_DEVICECHANGEに関してはフックできません。
 とりあえずローカルフックにてSetWindowsHookEx()でWH_CALLWNDPROCなどを指定していろいろ試しているのですが、spy++で該当メッセージがきちんと送られているのが確認できるものの、インストールしたフックプロシージャがよばれません。
#ちなみにWM_DEVICECHANGEはUSBや1394デバイスの抜き差しで発生するメッセージです。
 ご存知でしたらぜひ教えてください。
透明1ドットイメージ
透明1ドットイメージ
 
・うーん、なんでなんでしょ。特定のメッセージをフックしたい場合、どのフックで拾えばいいのかって結構調べるの大変なんですよね。いっそのことサブクラス化した方がいいかもしんない。サブクラス化っていうのはウィンドウプロシージャを置き換えるっていうもので、 Spy++ もこれをしてます。この方法だとすべてのメッセージを処理できます。
 
・方法は、 SetWindowLong() でウィンドウプロシージャへの関数ポインタを置き換えるというもの。でも SetWindowLong() は同プロセスでないと機能しないんで、システムフック( CBT が多いかな?)と組み合わせて使います。システムフックを使うと DLL を他のプロセスに刷り込むことができるんで、その中で SetWindowLong() を呼び出してサブクラス化します。たぶんネット調べればサンプルコードは見つかると思うです。 Spy++ で拾えているんならたぶんこっちの方が近道でしょう。
 
・でわまたっ!
透明1ドットイメージ
 
2000/11/29 (Wed)
・今日も WTL について。せっかくモーダルダイアログのプロジェクトなんだからってことで、コントロールまわりを使ってみましょう。まず、クラスウィザードですが……まったくと言っていいほど機能しません(泣)。 MFC 専用だからなんかなぁ。わては ATL コンポーネントって作ったことないんでよーわからんです。
 
・一応機能するのは、ボタン貼り付けて右クリックから「イベント」選ぶと、そこからイベントハンドラを生成することってことだけはできます。やっぱし maindlg.h の方に(汗)。でもこれが簡単に作れるのは少し助かるかも。あーあと、リソースはすべて「英語」になってるんで、使うんなら「日本語」に直さないと。っつーか、複数のリソースを選択していっぺんに日本語にしようとすると VC が落ちるんですけど(泣)。
 
・ DDX の話は明日に延ばして(爆)今日はあと CString について。なんと WTL には CString が付いてるんですよおにーさん! WTL の AtlMisc.h には CString の他にも CRect とか CRecentDocumentList ( MFC の CRecentFileList ?)とか CFindFile ( MFC の CFileFind )とかもー色々付いてるんです。……っつーか、ホンマに MFC って捨てられるんじゃ(汗)。
 
・でわまたっ!
透明1ドットイメージ
 
2000/11/30 (Thu)
・今日も WTL 。 MFC 使ってる人は DDX を使ったことあるでしょう。ダイアログにエディットボックス貼り付けて、それを特定のメンバ変数と結び付けるってやつ。 UpdateData() を呼ぶと、メンバ変数の中身をエディットボックスに反映させたり、逆にエディットボックスのデータをメンバ変数に書き込んだりってゆーの。
 
・ふっふっふー、そう、実は WTL でも DDX が使えるのです!!  AtlDdx.h ってファイルに DDX 用クラスとマクロが用意されてます。昨日言ったように、クラスウィザードは使えないんで自分で全部書かなきゃいけないんだけど(汗)。たとえばこんな感じに。
 
class CMainDlg
    : public CDialogImpl<CMainDlg>
    , public CWinDataExchange<CMainDlg>
{
// 略
    CString m_cStr;
    int m_i;

//    DDX マップ
    BEGIN_DDX_MAP( CMainDlg )
        DDX_TEXT( IDC_EDIT1, m_cStr )
        DDX_INT_RANGE( IDC_EDIT2, m_i, 0, 200 )
    END_DDX_MAP()

    // エディットボックスに送ります。
    LRESULT OnClickedButton1
        ( WORD wNotifyCode, WORD wID
        , HWND hWndCtl, BOOL& bHandled)
    {
        m_cStr = "あいうえお";
        m_i = 100;
        DoDataExchange(); 
        return 0;
    }

    // エディットボックスから受け取ります。
    LRESULT OnClickedButton2
        ( WORD wNotifyCode, WORD wID
        , HWND hWndCtl, BOOL& bHandled)
    {
        DoDataExchange( TRUE );
        OutputDebugString( m_cStr );
        OutputDebugString( "\n" );
        CString cStr;
        cStr.Format( "%d", m_i );
        OutputDebugString( cStr );

        return 0;
    }
};
	
 
・ まずダイアログクラスを CWinDataExchange からも派生するようにします。ちなみに ATL/WTL では多重継承をバリバリ使う必要に駆られます(汗)。 DDX に使うメンバ変数を用意したら、 BEGIN_DDX_MAP マクロ他を使ってメンバ変数とコントロールとを関連づけします。そしたらもうOK、 DoDataExchange() を呼び出せばデータが更新されます。
 
・この DoDataExchange が UpdateData() の代わり。 BEGIN_DDX_MAP がこの関数を作ります。関連づけする部分の、 DDX_TEXT が文字列として、 DDX_INT_RANGE が整数値として扱うためのマクロ。 DDX_INT_RANGE を見れば分かるとおり、 MFC みたいに範囲指定することができます(したくないときは DDX_INT を使います)。さらに、この範囲オーバーや型が合ってないときとかのエラーメッセージを表示するメンバ関数を作らなきゃならない仕組みになってたりします。
 
・なんかさ、「全部自分で書く」って、いいね(爆)。 MFC の DDX 使ってたときは、クラスウィザード任せで自分が手を出しづらい部分あったし、中身も複雑だったけど、 WTL は逆に自分で全部書かなきゃいけないし、 WTL のシステムは小さくて分かりやすいから全部自分でコントロールできるし、 WTL っていい感じだなー。明日はテンプレートなポリモーフィズム?
 
・でわまたっ!
 
 
(C)KAB-studio 2000 ALL RIGHTS RESERVED.