VC++での開発におけるFAQ[詳細]Update'97.11.26


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: Q172276BUG: CToolTipCtrl Does Not Display Text After Installing VS SP1
を参考にして、ツールヒントを出したいボタン等の親ウィンドウのクラスに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);
オーナードローのチェックボタン・ラジオボタンの作成 [New'97.9.4] 1.CButtonの派生クラスを作成する。(Create時にBS_OWNERDRAW|BS_PUSHBUTTONを指定する。)
2.SetCheck(),GetCheck()をvirtualでオーバーライドする。またチェック状態をメンバ変数に設定する。
3.BM_SETCHECKメッセージをON_MESSEAGEでメッセージをマップし、メンバ変数を更新する。
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以外) [New'97.8.28] 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のとき
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'97.8.13] (1)CreateView()で作成する。
(2)Viewのポインタを作成して、ポインタを用いてCreateを行う。 このようにしないと、CXXXViewのコンストラクタがPublicでないといって コンパイルエラーになります。また、強引にPublicにすると 実行時にエラーとなります。
     CRuntimeClass   *pViewClass=CXXXView;
     CXXXView * pNewView = (CXXXView *) pViewClass->CreateObject();
//   CXXXView *pNewView= new CXXXView;//newでも同様
     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かを判断する [New'97.6.5] 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」をクエリーで探して見てください。
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されたファイル名を読み込む
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		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;
}

戻る

All Rights Reserved.Copyright © 1997,K.Horishima
ホームページに記述してある内容の無断転載は禁止します。 転載する場合は必ず連絡を下さい。