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を開放 |
システムメニューにメニューを追加する | 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 |
一つのソースで英語対応を行う [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; } |