VC++関係[詳細] (最終更新日は '00.2.23 です。)

CFileDialogのカスタマイズを行う。 [New'98.12.18]

1.追加するダイアログリソースを定義する。
このとき、必ず子ウィンドウで、3D・コントロール・兄弟ウィンドウをクリップを指定する。
IDD_FILE_C_RANGE DIALOG DISCARDABLE  13, 28, 171, 22
STYLE DS_3DLOOK | DS_CONTROL | WS_CHILD | WS_CLIPSIBLINGS
FONT 9, "MS Pゴシック"
BEGIN
    CTEXT           "開始位置",IDC_STATIC,5,9,28,8
    EDITTEXT        IDC_STARTSEC,42,5,37,12,ES_AUTOHSCROLL
    CTEXT           "終了位置",IDC_STATIC,89,9,28,8
    EDITTEXT        IDC_ENDSEC,129,5,37,12,ES_AUTOHSCROLL
END

2.CFileDialogの派生クラスを作成する。(例えばCFileRangeDialog)
3.コントロールに対応したメンバ変数を定義し、対応つける。
4.OnFileNameOK()を定義し、その中で、OnOK()を呼び出す。
CFileRangeDialog::CFileRangeDialog(BOOL bOpenFileDialog, LPCTSTR lpszDefExt, LPCTSTR lpszFileName,
    DWORD dwFlags, LPCTSTR lpszFilter, CWnd* pParentWnd) :
    CFileDialog(bOpenFileDialog, lpszDefExt, lpszFileName, dwFlags, lpszFilter, pParentWnd)
{
    m_sEndSec = _T("");
    m_sStartSec = _T("");
}

void CFileRangeDialog::DoDataExchange(CDataExchange* pDX)
{
    CFileDialog::DoDataExchange(pDX);
    DDX_Text(pDX, IDC_ENDSEC, m_sEndSec);
    DDV_MaxChars(pDX, m_sEndSec, 8);
    DDX_Text(pDX, IDC_STARTSEC, m_sStartSec);
    DDV_MaxChars(pDX, m_sStartSec, 8);
}

BEGIN_MESSAGE_MAP(CFileRangeDialog, CFileDialog)
    //{{AFX_MSG_MAP(CFileRangeDialog)
    //}}AFX_MSG_MAP
END_MESSAGE_MAP()


BOOL CFileRangeDialog::OnInitDialog() 
{
    CFileDialog::OnInitDialog();

    // TODO: この位置に初期化の補足処理を追加してください
    //IDC_STARTSEC
    //IDC_ENDSEC
    return TRUE;  // コントロールにフォーカスを設定しないとき、戻り値は TRUE となります
                 // 例外: OCX プロパティ ページの戻り値は FALSE となります
}

void CFileRangeDialog::OnOK()
{
    CFileDialog::OnOK();
}

BOOL CFileRangeDialog::OnFileNameOK()
{
    OnOK();
    return CFileDialog::OnFileNameOK();
}
5.CFileDialogの派生クラスを使用する。
    CString	strDefExt((LPCSTR)IDS_DEFFILTER);
    CString	strExtType((LPCSTR)IDS_FILTER); 
    CFileRangeDialog FileOpen( FALSE,         //* [ファイル名を付けて保存] を構築
                            strDefExt,        //* デフォルト拡張子
                            NULL,             //* 初期値
                            OFN_OVERWRITEPROMPT|OFN_HIDEREADONLY |  OFN_PATHMUSTEXIST|OFN_ENABLETEMPLATE/*|OFN_ENABLEHOOK*/,
                            strExtType,       //* フィルタ
                            AfxGetMainWnd( ) ); //* 親ウィンドウ
    //* CHILDの追加
//	FileOpen.m_ofn.hInstance = AfxGetInstanceHandle( );
    CString strTipText=_T("部分保存");        //タイトル
    FileOpen.m_ofn.lpstrTitle=strTipText;
    FileOpen.m_ofn.nMaxFileTitle=strTipText.GetLength();
	FileOpen.m_ofn.lpTemplateName = MAKEINTRESOURCE(IDD_FILE_C_RANGE);	//* カスタマイズリソース
    int ret = FileOpen.DoModal();


65535以上の範囲のスクロールバー表示 [New'98.11.13]

1.範囲指定&初期位置
  SCROLLINFO scrollinfo;
  scrollinfo.cbSize=sizeof(scrollinfo);
  scrollinfo.fMask=SIF_POS|SIF_RANGE;        //位置とスクロール範囲指定
  scrollinfo.nMin=0;                         //最小値
  scrollinfo.nMax=m_dwOffsetMax;             //最大値
  scrollinfo.nPos=m_dwOffset;                //位置
  SetScrollInfo(SB_VERT,&scrollinfo,TRUE);
2.位置指定
  SCROLLINFO scrollinfo;
  scrollinfo.cbSize=sizeof(scrollinfo);
  scrollinfo.fMask=SIF_POS;                  //位置指定
  scrollinfo.nPos=m_dwOffset;                //位置
  SetScrollInfo(SB_VERT,&scrollinfo,TRUE);
3.位置取得(OnVScroll()などで)
  SCROLLINFO scrollinfo;
  DWORD nPos;
  scrollinfo.cbSize=sizeof(scrollinfo);
  GetScrollInfo(SB_VERT,&scrollinfo,SIF_POS|SIF_TRACKPOS );//位置を取得
  nPos=scrollinfo.nPos;                      //位置
  if (nSBCode==SB_THUMBTRACK) {              //スライダードラッグ中
    nPos=scrollinfo.nTrackPos;               //スライダードラッグ時の位置
  }


メッセージへのファイル名などの埋め込み [New'98.11.13]

1.AfxFormatString1()またはAfxFormatString2()を使用する。
リソースファイル
  IDS_ERR_SAVE_AS         "ファイル'%1'の保存でエラーが発生しました。"
コーディング
  CString strFileName;  //ファイル名
  CString strWk;
  AfxFormatString1( strWk, IDS_ERR_SAVE_AS, strFileName);
  AfxMessageBox(strWk);

2.CString::Format()を使用する。
リソースファイル
  IDS_ERR_COMMON_DLG      "エラーコード:%d"
コーディング
  DWORD dret;   //リターンコード
  CString sMsg;
  sMsg.Format(IDS_ERR_COMMON_DLG,dret);
  AfxMessageBox(sMsg);


CFontDialogのカスタマイズを行う。 [New'98.7.11]

1.includeディレクトリ(mfcなどではなくSDKレベル)にある、font.dlgをコピーする。
2.resource.hの最後の行に
  #include<Dlgs.h>
  を追加する。
3.font.dlgの内容をxxxx.rc(xxxはプロジェクト名)に追加する。場所は、ダイアログの定義部分の最後に追加する。
(font.dlgをxxx.rcにincludeしても良いが、編集が面倒になります。)
この場合シンボル、値は変更不可。
4.フォントをMS Pゴシック 9ポイントに変更する。
5.文字列を日本語に変更する。
6.CFontDialogの派生クラスを作成し、下記の手順で表示する。
	CCustomFontDialog   FontDlg(&m_logfont);      //CCustomFontDialogはCFontDialogの派生クラス
	FontDlg.m_cf.Flags |= CF_ENABLEHOOK | CF_ENABLETEMPLATE;		//* フラグ設定
	FontDlg.m_cf.hInstance = AfxGetInstanceHandle( );
	FontDlg.m_cf.lpTemplateName = MAKEINTRESOURCE(FORMATDLGORD31);	//* カスタマイズリソース
                                                                                       //ダイアログリソースは、必要な項目を含んでいる必要がある。
	int iret=FontDlg.DoModal();
7.通常のダイアログが出ることを確認したら、FORMATDLGORD31ダイアログに項目を追加、変更する。
8.OnInitDialogで追加した項目の初期化を行う。
9.必要に応じて、処理を追加する。

注意:もとのリソースが英語のため、日本語の選択コンボボックスは付かないようです。


アプリケーションのポインタを取得する [New'98.3.24]
AfxGetApp()で通常アプリケーションへのポインタが取得できます。

      CXXXApp *pWnd=(CXXXApp *)AfxGetApp();


メインウィンドウのポインタを取得する [New'98.3.24]
AfxGetMainWnd()で通常CMainFrameへのポインタが取得できます。

      CMainFrame *pWnd=(CMainFrame *)AfxGetMainWnd();


表示のちらつきをなくす [New'98.3.24]
OnEraseBkgnd()をオーバライドして、背景の消去を抑止する。

      CXXWnd::OnEraseBkgnd(CDC *pDC) {
          return 1;
      }


CImageListで256色のbitmapリソースを扱う [New'97.11.5]
CImageListのCreate時にbitmapリソースIDを指定すると、16色になってしまうため、 CImageListを色のbit数を指定してCreateしてからbitmapリソースをAddする。

//Create
CImageList m_imgList;
int index=-1;
#define MASK_COLOR RGB(255,0,255) //例えば紫色を透過色とする場合
BOOL bret=m_imgList.Create(cx,cy,ILC_COLOR8|ILC_MASK,0,1);
if (bret) {
	CBitmap bmp;
	bret=bmp.LoadBitmap(IDB_XXXX); //IDB_XXXXはbitmapリソーシID
	if (bret) {
		index=m_imgList.Add(bmp,MASK_COLOR);
	}
}
//表示
//CDC dc;
//CPOint pt;
BOOL bret=m_imgList.Draw(&dc,index,pt,ILD_NORMAL);


ダイアログでキャンセルボタンがないとき、ESCを効かなくする。 [New'97.10.20]
OnCancel()をオーバライドし、なにも動作しないようにする。


コントロールバーの状態を保存・回復する。 [New'97.10.13]
CDockStateを使用する。

[保存]
CDockState dockstate;
GetDockState(dockstate);       //CFrameWnd::
dockstate.SaveState(_T("xxxx"));   //xxxx:エントリ名
[回復]
CDockState dockstate;
dockstate.LoadState(_T("xxxx"));   //xxxx:エントリ名
SetDockState(dockstate);      //CFrameWnd::


起動時にスプラッシュウィンドウ(ロゴ)を表示する。 [New'97.10.9]
1.コンポーネントギャラリーでスプラッシュ スクリーンを指定して挿入を行う。
2.bitmapリソース IDB_SPLASHを編集する。
3.画面の表示が遅い場合は、CMainFrame::OnCreate()で自動挿入されたコードをCMainFrame::OnCreate()内のCFrameWnd::OnCreate()の直後へ移動する。


bitmapリソースを透過色を指定して表示する。 [New'97.10.3]

CImageList m_imglist;
cx=16;					//bitmapの横幅
nGrow=0;
crMask=RGB(255,0,255);//紫を透過色とする場合
m_imglist.Create( IDB_XXXX,  cx,  nGrow,  crMask );//bitmapリソースを登録
CDC *pdc;				//DC
int nImage=0;				//先頭のbitmap
CPoint pt;  				//表示座標
UINT nStyle=ILD_NORMAL;
pdc=&dc;
pt=CPoint(100,100);
m_imglist.Draw(pdc, nImage, pt, nStyle);//bitmapを表示する。


座標が特定の矩形領域内にあるか判断する。 [New'97.10.3]
CRect::PtInRect()を使用して判定する。


書式を付けて文字列を操作する。 [New'97.10.3]
CString::Format()を使用する。


ドライブ名、ディレクトリ、ファイル名、拡張子からパス名を得る [New'97.9.29]
_tmakepath()[ASCII/SJISだけなら_makepath()]を使用する。
これで、ドライブ名、ディレクトリ、ファイル名、拡張子からパス名を得ることができます。


絶対パスからファイル名等を取り出す。 [New'97.9.29]
_tsplitpath()[ASCII/SJISだけなら_splitpath()]を使用する。
これで、ドライブ名、ディレクトリ、ファイル名、拡張子を得ることができます。


非ビューウィンドウでOLE Drag&Dropを可能とする。 [New'97.9.23]
1.COleDropTargetの派生クラスを作る。
2.Dropを可能としたいウィンドウにCOleDropTargetの派生クラスのメンバ変数(m_DropTarget等)を定義する。
3.OnCreate()で、 m_DropTarget.Register(this) を追加する。
4.COleDropTargetの派生クラスでOnDragEnter(),OnDragLeave(),OnDragOver(),OnDrop(),OnScrollBy()をオーバーライドする。
5.OnDragEnter(),OnDragOver()で通常は、リターン値にDROPEFFECT_COPY か DROPEFFECT_MOVEを指定することで、カーソルがDrop可能表示となる。
6.OnDropでドロップされた内容を取得して、独自の処理を行う。
7.ウィンドウの一部だけをDrop可能とする場合は、OnDragEnter(),OnDragOver()で引数で渡ってくるpointをチェックし、NGの場合はDROPEFFECT_NONEを返す。
また、OnDrop()ではFALSEを返す。


Visual Studio Service Pack 1/Service Pack 2をインストールした後にビルドするとツールチップが表示されなくなる。 [New'97.9.18]
Visual Studio (VC++ 5.0) Service Pack 1のバグのためです。
Article ID: Q172276FIX: CToolTipCtrl Not Displaying Text After VS SP1, SP2 Install
を参考にして、ツールヒントを出したいボタン等の親ウィンドウのクラスにOnToolHitTest()をvirtualでオーバーライドすることで、回避できます。


文書ファイルに関連付いているアイコンを取得する。 [New'97.9.17]
::SHGetFileInfo()を使用する。


タイトルバーのフォントを取得する。 [New'97.9.16]
::SystemParametersInfo()でLOGFONTを取得し、これからCFontを作成する。

nNONCLIENTMETRICS nonclientmetrics;
nonclientmetrics.cbSize=sizeof(NONCLIENTMETRICS);
BOOL bret=::SystemParametersInfo(SPI_GETNONCLIENTMETRICS,nonclientmetrics.cbSize,&nonclientmetrics,0);
//nonclientmetrics.lfCaptionFont  //通常のタイトルバーのLOGFONT
//nonclientmetrics.lfSmCaptionFont //ツールバー等のタイトルバーのLOGFONT
CFont font;
bret=font.CreateFontIndirect(&nonclientmetrics.lfCaptionFont);


オーナードローのチェックボタン・ラジオボタンの作成 [Update'04.1.21]
1.CButtonの派生クラスを作成する。(Create時にBS_OWNERDRAW|BS_PUSHBUTTONを指定する。)
2.SetCheck(),GetCheck()をvirtualでオーバーライドする。またチェック状態をメンバ変数に設定する。
3.BM_SETCHECKメッセージをON_MESSAGEでメッセージをマップし、メンバ変数を更新する。
4.DrawItem()をオーバーライドし、メンバ変数の状態で表示内容を切り替える。


プロセスの終了を監視する方法 [New'97.8.28]
16bitのとき
(1)Windows APIのGetModuleUsageでプロセスが無くなったか監視する。
(2)Windows APIのFindWindowでプロセスのWindowが無くなったか監視する。
(3)Windows APIのtoolhelp系のNotifyRegisterで終了通知を受ける。
(4)Windows APIのtoolhelp系のタスクを検索するAPIで検索する。 (Windows95/NTのWOWで、32bitの終了を監視する場合に有用)
32bitのとき
(1)Windows APIのFindWindowでプロセスのWindowが無くなったか監視する。
(2)Windows APIのOpenProcessとGetExitCodeProcessを使用する。
(3)Windows APIのCreateProcessでプロセスを起動して、WaitForInputIdle で起動完了までアイドルして、WaitForSingleObjectで監視
(4)Windows95であれば、toolhelp32を使用する。
(5)Windows APIのCreateProcessでプロセスをデバッグモードで起動して、終了通知を受ける。 (監視スレッドを作り、CreateProcessはそのスレッドで実行し、デバッグメッセージ を逐次処理する)ただし、16bitの起動はできません。


プロセスに所属するウィンドウを取得する。(WindowsNT以外) [Update'98.7.22]
Windows3.1ならEnumTaskWindows,win32ならEnumThreadWindowsを使用する。
1.Windows 3.1の時

HWND hWndwk[(予定するhWnd数)]  //共通変数
int  wndCnt;
xxxxxx(xxxx,xxxx) {
    HANDLE        hThreadSnap = NULL;
    THREADENTRY32 te32        = {0};
・・・
    wndCnt=0;
//hTaskからWindow検索
    ret=EnumTaskWindows(hTask,EnumWndProc,0L);
//wndCntで個数,hWndwkでhWndを取得
・・・
}
BOOL CALLBACK EnumWndProc(hWnd,lParam) {
  hWndwk[wndCnt]=hWnd;
  wndCnt++;
  return TRUE;
}
2.Win32のとき
#include <tlhelp32.h>              // Required for ToolHelp32 functions 

typedef BOOL (WINAPI *MODULEWALK)(HANDLE hSnapshot, LPMODULEENTRY32 lpme); 
typedef BOOL (WINAPI *THREADWALK)(HANDLE hSnapshot, LPTHREADENTRY32 lpte); 
typedef BOOL (WINAPI *PROCESSWALK)(HANDLE hSnapshot, LPPROCESSENTRY32 lppe); 
typedef HANDLE (WINAPI *CREATESNAPSHOT)(DWORD dwFlags, DWORD th32ProcessID); 

HWND hWndwk[(予定するhWnd数)]  //共通変数
CREATESNAPSHOT pCreateToolhelp32Snapshot = NULL;
THREADWALK  pThread32First  = NULL;
THREADWALK  pThread32Next   = NULL;
xxxxxx(xxxx,xxxx) {
    HANDLE        hThreadSnap = NULL;
    THREADENTRY32 te32        = {0};
・・・
    wndCnt=0;
//toolhelp32でプロセスID(dwPID)からthreadIDを検索してWindow検索
    hKernel = GetModuleHandle("KERNEL32.DLL");
    if (hKernel) {
        pCreateToolhelp32Snapshot =
          (CREATESNAPSHOT)GetProcAddress(hKernel, "CreateToolhelp32Snapshot");
        pThread32First  = (THREADWALK)GetProcAddress(hKernel, 
                                                     "Thread32First");
        pThread32Next   = (THREADWALK)GetProcAddress(hKernel, 
                                                     "Thread32Next");
    } else {
	//Error
    }
    hThreadSnap = pCreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0);
    if (hThreadSnap == (HANDLE)-1) {
        //Erro
    }
    te32.dwSize = sizeof(THREADENTRY32);
    if (pThread32First(hThreadSnap, &te32)) {
        do  {
            if (te32.th32OwnerProcessID == dwPID) {
                ret=EnumThreadWindows(te32.th32ThreadID,EnumWndProc,0L);
            }
        } while (pThread32Next(hThreadSnap, &te32));
    } else {
        //Error
    }
    CloseHandle (hThreadSnap);
    FreeLibrary(hKernel);
//wndCntで個数,hWndwkでhWndを取得
・・・
}
BOOL CALLBACK EnumWndProc(hWnd,lParam) {
  hWndwk[wndCnt]=hWnd;
  wndCnt++;
  return TRUE;
}


16bit APから32bit DLLを呼び出す。 [New'97.8.28]
MSJ No.33(MSDN MSJ Vol.9 No.6 Test Drive Win32 ...)に記述があります。
また、MSDNの「Calling a Win32 DLL from a Win16 Application Under WOW」
に簡単な呼び方が記述されています。
1.LoadLibraryEx32W/GetProcAddress32W/CallProc32W/GetVDMPointer32W/
FreeLibrary32Wをkernelからインポートする。
2.32bit DLLを16bitAPでロードする。
DWORD FAR PASCAL LoadLibraryEx32W( LPCSTR, DWORD, DWORD);
3.32bit DLLのexportされた関数のアドレスを取得する。
DWORD FAR PASCAL GetProcAddress32W( DWORD, LPCSTR );
4.32bit DLLの関数をコールする。
DWORD FAR PASCAL CallProc32W( DWORD, ..., LPVOID, DWORD, DWORD );
5.32bitアドレスへの変換
DWORD FAR PASCAL GetVDMPointer32W( LPVOID, UINT );
6.32bit DLLを開放する。
BOOL FAR PASCAL FreeLibrary32W( DWORD );


OSの種類(95、NT)を判定する方法 [New'97.8.28]
1.Win32のとき
BOOL GetVersionEx(LPOSVERSIONINFO lpVersionInformation )で取得できます。
2.16bitのとき
GetWinFlagsの戻り値で判断できます。
GetWinFlagsの追加定義
#define WF_WINNT 0x4000 //GetWinFlagsでこの値でandを取って判断する。
詳細は、MSDNの「How to Determine If a VB App is Running Under Windows NT 3.x」, 「Determining System Version from a Windows-Based Application」を参考にして下さい。


経過時間を取得する。 [New'97.8.28]
BOOL QueryPerformanceCounter(LARGE_INTEGER *lpPerformanceCounter)で可能です。
ちなみに、タイマーの解像度は、QueryPerformanceFrequency()で調べられます。


Windows 3.1でドライブがCD-ROMかを判断する。 [New'97.8.23]
MSDNのCDで「Knowledge Base How to Determine Drive Types in Windows」を参照する。


REPORT表示のCListCtrlの行の高さを変える [New'97.8.23]
SetImageListで指定したい高さ分のアイコンを指定する。


文字列リソースからツールチップの文字列を取得する。 [New'97.8.23]
MFC内部の関数を使用する。
int nID; //文字列のリソースID
TCHAR szFullText[256];
CString strTipText;
AfxLoadString(nID, szFullText);
// this is the command id, not the button index
AfxExtractSubString(strTipText, szFullText, 1, '\n');
ツールチップのポインタを取得する。 [New'97.8.23]
MFC内部のメンバ変数を参照する。
CToolTipCtrl *pToolTip=AfxGetThreadState()->m_pToolTip;


ツールチップの内容を条件により変更する。 [Update'97.10.18]
(1)::SetWindowLong(m_hWnd,GWL_ID ,nID)でツールチップを変えたいウィンドウのIDを変更したあとのツールチップに対応するIDに書き換える。
(2)OnToolHitTest()をオーバーライドし、UpdateTipText()でツールチップを更新する。
OnToolHitTest()の戻り値はドキュメントと異なり、ヒットしたコントロールのIDが帰ってくるので、これを基に判断する。


メニューの表示文字列を条件により変更する。 [Update'97.8.21]
OnUpdateXXXでSetText()でメニューの文字列を変更する。


メニューに対するガイダンスを条件により変更する。 [Update'97.10.18]
(1)OnUpdateXXXでpCmdUI->m_nIDを変更したあとのガイダンスに対応するIDに書き換える。
(2)CFrameWnd::OnMenuSelect()でSetMessageText()でガイダンスを更新する。


システムメニューの内容を元に戻す。 [New'97.8.18]
GetSystemMenu(TRUE)を実行する。


ダイアログバーをリサイズ可能にする。 [Update'97.8.13]
1.ダイアログバーのCreate時にCBRS_SIZE_DYNAMICを指定する。
2.ダイアログバーの派生クラスで、CalcFixedLayout(),CalcDynamicLayout()にサイズ計算処理を入れる。
3.CMainFrameでEnableDocking()をオーバーライドし、MFCのソースの内容を一部変更する。
リサイズしたい位置のCDockBarのCreate時にWS_THICKFRAME|CBRS_BORDER_3D|CBRS_BORDER_XXXを追加指定する。指定した所がリサイズ可能となる。
4.CDockBarの派生クラスのOnSize処理でダイアログバーの再配置を行う。
*CDockBarクラスはテクニカルノートに少し記述があります。実態は、CFrameWndの子ウィンドウでコントロールバーのドッキング時の親ウィンドウになるようです。
コントロールバーがフロート時は親ウィンドウはCMiniFrameWndのようです。


ウィンドウの背景色を変更する。 [New'97.8.9]
PreCreateWindowで背景色を指定したクラスを登録して、ウィンドウを生成する。
例:CMainFrameの場合

BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs)
{
	BOOL bret=m_brsh.CreateSolidBrush(RGB(242,242,242));//メンバ変数に宣言
	cs.lpszClass = AfxRegisterWndClass(CS_DBLCLKS,
		AfxGetApp()->LoadStandardCursor(IDC_ARROW), m_brsh,
		AfxGetApp()->LoadIcon(IDR_MAINFRAME));
	return TRUE;
}


ドッキングしているコントロールバーの配置順序を変える。 [New'97.8.9]
コントロールバーのZオーダーを入れ替えたあと、再度位置計算を行う。

//CControlBar m_cbar;既に作成してドッキングしたコントロールバー
CWnd *pWnd=m_cbar.GetParent();//ステータスバー以外は親を求める
pWnd->SetWindowPos(&wndTop,0,0,0,0,SWP_NOMOVE|SWP_NOSIZE);//Zオーダーを先頭にする
AfxGetMainWnd()->RecalcLayout();


Windows95,WindowsNT 4.0でユーザーのログイン・ログオフを知る。 [New'97.8.7]
WM_USERCHANGEDメッセージを処理する。


ダイアログの背景色、コントロールの色を変える。 [New'97.7.31]
(1)CWinApp::SetDialogBkColor()を使用する。
(2)ダイアログの親ウィンドウでOnCtlColor()をオーバライドし、色を指定する。


WindowsNT 3.51でCButtonでビットマップが表示されない。 [New'97.7.29]
WindowNT 3.51ではBS_ICON と BS_BITMAPが支援されていないため。
MSDNで「PRB: CButton SetIcon and SetBitmap Work Only Under Windows 95」参照のこと。


ダイアログバー上のボタンにツールヒントを表示する。 [New'97.7.29]
ボタンのリソースIDを対応するメニューのリソースIDと同一にする。


ステータスバーに座標を表示する。 [New'97.7.29]
コンポーネントギャラリーでステータスバーを挿入後、挿入された内容(時間表示)を修正すると簡単です。

BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd)
	ON_WM_INITMENUPOPUP()
	ON_WM_MENUSELECT()
	ON_UPDATE_COMMAND_UI(ID_INDICATOR_XY, OnUpdateXY)
	//{{AFX_MSG_MAP(CMainFrame)
		// メモ - ClassWizard はこの位置にマッピング用のマクロを追加または削除します。
		//        この位置に生成されるコードを編集しないでください。
	ON_WM_CREATE()
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
//省略
	// CG: 次のブロックは「ステータス バー」コンポーネントにより追加されています。
	{
		// AppWizard の定義したスタティック変数 'indicators' のサイズを
		// 調べて保存します。
		int nOrigSize = sizeof(indicators) / sizeof(UINT);

		UINT* pIndicators = new UINT[nOrigSize + 1];        //+1は1個追加することを示す。
		memcpy(pIndicators, indicators, sizeof(indicators));

		// ステータス バー コンポーネントのステータス バー作成ルーチンを呼び出します。
		if (!InitStatusBar(pIndicators, nOrigSize, 60))
		{
			TRACE0("Failed to initialize Status Bar\n");
			return -1;
		}
		delete[] pIndicators;
	}
//省略
}
BOOL CMainFrame::InitStatusBar(UINT *pIndicators, int nSize, int nSeconds)
{
	// CG: 次のブロックは「ステータス バー」コンポーネントにより追加されています。
	m_nXYPaneNo = nSize++;
	pIndicators[m_nXYPaneNo] = ID_INDICATOR_XY;

	return m_wndStatusBar.SetIndicators(pIndicators, nSize);
}

void CMainFrame::OnUpdateXY(CCmdUI* pCmdUI)
{
	// 現在の座標を書式にしたがって変換します。
	CString strxy = _T("100,100");//<------------------座標を文字列にする。この場合は、(100,100)固定です。


	// BLOCK: 文字列の幅を計算します。
	CSize size;
	{
		HGDIOBJ hOldFont = NULL;
		HFONT hFont = (HFONT)m_wndStatusBar.SendMessage(WM_GETFONT);
		CClientDC dc(NULL);
		if (hFont != NULL) 
			hOldFont = dc.SelectObject(hFont);
		size = dc.GetTextExtent(strxy);
		if (hOldFont != NULL) 
			dc.SelectObject(hOldFont);
	}

	// 現在の座標を反映するようにペインを更新します。
	UINT nID, nStyle;
	int nWidth;
	m_wndStatusBar.GetPaneInfo(m_nXYPaneNo, nID, nStyle, nWidth);
	m_wndStatusBar.SetPaneInfo(m_nXYPaneNo, nID, nStyle, size.cx);
	pCmdUI->SetText(strxy);
	pCmdUI->Enable(TRUE);
}
//インクルードファイル
class CMainFrame : public CFrameWnd
{
protected: // シリアライズ機能のみから作成します。
	afx_msg void OnUpdateXY(CCmdUI* pCmdUI);
public:
	int m_nXYPaneNo;
//リソース
文字列リソースに ID_INDICATOR_XYを適当な文字列(たとえばxy)で定義しておく。


タイトルバーを独自に表示する。 [Update'97.8.12]
1.WM_NCACTIVATE,WM_NCPAINTを独自に処理する。
MSDNで「How to Draw a Custom Window Caption」を参考のこと。
2.void CFrameWnd::OnUpdateFrameTitle(BOOL bAddToTitle)をオーバーライドし、デフォルト処理後にWM_NCPAINT処理を呼び出す。
MSJ(日本語版) No.49 P160の記事も参考になります。[Add'97.11.26]


タイトルバーを消す [New'97.7.29]
ModifyStyle(WS_CAPTION|WS_SYSMENU,0)でスタイルから削除する。


ステータスバーに時刻を表示する。 [New'97.7.21]
コンポーネントギャラリーでステータスバーを挿入する。


ダイアログバー上のスクロール系コントロールの通知メッセージ取得方法 [New'97.7.18]
1.CDialogBarの派生クラスを作成し、派生クラスを使用してダイアログバーをCreateする。
2.派生クラスにメンバ関数OnHScroll()を定義し、CMainFrameへメッセージを中継する。
3.CMainFrame::OnHScroll()でコントロールIDで判別して処理する。


ダイアログバー上のコントロールの操作方法 [New'97.7.18]
1.操作したいコントロールに対応するメンバ変数をCMainFrameに宣言する。
CButton m_Btn1;//IDC_BTN1用のメンバ変数
2.CMainFrame::OnCreate()でダイアログバーの生成後、リソースIDでコントロールを動的サブクラス化する。
BOOL bret=m_Btn1.SubclassDlgItem(IDC_BTN1,&m_DlgBar);//m_DlgBarはダイアログバーのポインタ
3.メンバ変数でダイアログバー上のコントロールが操作できる。


OCXをダイアログに貼り付ける。 [New'97.7.17]
1.コンポーネントギャラリーでOCXを指定して挿入を行う。
2.ダイアログエディタに挿入したOCXが表示されるようになる。
3.ダイアログにOCXを貼り付ける。
4.コンテナの設定をしていない場合は、コンポーネントギャラリーでOLEコントロールコンテナを指定して挿入する。
5.OCXへの操作をする場合は、1で自動生成されたOCXに対応したクラスを使用する。


起動時に最大化表示を行う。 [New'97.7.10]
InitInstance()の最初で、CWinAppのメンバ変数m_nCmdShowにSW_SHOWMAXIMIZEDを代入する。


ダイアログのコントロールに対するメンバ変数を配列にする。 [New'97.7.10]
1.コントロールのIDC_XXXを通し番号で設定する。
2.ClassWizardとは関係なくメンバ変数を記述する。

例:10個のエディットコントロールの場合
変数宣言 xxxdlg.h 
        // ダイアログ データ
	//{{AFX_DATA(CXXXDlg)
	enum { IDD = IDD_ABOUTBOX };
	//}}AFX_DATA
	CString	m_edit[10];                    <-----AFX_DATAの外に宣言

xxxdlg.cpp
CXXXDlg::CXXXDlg() : CDialog(CXXXDlg::IDD)
{
	//{{AFX_DATA_INIT(CXXXDlg)
	//}}AFX_DATA_INIT
        int nID = IDC_EDIT1;
        for ( int   i = 0; i < 10; i++) {    //たとえば10個のとき
	  m_edit[i] = _T("");                     <-----AFX_DATA_INITの外に宣言
        }
}
void CXXXDlg::DoDataExchange(CDataExchange* pDX)
{
         CDialog::DoDataExchange(pDX);
	//{{AFX_DATA_MAP(CXXXDlg)      <-----残しておく
	//}}AFX_DATA_MAP                    <-----残しておく
        int nID = IDC_EDIT1;
        for ( int   i = 0; i < 10; i++) {    //たとえば10個のとき
	  DDX_Text(pDX,nID, m_edit[i]);
          nID++;
        }
}


明示的にアクティブViewを指定する。 [New'97.7.10]
CFrameWnd::SetActiveView()でアクティブになるViewを指定する。


CViewをCreateする。 [Update'98.1.25]
(1)CreateView()で作成する。
(2)Viewのポインタを作成して、ポインタを用いてCreateを行う。 このようにしないと、CXXXViewのコンストラクタがPublicでないといって コンパイルエラーになります。また、強引にPublicにすると 実行時にエラーとなります。

     CRuntimeClass   *pViewClass=RUNTIME_CLASS(CXXXView);
     CXXXView * pNewView = (CXXXView *) pViewClass->CreateObject();
     if (pNewView == NULL) {
         //エラー
     }
     if (!pNewView->Create(NULL, NULL, AFX_WS_DEFAULT_VIEW,
          CRect(0,0,0,0), this, AFX_IDW_PANE_FIRST, &context)) {
         //エラー
     }


分割ウィンドウのCViewのポインタを取得する。 [New'97.7.10]
MFC AppWizardで分割ウィンドウを作成したときは、CMainFrame::OnCreateClient()で CSplitterWndのポインタがCMainFrameのメンバ変数m_wndSplitterを使用して、 m_wnsSplitter.GetPane()でViewのポインタを取得できる。


初めて使用したときにコンパイルエラーとなる [Update'97.7.6]
CTreeView等を利用するときは、stdafx.hに#include <afxcview.h>を追加する。


CTabCtrlのフォントを変更する。 [New'97.6.28]
CTablCtrl::SetFontでフォントを変更する。
このとき、指定したCFontはCTabCtrlを破棄するまでメンバ変数で保持
しておく。


コンボボックスのあるツールバーの作成 [New'97.6.28]
コンポーネントギャラリーでダイアログバーを挿入して
自動生成されたダイアログリソースにボタン、コンボボックスを追加する。


分割した画面をさらに分割する [New'97.6.28]
CViewのOnCreateの中で、CSplitterWndで分割ウィンドウを作成する。
そのとき、CreateViewに渡すpContextには、lpCreateStruct->lpCreateParams
を指定する。


現在アクティブ(前景)になっているトップレベルウィンドウを取得する。 [New'97.6.26]
CWnd::GetForegroundWindow()を使用する。戻り値がNULLの場合があるので注意する必用がある。

CWnd *pActiveWnd=CWnd::GetForegroundWindow();
if (pActiveWnd!=NULL) {
//処理
}


CWinApp内でCDocumentポインタを取得する方法 [New'97.6.23]
Documentが一つしかない場合

POSITION posDocTemp=CWinApp::GetFirstDocTemplatePosition( );//まずCDocTemplateを取得
CDocTemplate* pDocTemplate=GetNextDocTemplate( posDocTemp );
POSITION posDoc=pDocTemplate->GetFirstDocPosition( );//次にCDocumentを取得
CDocument* pDoc=pDocTemplate->GetNextDoc( posDoc);


CDocument内でCViewポインタを取得する方法 [New'97.6.23]
Viewが一つしかない場合

POSITION posView = CDocument::GetFirstViewPosition();
CView* pFirstView = CDocument::GetNextView( posView );


CListCtrlにサブアイテム(カラム)を追加する。 [New'97.6.23]
1.カラムを追加する。
CListCtrl::InsertColumn(nCol,_T("サブアイテムの見出し"));
2.行を追加する。
CListCtrl::InsertItem(nItem,_T("先頭のアイテムの内容"));
3.サブアイテムを設定する。
CListCtrl::SetItem(nItem,nSubItem,LVIF_TEXT,_T("サブアイテムの内容"),0,0,0,0);


EXE,DLLが呼び出しているDLLを確認する。 [New'97.6.23]
VC++のインストールディレクトリ下のBINディレクトリ(たとえばc:\msdev\bin)にあるdumpbinを使用する。
使用方法
dumpbin /IMPORTS ファイル名


ON_THREAD_MESSAGEで使用するハンドラの型 [New'97.6.17]
戻り値の型はLRESULTではなくvoidでないとコンパイルエラーとなる。


テキストファイルを行単位にアクセスする [New'97.6.17]
読み込み:CStdioFile::ReadString
書き込み:CStdioFile:WriteString


CImageList::CreateのI/F誤り [New'97.6.17]

誤 BOOL Create( int cx, int cy, BOOL bMask, int nInitial, int nGrow );
正 BOOL Create( int cx, int cy, UINT frags, int nInitial, int nGrow );

frags   作成するイメージ リストの種類を指定します。この引数には、以下の値の組み合わせを指定できます。
   値              説明
ILC_COLOR4	4 ビットのデバイスに依存しないビット マップ (DIB) セクション。
ILC_COLOR8	8 ビットの DIB セクション。
ILC_COLOR16	16 ビットの DIB セクション。
ILC_COLOR24	24 ビットの DIB セクション。
ILC_COLOR32	32 ビットの DIB セクション。
ILC_COLORDDB	デバイスに依存するビット マップを使用
ILC_MASK	2 つのビット マップを使い、1 つはマスクとして使用するモノクロのビット マップを使用。この値がない場合は、イメージ リストに含まれるビット マップは 1 つだけとなります。
ILC_PALETTE	イメージ リストを持つカラー パレットを使用。


Windows95のインジケータ領域にアイコンを登録する [New'97.6.10]
1.Windows APIのShell_NotifyIconを使用する。
ヘルプで「Adding and Deleting Taskbar Icons」を参照のこと。

// 作成したウインドウのアイコンをタスクバーに設定する
#define WM_USER_TRY WM_USER+1    //ユーザメッセージ
#define ID_SHL_ICON 1
NOTIFYICONDATA nid;
memset( &nid, 0, sizeof( NOTIFYICONDATA ) );
nid.cbSize = sizeof(NOTIFYICONDATA);
nid.hWnd = hwnd; //WM_USER_TRYを受け取るウィンドウ
nid.uID = ID_SHL_ICON;//ID
nid.uFlags = NIF_MESSAGE | NIF_ICON|NIF_TIP ;
nid.uCallbackMessage = WM_USER_TRY;// 定義したユーザメッセージ
nid.hIcon = hicon;                 // 登録したいアイコンのハンドル
_tcscpy( nid.szTip, _T("ツールチップ") ); //登録したいツールチップ
BOOL bret=::Shell_NotifyIcon( NIM_ADD, &nid );

// タスクバーからアイコンを消す
#define WM_USER_TRY WM_USER+1
#define ID_SHL_ICON 1
NOTIFYICONDATA nid;
memset( &nid, 0, sizeof( NOTIFYICONDATA ) );
nid.cbSize = sizeof(NOTIFYICONDATA);
nid.hWnd = hwnd;
nid.uID = ID_SHL_ICON;
nid.uFlags = 0;
BOOL bret=::Shell_NotifyIcon( NIM_DELETE, &nid );

// メニューを表示する
#define WM_USER_TRY WM_USER+1
#define ID_SHL_ICON 1
    switch( message )  {
      case  WM_USER_TRY:
        if( lParam == WM_RBUTTONDOWN ) { // アイコン上で右クリック
          ::GetCursorPos( &point );
          ::SetForegroundWindow( hWnd );
          ::TrackPopupMenu( hMenu, 
              TPM_BOTTOMALIGN | TPM_LEFTALIGN | TPM_RIGHTBUTTON, 
              point.x, point.y, 0, hWnd, NULL );//メニューを表示する
        }
        break;
    }


newではデフォルトでは例外は発生しない [New'97.6.10]
newでメモリ不足が発生したとき、デフォルトでは例外は発生せず、0(NULL)が帰ってくる。
VC++のヘルプで「new」とか「_set_new_handler」を参照のこと。


リムーバブルメディアがFDかを判断する [Update'00.1.19]
1.メディアタイプ情報を取得する。
(1)WindowsNTの場合
IOCTL_DISK_GET_MEDIA_TYPESを指定してDeviceIoControlを発行する。

    DISK_GEOMETRY SupportedGeometry[20];
    DWORD SupportedGeometryCount;
 
    HANDLE hDisk = CreateFile("\\\\.\\A:", 0, FILE_SHARE_READ,
                   NULL,OPEN_ALWAYS,0,NULL);
    DeviceIoControl(hDisk,
          IOCTL_DISK_GET_MEDIA_TYPES,
          NULL,0,
          SupportedGeometry,sizeof(SupportedGeometry),
          &ReturnedByteCount,
          NULL)
  //Geometry[ ].MediaTypeで判断
   SupportedGeometryCount = ReturnedByteCount /  sizeof(DISK_GEOMETRY);
   for (i=0;i<SupportedGeometryCount ;i+;) {//そのドライブが支援しているメディアタイプ個数
     switch ( Geometry[i].MediaType ) {
        case F5_1Pt2_512:
           MediaType = "5.25, 1.2MB,  512 bytes/sector";
           break;
        case F3_1Pt44_512:
           MediaType = "3.5,  1.44MB, 512 bytes/sector";
           break;
        case F3_2Pt88_512:
           MediaType = "3.5,  2.88MB, 512 bytes/sector";
           break;
        case F3_20Pt8_512:
           MediaType = "3.5,  20.8MB, 512   bytes/sector";
           break;
        case F3_720_512:
           MediaType = "3.5,  720KB,  512 bytes/sector";
           break;
        case F5_360_512:
           MediaType = "5.25, 360KB,  512 bytes/sector";
           break;
        case F5_320_512:
           MediaType = "5.25, 320KB,  512 bytes/sector";
           break;
        case F5_320_1024:
           MediaType = "5.25, 320KB,  1024 bytes/sector";
           break;
        case F5_180_512:
           MediaType = "5.25, 180KB,  512 bytes/sector";
           break;
        case F5_160_512:
           MediaType = "5.25, 160KB,  512  bytes/sector";
           break;
        case RemovableMedia:
           MediaType = "Removable media other than floppy";
           break;
        case FixedMedia:
           MediaType = "Fixed hard disk media";
           break;
        default:
           MediaType = "Unknown";
           break;
     }
   }
   CloseHandle(hDisk);
詳細は、VCのヘルプで「Getting Floppy Drive Information」を探して見てください。
(2)Windows95の場合
VWIN32_DIOC_DOS_IOCTLを指定してDeviceIoControlを発行する。(int 21h ファンクション440Dh 60h)
#define VWIN32_DIOC_DOS_IOCTL 1 
typedef struct _DEVIOCTL_REGISTERS { 
    DWORD reg_EBX; 
    DWORD reg_EDX; 
    DWORD reg_ECX; 
    DWORD reg_EAX; 
    DWORD reg_EDI; 
    DWORD reg_ESI; 
    DWORD reg_Flags; 
} DEVIOCTL_REGISTERS, *PDEVIOCTL_REGISTERS; 
//int 21h 440Dh 60hのファンクションを使用して取得する。
    DEVIOCTL_REGISTERS reg; 
//構造体はMSDNでDEVICEPARAMS,EA_DEVICEPARAMETERSで内容を
//確認してください。
    DEVICEPARAMS deviceparams;
    EA_DEVICEPARAMETERS  exdeviceparams;
//ブロックデバイスのデバイスパラメタを返す(int 21h 440Dh 60h) 
    reg.reg_EAX = 0x440D;
    reg.reg_EBX = nDrive;  //1=a:,2=b:
//48h(OSR2の指定)で一度チェックして、NGなら08hで再度発行する。
//MSDN 440Dhで検索して60hの記述のままです。
    reg.reg_ECX = 0x4860;
    reg.reg_EDX = (DWORD) &exdeviceparams;
    hDevice = CreateFile("\\\\.\\vwin32", 
        GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, 
        (LPSECURITY_ATTRIBUTES) NULL, OPEN_EXISTING, 
        FILE_ATTRIBUTE_NORMAL, (HANDLE) NULL); 
    fResult = DeviceIoControl(hDevice, VWIN32_DIOC_DOS_IOCTL, 
            preg, sizeof(*preg), preg, sizeof(*preg), &cb, 0); 
    if (!fResult) {                   //エラーならOSR2ではない
      reg.reg_EAX = 0x440D;
      reg.reg_EBX = nDrive;
      reg.reg_ECX = 0x0860;           //08hにして再発行
      reg.reg_EDX = (DWORD) &deviceparams;
      fResult = DeviceIoControl(hDevice, VWIN32_DIOC_DOS_IOCTL, 
            preg, sizeof(*preg), preg, sizeof(*preg), &cb, 0); 
      if (fResult) {
//deviceparams.bDevTypeで0,1,2,3,4,7,8ならFD
//この値が何に対応しているかは不明です
//MSDNの「How to Determine Drive Types in Windows」の
//記述のままです。(Windows 3.1のKBですが)
      }
    } else {
//exdeviceparams.bDevTypeで0,1,2,3,4,7,8ならFD
//この値が何に対応しているかは不明です
    }
    CloseHandle(hDevice);
VCのヘルプで「Calling DeviceIoControl on Windows 95」、MSDNで「How to Determine Drive Types in Windows」をクエリーで探して見てください。
追加('00.1.19 dioさんからの情報です。ありがとうございます)
MSDNの「HOWTO: Getting Floppy Drive Type Information」から、
0: // 5.25 360K floppy
1: // 5.25 1.2MB floppy
2: // 3.5  720K floppy
3: // 8" low-density floppy
4: // 8" high-density floppy
5: // hard drive
6: // tape drive
7: // 3.5  1.44MB floppy
8: // optical disk
9: // 3.5  2.88MB floppy
のようです。
2.ドライブに対するエクスプローラのアイコンの番号を取得してみる。


タイトルを変更する [New'97.5.31]
1.CWinApp::m_pszAppNameを変更してメッセージBOXのタイトルを変更する。
m_pszAppNameは文字列ポインタのため、新しいタイトルをCWinAppのメンバ変数で定義して、そのポインタを代入する。
2.SetWindowTextでCMainFrameのタイトルを変更する。


リアルモードのドライバを使用したCD−ROM等でのメモリマップドファイルの注意 [Update'97.6.10]
リアルモードのドライバがWindows95で拡張されたファイルの情報取得APIを 支援していないとき、4096BYTE以上をアクセスするとAPエラーとなる場合がある。 そのため、例外処理をする必要がある。
(ISO 9660形式のVIDEO CDをパラレル接続のSCSI CD/SoundBlaster経由のCD参照で発生した)


非矩形ウィンドウを作る [New'97.5.31]
::SetWindowRgnでウィンドウの領域を指定する。


256色でのビットマップの表示 [New'97.5.31]
1.コンポーネントギャラリーでパレットサポートを挿入する。
2.WM_QUERYNEWPALETTE,WM_PALETTECHANGED[hWndが自分のウィンドウでないとき]
(問題があればWM_ACTIVATEAPP[自分がアクティブになったとき],WM_PAINTも)でRealizePaletteを行なう。
また、RealizePaletteの戻り値が0でないときは、InvalidateRectで再表示を行なう。(WM_PAINT以外)


256色のビットマップリソースの扱い [New'97.5.31]
LoadResourceで直接参照する(LoadBitmapでは16色しか対応していない)
VC++ 4.0のヘルプで「Retrieving Palette Information from a Bitmap Resource」を参照のこと


既に起動しているAPを終了させる。

		bret=::PostMessage(hWnd,WM_SYSCOMMAND,SC_CLOSE,0L);
注意:終了させようとしているAPがメッセージBOXやダイアログを表示しているときは、
まず、メッセージBOX,ダイアログを閉じる必要がある。メインウィンドウに対して終了要求を行うと、
そのAPでアプリケーションエラーが発生する。


EXEのバージョンリソースを指定する

1.リソースのバージョン情報を変更する。
2.エクスプローラでEXEのプロパティでバージョン情報を確認する。


EXEのアイコンを指定する リソースのアイコンの指定で 16x16 ,32x32共に変更する。
16x16のアイコンを変更しないとエクスプローラの小さいアイコン・詳細表示のときMFCのアイコンが表示される。


カーソルを時計にする
1.時計にする。
(1)AfxGetApp()->DoWaitCursor(1);
2.元に戻す。
(1)AfxGetApp()->DoWaitCursor(-1);


ダイアログのアイテムの内容の設定、取得
1.初期値を入れる。
(1)ClassWizardでアイテムにメンバ変数を割り付ける。
(2)DoModal()を呼び出す前にメンバ変数に値を代入する。
2.設定値を参照する。
(1)OnOKを定義する。
(2)CDialog::OnOK()を先に呼んでからメンバ変数を参照する。(CDialog::OnOK()を呼ばないとメンバ変数に値が代入されません)


ダイアログベースアプリケーションのアイコンの指定 (1)16bitの場合
VC++ 1.5 MFCでダイアログベースのAPを作る場合はダイアログのクラスが#32770固定
であるために、SetClassWordでアイコンを指定すると他のダイアログベースのAP
(Windowsセットアップ等)とアイコンが同じになってしまいます。
これを回避するためには、#32770からクラスをサブクラスさせかつリソースファイルにCLASS
指定をします。(MSDN MSJ '95/5 Windows Q&A参考)

リソースファイル:
ICON_MYAPPLI DIALOG 54, 48, 300, 140
STYLE WS_OVERLAPPED | WS_VISIBLE | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX
CLASS "ICON_MYAPPLI" //<---------------これが必要
CAPTION "XXXXXX"

ソース:

    if ( !GetClassInfo( 0, MAKEINTRESOURCE(32770), &wndclass ) )
        return 0;
    wndclass.hInstance = HInstance;
    wndclass.hIcon = LoadIcon(HInstance,"ICON_MYAPPLI");
    wndclass.lpszClassName = "ICON_MYAPPLI"; //<---リソースファイルのCLASSと合わせる
    if ( !RegisterClass(&wndclass) )
        return 0;
(2)32bitの場合
SetIconで指定する。(?)


タイトルに文書名(Untitled-)を表示しなくする

BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs)
{
	// TODO: この位置で CREATESTRUCT cs を修正して、Window クラスやスタイルを
	//       修正してください。
    	cs.style ^= FWS_ADDTOTITLE;
	return CFrameWnd::PreCreateWindow(cs);
}


タイトルをプロジェクト名と違うものにする
(1)プロジェクトワークスペースを新規作成するときMFC AppWizard ステップ 4/6で高度な設定で メインフレームのキャプション を書き換える。
(2)リソースファイルのStringTableの IDR_MAINFRAME AFX_IDS_APP_TITLE を書き換える。


メニューバーをなくす [Update'97.11.25]

BOOL CMainFrame::OnCreateClient(LPCREATESTRUCT lpcs, CCreateContext* pContext) 
{
	// TODO: この位置に固有の処理を追加するか、または基本クラスを呼び出してください
	SetMenu(NULL);
	BOOL bret=CFrameWnd::OnCreateClient(lpcs, pContext);
	return bret;
}


ウィンドウのリサイズ時に最小サイズを設定する

void CMainFrame::OnGetMinMaxInfo(MINMAXINFO FAR* lpMMI) 
{
        // TODO: この位置にメッセージ ハンドラ用のコードを追加するかまたはデフォルトの処理を呼び出してください
        CFrameWnd::OnGetMinMaxInfo(lpMMI);
//必ずデフォルトの処理を先に行う
        lpMMI->ptMinTrackSize.x=最小の幅;
        lpMMI->ptMinTrackSize.y=最小の高さ;
        lpMMI->ptMaxTrackSize.x=最大の幅;
        lpMMI->ptMaxTrackSize.y=最大の高さ;
}


二重起動の抑止

BOOL CXXXXApp::InitInstance()
{
	//* プログラムの複数起動抑止
	HWND hWndCap,hWndPopup;
	CString strCaption;
	HANDLE hPrevMutex = OpenMutex(MUTEX_ALL_ACCESS,FALSE,_T("h_XXXX_PrevInstance"));//プログラムで一意的な文字列
	if(hPrevMutex)		//* もし、オープンできれば以前のアプリケーションが起動している
	{
		CloseHandle(hPrevMutex);				//* クローズ
		strCaption.LoadString(AFX_IDS_APP_TITLE);
		hWndCap = FindWindow(NULL,strCaption);			//* APのハンドル取得
		if( hWndCap != NULL ){
			//* アクティブ化
		}
		return FALSE;						//* 終了
	}
	hExeCheckMutex = CreateMutex(FALSE,0,"h_XXXX_PrevInstance");//* 複数起動確認用ミューテックス作成
	//以下省略
	return TRUE;
}
int CXXXXApp::ExitInstance()
{
    ReleaseMutex(hExeCheckMutex);					//* Mutexを開放
return CWinApp::ExitInstance(); }


システムメニューにメニューを追加する

BOOL CMainFrame::OnCreateClient(LPCREATESTRUCT lpcs, CCreateContext* pContext) 
{
	// TODO: この位置に固有の処理を追加するか、または基本クラスを呼び出してください
	CMenu *sysmenu=GetSystemMenu(FALSE);
	sysmenu->AppendMenu(MF_SEPARATOR);
	sysmenu->AppendMenu(MF_STRING,ID_APP_ABOUT,_T("バージョン情報(&A)..."));
	bret=CFrameWnd::OnCreateClient(lpcs, pContext);
	return bret;
}
void CMainFrame::OnSysCommand(UINT nID, LPARAM lParam) 
{
	// TODO: この位置にメッセージ ハンドラ用のコードを追加してください
	if (nID==ID_APP_ABOUT)
		OnAppAbout();
	else
		CFrameWnd::OnSysCommand(nID,lParam);
}


Docと関係なしにエクスプローラからDropされたファイル名を読み込む [Update'98.6.28]

BOOL CXXXXApp::InitInstance()
{
        //途中省略
	// ドラッグ/ドロップ オープンを許可します
	m_pMainWnd->DragAcceptFiles();
	return TRUE;
}

void CMainFrame::OnDropFiles(HDROP hDropInfo) 
{
	// TODO: この位置にメッセージ ハンドラ用のコードを追加するかまたはデフォルトの処理を呼び出してください
	UINT filecnt;
	UINT usize;
	UINT i;
	char	buf[MAX_PATH+1];
	int	pos;
	CXXXXView	*lview=(CXXXXView *)GetActiveView();

	filecnt=::DragQueryFile(hDropInfo,0xffffffff,buf,sizeof(buf)-1);//Dropされたファイル数を取得
	for (i=0;i<filecnt;i++) {
		usize=::DragQueryFile(hDropInfo,i,buf,sizeof(buf)-1);//Dropされたファイル名を取得
		//ファイル名を保存する処理
	}
        ::DragFinish(hDropInfo);
//	CFrameWnd::OnDropFiles(hDropInfo);//これを実行するとドキュメント名に反映される
}


一つのソースで英語対応を行う [Update'97.6.28]
1.文字列を全てリソースファイルのStringTableに登録し、リソースを参照するようにする。
2.リソースファイルのStringTableでStringTableをコピーの複写でコピーしそのとき、言語を英語(アメリカ)と指定する。
3.リソースファイルのダイアログ、バージョン情報、メニューをコピーの複写でコピーしそのとき、言語を英語(アメリカ)と指定する。 EXEを1つの言語のみ専用にするときは 条件を日本語と英語で異なるマクロを指定する。(例 日本語:_LANG_JP、英語:_LANG_US)
このとき、クラスウィザードでボタン等へのメンバ変数割り当ては、マクロを指定する前に行う。
(クラスウィザードに出てこなくなる。その場合は、一度マクロの指定を解除する。)
4.プロジェクトの設定でリソースで言語を英語(U.S.)と指定する。また、3.で指定したマクロ名を定義する。
5. EXEを1つの言語のみ専用にするときは (たとえば英語)ビルドするときに、StringTableのデフォルトを日本語以外にし、ビルド後日本語に戻す。 日本語以外にしたときは、StringTableを開かず、また絶対に保存しないこと。(日本語が全て?に化けます)


CListViewでカラムにアイコンを表示する [Update'97.11.25]
1.CListViewから派生クラスを作成する
2.ClistViewのCreateで LVS_OWNERDRAWFIXED を指定する。

int CXXXXListView::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
	lpCreateStruct->style |= LVS_REPORT | LVS_OWNERDRAWFIXED | LVS_NOSORTHEADER;	//.レポートビューを指定
	if (CListView::OnCreate(lpCreateStruct) == -1){				//.リストビューのOnCreateをコール
		return -1;
	}
	return 0;
}
void CXXXXListView::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)
{
	CListCtrl& ctlList = (CListCtrl&) GetListCtrl();			//.リストへの参照取得
	CDC* pDC = CDC::FromHandle(lpDrawItemStruct->hDC);
//途中省略
	return;
}