カテゴリ:C/C++/Win32( 131 )

e87.com(千趣会イイハナ) 花を贈るなら日比谷花壇

C++.NET 2008

気にくわない。
なぜかって?
ソースがきれいに書けないから。。。
美しくない。。。
見難い。。。
醜い。。。

慣れれば、きれいに見えてくるのかな~???
[PR]
by isoq | 2009-02-24 14:27 | C/C++/Win32
e87.com(千趣会イイハナ) 花を贈るなら日比谷花壇

MFC:ツールバーの位置・状態を LoadBarState / SaveBarState 関数でまともに保存・読み込みを行う


MFCプログラムで、ツールバーの状態を LoadBarState / SaveBarState 関数にて記録・復元を行うときに、ツールバーが複数個ある場合に、デフォルトのコードではまともに動作しない。(ツールバーの位置が入れ替わったり、復元後におかしな位置になったり、、、)
これを解決するには、ツールバーの CreateEx の第5引数に、コントロールのIDを指定する必要がある。


    if (!m_wndToolBar.CreateEx(this, TBSTYLE_FLAT, WS_CHILD | WS_VISIBLE | CBRS_TOP
        | CBRS_GRIPPER | CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC, CRect(0,0,0,0), IDR_MAINFRAME) ||
        !m_wndToolBar.LoadToolBar(IDR_MAINFRAME))
    {
        TRACE0("ツール バーの作成に失敗しました。\n");
        return -1; // 作成できませんでした。
    }

    if (!m_wndToolBar2.CreateEx(this, TBSTYLE_FLAT, WS_CHILD | WS_VISIBLE | CBRS_TOP
        | CBRS_GRIPPER | CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC, CRect(0,0,0,0), IDR_TOOLBAR2) ||
        !m_wndToolBar2.LoadToolBar(IDR_TOOLBAR2))
    {
        TRACE0("ツール バーの作成に失敗しました。\n");
        return -1; // 作成できませんでした。
    }

[PR]
by isoq | 2009-01-27 12:31 | C/C++/Win32
e87.com(千趣会イイハナ) 花を贈るなら日比谷花壇

shared_ptr の使い方が難しい

4年くらい前のコードを改善することになって苦戦中。。。
すっかり忘れている。

しかも、boost ライブラリを使用していて、
shared_ptr を利用している。

この頃、C++命でいろいろなライブラリを試した時期だった。
1人開発だと柔軟性が在って、逆に統一性が無いのが難点。
まだまだ、日々模索の状況です。

ところで、shared_ptr。
不要になると、瞬時に自動的にメモリを解放してくれて便利なんですが、
継承があるクラスをshared_ptrで使おうとすると、
使い方がいまいち判らない。

きっと、うまい方法が隠されているんじゃないかと思って調べてみると、、、
今頃になって、
- dynamic_pointer_cast<>
- static_pointer_cast<>
という関数でできるらしい事が判明。。。
もっと早く知っていれば。。。

(ちなみに、VCでは、TR1のshared_ptr がサポートされていますね。)

知らなかったので、どうやっていたかというと、、、
例えば、ベースクラスから複数のクラスに派生している場合で、
しかもそのベースクラスがコンポジットをサポートする場合。

全てのノードをベースクラスの shared_ptr と weak_ptr で
扱って、ツリーリストを構築するのですが、そのダウンキャストは
shared_ptr から生ポインタを取り出して、dynamic_cast
して利用していました。

これだと、shared_ptr の御利益が半減してしまっていました。。。

なんだかな。。。
[PR]
by isoq | 2009-01-07 14:04 | C/C++/Win32
e87.com(千趣会イイハナ) 花を贈るなら日比谷花壇

スレッドでよくやるミス<デッドロック>

スレッドプログラムでよくやるミスがあります。

メインスレッドでサブスレッドを起動し、
メインスレッドから、サブスレッドに中止命令を出したとき。
サブスレッドが比較的早く応答するときには、
メインスレッドで中止命令を出した直後に、
サブスレッドの停止待ちをすることがあります。

でも、サブスレッドの停止までの処理の中に、
メインスレッドで処理されるべきWindowsメッセージを
SendMessage で飛ばす処理が含まれていると、
SendMessage が処理されて戻るのを待ちますが、
いくら待っても SendMessage は処理されません。

メインスレッドは、サブスレッドの終了待ちループに突入しているため、
メッセージループが回っていないためです。

解決方法は、
1.メインスレッドのタイマなどでサブスレッドの終了待ちをするようにする
2.サブスレッドから SendMessage を使用する処理を使用しないようにする
3.サブスレッドの終了待ちの間にメッセージ処理を行う

上から順にインテリジェントなんだけど、
今回は、3で対処。
[PR]
by isoq | 2008-12-24 18:05 | C/C++/Win32
e87.com(千趣会イイハナ) 花を贈るなら日比谷花壇

Windows インストーラで、他のプログラムのインストール先を調べて、そこにインストール

とあるプラグインソフトのインストーラをVSのSetupプロジェクトで作ってまして、
メインアプリケーションのインストール先を調べる手段に困っています。

そのプログラムのインストール先情報は、レジストリを見れば一目瞭然なのですが、
そのインストール先のパスが書かれているキーの途中に、
プログラムのバージョンが入っているのです。

これが曲者で、バージョンが変わるたびに、
インストール先のパスが書かれたレジストリキーが変わってしまう。
Visual Studio付属のSetupプロジェクトの起動条件で、
レジストリを検索しようとしているのですが、
柔軟にできていないので、目的のレジストリを見つけれらない。

ファイル検索で、実行ファイルのパスは取得できるけど、
ファイル名(XXX.exe)入りのパスしか取得できない。

そして、これこそは!と発見した方法。
「Windows インストーラ検索」
起動条件の対象コンピュータの検索に、Windows インストーラの
情報を検索して、インストール先のパスを返してくれる。
ありがたや。

参考リンク1: 起動条件エディタの使い方
参考リンク2: Orcaの入手法

やろうとしてみたところ、なんと!
メインプログラムが Install Shieldでした、、、
つかえねぇ~~~~~

追記:
Install Shieldでも、最近は内部で msi 使っているんですね。
インストーラの実行ファイルを実行後から、インストーラが起動するまでの
ファイルアクセスを Microsoft SysInternals の Filemon で調べたら、
インストーラが TEMP フォルダに msi を解凍していることを突き止めました。

そこで、インストーラをそのままにして、その msi を Orca で表示すると、
求めていた Component Id を取得することができました。
やった~~~~~~~~!

でも、このソフトの場合、 EXE のComponent Id を使うと、バージョン番号が
付いたフォルダ名の上を指しているらしく、ひとつ上のディレクトリが取得できました。
EXEと同じ階層にあるディレクトリの Component Id を使ってみたところ、
EXEのインストールパスが取れました。
やったwwwwwwwwwwwwwwww!

ところで、この Component Id って、バージョンアップで変わらないよね???
不安だ。。。
[PR]
by isoq | 2008-12-24 17:30 | C/C++/Win32
e87.com(千趣会イイハナ) 花を贈るなら日比谷花壇

VC++ 7.0 以降で正規表現

VC7で、正規表現を使いたいと思って調べてみたら、ATLでサポートされているんですね。
サンプルもMSDNに載っていて、簡単そうだし。
でも、正規表現の表現方法って、どうしてライブラリごとに違うんだろうか??
似通ってはいるけど、ライブラリごとに少しずつ違う。

とりあえず、テスト的なコードで動作を確認。

#include <atlrx.h>

...(中略)...

CAtlRegExp<> regex;

REParseError status = regex.Parse("^[0-9]+$");
if (REPARSE_ERROR_OK != status)
{
    AfxMessageBox("Parse Error!");
    return;
}

CAtlREMatchContext<> match;
if(regex.Match("0123", &match))
{
    AfxMessageBox("Match!");
}
else
{
    AfxMessageBox("Miss match!");
}
return;

[PR]
by isoq | 2008-11-19 22:13 | C/C++/Win32
e87.com(千趣会イイハナ) 花を贈るなら日比谷花壇

MFCでWindowsが終了(ログオフ)されるときの処理を書く

Widnowsのユーザーのログオフに応じて、終了処理をするには、

WM_QUERYENDSESSION, WM_ENDSESSION メッセージに応答する処理を書く必要がある。

MFCでは、CWnd::OnQueryEndSession(), CWnd::OnEndSession(BOOL bEnding) をオーバーライドして実装する。

WM_QUERYENDSESSION は、ログオフ前にすべてのプリグラム向けて、
「今終われる?」 と聞くためにWidnowsから送られてくるメッセージ。

これに TRUE (終われるよ~) と返すと、今度は、WM_ENDSESSION が送られてくる。
「じゃ、終わってね~」 というかんじ。

OnEndSession の bEnding は、TRUE (ログオフするよ)、FALSE (やっぱやめ)となる。

つまり、WM_QUERYENDSESSION を送ってから、ログオフに対応出来ないアプリケーションが1つでもある場合(OnQueryEndSession() にFALSEを返す)、OnEnsSession の bEnding が FALSE (やっぱやめ)となる。

---

でも、実際に、この2つのメッセージをちゃんと実装しているプログラムって少ないみたい。
OnEndSession() が呼ばれて、bEnding が TRUE の時だけ終了処理をするはずなのに、
OnQueryEndSession() が呼ばれると、ばたばたと終了処理が始まる。
で、OnEndSession() が FALSE で呼ばれても、ほとんどのプログラムは、
さらにばたばたと終了する。

残るプログラムはわずかだけ。

ログオフに全く応答しないで、強制終了されるよりはましだけどね。
[PR]
by isoq | 2008-09-26 16:00 | C/C++/Win32
e87.com(千趣会イイハナ) 花を贈るなら日比谷花壇

ツリーコントロールのアイテムをチェックボックスやラジオボタンにするには

ツリーコントロールのアイテムにチェックボックスを表示するには、ツリーコン
トロールのスタイルを設定するだけで出来る。

MFCでやるなら、IDEのツリーコントロールのプロパティから「CheckBoxes」を
Trueにセットするだけ。

でも、この方法だと、チェックボックスがショボかったり、ラジオボタンは不可
能だったり、、、する。

では、どうやってラジオボタンや見栄えの良いチェックボックスを表示するか?

自分でアイコンを作って、実装するしかない。

作るアイコンは、

 ・チェックボックス(チェックされていない)
 ・チェックされたボックス
 ・押されていないラジオボタン
 ・押されたラジオボタン

の4種類。

あとは、アイコンとしてこれらの画像を表示して、クリック等のイベントに応答
して、アイコンを入れ替えたりするだけ。

だけ。。。とは言っても、

実装には結構時間がかかりそう。。。
[PR]
by isoq | 2008-09-26 14:30 | C/C++/Win32
e87.com(千趣会イイハナ) 花を贈るなら日比谷花壇

ダイアログのメニューの有効無効やチェックなどを設定する

MFCのDocument/Viewだと、Update Command UIメカニズムが実装されているので、OnUpdateXXX() 関数をIDEから追加するだけでメニュー項目の保守が出来るけど、Dialogには、実装されていないので、自分で実装しないといけない。
MFCのソースを覗けば、再利用可能なコードがすぐに見つかる。
簡単な見つけ方は、テストのDocoument/Viewプロジェクトを作って、OnUpdateXXX()を実装してから、ブレークポイントを置いて、その関数がどこから呼ばれるのかを呼び出し履歴から見てみればすぐに判る。

私的には、メニューが複雑になるとOnUpdateXXX()関数が乱立してコード中に散乱するのが醜いので、もっとスマートに書けない物かと。

次のようにすると、ダイアログでもメニューの保守が出来て、メニューIDごとに処理内容を決まった関数で決める事が出来る。


void CXXDlg::UpdateMenu(CMenu* pMenu)
{
       int menuCount = pMenu->GetMenuItemCount();
       for(int i=0; i<menuCount; i++)
       {
               MENUITEMINFO menuItemInfo;
               ::memset(&menuItemInfo, 0, sizeof(MENUITEMINFO));
               menuItemInfo.cbSize = sizeof(MENUITEMINFO);
               menuItemInfo.fMask = MIIM_STATE | MIIM_ID;
               if(pMenu->GetMenuItemInfo(i, &menuItemInfo, TRUE))
               {
                       if(UpdateMenuItem(&menuItemInfo))
                       {
                               pMenu->SetMenuItemInfo(i, &menuItemInfo, TRUE);
                       }
               }
       }
}

bool CXXDlg::UpdateMenuItem(MENUITEMINFO* pMenuItemInfo)
{
       bool enable = SomeFunc();
       switch(pMenuItemInfo->wID)
       {
       case ID_A:
       case ID_B:
       case ID_C:
       case ID_D:
               pMenuItemInfo->fState = enable ? MFS_ENABLED : MFS_DISABLED;
               return true;
       }
   return false;
}

void CXXDlg::OnInitMenuPopup(CMenu* pPopupMenu, UINT nIndex, BOOL bSysMenu)
{
       UpdateMenu(pPopupMenu);
       __super::OnInitMenuPopup(pPopupMenu, nIndex, bSysMenu);
}

[PR]
by isoq | 2008-09-16 14:12 | C/C++/Win32
e87.com(千趣会イイハナ) 花を贈るなら日比谷花壇

複数のライブラリ(.lib)ファイルを1つのライブラリ(.lib)ファイルにまとめる方法

複数のライブラリ(.lib)ファイルは、1つにまとめる事が出来る。
方法は、コマンドラインからVCに付属のLIB.exeを使用する。
次のようなコマンドとなる。

lib /OUT:c:\xxx\yyy.lib c:\zzz\*.lib


xxx\yyy の方が出力先ファイルパス。
zzz の方が、入力元の複数のライブラリファイルを入れたディレクトリ。

世の中には、たくさんのライブラリからなるSDKなんかもあるので、関連するライブラリファイルをまとめておくと、便利。

同じ方法で、objファイルをまとめたライブラリファイルを作成する事も出来ると思う。
(というか、こっちの方が正当な使い方かな?)

ちなみに、LIB.exeは、VCのインストール先ディレクトリにインストールされる。

Microsoft Visual Studio XXX\VCX\Bin

の中。

実行するには、MSPDBxx.DLL が必要になる。
VC6なら、 MSPDB60.dll。
VC71なら、 MSPDB71.DLL。

このDLLは、VSインストール先の CommonX\IDE フォルダに入っているので、実行する前にBinディレクトリにコピーしておく必要がある。

[追記 09/10/10]
Visual Studio 2008(VC9) では、bin ディレクトリに MSPDB80.dll をコピーすると、
通常のプログラムのコンパイル時に C1902 エラーが出るようになる。
一時的にコピーして使い終わったら削除するか、lib.exe を別ディレクトリに
コピーして、使用した方がよさそう。。。

参考サイト:http://msdn.microsoft.com/ja-jp/library/e17b885t(VS.80).aspx
[PR]
by isoq | 2008-08-27 16:25 | C/C++/Win32
e87.com(千趣会イイハナ) 花を贈るなら日比谷花壇