VC & MFC に関する覚え書き

私が調べたり 人から聞かれたりした VC や MFC に関するメモを残すページです。

  1. VC の STL に関するバグ情報
  2. CTreeCtrl を高速に書き換えるには?
  3. 指定されたパスにファイルが存在するかどうかの判定
  4. タスクトレイにアイコンを登録する方法
  5. 実行形式 EXE に含まれているアイコンを拾得する
  6. IE4 タスクバーのクイック機能バーにある「デスクトップの表示」をプログラム的に 実現する(?)
  7. Visual Studio のデバッグウィンドウに独自のメッセージを出力する
  8. Visual Studio を Emacs ライクのキーバインディングにする
  9. Visual Studio の任意のキーワードに色を付ける

VC の STL に関するバグ情報


VC5、VC6 の STL にはいくつかのバグが存在する。
http://www.dinkumware.com/vc_fixes.html
を参照のこと。


CTreeCtrl を高速に書き換えるには?

CTreeCtrl の項目を書き換える場合、 DeleteAllItems を行った後 各項目を InsertItemで追加して行く。 ただし、InserItem メソッドは1回よばれるごとに ツリービューの画面を更新するため、 大量のアイテムを挿入すると スクロールバーがぐにゅーーと動いてしまう。
瞬間的に画面を更新するためには、 CTreeCtrl の書き換えを行っている ルーチンを CWnd::LockWindowUpdate()CWnd::UnlockWindowUpdate() で囲むとロックが掛かり、 処理が終了するまで画面の再描画が掛からない。



指定されたパスにファイルが存在するかどうかの判定

あるパスに本当にファイルが存在するかどうかを 判定するには、 GetFileAttributes API を使えばよい。
DWORD GetFileAttributes(
  LPCTSTR lpFileName // pointer to the name of a file or directory
);
ファイルが存在しない場合は 0xFFFFFFFF を返す。

p.s.

PathFileExists API を用いればよいという 御指摘を頂いた。
       
BOOL PathFileExists(
  LPCTSTR lpszPath
);       
ただし、 この API を使うには Internet Explorer 4.0 以降が インストールされた環境が必要。


タスクトレイにアイコンを登録する方法

CDialog クラスの派生型なら
protected:
    NOTIFYICONDATA		m_stNtfyIcon;
をメンバ変数として追加。

アイコンの登録
CMyDialog::OnInitDialog あたりに
    
    /////////////////////////////////////////////////
    // アイコンをタスクトレイに表示します。
    m_stNtfyIcon.cbSize = sizeof( NOTIFYICONDATA ); 
    m_stNtfyIcon.uID	= 0;
    m_stNtfyIcon.hWnd	= m_hWnd;
    m_stNtfyIcon.uFlags = NIF_MESSAGE | NIF_ICON | NIF_TIP;
    m_stNtfyIcon.hIcon	= AfxGetApp()->LoadIcon( IDR_MAINFRAME );
    m_stNtfyIcon.uCallbackMessage = WM_USER_NTFYICON;
    lstrcpy( m_stNtfyIcon.szTip, _T( "テスト" ) );
    ::Shell_NotifyIcon( NIM_ADD, &m_stNtfyIcon );
アイコンの削除
CMyDialog::OnDestroy あたりに
    //タスクトレイのアイコンを削除します。
    ::Shell_NotifyIcon( NIM_DELETE, &m_stNtfyIcon );
タスクトレイ上のアイコンに操作があった場合の処理
LRESULT CMyDialog::WindowProc(UINT message, WPARAM wParam, LPARAM lParam) 
{
	switch( message )
	{
		case WM_USER_NTFYICON:  //アイコンからのメッセージ。
		{
			if( lParam == WM_LBUTTONDOWN ){
			// 左クリック時の処理
			}
			else if( lParam == WM_RBUTTONDOWN ){
				// 右クリック時の処理
			}
		}
		return 0;
	}       
	return CDialog::WindowProc(message, wParam, lParam);
}
参考のページ
http://www.omninet.co.jp/winmnt/



実行形式 EXE に含まれているアイコンを拾得する

2 通りの方法があります。
ExtractIcon (IExtractIcon?) を使う方が、 SHGetFileInfo を使うより 一寸速いそうです。
アイコンを拾得したい実行形式 EXEのパスを szFileName とすると

  1. ExtractIcon API を使う。
    HICON hIcon = ::ExtractIcon( AfxGetInstanceHandle(), szFileName, i ) ;
    
    で、ICONハンドルが取れる。

  2. SHGetFileInfo API を使う。
    SHFILEINFO	sfi;
    DWORD	dwRet;
    HICON	hIcon;
    
    // タイトルの拾得
    dwRet = ::SHGetFileInfo( szFileName,
    		0, &sfi, sizeof(SHFILEINFO FAR), SHGFI_DISPLAYNAME ); 
    // sfi.szDisplayName;
    
    // 小さいアイコンの拾得	
    dwRet = ::SHGetFileInfo( szFileName,
    		0, &sfi, sizeof(SHFILEINFO FAR), SHGFI_ICON | SHGFI_SMALLICON );
    // sfi.hIcon 
    
    // 大きいアイコンの拾得
    dwRet = ::SHGetFileInfo( szFileName,
    		0, &sfi, sizeof(SHFILEINFO FAR), SHGFI_ICON | SHGFI_LARGEICON );
    // sfi.hIcon
    



IE4 タスクバーのクイック機能バーにある「デスクトップの表示」をプログラム的に 実現する(?)

IE とのディスクトップの統合を行った時にあらわれる「デスクトップの表示」と いうアイコンを増設される。 この「デスクトップの表示」は .scf という拡張子 を持つ「Winodows エクスプローラコマンド」と よばれるファイルで、 IE4 のシェルの未統合時にはダブルクイック時には 正常に機能しない。
なんとかこの機能が使えぬものかと同様な効果を持つプログラムを試作した。 プログラムのコアの部分だけを載せると以下のようになる。
要はウィンドウアニメーションを off にしてから、ウィンドウを最小化していく だけ。
ANIMATIONINFO	info;
int  iMinAnimate; 

info.cbSize = sizeof( ANIMATIONINFO	);

::SystemParametersInfo( SPI_GETANIMATION, sizeof(info), (PVOID)&info, 0 ); 

if( info.iMinAnimate ){
    info.iMinAnimate = 0;
    ::SystemParametersInfo( SPI_SETANIMATION, sizeof(info), (PVOID)&info, 
	                            SPIF_SENDCHANGE ); 
    ::EnumWindows(EnumWindowsProc, 0);
    info.iMinAnimate = 1;
    ::SystemParametersInfo( SPI_SETANIMATION, sizeof(info), (PVOID)&info, 
                            SPIF_SENDCHANGE ); 
}
else{
    ::EnumWindows(EnumWindowsProc, 0);
}
コールバック関数は以下のようになる。
最小化の対象とするのは、ウィンドウスタイルとして WS_VISIBLE をとり、拡張ウィ ンドウスタイルとして WS_EX_TOOLWINDOW をとらないウィンドウのみ。 これはタスクバーに現れるウィンドウに相当する。

static BOOL CALLBACK EnumWindowsProc(HWND hwnd, LPARAM lParam )
{
    if( ::IsIconic( hwnd ) == 0) {
        if( ( GetWindowLong( hwnd,  GWL_STYLE ) & WS_VISIBLE ) ){
            if(! (GetWindowLong(hwnd,GWL_EXSTYLE) & WS_EX_TOOLWINDOW) ){
                ::ShowWindowAsync(hwnd, SW_SHOWMINNOACTIVE );
            }
        }
    }
    return TRUE;
}



Visual Studio のデバッグウィンドウに独自のメッセージを出力する

MFC
   TRACE("メッセージ \n");
ATL
   _RPT0(_CRT_WARN, "メッセージ \n");



Visual Studio を Emacs ライクのキーバインディングにする

メニューの「ツール(T)」→「オプション(O)」を押して、 オプションダイアログを出す。
オプションダイアログの「互換性」タブの 「現在のソースエディッタのエミュレーション(C)」を Epsilonに設定すればよい。



Visual Studio の任意のキーワードに色を付ける

まず、MSDEV.EXE のあるディレクトリを探す。
(例えば、 "C:\Program Files\Microsoft Visual Studio\Common\MSDev98\Bin\")
このディレクトリに USERTYPE.DAT と名前の テキストファイルを置く。
このファイルに自分が色を着けたいキーワードを1行づつe 書いていく。
intptr_t
uintptr_t
size_t
次にVisual Studio を起動した時から、 設定が有効になる。

キーワードに着けたい色は変更可能である。 メニューの「ツール(T)」→「オプション(O)」を押して、 オプションダイアログを出す。
この「色」ボックスの 「ユーザー定義キーワード」を 変更すればよい。

Written by NAKAMURA Minoru, Email: nminoru atmark nminoru dot jp, Twitter:@nminoru_jp