自分用の偏ったKnow-how集。VC++編(一部例外あり)。
スタイルにWS_EX_TOOLWINDOWを指定したウィンドウを、アプリケーションのMainFrameにする。
ウィンドウの形のリージョンを作成し、CWin::SetWindowRgn()で設定する。
ビットマップを作成し、この関数を呼べばいい。与えるビットマップの左上角の色が透明色の扱いになる。
HRGN ::CreateRgn(HBITMAP bitmap) { BITMAP bm; BITMAPINFOHEADER bi; HDC hDC; HRGN hRgn = NULL; LPRECT lpRect; LPRGNDATA lpRgnData; LPCOLORREF lpScanData; int x, y, z, len, nRect = 0; COLORREF transcolor; hDC = CreateCompatibleDC( NULL ); if ( hDC ) { GetObject( bitmap, sizeof(BITMAP), &bm ); lpRgnData = (LPRGNDATA) new BYTE[sizeof(RGNDATAHEADER) + sizeof(RECT) * bm.bmWidth * bm.bmHeight]; if ( lpRgnData ) { lpRect = (LPRECT) lpRgnData->Buffer; lpScanData = new COLORREF[bm.bmWidth]; if ( lpScanData ) { ZeroMemory( &bi, sizeof(BITMAPINFOHEADER) ); bi.biSize = sizeof(BITMAPINFOHEADER); bi.biWidth = bm.bmWidth; bi.biHeight = bm.bmHeight; bi.biPlanes = 1; bi.biBitCount = 32; bi.biCompression = BI_RGB; bool first = true; for( y = 1; y <= bm.bmHeight; y++ ) { GetDIBits( hDC, bitmap, bm.bmHeight - y, 1, lpScanData, (LPBITMAPINFO) &bi, DIB_RGB_COLORS ); for( x = 0; x < bm.bmWidth; x++ ) { if (first) { transcolor = lpScanData[x]; first = false; } if ( lpScanData[x] != transcolor ) { for( len = 1, z = x++; x < bm.bmWidth; x++, len++ ) { if ( lpScanData[x] == transcolor ) { break; } } lpRect->left = z; lpRect->top = y - 1; lpRect->right = z + len; lpRect->bottom = y; lpRect++; nRect++; } } } lpRgnData->rdh.dwSize = sizeof(RGNDATAHEADER); lpRgnData->rdh.iType = RDH_RECTANGLES; lpRgnData->rdh.nRgnSize = sizeof(RGNDATAHEADER) + sizeof(RECT) * nRect; lpRgnData->rdh.nCount = nRect; lpRgnData->rdh.rcBound.left = lpRgnData->rdh.rcBound.top = 0; lpRgnData->rdh.rcBound.right = bm.bmWidth; lpRgnData->rdh.rcBound.bottom = bm.bmHeight; hRgn = ExtCreateRegion( NULL, lpRgnData->rdh.nRgnSize, lpRgnData ); delete lpScanData; } delete lpRgnData; } DeleteDC( hDC ); } return hRgn; }
old: for( y = 1; y < bm.bmHeight; y++ )
new: for( y = 1; y <= bm.bmHeight; y++ )
こんなページ存在自体を忘れていたのですが、ここをご覧になったFさんとおっしゃる方から上記の間違いの指摘をいただきました。訂正させていただきます。ありがとうございます。(2003/11/29追記)
VC++6でAppWizardを使ってMFC Applicationを作ると、CYourApplicationApp::InitInstance()内に以下のようなコードが挿入される。
// DDE、file open など標準のシェル コマンドのコマンドラインを解析します。 CCommandLineInfo cmdInfo; ParseCommandLine(cmdInfo); // コマンドラインでディスパッチ コマンドを指定します。 if (!ProcessShellCommand(cmdInfo)) return FALSE;
このコードがコマンドラインを解析して、パラメータで指定されたファイルを開いたり、印刷したりする。 ところが、アプリケーションの種類をダイアログベースや"ドキュメント/ビューアーキテクチャのサポート"をオフにして作成すると、このコードが生成されない。で、どうするかというと、CMainApp::m_lpCmdLineというメンバ変数を直に参照する。これは LPTSTR 型のパブリック変数で、コマンドラインの引数がそのまま入っている。
メンバ宣言
// アイコン情報 NOTIFYICONDATA m_icon;
OnInitDialog()などで..
// アイコン情報初期化 ZeroMemory(&m_icon, sizeof(NOTIFYICONDATA)); // アイコンのファイルサイズ m_icon.cbSize = sizeof(NOTIFYICONDATA); // アイコンの識別ID m_icon.uID = 1; // イベントと関連づけるウインドウ m_icon.hWnd = GetSafeHwnd(); // アイコンの設定 m_icon.uFlags = NIF_MESSAGE | NIF_ICON | NIF_TIP; // アプリケーションのアイコン m_icon.hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME); // バルーンの文字列 lstrcpy(nIcon.szTip, (::AfxGetAppName()); // タスクトレイに表示 ::Shell_NotifyIcon( NIM_ADD, &m_icon);
OnInitDialog()などで..
// タスクトレイのアイコンを削除 Shell_NotifyIcon( NIM_DELETE, &m_icon); // タスクトレイを更新する PostMessage(WM_NULL, 0, 0);
::LoadImage()を使って標準(32x32)ではないサイズのアイコンをロードする。
m_icon.hIcon = (HICON)::LoadImage( ::AfxGetInstanceHandle(), MAKEINTRESOURCE(IDR_MAINFRAME), IMAGE_ICON, 16, // desired width 16, // desired height LR_DEFAULTCOLOR);
ヘッダのDECLARE_MESSAGE_MAPの前に..
afx_msg LRESULT OnNotifyTrayicon(WPARAM, LPARAM);
本体のMESSAGE_MAPの前に..
#define NOTIFY_TRAYICON (WM_USER + 1)
本体のMESSAGE_MAP内で..
ON_MESSAGE(NOTIFY_TRAYICON, OnNotifyTrayicon)
アイコンをShell_NotifyIconする前に..
// アイコンに関するイベントの識別子 m_icon.uCallbackMessage = NOTIFY_TRAYICON;
本体にポップアップを表示する関数を追加
LRESULT CYourApp::OnNotifyTrayicon(WPARAM wparam, LPARAM lparam) { if(lparam == WM_RBUTTONDOWN) { CPoint point; ::GetCursorPos(&point); SetForegroundWindow(); m_popup.GetSubMenu(0)->TrackPopupMenu(TPM_LEFTALIGN | TPM_LEFTBUTTON, point.x - 2, point.y - 2, this); } return 0; }
Internet Explorer | -kをつける。 |
---|---|
Netscape Navigator | -skをつける。すでにNavigatorが起動していると効果がない。 |
HRESULT CreateLink(LPCSTR lpszPathObj, LPSTR lpszPathLink, LPSTR lpszDesc) { HRESULT hres; IShellLink* psl; // Get a pointer to the IShellLink interface. hres = CoCreateInstance(&CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, &IID_IShellLink, &psl); if (SUCCEEDED(hres)) { IPersistFile* ppf; // Set the path to the shortcut target, and add the // description. psl->lpVtbl->SetPath(psl, lpszPathObj); psl->lpVtbl->SetDescription(psl, lpszDesc); // Query IShellLink for the IPersistFile interface for saving the // shortcut in persistent storage. hres = psl->lpVtbl->QueryInterface(psl, &IID_IPersistFile, &ppf); if (SUCCEEDED(hres)) { WORD wsz[MAX_PATH]; // Ensure that the string is ANSI. MultiByteToWideChar(CP_ACP, 0, lpszPathLink, -1, wsz, MAX_PATH); // Save the link by calling IPersistFile::Save. hres = ppf->lpVtbl->Save(ppf, wsz, TRUE); ppf->lpVtbl->Release(ppf); } psl->lpVtbl->Release(psl); } return hres; }
InitInstance()で.. m_hEvent = ::CreateEvent(NULL, FALSE, FALSE,_T("UNIQUE ID")); if (m_hEvent == NULL) { return FALSE; } if (::GetLastError() == ERROR_ALREADY_EXISTS) { ::CloseHandle(m_hEvent); return FALSE; } ExitInstance()で.. ::CloseHandle(m_hEvent);
そういえば「ワーニング」ってバカっぽいって話がどこかであったな。でもまあいいや。バカだし。
#pragma warning( disable : 4507 )
警告の指定子 | 意味 |
---|---|
once | 指定したメッセージは 1 回だけしか表示しません。 |
default | 指定したメッセージの動作はコンパイラのデフォルトと同じです。 |
1,2,3,4 | 指定した警告メッセージに指定の警告レベルを割り当てます。 |
disable | 指定した警告メッセージの出力を行いません。 |
error | 指定した警告メッセージをエラーとして出力します。 |
任意の警告番号
if (CAtisViewerApp::GetComCtl32Version() >= COMCTL32_471) {
OSVERSIONINFO Info; Info.dwOSVersionInfoSize = sizeof Info; GetVersionEx( &Info );
CString::LoadStringを使う
BOOL CCLTVView::OnEraseBkgnd(CDC* pDC) { CBrush br(GetSysColor(COLOR_3DSHADOW)); FillOutsideRect(pDC, &br); return TRUE; }
COLORREF ::GetSysColor(id);
システムメニューの「閉じる」を無効にすれば、連動してウィンドウ右上の閉じるボタン(×)も無効に。
CMenu *menu=CWnd::GetSystemMenu(FALSE); menu->EnableMenuItem(SC_CLOSE,MF_BYCOMMAND|MF_GRAYED);
以下のようにすれば、有効に戻すことも可能。
CMenu *menu=CWnd::GetSystemMenu(FALSE); menu->EnableMenuItem(SC_CLOSE,MF_BYCOMMAND|MF_ENABLED);
ほかの[_](最小化=SC_MINIMIZE)や[□](最大化=SC_MAXIMIZE)についても同様。
リソースエディタで適当なダイアログバーを作成する。
CMainFrameにメンバ変数を追加する
protected: CDialogBar m_wndDialogBar;
CMainFrame::OnCreate()内でダイアログバーを生成する
EnableDocking(CBRS_ALIGN_ANY); // すでに指定されていれば不要 if (!m_wndDialogBar.Create(this,IDD_DIALOGBAR,CBRS_TOP,IDD_DIALOGBAR)) { TRACE0("Failed to create status bar\n"); return -1; // 作成に失敗 } m_wndDialogBar.EnableDocking(CBRS_ALIGN_TOP | CBRS_ALIGN_BOTTOM); DockControlBar(&m_wndDialogBar);
CMainFrame.cppの先頭にあるメッセージマップにエントリーする
ON_BN_CLICKEDとかは各コントロールクラスの説明に記載されている。 IDC_EDIT1とかはダイアログバーに貼り付けたコントロールのID。 ハンドラ名(OnBnClickedとか)は任意。
BEGIN_MESSAGE_MAP(CMainFrame, CMDIFrameWnd) //{{AFX_MSG_MAP(CMainFrame) ON_WM_CREATE() ON_WM_KEYDOWN() ON_WM_LBUTTONDOWN() //}}AFX_MSG_MAP ON_EN_CHANGE(IDC_EDIT1,OnEnChange) // これはエディットの変更 ON_BN_CLICKED(IDC_BUTTON1,OnBnClicked) //これはボタンクリック END_MESSAGE_MAP()
CMainFrame.hの末尾にあるテーブルにメッセージハンドラの宣言を追加する
// 生成されたメッセージ マップ関数 protected: //{{AFX_MSG(CMainFrame) afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct); afx_msg void OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags); afx_msg void OnLButtonDown(UINT nFlags, CPoint point); //}}AFX_MSG afx_msg void OnEnChange(); // ←これ afx_msg void OnBnClicked(); // ←これも DECLARE_MESSAGE_MAP()
ハンドラをCMainFrame.cpp内に記述する
void CMainFrame::OnEnChange() { CEdit *edit1 = (CEdit *)m_wndDialogBar.GetDlgItem(IDC_EDIT1); CString edit1Value; edit1->GetWindowText(edit1Value); SetWindowMessage(edit1Value); // ... } void CMainFrame::OnBnClicked() { // ... }
グローバルメモリのハンドラを用意。
// グローバルメモリ IMalloc* g_pMalloc;
コンストラクタなどで初期化。
CoGetMalloc(1,>m_pMalloc);
デストラクタなどで開放。
g_pMalloc->Release();
こういうコードを用意する。
// !危険(リエントラント未対応部分) _TCHAR shared_path_block[_MAX_PATH]; // コールバック関数 int WINAPI BrowseCallbackProc(HWND hwnd,UINT uMsg,LPARAM lParam,LPARAM lpData) { switch (uMsg) { case BFFM_INITIALIZED: // shared_path_blockを反映する SendMessage(hwnd, BFFM_SETSELECTION,TRUE,(LPARAM)shared_path_block); break; } return 0; }
こういう関数を呼ぶ。
void CYourApp::ShowPathDialog(CString &strPath, UINT nCaptionID) { BROWSEINFO bi; LPITEMIDLIST pidlMyComp; LPITEMIDLIST pidlBrowse; // PIDL確保 if (!SUCCEEDED(SHGetSpecialFolderLocation( AfxGetMainWnd()->GetSafeHwnd(), CSIDL_DESKTOP, &pidlMyComp))) { // 失敗 return; } if (strPath.IsEmpty()) { // カレントディレクトリ取得 _TCHAR path[_MAX_PATH]; _tgetcwd(path, _MAX_PATH); strncpy(shared_path_block, path, _MAX_PATH); } else { strncpy(shared_path_block, strPath, _MAX_PATH); } // BROWSEINFO構造体作成 bi.hwndOwner = AfxGetMainWnd()->GetSafeHwnd(); bi.pidlRoot = pidlMyComp; bi.pszDisplayName = shared_path_block; CString title((LPCSTR)nCaptionID); bi.lpszTitle = title; bi.ulFlags = 0; bi.lpfn = BrowseCallbackProc; // コールバックしなければNULL(bi.lpfn = NULL;) bi.lParam = 0; // ダイアログ表示 pidlBrowse = SHBrowseForFolder(&bi); if (pidlBrowse != NULL) { // パスの取得 LPTSTR p = strPath.GetBuffer(_MAX_PATH); SHGetPathFromIDList(pidlBrowse, p); strPath.ReleaseBuffer(); // PIDL解放 g_pMalloc->Free(pidlBrowse); } // メモリ解放 g_pMalloc->Free(pidlMyComp); }
簡単。でもたぶん昔の環境だと動かない。
::ShellExecute(m_hWnd, "open", "septigram\\index.html", NULL, "C:\\pub", SW_SHOW);
char fullpath[_MAX_PATH]; ::GetModuleFileName(NULL, fullpath, sizeof(fullpath)); char *p = ::strrchr(fullpath, '\\'); if (p != NULL) { *(p + 1) = '\0'; }