MASATOの開発日記 2000年2月


2/24

新規ドキュメントに無題以外を使う方法。

 アプリケーションを起動した時、MFCのSDIやMDIだと「無題.なんとか」という新しいドキュメントが出来上がっています。私はこの「無題」というのがひじょーに気になったので変更してみました。

 変更するのは、リソースのStringTableのIDR_MAINFRAMEです。
これの、二つ目と三つ目の\nの間にデフォルトにしたい名前を入れます。
(最初は二つ目と三つ目の\nの間には何も文字が入っていません。何も文字が入ってないと無題となるようです。)

 OnNewDocumentで強引にタイトルを変えてしまう方法もあります。
-----
if (!CDocument::OnNewDocument())
    return FALSE;
SetTitle("Default");    // <-追加
-----
これでばっちり「Default.なんとか」になります。
しかし、SDIでは問題が無いのですが、MDIだと問題が発生します。MDIでは「無題1」「無題2」・・・という名前のドキュメント名になりますが、この方法では全て「Default」となってしまいます。別にそれでも構わないというのならば良いのですが、本来は「無題」と入るところを別の名前に変えたい時は、この方法ではうまく行きません。

(5/8) StringTableを書き換えて変更する手法を追加。
(6/24) MDIでは問題が発生する事を追記。
 

起動した時、既存のドキュメントを開く方法。

 そのうち、起動した時に最初からなにかドキュメントが立ち上がっていてほしいと思った。ファイル名はユーザーに設定してもらう事になるんだろうけど。たとえば、Iriaは立ち上げたとき、Default.iriというファイルがすでに開かれている。こういうのを作ってみたいと思った。変更する場所はAppクラスのInitInstanceの、コマンドライン解析部である。
-----
// DDE、file open など標準のシェル コマンドのコマンドラインを解析します。
CCommandLineInfo cmdInfo;
ParseCommandLine(cmdInfo);
if (cmdInfo.m_nShellCommand != CCommandLineInfo::FileNew
    || OpenDocumentFile("Default.bok") == NULL){
    // コマンドラインでディスパッチ コマンドを指定します。
    if (!ProcessShellCommand(cmdInfo))
        return FALSE;
}
-----
(3/11)指定したドキュメントを開けなかった場合、エラー終了するのでは無く、新規ドキュメントを開くように変更。
この例だと、Default.bokというファイルを開いている。
要は、引数が無い、すなわち新規作成の時は、OpenDocumentFile関数を用いて勝手に指定したファイルを開いてしまっているのである。これで普通に起動した時はばっちりDefault.bokを開いてくれた。めでたしめでたし。
 

2/22

ドロップ又はペーストされたURLショートカットの解析方法。

 前回はわからなかったCOleDataObjectに含まれているFileContentsの解析に成功。
-----
FORMATETC fetc;
fetc.cfFormat = format;
fetc.ptd = NULL;
fetc.dwAspect = DVASPECT_CONTENT;
fetc.lindex = 0;
fetc.tymed = (DWORD) -1;
-----
どうやらこれでFileContents部は読み込めるようだ。キーポイントはfetc.lindex = 0;ヘルプをじっくり読んでみたところ、FileGroupDescriptorにおける番号と対応しているようだ。英語だったので今まではどうやら読み損ねていたようだ。FileContents部の中身は予想通りファイルの中身。まあ当たり前か。どんな中身かは*.URLファイルをてきとーに開けば分かります。簡単な内容です。FileContentsを設定する時は、fetc.tymed = TYMED_HGLOBAL;とするべきでしょう。読み込む時にこれにしても読み込めるはず。これで、FileGroupDescriptorでファイル名&サイズを指定し、FileContentsのlindexで番号を指定してファイルの中身を入れておけば、アプリからエクスプローラーかなにかにドロップした時にどんなファイルでも作れるはずです。しかも複数ファイルもできるはず。詳しいソースを後で作ってみて確認する予定。
 これでドラッグ元&ドロップ先の使い方は大体習得。いよいよブックマークエディタに応用を開始します。
 

2/19

 今回はドロップ元作成にチャレンジ。ブラウザからリンクをデスクトップにドラッグ&ドロップすると、ショートカットが出来ます。あれと同じような事をやりたいのですが、いまいちやり方が不明。以前作ったドロップ君というドロップデーター解析ツールを使って、IEからドロップしたものはどのようなデーターが含まれているのかと見てみたのですが中身がいまいち不明。COleDataObjectに含まれているFileContentsってデーターはなんだろうなぁ。どうやって中身を見るんだろう・・・。

URLを指定してブラウザを起動する。

 それと、もう一つ謎だったのがブラウザ起動方法。
-----
ShellExecute(*AfxGetMainWnd(), "open", "http://hogehoge...", NULL, NULL, SW_SHOW);
-----
これで行けると思ったのだが、いざ実行してみると、VisualStudioのデバッグウィンドウに例外が発生したとか表示されている。まあ、普通にブラウザは起動されているし、例外ダイアログも飛び出さないので、多分catchされている例外だと思うのだが・・・。なんか気になる。
dirにGetCurrentDirectryの値を入れ、
-----
ShellExecute(AfxGetMainWnd()->GetSafeHwnd(), "open", "http://hogehooge...", "", dir, SW_SHOW);
-----
としてもやはり例外は出ているようだ。まあ、たぶんちゃんとcatchされているだろうから良しとするか。ちなみにこの現象はIE4とNetscape4.5で確認。
 

2/18

RegisterClassの役割とは?

 大昔買った、Inside Visual C++ version 4という分厚い本を眺めていると、カスタムコントロールの例がある。これを眺めて初めてRegisterClassの意味が分かる。ついでにCListViewやCCtrlViewがやっている事も分かる。CCtrlViewが何をやっているのか以前ソースを眺めた事があるのだが、なんだか何もやっているように思えない。CListViewならば、CListCtrlのメンバ変数を持っていて、それを使って何かしているのかな〜とか思っていたのだが、何もメンバ変数を持っていない。CCtrlViewも何もメンバ変数を持っていない。その下はCViewだし・・・。CListView::GetListCtrl()を見てみると、return *(CListCtrl*)this; との事。いったいこりゃなんじゃ。自分自身を勝手にCListCtrlに変えていいのかなぁ・・・。ところが上のInside Visual C++を読んで謎が解けた。この手の分厚い専門書は、結構長い期間役に立つなぁと思った。買って最初のうちは、理解できたのは最初のちょこっと。それから少しずつ経験をつむに連れて少しずつ理解出来るようになっていく。まだこの本には理解しきれていない部分が一杯ある。これはまた将来役に経つのだろう。
 それはそうと、RegisterClassだが、MFC以外はどうなっているのかわからないのでとりあえずMFC限定で書くと、まず、RegisterClassで、WindowProcと、ClassNameを関連付ける。でもってこれをWindowsに登録しているようだ。でもって、CCtrlViewでは、名前からWindowProcを取得しているようだ。CListViewのコンストラクタの、WC_LISTVIEWってやつがListCtrlを指す文字列なのだろう。ちなみにInside Visual C++のWindowProcは以下のようになっていた(勝手に引用していいのかな)
---- Inside Visual C++ version 4 p.524 より引用(一部不必要な部分は改変) ----
LRESULT CALLBACK WndProc(HWMD hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    CWnd* pWnd;
    pWnd = CWnd::FromHandlePermanent(hWnd);
    if (pWnd == NULL){
        pWnd = new (CWndの派生クラス)
        pWnd->Attach(hWnd);
    }
    return AfxCallWndProc(pWnd, hWnd, message, wParam, lParam);
}
---- 引用ここまで ----
用はまだCWndクラスに関連付けられてないウィンドウハンドルを用いて何かしようとすると、newでしっかりとCWndクラスのオブジェクトを作った挙げ句にしっかりとAttachで関連付けられているわけです。この機構があれば、WC_LISTVIEWという文字列だけから、リストコントロールオブジェクトを作成できるわけです。ちなみにここでnewしたものは、PostNcDestroyでdelete this; とされているようです。この機構をちょっと真似て、前に手に入れたTreeListViewのRegisterClassのあたりを少し変えてみたら、例外が飛び出る事も無く、無事動いた!わーい。
 

2/17

ブックマーク整理ツールを作ろう!

 なんとなく世のためになるようなツールを作ろうと思い至ったので、ブックマーク整理ツールなんぞの開発を始めてみる。ネットスケープのブックマーク整理ツール見たく、TreeView + ListView みたいな表示ができれば理想なのだがやり方が良く分からない。エクスプローラーみたく左側をTreeViewで右側をListViewにしようかな〜とか思っていたらCodeGuru homepageここに!あるじゃないか!「リストビューコントロール」の「ツリーリスト:マルチカラムをもつツリーコントロール」ってやつです。
 とりあえずソースを落として構築してみようとしたが、リソースが何語かわからないけど文字化け。その結果リソースファイルの文字列の右側の"が消えたりしている。とりあえず全部エラーを消して実行。おお!かっこいいコントロールじゃないか!まあHeaderの列と列の間をダブルクリックしても自動サイズ調整機能が無いのは残念。けれど、いざ自分のソースで使おうと思ったら使い方が良く分からない。うまく出来たと思ったのだが終了するときに例外が出る。まあ、解析は後回しでいいや。ということで、まずは最初の計画通りエクスプローラー形式を目指す。Tree+ListViewは、バージョン2で実現する事にする。ソースは手元にあるんだし焦る事は無い。エクスプローラー形式もドラッグ&ドロップのサポートとか右と左のビューをちゃんと同期して表示させるとか結構難しい所あるしね。
 今回の技術的目標は、ドラッグ&ドロップのしっかりとしたサポート。ドロップは以前ちょっとやったのであまり難しくないと思うが、ドラッグは難しそうだ・・・。ドロップも、どこにドロップしたかによって処理を微妙に分岐させなくてはならないので実はややこしそうだ。まあ何事も訓練訓練。



戻る
トップページへ
masato@mb.kcom.ne.jp