操作 | イベントハンドラ |
Enter | OnOK() |
Esc | OnCancel() |
Alt+F4 |
リソースファイル(*.rc)内でコントロールが定義される順番が、そのままタブオーダとして解釈される。
異なるコントロールを連携させて使用する場合がある。連携させるには、タブオーダを連続させる必要がある。
グループ化したいラジオボタンのタブオーダを連続させ、先頭のラジオボタンのプロパディでグループをTRUEにする。
エディットボックスのタブオーダをスピンコントロールの直前の値にすることで、そのエディットボックスをスピンコントロールのバディコントロールとして設定することができる。
この場合、値の取得やコントロールの操作は全てCSpinButtonCtrl変数に対して行い、CEditは使用する必要がない。
複数のコントロールが重なっている場合、タブオーダの小さいコントロールが優先。
グループボックスコントロールを使用する際などは注意。
クラスウィザードに目的のメッセージが表示されていない場合、表示内容がフィルタリングされている可能性がある。 「詳細設定オプション」で「メッセージフィルタ」を変更することで、目的に合ったメッセージを表示できる。
例)ダイアログクラスで初期状態ではフィルタリングされているメッセージ。
ファイルのドラッグ&ドロップ
ウィンドウのアクティブ/非アクティブ
CWnd::SetFocus() ではなく、CDialog::GotoDlgCtrl() を用いる。
CWnd::SetFocus()を用いてもフォーカスは移動するが、画面描画上は移動していないように見えてしまうことがある。
1 2 3 |
|
ダイアログ表示直後に指定コントロールへフォーカス設定するには、OnInitDialog() で GotoDlgCtrl() を呼び出した後、OnInitDialog() の戻り値を FALSE にする必要がある。
コード上でフォントの設定をすると直ることがある。
通常、ツールバーはSDIかMDIのアプリケーションにしか用意されないが、以下の手順でダイアログにも使用できる。
※ダイアログに配置するコントロールの位置は、ツールバーの範囲を考慮する必要がある。また、ドッキング可能にすることはできない。
<ツールバーの作成>
1 |
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
|
クラスウィザードは対応していないため、自分で定義する必要がある。(以下、ボタンのIDを ID_XXXとする)
1 2 3 4 5 6 7 8 |
|
1 2 3 4 5 6 7 |
|
1つのイベントハンドラと対応する1つのリソースIDを用意し、そのIDを以下のような複数のリソースで共用することができる。同一IDを持っている処理は同じイベントハンドラが呼び出される。
1つのイベントハンドラに対して複数のIDをメッセージマップに登録することができる。
例えば、2つのラジオボタンのどちらをクリックしたときも同じ処理を行いたい場合は、両方のクリックイベントに対して同じイベントハンドラ(関数)を指定する。
アプリケーションクラスのメッセージ処理を修正することで、無効化できる。
1 2 3 4 5 6 7 |
|
アプリケーションのCWinAppを継承したクラスのExitInstance()をオーバーライドし、戻り値を設定すればよい。
通常、ウィンドウプロシージャやダイアログプロシージャの戻り値は、メッセージを処理したか否かをBOOL型で返すが、WM_INITDIALOGだけは戻り値に特別な意味がある。
TRUE を返すと、タブオーダーが一番若いコントロールに自動的にフォーカスが当てられる。
FALSE を返すと、何も行われない。(自分でフォーカスを当てるコードを書く必要がある。)
ダイアログ生成時に明示的にあるコントロールにフォーカスを当てたい場合や、ダイアログを非表示で生成しておき後で表示するような場合は、FALSEを返す必要がある。(後者のケースは、ダイアログ生成時にフォーカスが奪われてしまうのを防ぐため)
CDialogBarクラスにはOnInitDialog()が用意されていないため、自分でON_MESSAGE()でWM_INITDIALOGをハンドルする必要がある。
参考:http://support.microsoft.com/kb/185672/ja
MFCで作られたダイアログは、自動的に中央に移動する機能が組み込まれている。
通常、OnInitDialog()でMoveWindow()等を呼び出し、明示的に表示位置を移動している場合は中央に移動することはないが、ある条件を満たすと中央に移動させられてしまう。
例として、(0, 0)の位置に移動しようとしたときに現象が発生する。
以下の条件のいずれかを満たしている場合は中央移動は行われない(一部抜粋)
詳細は関連するMFCの関数を参照。
ダイアログエディタ上で、コンボボックスの右端の▼マークをクリックすると、ドロップダウンリストのサイズ変更状態になる。
リストビューのヘッダに対して以下の定数を設定する。
HDF_SORTUP | 昇順(▲) |
HDF_SORTDOWN | 降順(▼) |
※この機能はXP以降の機能なので、VC6.0(1998年)時点では未対応。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
|
ツリービューコントロールを全展開する関数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
|
スピンコントロールの値が変更された場合のイベントハンドラは、バディされたエディットコントロールのEN_CHANGEイベントで行う。
しかし、スピンコントロールとエディットコントロールを自動でバディする設定の場合は、OnInitDialog()よりも前に自動的にバディされたタイミングでEN_CHANGEイベントが発生してしまう。すると、まだ用意されていないコントロールにアクセスされてしまい、実行時エラーになってしまうことがある。
対処策としては、自分でエディットコントロールにバディするコードを書くか、フラグを用意してOnInitDialog()コール前ならEN_CHANGEイベントハンドラで何も処理しない設計にしておく。
リッチエディットコントロール(CRichEditCtrl)を使用する場合は、通常のエディットコントロール(CEdit)と違って予め準備をしておく必要がある。
1 2 3 4 |
|
単語境界やワードラップ機能は、どのように文字列のワード区切りを判断しているかに依存する。
ワード区切りの方法を変更するには、以下のキーワードを調べる。(まだ試していない)
コントロールのプロパティの「通知」の有無の違いによって、イベントハンドラがコールされる順番を検証。
(CWnd::Create()でコントロールを作成する場合は、「SS_NOTFY」フラグに該当する。)
ActiveXコントロールを使用したMFCアプリケーションを作成すると、デフォルトの動作ではActiveXコントロールが登録されていないと何の表示も行われずに終了してしまう。
それだと、なぜアプリケーションが起動しなかったのかが分からないため、この方法を用いてエラーメッセージを表示するとよい。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
|
1 2 3 4 5 6 7 |
|
親ダイアログクラスの初期処理で、CWnd::SubclassDlgItem()を使用することで行う。
ClassWizardを使用して派生クラスの型のコントロール変数を作成することで行う。
派生クラスのヘッダやソースファイルがクラスウィザードに登録されていないと、画面上で変数の型として選択できないので注意。
その場合は、直接ヘッダファイル内の変数定義の型名を編集すればOK。
※サブクラス化とは、C++の「クラスの継承」のことではない。
既存のウィンドウプロシージャを、独自のウィンドウプロシージャに差し替えることを指す。
OnCreate()はコールされないため、初期処理を記述することはできない。
派生クラスでは、PreSubclassWindow()をオーバライドして、そこに初期処理を書く。
元のクラスが構築されて(OnCreate)、サブクラス化が行われるのであって、派生クラスが直接構築されるわけではない。
MFCを継承している場合は、クラスウィザードに派生クラスを認識させておく必要がある。
(認識されているかどうかは、クラスウィザードの「クラス名」に表示されるかどうかで判断できる)
認識されていない場合は、以下の操作ができない。
プロジェクト内でクラスを作成した場合は自動的に認識されるが、外部から持ってきたコードを用いる場合は、 一度clwファイルを削除してクラスウィザードを作り直すときに、ファイルを含める必要がある。
※ちなみに、MFC継承クラスをさらに継承した場合は上記作業を行っても不可。仕様上は問題なくイベントハンドラを実装できるはずなので、手動で行うしかない?
操作 | Win32API | MFC | |||
Set | Get | Set | Get | ||
ウィンドウ情報 | - | ::GetWindowInfo | - | CWnd::GetWindowInfo | |
親ウィンドウ | - | ::GetParent | - | CWnd::GetParent | |
関連ウィンドウ | - | ::GetWindow | - | CWnd::GetWindow | |
スタイル | ::SetWindowLong | ::GetWindowLong | CWnd::ModifyStyle | CWnd::GetStyle | |
拡張スタイル | CWnd::ModifyStyleEx | CWnd::GetExStyle | |||
インスタンスハンドル | - | - | |||
ウィンドウプロシージャ | - | - | |||
(特記) | 使用可否 | ::EnableWindow | ::IsWindowEnable | CWnd::EnableWindow | CWnd::IsWindowEnable |
表示状態 | ::ShowWindow | ::IsWindowVisible | CWnd::ShowWindow | CWnd::IsWindowVisible | |
ウィンドウクラス登録 | ::RegisterClassEx | - | - | - | |
ウィンドウクラス登録解除 | ::UnregisterClass | - | - | - | |
コントロールID | - | ::GetDlgCtrlID | CWnd::SetDlgCtrlID | CWnd::GetDlgCtrlID | |
ドラッグ&ドロップ許可 | ::DragAcceptFiles | - | CWnd::DragAcceptFiles | - | |
アクティブ | ::SetActiveWindow | ::GetActiveWindow | CWnd::SetActiveWindow | static CWnd::GetActiveWindow | |
位置 | スクリーン座標 | ::MoveWindow | ::GetWindowRect | CWnd::MoveWindow | CWnd::GetWindowRect |
クライアント座標 | - | ::GetClientRect | - | CWnd::GetClientRect | |
位置データ | ::SetWindowPlacement | ::GetWindowPlacement | CWnd::SetWindowPlacement | CWnd::GetWindowPlacement | |
Zレベル | ::SetForegroundWindow | ::GetForegroundWindow | CWnd::SetForegroundWindow | static CWnd::GetForegroundWindow | |
::SetWindowPos | - | CWnd::SetWindowPos | - | ||
中央へ移動 | - | - | CWnd::CenterWindow | - | |
キャプション | ::SetWindowText | ::GetWindowText | CWnd::SetWindowText | CWnd::GetWindowText | |
透明度 | ::SetLayeredWindowAttributes | ::GetLayeredWindowAttributes | CWnd:: SetLayeredWindowAttributes | CWnd:: GetLayeredWindowAttributes | |
フォント | - | - | CWnd::SetFont | CWnd::GetFont | |
操作 | 閉じる | ::DestroyWindow | - | CWnd::DestroyWindow | - |
最大化 | ::ShowWindow | ::IsZoomed | CWnd::ShowWindow | CWnd::IsZoomed | |
最小化 | ::ShowWindow ::CloseWindow | ::IsIconic | CWnd::ShowWindow CWnd::CloseWindow | CWnd::IsIconic | |
メッセージ送信(同期) | ::SendMessage | - | CWnd::SendMessage | - | |
メッセージ送信(非同期) | ::PostMessage | - | CWnd::PostMessage | - | |
再描画 | ::UpdateWindow | - | CWnd::UpdateWindow | - |
ウィンドウの矩形を計算し、::MoveWindow() で移動する。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
|
CWnd::CenterWindow() を使用する。
1 2 |
|
OSの設定(フォントやテーマ等)に依存する。
1 |
|
::AllocConsole(), ::FreeConsole()を用いる。
コンソールへの入出力をするためには、標準入出力を割り当てるか専用の関数でハンドルを取得する。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
|
CWnd::LockWindowUpdate() と CWnd::UnlockWindowUpdate() で、処理を挟み込む。
1 2 3 4 5 |
|
大きなツリービューへのアイテムの追加など、時間がかかる処理は描画更新を抑制することで、画面のチラつきを防止できる。
大きいアイコン(32x32)と小さいアイコン(16x16)の両方を用意してあるのに、小さいアイコンがうまく適用されないことがある。
その場合は、OnInitDialog() 等のアイコン設定処理で、小さいアイコン設定の処理をコメントアウトするとよい。
1 2 |
|
※正式な修正方法ではないかも。
取得の手順。
メニューの項目は、0から始まるインデックスで位置を指定する
サブメニュー内は、それぞれで0から始まるインデックスを持つ。
メニュー項目の取得は、MENUITEMINFO構造体を介して行う。
MENUITEMINFO::cbSize に構造体のサイズを設定し、必要なメンバ変数に対応したフラグを MENUITEMINFO::fMask に設定する。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
|
メニュー項目に変更を行っても自動的に描画更新されないため、明示的に描画更新する必要がある。
::DrawMenuBar()
CWnd::DrawMenuBar()
ウィンドウの描画更新を促すには、WM_PAINTを発行する必要がある。ただし、ウィンドウに直接WM_PAINTを送るのではなく、下記の手順を踏む必要がある。
1 2 3 |
|
ウィンドウの一部だけを再描画させる場合は、CWnd::InvalidateRect()の第一引数にNULLではなく、RECT*型の領域を渡す。
最前面ウィンドウを親に持つメッセージボックスを作成すればよい。
親ウィンドウは非表示にしておけば、メッセージボックスのみ表示される。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
|
ウィンドウの再表示を行う際、::ShowWindow()の第2引数に「SW_SHOWNORMAL」や「SW_RESTORE」を渡すだけでは、ウィンドウの状態(最小化、最大化)によって動作が異なってしまう。(ヘルプを読むと「SW_SHOWNORMAL」でよさそうだが。。)
以下のように場合分けをすることで解決できる。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
|
再描画のたびにウィンドウメッセージでアクティブ通知を行う。
1 2 3 4 5 6 7 |
|
ウィンドウメッセージの処理を行いたいがウィンドウの実体は必要無いというときは、メッセージ専用ウィンドウを利用することができる。
(ウィンドウ列挙等の対象からも外れる)
使用する場合は、予め下記の定数を設定しておく必要がある。
#define WINVER 0x0500 // 0x0500以上ならOK
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
|
1 2 3 4 5 |
|
自作のメッセージの定義は、以下の2通り。
自分でウィンドウプロシージャを定義する。
1 2 3 4 5 6 7 8 9 10 11 12 |
|
CWnd::PreTranslateMessage() をオーバーライドして、対応するメッセージフック処理を書く。
MFCにデフォルトで定義されているメッセージ処理を行わせない場合は、TRUE を返す。
1 2 3 |
|
「ALT+F」などのメッセージも、キー押下と解放のタイミングと組み合わせで実現可能。「PrntScrn」や「NumLock」も可能。
↓ WM_CLOSE
↓ WM_DESTROY
↓ WM_QUIT
ウィンドウにコマンドIDを付与した WM_COMMAND メッセージを送ることで実行できる。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
|
1 2 3 |
|
1 2 3 4 5 6 |
|
1 2 3 4 5 6 |
|
1 2 3 4 5 6 |
|
マウスドラッグやWin7のスナップ機能などによるウィンドウサイズの変更時に、ウィンドウサイズを制限する場合は、WM_GETMINMAXINFO をハンドルする。
※デフォルト拡張子は「.」を含まない。
ファイル選択ダイアログを使用していると、呼び出し元のアプリケーションごと強制終了してしまう現象が発生している。PCによって起きたり起きなかったりする。
AdobeReader7.0がインストールされていること。
現象は、あるアプリケーションでファイル選択ダイアログを立ち上げ(メモ帳の開くなど)、何かのファイル(フォルダでは起きない)にカーソルを合わせ、ツールチップを表示させる。
一度ファイル選択ダイアログを閉じて再度同じ操作をすると、ツールチップが表示される瞬間に強制終了される。
根本的な解決策は分かっていない。AdobeReader7.0が原因という話もあるが、アンインストールしても改善しなかった。
自作のアプリケーションであれば、ファイル選択ダイアログを起動する前に、CoInitialize()を呼ぶと落ちなくなる。ただし、CoInitialize() を使用するのであれば、対応する CoUninitialize() を忘れないこと。
既存のアプリケーション(メモ帳など)では、フォルダオプションでツールチップ表示機能をOFFにするしかない。
本当に原因なのかは未確認だが、ネットに pdfshell.dll が原因ではないかという記述を見つけた。下記の何れかに存在する。
→ (AdobeReaderインストールフォルダ)\ActiveX
→ C:\Program Files\Common Files\Adobe\Acrobat\ActiveX
Wwindowsプログラミングをする上で、文字列を「マルチバイト」と「ワイド文字」のどちらで扱うかに気をつける必要がある。
char型に格納して扱う。Asciiコードなどの半角英数字は1バイトだが、日本語等の全角文字は2バイトなので、2要素に分割して格納される。
wchar_t型に格納して扱う。1文字を常に2バイト(1つの数値)で扱う。
wchar_t型は、C言語では unsigned short に typedef されており、C++では予約語になっている。
Win32APIやMFCには、これらの文字セットの切り替えを容易にした仕組み(thunk)が用意されており、これに則ってプログラミングすることで、どちらの文字セットを使用するかをコンパイルスイッチで切り替えることができる。
サンク | マルチバイト文字(MBCS) | ワイド文字(Unicode) | |
文字 文字列 | _T('~') _T("~") | '~' "~" | L'~' L"~" |
変数型 | TCHAR | CHAR char | WCHAR wchar_t |
LPTSTR TCHAR* | LPSTR char* | LPWSTR wchar_t* | |
LPCTSTR const TCHAR* | LPCSTR const char* | LPCWSTR const wchar_t* | |
Win32API 関数(例) | MessageBox() | MessageBoxA() | MessageBoxW() |
Win32API 構造体(例) | OPENFILENAME | OPENFILENAMEA | OPENFILENAMEW |
MFC クラス(例) | CString/ CStringT(※VC6.0では未対応) | CStringA | CStringW |
分類 | サンク | マルチバイト文字(MBCS) | ワイド文字(Unicode) |
文字列 | _tcscat | strcat | wcscat |
_tcschr | strchr | wcschr | |
_tcscmp | strcmp | wcscmp | |
_tcscpy | strcpy | wcscpy | |
_tcscspn | strcspn | wcscspn | |
_tcslen | strlen | wcslen | |
_tcsncat | strncat | wcsncat | |
_tcsncmp | strncmp | wcsncmp | |
_tcsncpy | strncpy | wcsncpy | |
_tcspbrk | strpbrk | wcspbrk | |
_tcsrchr | strrchr | wcsrchr | |
_tcsspn | strspn | wcsspn | |
_tcsstr | strstr | wcsstr | |
_tcstod | strtod | wcstod | |
_tcstok | strtok | wcstok | |
_tcstol | strtol | wcstol | |
_tcstoul | strtoul | wcstoul | |
_tcsicmp | _stricmp | _wcsicmp | |
_tcsnicmp | _strnicmp | _wcsnicmp | |
_tcslwr | _strlwr | _wcslwr | |
_tcsupr | _strupr | _wcsupr | |
入出力 | _tprintf | printf | wprintf |
_ftprintf | fprintf | fwprintf | |
_stprintf | sprintf | swprintf | |
_vtprintf | vprintf | vwprintf | |
_vftprintf | vfprintf | vfwprintf | |
_vstprintf | vsprintf | vswprintf | |
_tscanf | scanf | wscanf | |
_ftscanf | fscanf | fwscanf | |
_stscanf | sscanf | swscanf | |
_gettchar | getchar | getwchar | |
_fgettc | fgetc | fgetwc | |
_getts | gets | _getws | |
_fgetts | fgets | fgetws | |
_puttchar | putchar | putwchar | |
_fputtc | fputc | fputwc | |
_putts | puts | _putws | |
_fputts | fputs | fputws | |
変換 | _ttoi | atoi | _wtoi |
_ttol | atol | _wtol | |
_ttof | atof | _wtof | |
ファイル | _tmkdir | _mkdir | _wmkdir |
_trmdir | _rmdir | _wrmdir | |
_tremove | remove | _wremove | |
_trename | rename | _wrename | |
_tfopen | fopen | _wfopen | |
_tpopen | _popen | _wpopen | |
_tfullpath | _fullpath | _wfullpath | |
_tmakepath | _makepath | _wmakepath | |
_tsplitpath | _splitpath | _wsplitpath | |
文字 | _istalnum | isalnum | iswalnum |
_istascii | isascii | iswascii | |
_istcntrl | iscntrl | iswcntrl | |
_istalpha | isalpha | iswalpha | |
_istdigit | isdigit | iswdigit | |
_istgraph | isgraph | iswgraph | |
_istlower | islower | iswlower | |
_istprint | isprint | iswprint | |
_istpunct | ispunct | iswpunct | |
_istspace | isspace | iswspace | |
_istupper | isupper | iswupper | |
_totupper | toupper | towupper | |
_totlower | tolower | towlower | |
その他 | _tsystem | system | _wsystem |
constな文字列型(LPCTSTR)への変換しか許されていない。
それ以外は、変換関数が用意されていないため。
::LCMapString()で、ひらがな/カタカナ、半角/全角、大文字/小文字の相互変換が可能。
これらは、「バイト数」ではなく「文字数」を定義したもの。
マルチバイト文字を扱う場合は注意が必要。
マクロ名 | 値 | 意味 |
_MAX_PATH | 260 | フルパス |
_MAX_DRIVE | 3 | ドライブ |
_MAX_DIR | 256 | ディレクトリ |
_MAX_FNAME | 256 | ファイル名(拡張子除く) |
_MAX_EXT | 256 | 拡張子(「.」含む) |
↑ <stdlib.h> に定義されている
変換元 src | ||||
char [] | (STL) string | CString | ||
変換先 dst | char [] | strcpy(dst, src.c_str()); | strcpy(dst, src); | |
(STL) string | dst = src; dst = string(src); string dst(src); | dst = src.c_str(); dst = CString(src.c_str()); CString dst(src.c_str()); | ||
CString | dst = src; dst = CString(src); CString dst(src); | dst = src.c_str(); dst = CString(src.c_str()); CString dst(src.c_str()); | ||
BSTR | dst = ::SysAllocString(src); : ::SysFreeString(dst); | dst = ::SysAllocString(src.c_str()); : ::SysFreeString(dst); | dst = src.AllocSysString(); : ::SysFreeString(dst); | |
CComBSTR | dst = src; dst = CComBSTR(src); CComBSTR dst(src); | dst = src.c_str(); dst = CComBSTR(src.c_str()); CComBSTR dst(src.c_str()); | dst.Attach(src.AllocSysString()); |
変換元 src | |||
BSTR | CComBSTR | ||
変換先 dst | char [] | ::WideCharToMultiByte(CP_ACP, 0, (OLECHAR*)src, -1, dst, sizeof(dst)-1, NULL, NULL); | 直接変換する方法はない |
(STL) string | 直接変換する方法はない | 直接変換する方法はない | |
CString | dst = src; dst = CString(src); CString dst(src); | dst = (BSTR)src; dst = CString((BSTR)src); CString dst((BSTR)src); | |
BSTR | dst = src.Copy(); : ::SysFreeString(dst); | ||
CComBSTR | dst = src; dst = CComBSTR(src); CComBSTR dst(src); |
_ismbblead(),_ismbbtrail() を使用すると、「その文字がマルチバイト文字の第1バイト/第2バイトに相当するか」をチェック可能。
しかし、マルチバイト文字の第1バイトと第2バイトの取り得る数値の範囲は重複しているため、この関数では「そのバイトが第1バイトと第2バイトのどちらか」という判定には使えない。
例)「り」(0x82E8) の第2バイトである「0xE8」は、第1バイト/第2バイトどちらでも使用される値である。
その場合は、_ismbslead(), _ismbstrail() を使用し、文脈から判定させることで解決できる。
ただし、指定した文字列全体のチェックを行うため、パフォーマンスは低いことに注意。
ファイル属性を取得する ::GetFileAttributes() で確認可能。ファイルが存在しない場合は、0xFFFFFFFF を返す。
または、PathFileExists() や PathIsDirectory()。
access() や stat() 。
ファイルを右クリックして「プロパティ」を選択したときのダイアログのこと。::ShellExecuteEx() を使用する。
なぜかできない。CFile::SetStatus() だと例外が発生し、::SetFileAttributes() だと何も起こらず変更もされない。
MFCクラス | 用途 | 備考 |
CPaintDC | 更新領域のみに対して描画する場合に使用する。 | ・コンストラクタでBeginPaint()、デストラクタでEndPaint()が呼び出されているため、クリッピングリージョンが自動的に設定される。(WS_CLIPSIBLINGSスタイルで兄弟ウィンドウをクリップにしている場合など、自動的に適用される) ・OnPaint()の処理内でしか使用できない。OnDraw()の引数で渡されるpDcも元はこれ。(OnDraw()はOnPaint()から呼び出されている) |
CClientDC | ウィンドウのクライアント領域全体に対して描画する場合に使用する。 | ・コンストラクタでGetDC()、デストラクタでReleaseDC()が呼び出される。 ・領域のクリッピング等は自前で行う必要がある。 |
CWindowDC | ウィンドウの非クライアント領域(キャプションやメニューなど)も含めた領域全体に対して描画する場合に使用する。 | ・コンストラクタでGetWindowDC()、デストラクタでReleaseDC()が呼び出される。 ・領域のクリッピング等は自前で行う必要がある。 |
1つ1つの描画処理を行うたびに画面が更新されてしまうことによってチラつきが発生してしまう。そこで、描画処理は裏画面に対して行っておき、描画処理が終わった時に画面更新を1度だけ行うことでチラつきを防ぐ手法がダブルバッファリング。以下はダブルバッファリングの実装例。
1 2 3 4 5 6 |
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
|
1 2 3 4 5 6 |
|
1 2 3 4 5 6 |
|
1 2 3 4 5 |
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
|
メモリ上のビットマップを複製する方法。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
|
ビットマップファイルは次のような構造になっている。
上記の順番でバイナリデータをファイルに保存していくことで、ビットマップファイルを作成できる。
以下に、24bitフルカラーでのビットマップファイルの保存処理の例を示す。
※フルカラーの場合、カラーパレットは格納しない。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 |
|
WS_CLIPSIBLINGSスタイルを指定すると、OnPaint()やOnDraw()に用意される標準のデバイスコンテキストは兄弟ウィンドウがクリップ(兄弟ウィンドウの上に描画処理を行わないようにリージョンを除外すること)された状態となる。理由は、BeginPaint() によって作られたDCのため。(WS_CLIPCHILDRENスタイルの場合も同様に、子ウィンドウがクリップされた状態になると思われる。)
しかし、CClientDCでクライアント領域全体のデバイスコンテキストを取得してそれに対して描画を行うような場合は、常に領域全体が描画対象になっているため、必要に応じて自前でクリップ処理を作成するしかない。
自作コントロールの描画処理を行う場合などは注意が必要。
以下、兄弟ウィンドウをクリップする処理を自前で作成する場合の例。
(※コントロール描画用のデバイスコンテキストとして CClientDC型 のメンバ変数 m_pDC が用意されているものとする。)
1 2 3 4 5 6 7 8 9 10 11 12 13 |
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
|
フォントの設定にCFontクラスのオブジェクトを用いる場合、メンバ変数にしておく必要がある。
ローカル変数だと、スコープを抜けたときに変数が自動的に破棄され、デストラクタの働きによってフォントの内容が削除されてしまうため、正しくフォントが反映されない。
コンピュータの世界でよく用いられる長さに関する単位。
単位 | 説明 | 換算 |
pixel | 文字や画像を表示する際の最小要素。画素。 ディスプレイ上ではdotと同義。 | - |
Twip | もとはVBでフォーム設計する際に用いられる長さの単位。 リッチエディットコントロール上ではこの単位がもちいられる。(要確認) mmやinchよりも細かく指定できる。 | 1Twip = 1/20point = 1/1440inch |
point | フォントの大きさを表す | 1point = 1/72inch |
inch | 一般的に使われる長さ。コンピュータの世界ではmmより使われる頻度が高い? | - |
dpi | dot per inch。1inchあたりのdot数。 ディスプレイ上では1inchあたりのpixel数と同義。 PCの解像度は通常96dpi。 | - |
アクセント記号を含めた高さをセル高さ(Cell Height)、含めない高さを文字高さ(Char Height)と呼ぶ。
(MSのサイトから抜粋 http://support.microsoft.com/kb/32667/ja)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ O O _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /\ / \ / \ _ _ _ _ _ _ _ _ _ /______\ _ _ _ ___ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ / \ / \| / \ | | _ _ _ _ _ _ _ _ /_ _ _ _ _ _ \ _ \___/| _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ | | _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _\___/_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ | |- External Leading _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _ _ | O O |- Internal Leading _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _ _ | /\ | / \ | / \ | /______\ _ _ _ ___ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ Char Height -| / \ / \| (Em) | / \ | | | /_ _ _ _ _ _ \ _ \___/| _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ | | | | _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _ _\___/_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ | | | O O | | | | /\ | | / \ | | / \ |- Ascent Cell Height -| /______\ ___ | | / \ / \| | | / \ | | | | /_ _ _ _ _ _ \ _ \___/| _ _ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ | | | | | |- Descent _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _ _\___/_ _ _ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _
LOGFONT:lfHeightでフォントの高さ、LOGFONT:lfWidthでフォントの幅を指定する。
1 2 |
|
ソースコード(エントリポイント)を持たないDLLを作るには、プロジェクト設定の「リンク」タブの「一般」カテゴリで、「プロジェクトオプション」に "/NOENTRY" を追加する。
WIN32APIの ::GetModuleFileName() を使用することで、実行ファイルのパスを取得できる。
DLL内部のコードから ::GetModuleFileName() を使用した場合、第1引数にDLLのインスタンスハンドルを渡せばDLLのパスが取得できるが、NULLを渡した場合は呼び出し元のEXEのパスの取得となる。
DLLからモードレスダイアログを表示する場合、タブストップやキー入力等の処理がデフォルトで行われない。→参考
モーダルダイアログのようにタブストップ等を処理させるには、メッセージをフックする必要がある。
1 |
|
1 2 3 4 5 6 7 |
|
1 2 |
|
1 2 |
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
|
DLL内でダイアログを作成して表示するコードを用意して使用する場合、exportする関数の先頭に以下のコードを記述する必要がある。(COMのDLLも同様)
1 |
|
EXEからexportした関数が呼び出された状態では、リソースハンドル等はEXE用のものを使用する状態になっているため、DLL内では正しい処理が行われない。
上記のコードによって、モジュール状態がDLL用のものに切り替わるため、正しい処理が行える。また、スコープを抜けるときに元の状態に戻してくれるため、EXE側に処理が帰った後も問題がない。
DLLは親となるプロセスにロードされるため、呼び出し側のEXEが必要になる。
[注意点]
プロジェクトにlibファイルをリンクするには以下の3つの方法がある。
1 |
|
自作クラスなどの汎用的なコードは、スタティックライブラリ化しておくと再利用しやすい。
Win32API等のOSの機能を使用する場合、OSのバージョンによって利用できる機能と利用できない機能が存在するため、例えばWinXPから実装された機能を使用するアプリケーションは、Win2kでは動作が保証されないことになる。
つまり、アプリケーションを作成する場合、実行対象のWindowsの最小バージョンを決めておき、それより後のバージョンで実装された機能を使用しないようにする必要がある。
そこで、Windows用のヘッダファイルには以下のマクロが用意されており、定義された値によって機能が限定されるように作られている。アプリケーションを作る場合、使用する機能によってはこのマクロの値を適宜設定する必要がある。(stdafx.h内のWindows用のヘッダファイルのインクルードよりも前に定義する)
Windows | WINVER _WIN32_WINNT |
Windows 95 | 0x0400 |
Windows 98 | 0x0410 |
Windows Me | 0x0500 |
Windows NT 4.0 | 0x0400 |
Windows 2000 | 0x0500 |
Windows XP Windows Server 2003 | 0x0501 |
Windows XP SP2 Windows Server 2003 SP1 | 0x0502 |
Windows Vista | 0x0600 |
Windows 7 | 0x0601 |
Windows 8 | 0x0602 |
IE | _WIN32_IE |
Windows 95 Windows NT 4.0 | 0x0200 |
Internet Explorer 4.0 | 0x0400 |
Internet Explorer 4.01 | 0x0401 |
Internet Explorer 5.0, 5.0a, 5.0b | 0x0500 |
Internet Explorer 5.01 | 0x0501 |
Internet Explorer 5.5 | 0x0550 |
Internet Explorer 6.0 | 0x0600 |
Internet Explorer 6.0 SP1 | 0x0601 |
Internet Explorer 6.0 SP2 | 0x0603 |
Internet Explorer 7.0 | 0x0700 |
Internet Explorer 8.0 | 0x0800 |
Internet Explorer 9.0 | 0x0900 |
Internet Explorer 10.0 | 0x0A00 |
::GetCommandLine()で取得可能。
また、WinMain()で起動された場合は、__argv/__argc マクロを使用することで引数リストを受け取れる。main()の引数 argv/argc のように扱えるので便利。
CWinApp::m_lpCmdLine に格納されている。
CWinApp 派生クラスの InitInstance() で、ウィンドウ起動処理に以下を追加。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
|
※ <afxmt.h>をインクルードする必要がある。
※ ミューテックス作成時に渡す文字列は大文字小文字を区別することに注意。
::LoadIcon() であらかじめ用意されているカーソルから砂時計カーソルを取得して ::SetCursor() で使用する。
1 2 3 4 5 6 7 8 9 |
|
任意の処理の先頭で CWaitCursor型の変数を定義するのみ。
CWaitCursorクラスのコンストラクタが砂時計カーソルを設定し、デストラクタが元に戻す。
1 2 3 4 5 6 |
|
CWnd::OnSetCursor() を実装する。
引数の nHitTest でカーソル位置、message でマウス状態を判断することができる。nHitTest に用いられるマウス列挙子は、MSDNの CWnd::OnNcHitTest() の項を参照。message は、マウス関連のウィンドウメッセージが格納される。
実際に設定するにはカーソルハンドルを指定する必要がある。OSに用意されているストックオブジェクトを用いる場合、::LoadCursor() の第一引数にNULLを渡し、第二引数にリソースIDを指定する。ストックオブジェクトのIDは、MSDNの::LoadCursor() の項を参照。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
|
アプリケーションのショートカットキーを実現するアクセラレータの使用方法。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
|
タスクトレイに常駐するアプリケーションの基本的な作成方法。
1 |
|
1 |
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 |
|
1 2 |
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
|
通常、異なるアプリケーション間では別々のメモリ空間が使用されるため、メモリを共有することができない。(アプリAのメモリアドレス0x00001111は、アプリBのメモリアドレス0x00001111とは別の領域である)
そこで、OS側に仮想的なメモリ空間を作成してもらい、そのメモリ空間をそれぞれのアプリケーションが自プロセスのメモリ空間にマッピングして使用することで、あたかも同じメモリを操作しているように振る舞うことができる。
アプリAが共有メモリの内容を変更すると、それをマッピングしている全てのプロセスの共有メモリが同じように変更される。
変更が即時反映されるファイルを複数プロセスで同時にオープンしているイメージ。共有メモリは実体がない(正確にはOSが管理するメモリ空間に実体を持つらしい)ため、一意な名前をつけて識別する必要がある。
1 2 3 4 5 |
|
1 2 3 4 5 6 7 |
|
1 2 3 4 5 6 7 |
|
対象の実行ファイルのパスから、バージョン情報を取得できる。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
|
外部コマンドを起動して標準出力をリダイレクトする方法。(test.exe > stdou.txt)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
|
※標準出力のリダイレクトを追記させる場合は、予めファイルを追記モードで開き、シークを終端に移動しておく手順が必要。(test.exe >> stdou.txt)
同様の手順で、標準入力や標準エラー出力もリダイレクト可能。
1 2 3 4 5 6 7 8 9 |
|
1 2 3 4 5 6 7 8 9 |
|
1 2 3 4 5 |
|
リストビュー、ツリービュー、タブなどのコントロールにアイコンを表示する場合は、イメージリストを使用した方法を使用する必要がある。
あらかじめ、CListCtrl::SetImageList()、ListView_SetImageList() などでイメージリストをコントロールに登録しておき、CListCtrl::InsertItem()、ListView_InsertItem() でアイテムを挿入する際にアイコンのインデックスを指定することで表示される。
※コントロールにシステムイメージリストを使用する場合は、ウィンドウスタイルに LVS_SHAREIMAGELISTS (リストビューコントロールの場合) を設定しておくこと。
セマフォ | ミューテックス | クリティカルセクション | ||
同時に所有できる数 | 上限を設定可能 | 1つまで | 1つまで | |
使用可能な範囲 | プロセスをまたいで使用可能 | プロセスをまたいで使用可能 | 同一プロセス内でのみ使用可能 | |
Win32API | オブジェクトの作成 | CreateSemaphore | CreateMutex | InitializeCriticalSection |
所有権の取得 | WaitForSingleObject に代表される待機関数 | EnterCriticalSection | ||
所有権の破棄 | ReleaseSemaphore | ReleaseMutex | LeaveCriticalSection |
カテゴリ | マクロ名 | 意味 |
ANSI C (C90) | __STDC__ | 標準規格のC言語であることを示す K&Rとの区別に用いる |
__FILE__ | ソースファイルパス | |
__LINE__ | ソースの行番号 | |
__TIMESTAMP__ | コンパイル日時 | |
__DATE__ | コンパイル日 | |
__TIME__ | コンパイル時刻 | |
C99 | __func__ | 関数名 |
C++ | __cplusplus | C++であることを示す 値が1とは限らない |
文字セット (どちらか一方) | _MBCS | マルチバイト文字セットであることを示す |
_UNICODE | ワイド文字(Unicode)セットであることを示す | |
ビルド構成 (どちらか一方) | _DEBUG | Debug版 |
NDEBUG | Release版 |
ある関数Aでconst修飾された引数を、さらに関数Bの非constな引数として渡すことができてしまう。もちろん関数B内で値の書き換えも可能。
コンパイラの警告レベルによっては、警告は出力される。
CALLBACK関数は、グローバル関数やstaticメンバ関数などの静的な関数として定義する必要がある。
その他、関数ポインタを使用する仕組みも同様。
クラスのメンバ関数はインスタンスが生成されるまでアドレス空間のどの位置に配置されるかが決まっていないため、ポインタにアドレスを格納できない。
参考:http://katsura-kotonoha.sakura.ne.jp/prog/c/tip00003.shtml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 |
|
C++では、関数のオーバーロードを実現するために、関数シグネチャ(定義)から関数名、引数の型、修飾子などの情報を混合したシンボルを作成し、関数を一意に識別している。
このシンボル名を作成することをマングルと呼ぶ。
マングルの方法は、コンパイラによって異なる。
VC++を使用する場合はマイクロソフトの規約にしたがってマングルされる。先頭が?、末尾がZの形式(�㡧?Func@CClass@@QAEXH@Z)
逆に、シンボルを関数名に戻すことをデマングルと呼ぶ。
VC++の場合、Win32APIの::UnDecorateSymbolName()を使用することでデマングルが可能。
参考URL:
http://kone.vis.ne.jp/diary/diaryb13.html#080315
http://www.kegel.com/mangle.html
http://en.wikipedia.org/wiki/Microsoft_Visual_C%2B%2B_Name_Mangling
例えば、メモリアクセス違反(アクセスバイオレーション)などが構造化例外。
C++のtry-catch構文でキャッチするためにはコンパイルオプション「/EHa」が必要。(VC6の場合は設定画面に項目がないため、自分で追記する必要がある)
ただし、発生する例外はCException型ではないことに注意。以下のように全ての例外をキャッチすれば捕まるが、詳細情報は取れない。
1 2 3 4 5 |
|
Visual Studio を使用している場合は、MS独自仕様の __try-__except構文で構造化例外をキャッチできる。
これはC言語のソースでも可能で、コンパイルオプションも不要。
1 2 3 4 5 6 7 8 9 |
|
作成されるすべてのオブジェクト、派生クラスのオブジェクトでひとつの静的変数として値をやりとりできる。
staticなメンバ変数と同じ。(スコープはその関数内のみという点が異なる)
クラスのインスタンス生成無しで関数を呼び出せる。
1 2 |
|
関数のシグネチャがCとCPPで異なるため、単純なextern宣言では呼び出せない。(リンクエラーになる)
1 2 3 4 5 6 7 8 |
|
クラスのメンバ変数を初期化する際、コンストラクタで初期値を代入することもできるが、これは厳密な意味での「初期化」ではなく、値の「代入」である。
厳密に初期化を行う場合は、メンバ初期化子「:」を用いる。コンストラクタ初期化子とも呼ばれる。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
|
1 2 3 4 5 6 7 8 9 10 11 |
|
1 2 3 4 5 6 7 8 |
|
typeid演算子によって、オブジェクトが何のクラスのインスタンスなのかを実行時に知ることができる。
使用するには、プロジェクトの設定で「ランタイムタイプ情報(RTTI)を有効にする」にチェックを付けることでコンパイルオプション「/GR」を指定しなければならない。
自身のクラス型のオブジェクトのprivateメンバは、たとえインスタンスが異なっていたとしても「.」「->」でアクセス可能。
例)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
|
VC6で生成されるMFC派生クラスのヘッダファイルの例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
|
説明
概要 | 説明 | 追加 | |
① | CObjectクラスの 機能の使用宣言 | 全てのMFCクラスの基底クラスであるCObjectの機能を使用する場合は、hファイルに DECLARE_DYNAMIC マクロを追加する必要がある。 また、その場合はcppファイルにも対応する IMPLEMENT_DYNAMIC マクロを追加する必要がある。 VC6では、自動的に追加される訳ではないので注意。 | 任意 |
② | コンストラクション | コンストラクタやCWnd::Create()のような、そのクラスのオブジェクトを使用する前に必ずコールする必要のあるメンバ関数を定義する。 | 任意 |
③ | アトリビュート | そのクラスの属性(プロパティ)を制御する公開メンバ変数や、Set/Getメンバ関数を定義する。 Getメンバ関数はconstにすべきである。 | 任意 |
④ | オペレーション | そのクラスのオブジェクトに対して、何らかの操作を行わせるための公開メンバ関数を定義する。 | 任意 |
⑤ | オーバーライド | MFC基底クラスの仮想関数のオーバーライドを定義する。 | ウィザード |
⑥ | インプリメンテーション (公開メンバ) | そのクラスの実装のための公開メンバ(通常、クラスの使用者が知る必要のないメンバ)を定義する。 | ウィザード |
⑦ | インプリメンテーション (被保護メンバ) | そのクラスの実装のための被保護メンバ(通常、クラスの使用者が知る必要のないメンバ)を定義する。 | ウィザード |
⑧ | Window メッセージハンドラ | Windowメッセージハンドラ(メンバ関数)を定義する。 | ウィザード |
⑨ | インプリメンテーション (非公開メンバ) | そのクラスの実装のための非公開メンバ(通常、クラスの使用者が知る必要のないメンバ)を定義する。 | ウィザード |