VC++ / C++


VC++/C++

目次

コンパイラオプション

 /MT …… 静的リンク  /MD …… 動的リンク  /MTd …… 静的リンク (デバッグ版)  /MDd …… 動的リンク (デバッグ版)

デザインパターン

コマンド

// 
undoPoint_ = -1;
CCommand* pCommand = new CNoCommand();
addCommandHistory(pCommand);
// コマンド履歴追加
void CPictureDrawView::addCommandHistory(CCommand* pCommand)
{
  // undo中なら、以降のコマンド履歴は必要なし
  while (m_pPimpl->undoPoint_ < (int)m_pPimpl->commandHistory_.size()-1)
  {
	delete m_pPimpl->commandHistory_[(int)m_pPimpl->commandHistory_.size()-1];
		m_pPimpl->commandHistory_[(int)m_pPimpl->commandHistory_.size()-1] = 0;
		m_pPimpl->commandHistory_.pop_back();
  }
  m_pPimpl->commandHistory_.push_back(pCommand);
  m_pPimpl->undoPoint_++;
}
// リドゥ
void onRedo()
{
  if (m_pPimpl->undoPoint_ < (int)m_pPimpl->commandHistory_.size()-1)
  {
	m_pPimpl->undoPoint_++;
	m_pPimpl->commandHistory_[m_pPimpl->undoPoint_]->redo();
  }
}
// アンドゥ
void onUndo()
{
  if (m_pPimpl->undoPoint_ > 0)
  {
	m_pPimpl->commandHistory_[m_pPimpl->undoPoint_]->undo();
	m_pPimpl->undoPoint_--;
  }
}

#pragma once

ヘッダファイルの重複を防ぐディレクティブ


_mkdir

#include <direct.h>
#include <errno.h>
int iRet = _mkdir(mailPath.c_str());
// 成功なら 0、失敗なら-1
// errno == EEXISTなら既にフォルダが存在、errno == ENOENTならパスがおかしい
 または派生クラスのメンバなどのCWinThreadオブジェクトのメンバデータを初期化する場合に使用。
     初期化完了後にスレッドを実行するには、CWinThread::ResumeThreadを使用。
     これを使用するまでスレッドは実行されない
  -0: 作成直後にスレッドを開始
// スレッドの作成と開始
m_pThread = ::AfxBeginThread(WatchFile, (LPVOID)this,
  THREAD_PRIORITY_NORMAL, 0, CREATE_SUSPENDED, NULL);   // WatchFileはスレッド関数
m_pThread->m_bAutoDelete = FALSE;
m_pThread->ResumeThread();
// スレッド関数
UINT FootView::WatchFile(LPVOID pParam)
{
   FootView* pFootView = (FootView*)pParam;
   int UpdateTime = 100;
   while (1)
   {
         pFootView->readFileLines(false);    // ただの処理
         // シグナル状態になるかタイムアウトになるまで待つ
 	DWORD ret = ::WaitForSingleObject(pFootView->m_hEventStop, UpdateTime);
	switch (ret)
	{
	  case WAIT_OBJECT_0:  // シグナル状態
		return 0;
		break;
	  case WAIT_TIMEOUT:   // タイムアウト
		break;
	  case WAIT_FAILED:
	  case WAIT_ABANDONED:
	  default:
		break;
        }
   }
   return 0;
}

boost/format

sprintfのc++版

typdef boost::basic_format<TCHAR> TFormat
#include <iostream>
#include <boost/format.hpp>
using namespace std;
using namespace boost;
using namespace boost::io;
try
{
   // printf的な使い方
   cout << format("%d") % 10;
   // 文字列として取り出し
   string s;
   s = str(format ("数字 : %d 、文字 : %s") % 30 % "あああ");
}
// Too much arguments
catch (boost::io::too_many_args& ex)
{ 
   cerr <<  ex.what() << endl;
}
// Too few arguments
catch (boost::io::too_few_args& ex)
{ 
   cerr <<  ex.what() << endl;
}

boost/lexical_cast

#include <string>
#include <boost/lexical_cast.hpp>
try
{
 TString str;
 int number = lexical_cast<int>(str);
 str = lexical_cast<TString>(number);
}
catch(boost::bad_lexical_cast & ex)
{
 ::AfxMessageBox(_T("失敗"));
}

boost/shared_ptr

#include <boost/share_ptr.hpp>
// ppatを何度コピーしようとも、ppatが参照されなくなるまでdeleteされない
typedef boost::shared_ptr<pattern> pattern_type
pattern_type ppat = pattern_type(new pattern(...));
// 生のポインタ
pattern* pat = ppat.get();
// 生成時はnull
pattern_type pnull;
// ローカル変数に使用すると、ブロック終了後にdeleteされるので注意
// 指す先を変更するには、
shared_ptr<Foo> p(new Foo(0));
p.reset(new Foo(1));  // このとき Foo(0)のデストラクタが走る

boost/tokenizer

#include <boost/tokenizer.hpp>
std::string str
typedef boost::tokenizer<boost::char_separator<char>> tokenizer;
boost::char_separator<char> sep("/");
tokenizer token(str, sep );
for (tokenizer::iterator it=token.begin(); it!=token.end(); ++it)
{
}

boost/date_time/gregorian/gregorian

#include "boost/date_time/gregorian/gregorian.hpp"
using namespace boost::gregorian;
date d( Year, Month, Day );
// N日後
date d2 = d + date_duration(N);
d.year()          // 年
d.month()         // 月
d.day()           // 日
d.day_of_week()   // 曜日
d.is_not_a_date() // 日付が存在しないならtrueを返す

BSTR

// 初期化
BSTR var(::SysAllocString(L""));
// CString -> BSTR
CString src("");
BSTR var(src.AllocSysString());
// BSTR ->CString
BSTR var;
CString src = CString(var);
// 比較
strcmp(va1, var2)==0

CButton

Create (LPCTSTR lpszCaption,  // ボタンコントロールのテキスト
  DWORD dwStyle,              // ボタンコントロールのスタイル
  const RECT& rect,           // ボタンコントロールのサイズと位置
  CWnd* pParentWnd,           // ボタンコンロールの親ウィンドウ。通常はCDialog
  UINT nID                    // ボタンコントロールのリソースID
  CButton* pButton = new CButton();
  pButton->Create(NULL, WS_CHILD|WS_VISIBLE|BS_PUSHBUTTON, CRect(0, 0, 0, 0), this, ID);

CClientDC

  • pWndで指定されるCWndのクライアント領域にアクセスするするCClientDCオブジェクトを構築
  • OnDrawメソッド以外で描画を行うときに使う
    CClientDC dc(pWnd)

CColorDlg

COLORREF Col;
CColorDialog ColorDlg(RGB(0,0,0), 0x10, NULL);
if (ColorDlg.DoModal() == IDOK)
{
   Col = ColorDlg.GetColor();
   int r, g, b;
   //r=Col&0xff;//赤情報取り出し
   r = GetRValue(col);           
   //g=(Col>>8)&0xff;//緑情報取り出し
   g = GetGValue(col);
   //b=(Col>>16)&0xff;//青情報取り出し
   b = GetBValue(col);
   m_ForwardColor.Format("RGB(%d, %d, %d)", r, g, b);//CString文字列に変換
}

CComboBox

CComboBox m_MonthCtrl;
TString Item = _T("項目");
m_MonthCtrl.AddString(Item.c_str());  // 項目の追加

CDateTimeCtrl

// 日時のセット
CDateTimeCtrl* pDate = (CDateTimeCtrl*)GetDlgItem(IDC_DATE);
ASSERT(pDate);
CTime tm(2007, 6, 6, 1, 2, 3); // 2007/06/06 01:02:03
pDate->SetTime(&tm);

CDialog

// ダイアログの呼出
CMyDlg dlg(this);
dlg.DoModal();     // モーダルダイアログボックスの起動。OKなどが押されるまで親の操作は不可
// 初期化処理
BOOL OnInitDialog()
{ // クラスビューから該当クラスを探し、そのプロパティのオーバーライドから作成
  if (!__super::OnInitDialog())
  {
    FALSE
  }
}
// ダイアログの貼り付け
CRect rect;
GetClientRect(&rect);
CDialog* pDialog = new CDialog();
pDialog->Create(IDD_DIGEST_DIALOG, this);
pDialog->MoveWindow(rect.left, rect.top, rect.right, rect.bottom);
pDialog->ShowWindow(SW_SHOW);
// ダイアログの終了
EndDialog(IDOK);
// サイズ変更
リソースの設定で、「ダイアログ枠」から「サイズ変更枠」に変更する

CEditCtrl

改行位置には\r\nが必要

CFontDialog

	LONG  pointSize = -MulDiv(Font.Size, GetDeviceCaps(GetDC()->GetSafeHdc(), LOGPIXELSY), 72);
	CFontDialog dlg;
	dlg.m_cf.Flags |= CF_NOSCRIPTSEL | CF_INITTOLOGFONTSTRUCT;
	dlg.m_cf.Flags &= ~CF_EFFECTS | CF_USESTYLE;
	strcpy_s(dlg.m_cf.lpLogFont->lfFaceName, Font.Name);
	if (Font.Style.Compare(_T("標準"))==0)
		dlg.m_cf.lpLogFont->lfWeight = FW_NORMAL;
	else if (Font.Style.Compare(_T("斜体"))==0)
		dlg.m_cf.lpLogFont->lfItalic = true;
	if (Font.Style.Compare(_T("太字"))==0)
		dlg.m_cf.lpLogFont->lfWeight = FW_BOLD;
	if (Font.Style.Compare(_T("太字 斜体"))==0)
	{
		dlg.m_cf.lpLogFont->lfWeight = FW_BOLD;
		dlg.m_cf.lpLogFont->lfItalic = true;
	}
	dlg.m_cf.lpLogFont->lfHeight = pointSize;
	if (dlg.DoModal() == IDOK) {
	    Font.Name = dlg.GetFaceName();
		bool IsBold = dlg.IsBold();
		bool IsItalic = dlg.IsItalic();
		if (IsBold)
		{
			if (IsItalic)
				Font.Style = "太字 斜体";
			else
				Font.Style = "太字";
		} else if (IsItalic)
			Font.Style = "斜体";
		else
			Font.Style = "標準";
		Font.Size = dlg.GetSize() / 10;
	}

CListCtrl

複数選択させないためには、Single Selectionをtrueに。

//選択されている項目のindexを取得
index=-1;
while ((index = GetNextItem(index, LVNI_ALL|LVNI_SELECTED))!=-1)
     // 選択されている項目のindexのとき
// 1行選択モード&グリッドにするには以下の記述が必要
CListCtrl* pList = (CListCtrl*)GetDlgItem(IDC_LOGINFO_LIST);
ASSERT(pList);
DWORD dRet = pList->SetExtendedStyle(LVS_EX_FULLROWSELECT | LVS_EX_GRIDLINES); 
// 見出しの追加
CListCtrl* pList = (CListCtrl*)GetDlgItem(IDC_LIST_KEYWORD);
ASSERT(pList);
int iRet(-1);
if (pList->GetSafeHwnd())
{
  iRet = pList->InsertColumn( 0, "キーワード", LVCFMT_LEFT, 125, -1);
  ASSERT(iRet!=-1);
  iRet = pList->InsertColumn( 1, "前景色", LVCFMT_LEFT, 125, -1);
  ASSERT(iRet!=-1);
  iRet = pList->InsertColumn( 2, "背景色", LVCFMT_LEFT, 125, -1);
  ASSERT(iRet!=-1);
}
// 項目の追加
// No Column Headerをtrueにしている場合も、項目を追加する必要あり!
CListCtrl* pList = (CListCtrl*)GetDlgItem(IDC_LIST_KEYWORD);
ASSERT(pList);
bool bRet(false);
for (int i=0; i<(int)SettingList.size(); ++i)
{
  int nItem = m_KeywordList.InsertItem( i, SettingList[i].Keyword, 0);
  bRet = pList->SetItem( nItem, 1, LVIF_TEXT, SettingList[i].ForwardColor, 0, 0, 0, 0);
  ASSERT(bRet);
  bRet = pList->SetItem( nItem, 2, LVIF_TEXT, SettingList[i].BackColor, 0, 0, 0, 0);
  // チェックをつける
  bRet = pList->SetCheck(nItem, SettingList[i].Check);
  ASSERT(bRet);
}
// チェックボックスのチェック
void ColorSettingDlg::OnLvnItemchangedListKeyword(NMHDR *pNMHDR, LRESULT *pResult)
{
  LPNMLISTVIEW pNMLV = reinterpret_cast<LPNMLISTVIEW>(pNMHDR);
  // TODO: ここにコントロール通知ハンドラ コードを追加します。
  UINT newimage;
  if ((newimage = pNMLV->uNewState & LVIS_STATEIMAGEMASK)
		!=(pNMLV->uOldState & LVIS_STATEIMAGEMASK))
  {
     if (newimage == INDEXTOSTATEIMAGEMASK(2))
     { // チェックが押された
     } else if (newimage == INDEXTOSTATEIMAGEMASK(1))
     { // チェックが外された
     }
  }
  *pResult = 0;
}
// 表示内容の取得
CString GetItemText(int nItem, int nSubItem)
// 選択アイテムの取得(単一選択)
void CModifyDialog::OnLvnItemchangedList(NMHDR *pNMHDR, LRESULT *pResult)
{
	LPNMLISTVIEW pNMLV = reinterpret_cast<LPNMLISTVIEW>(pNMHDR);
	// TODO: ここにコントロール通知ハンドラ コードを追加します。
	UINT NewState = pNMLV->uNewState;
	if (NewState==3)
	{ // 選択された!
		int nItem = pNMLV->iItem;
		UINT state = m_DrLst.GetItemState( nItem, LVIS_SELECTED );
		if( state == LVIS_SELECTED )
		{
			UINT index = m_DrLst.GetSelectedColumn();
			m_ID = m_DrLst.GetItemText(index, 0);
			m_Name = m_DrLst.GetItemText(index, 1);
			m_Weekday = m_DrLst.GetItemText(index, 2);
			m_Max = m_DrLst.GetItemText(index, 3);
			UpdateData(false);
		}
	}
}

CloseHandle(HANDLE hObject)

戻り値: BOOL
オープンしているカーネルオブジェクトのハンドルをクローズ。オブジェクトのハンドルの参照カウンタを1つ減らす。参照カウンタが0になった時点で、そのオブジェクトはメモリから開放される

COLORREF

COLORREF Col;
Col = ColorDlg.GetColor();
int r, g, b;
r = Col&0xff;
g = (Col>>8)0xff;
b = (Col>>16)0xff;
Format("%d, %d, %d", r, g, b);

CPaintDC

CPaintオブジェクトを構築し、塗りつぶす対象となるアプリケーションウィンドウを用意

CPaintDC dc(pWnd)

CreateEvent()

引数: 
 lpEventAttributes: セキュリティ記述子
 bManualReset: FALSEにすると、WaitForSingleObjectが制御を戻したとき、自動的に非シグナル状態に
 bInitialState: 初期状態 TRUE:シグナル状態 FALSE:非シグナル状態
 lpName: オブジェクトの名前
HANDLE m_hEventStop = ::CreateEvent(NULL, TRUE, FALSE, NULL);

CRect

//各辺を中心から外側に向かって移動させることで CRect を拡大
InflateRect(int x, int y)
InflateRect(int l, int t, int r, int b)
// Rectをコピー
CopyRect(CRect rect)
// 戻り値のメンバである cx と cy が CRect の高さと幅を持つ
Size()
//四角形がフォーカスを持つことを示すために使われるスタイルで四角形を描画
DrawFocusRect(LPCRECT lpRect);
//lpRect で指定された四角形の周囲に境界線を描く
FrameRect(LPCRECT lpRect, CBrush* pBrush)

CRichEditCtrl

ユーザがテキストを入力し編集できるウィンドウ

ReplaceSel: オブジェクト内の現在の選択を指定されたテキストに置き換え
CHARFORMAT2 cf;
TString FontName;
::memset(&cf, 0, sizeof(CHARFORMAT2));
cf.cbSize = sizeof(CHARFORMAT2);
cf.cbSize = sizeof(cf);
cf.dwMask = CFM_COLOR | CFM_BACKCOLOR | CFM_ITALIC | CFMBOLD | CFM_SIZE | CFM_FACE | CFM_SPACING;
::_tcscpy_s(cf.szFaceName, LF_FACESIZE, FontName);
cf.sSpacing = 0;
cf.dwEffects = CFE_ITALIC | CME_BOLD | UNDERLOINE | STRIKEOUT;
cf.yHeight = 300;
cf.crTextColor = RGB(255, 0, 0);
cf.crBackColor = RGB(0, 255, 0);
// ダブルクリックで単語選択
// 自動垂直スクロール
// 常に選択状態
// 読取専用
editCtrl.SetOptions(ECOOP_SET, ECO_AUTOWORDSELECTION | ECO_AUTOVSCROLL | ECO_NOHIDESEL | ECO_READONLY);
// 右端で折り返す
SendMessage(EM_SETTARGETDEVICE, NULL, 0);
// 右端で折り返さない
SendMessage(EM_SETTARGETDEVICE, NULL, 1);

CSpinButtonCtrl

CSpinButtonCtrl m_YearCtrl;
CEdit* pYear= (CEdit*)GetDlgItem(IDC_EDIT_YEAR2);
ASSERT(pYear);
m_YearCtrl.SetBuddy(pYear);    // pYearと対に
m_YearCtrl.SetRange(0, 9999);
void CCalendarDlg::OnDeltaposSpinYear(NMHDR *pNMHDR, LRESULT *pResult)
{
   LPNMUPDOWN pNMUpDown = reinterpret_cast<LPNMUPDOWN>(pNMHDR);
   // TODO: ここにコントロール通知ハンドラ コードを追加します。
   if (pNMUpDown->iDelta > 0)
   { // 上が押された
   } else
   { // 下が押された
   }
   *pResult = 0;
}

CStdFile

|modeCreate|ファイルがない場合には作成し、そんざいする場合には内容長を0にする|
|modeNoTruncate|modeCretateとともに使用し、存在する場合には内容はそのままで開く|
|modeRead|読み込み専用として開く|
|modeReadWrite|読み込み/書き込み両用で開く|
|modeWrite|書き込み専用として開く|
|modeNoInherit|子プロセスにファイルを継承しない|
|shareDenyNone|読み込み/書き込みとも他のプロセスと共有する|
|shareDenyRead|書き込みのみ他のプロセスと共有する|
|shareDenyWrite|読み込みのみ他のプロセスと共有する|
|shareExclusive|他のプロセスとファイルを共有しない|
|CFile::begin|ファイルの最初|
|CFile::current|現在位置|
|CFile::end|ファイルの終わり|

Eclipse(int x1, int y1, int x2, y2)

戻り値: bool

x1: 楕円に外接する四角形の、左上隅の論理 x 座標。
y1: 楕円に外接する四角形の、左上隅の論理 y 座標。
x2: 楕円に外接する四角形の、右下隅の論理 x 座標。
y2: 楕円に外接する四角形の、右下隅の論理 x 座標。

EnableMenuItem(リソースID, MFS_GRAYED | MY_BYCOMMAND)

メニューの項目を無効に

EnableWindow(0:無効, 1:有効)

ウィンドウのマウス入力とキーボードを有効/無効にする

FlashWindow

// ウィンドウの点滅を行う
// 成功するとtrue、失敗するとfalseを返す
BOOL FlashWindow(HWND hWnd, BOOL bInvert);
// binvert: ウィンドウ(のタイトルバー)を反転させるのか(true)、正常な状態に戻するのか(false)を指定。

GetClientRect(LPRECT lpRect)

戻り値: BOOL
クライアント領域の座標を取得する

GetWindowRect(LPRECT lpRect)

戻り値: BOOL
ウィンドウの境界線の寸法を取得する

Invalidate

ウィンドウズにメッセージをポスト。現在実行中のハンドラや先にポストされていたメッセージに対応するハンドラの実行終了を待つ。WM_PAINTメッセージは関数を抜けてから

CRect myRect;
myRect.SetRect(0, 0, 200, 200);
InvalidateRect(&myRect);
myRectだけ再描画

map

std::map<int, char> var; // keyを整数型,valueを文字型とする連想配列を作成
var.insert(std::make_pair(3, 'a')); // keyが3,valueが'a'の要素を追加
std::map<int, char>::iterator i = var.find(4); // iはkeyが4の要素を指す反復子
std::map<int, char>::iterator j = var.end(); // jはvarの終端を指す反復子
if (i==j) { // 要素が見つからなかった場合,findの返り値は終端を指す反復子になります。 
// 見つからなかった… 
} else { 
// 見つかった!!!!
 int key = i->first; // 当然keyの値は4
 char value = i->second; // valueは'c' 
 // ちなみに
 i->first = 10; // NG!!!! keyは書き換えられない。
 i->second = 'x'; // OK!!!! valueは書き換えられる。
}

MessageBeep

// 設定されたサウンドを鳴らす。ビープ音の発生に成功するとtrue、失敗するとfalse
BOOL MessageBeep(UINT soundType)
MB_OK一般の警告音
MB_ICONHANDシステムエラー
MB_ICONEXCLAMATIONメッセージ(警告)
MB_ICONQUESTIONメッセージ(問合せ)
MB_ICONASTERISKメッセージ(情報)
0xFFFFFFFF単純なビープ音

ofstream

typedef std::ofstream TOFStream;
#include <fstream>
int main()
{
   std::ofstream ofs( "test.txt", ios::out | ios::app);
   ofs << "testmessage" << 123 << std::endl;
   return 0;
}
// ファイルはデストラクタによって自動的に閉じられる
フラグ説明
out書き込み専用に開く。デフォルト。
app追記用に開く。
ateファイルを開くと、自動的に末尾に移動する。
truncファイルを開くと、以前の内容を全て削除する。
binary特殊な文字を置換しない。

ON_COMMAND_RANGE(id1, id2, memberFxn)

id1: 連続するコマンドIDの先頭コマンドID
id2: 連続するコマンドIDの末尾コマンドID
memberFxn: コマンドが割り当てられるメッセージハンドラ関数
このマクロを使って連続する範囲のコマンドIDを1つのメッセージハンドラ関数に割り当てる。
OnmemberFxn(UINT nID): nIDを使える
// ヘッダに
afx_msg void OnCalDay(UINT id);
// メッセージマップに
ON_COMMAND_RANGE(id1, id2, OnCalDay)
// 本体
void OnCalDay(UINT id)
{
  // idを使って処理
}

OnCtrlControl

HBRUSH CCalendarDlg::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)
{
  HBRUSH hbr = CDialog::OnCtlColor(pDC, pWnd, nCtlColor);
  if (pWnd->GetSafeHwnd() == m_CalLastMonth.GetButton(i)->GetSafeHwnd())
	pDC->SetTextColor(RGB(255, 0, 0));
  switch (pWnd->GetDlgCtrlID())
  {
    case IDC_STATIC_SUN:
         break;
    default:
         break;
  }
  // TODO:  既定値を使用したくない場合は別のブラシを返します。
  return hbr;
}

Pimpl

Exceptional C++ 4章

  • コンパイル時の依存性を最小限にする
    • 不必要なヘッダを除去する
      • 先行宣言で十分な場合は、定義を#includeしない。 クラスTの完全な定義が必要になるのは、主に次の2つの状況
  • Tオブジェクトのサイズが必要な場合
    • たとえば、スタック上にTを確保する、別の型のメンバー変数として直接保持する
  • Tのメンバーの名前が必要な場合や、メンバー関数を呼び出す必要がある場合
    • たとえば、メンバー関数を呼び出す
    • パラメータおよび戻り値の型としてだけ利用されるときは先行宣言で十分
    • ストリームの先行宣言で十分な場合は、#include<iosfwd>
  • よく使われるクラスにはコンパイラファイアウォールイディオム(pimplイディオム)を使う
  • pimplオブジェクトの中には、すべてのprivateメンバを入れる
    • 仮想関数はダメ
      struct Pimpl;
      Pimpl* m_pPimpl;

C++ Coding Standards 22

  • 定義依存を最小化しよう循環依存を避けよう

PreTranslateMessage

BOOL DigestInfoView::PreTranslateMessage(MSG* pMsg)
{
  if (WM_LBUTTONDBLCLK == pMsg->message)
  {
     m_pCmdTarget->SendMessage(WndMsg::WM_DIGEST_DOUBLE_CLICK, reinterpret_cast<WPARAM>(&m_carteID));
     // メッセージの処理をさせたくなければtrueを返す
     return TRUE;
   } 
   return CHtmlView::PreTranslateMessage(pMsg);
}

RadioButton

CButton* pRadio = (CButton*)GetDlgItem(IDC_RADIO_3MONTH);
ASSERT(pRadio);
pRadio->SetCheck(1);  // ボタンチェック

Rectangle(int x1, int y1, int x2, int y2)

戻り値: bool

x1: 四角形の左上隅の x 座標を指定します (論理単位)。
y1: 四角形の左上隅の y 座標を指定します (論理単位)。
x2: 四角形の右下隅の x 座標を指定します (論理単位)。
y2: 四角形の右下隅の y 座標を指定します (論理単位)。

reinterpret_cast

reinterpret_cast<変換後><変換前>

ResetEvent(HANDLE hEvent)

戻り値: BOOL
オブジェクトを非シグナル状態に

ScreenToClient(LPRECT lpRect)

戻り値: BOOL
スクリーン座標をクライアント座標に変換する

SendMessage

ウィンドウにメッセージを送信する。
この関数は、指定したウィンドウのウィンドウプロシージャが処理を終了するまで制御を返さない

引数:
   HWND   hWnd,    // ウィンドウハンドル
   UINT   Msg,     // メッセージコード
   WPARAM wParam,  // wParamパラメータ
   LPARAM lParam   // lParamパラメータ
// 呼出側
  // 変数宣言
  CWnd* m_pCmdTarget;
  // 関数宣言
  void SetCmdTarget(CWnd* pWnd)
  {
     m_pCmdTarget = pWnd;
  }
  // ウィンドウメッセージWM_CAL_SELECTを送る
  TString Date = _T("2006/01/01");
  m_pCmdTarget->SendMessage(WndMsg::WM_CAL_SELECT, reinterpret_cast<WPARAM>(&Date));
// 受取側
  // ヘッダに
  afx_msg LRESULT onCalSelect(WPARAM wParam, LPARAM lParam);
  // メッセージマップに
  ON_MESSAGE(WndMsg::WM_CAL_SELECT, &GairaiViewHeader::onCalSelect) // ユーザー定義メッセージは、通常、WM_USER から 0x7FFF までの範囲で定義
  // どこかで
  呼出側ポインタ->SetCmdTarget(this);
  // 本体
  LRESULT GairaiViewHeader::onCalSelect(WPARAM wParam, LPARAM /* lParam */)
  {
	TString* Date = reinterpret_cast<TString*>(wParam);  // 2006/01/01が抜き出せる
       return 0;
  }

SetEvent(HANDLE hEvent)

戻り値: BOOL
オブジェクトをシグナル状態に

スレッドの終了処理

bool bRet = ::SetEvent(m_hEventStop);
if (!bbRet)
{
 ::AfxMessageBox(_T("終了イベントのセットに失敗しました"));
 return;
}
if (m_pThread != NULL)
{ // スレッド実行中
  // スレッドの終了を待つ
  ::WaitForSingleObject(m_pThread->m_hThread, INFINITE);
  // スレッドオブジェクト破棄
  delete m_pThread;
  m_pThread = 0;
}
// 終了イベントクリア
bool bRet = ::ResetEvent(m_hEventStop);
if (!bRet)
{
 ::AfxMessageBox(_T("終了イベントのクリアに失敗しました"));
 return;
}

SetTimer(nIDEvent, nElapse, LpfnTimer)

  • nIDEvent: 0以外のタイマ識別子を指定
  • nElapse: タイムアウト値をミリ秒単位で指定
  • lpfnTimer: WM_TIMERメッセージを処理するためのアプリケーションが用意したTimerProcコールバック関数のアドレスを指定。NULLの場合は、Cwndオブジェクトによって処理される。 フォーム(orダイアログ)全体をマウスで指定して、フォームのプロパティ「メッセージ」アイコンをクリックして「WM_TIMER」から「OnTimer」を追加

STLを使うには...

std::vector<int> a;

tmpfile

// テンポラリファイル用のファイル名を取得する。
// テンポラリファイルを作成し、そのファイルへのファイルポインタを返す。
// 作成に失敗した場合には、NULLが返される。
CStdioFile *myFile = new CStdioFile(fp);

tmpnam

// テンポラリファイル用のファイル名を取得する。
//ファイル名は最大TMP_MAX個まで取得可能で、ファイル名の長さは最大L_tmpnamバイトになる。
// ファイル名の取得に失敗するとNULLを返す
char *tmpnam(char *string)
char tmpfilename[L_tmpnam];
if (tmpnam(tmpfilename)==NULL)
{
  // エラー処理
}
try {
  CFile aFile(_T(tmpfilename), CFile::modeCreate|CFile::modeWrite|CFile::shareExclusive);
}
catch (CFileException *e) {
  e->Delete();
}

TString

typedef std::basic_string<TCHAR> TString
CString c;
TString t;
t = (LPCTSTR)c;    // CSTring -> TString
c = t.c_str();     // TString -> CString
#include <boost/format.hpp>
#include <boost/lexical_cast.hpp>
// TString から Int を得る
int GetIntFromTString(TString src)
{
   int dst;
   try
   {
       dst = lexical_cast<int>(src);
   }
   catch(boost::bad_lexical_cast & ex)
   {
	::AfxMessageBox(_T("失敗"));
	const TString msg
		= io::str(TFormat(Msg::ERR_LEXICAL_CAST_FAILURE)
				% ex.what());
	theApp.getLogger()->writeLog(LogType::LT_ERROR, msg);
	return -1;
    }
    return dst;
}
// int から TString を得る
TString GetTStringFromInt(int src)
{
   TString dst;
   try
   {
	dst = lexical_cast<TString>(src);
   }
   catch(boost::bad_lexical_cast & ex)
   {
	::AfxMessageBox(_T("失敗"));
	const TString msg
		= io::str(TFormat(Msg::ERR_LEXICAL_CAST_FAILURE)
				% ex.what());
	theApp.getLogger()->writeLog(LogType::LT_ERROR, msg);
	return _T("");
   }
   return dst;
}
// \ を \\ に変換
TString filePath = "c:\temp\"
TString result = _T("");
TString searchString = _T("\\");
string::size_type findPos = 0;
string::size_type searchPos = 0;
while (findPos != string::npos)
{
  findPos = filePath.find(searchString, searchPos);
  if (findPos != string::npos)
  {
	result += filePath.substr(searchPos, findPos-searchPos) + "\\\\";
	searchPos = findPos + searchString.length();
  }
}
findPos = filePath.find_last_of(searchString);
TString file = result + filePath.substr(findPos+searchString.length());
// file = "c:\\temp\\"

TRACE

デバッグ出力に表示、デバッグモードでのみ実行される。

Update関数

Dialogの値をそのメンバ関数に取り込む時 -> 引数をtrueにする
メンバ変数の値をそのDialogに返す時 -> 引数をfalseにする

UpdateAllViews(CView* pSender, LPARAM lHint=0L, CObject* pHint=NULL)

ドキュメントの変更をビューに通知する

pSender: ドキュメントを変更したビューへのポインタ。すべてのビューを更新する場合は、NULL を指定します。
lHint: 変更に関する情報を指定します。 
pHint: 変更に関する情報が格納されているオブジェクトへのポインタ。 

View

親ウィンドウを移動してもOnMove、OnMovingなどは呼ばれない。処理させたいときはMainfrmなどから呼ぶ。

参照渡し

C++では値渡しが基本。参照渡しにしたい場合は、

void swap(int& x, int& y)
{
 int tmp = x;
 int x = y;
 int x = tmp;
}

UpdateWindow()

アプリケーションのキーをバイパスして、直接WM_PAINTメッセージを送る

Viewの作成

CView *MyView = (CView *)RUNTIME_CLASS(CCanvas)->CreateObject();
MyView->Create(NULL, NULL, WS_CHILD|WS_VISIBLE, rect, this, IDC_CANVAS_VIEW);

WaitForSingleObject(HANDLE hHANDLE, DWORD dwMilliseconds)

hHANDLE: オヴジェクトのハンドル
dwMilliseconds: タイムアウト時間

指定されたカーネルオブジェクトがシグナル状態になるか、指定された時間が経過するまでスレッドをスリープ。 0を指定するとオブジェクトがシグナル状態かどうかを調べてすぐに制御を返す。 INFINITEを指定すると、オブジェクトがシグナル状態になるまで待ち続ける

WAIT_OBJECT_0: オブジェクトがシグナル状態
WAIT_TIMEOUT: タイムアウト時間が経過

スレッドが終了する = シグナル状態になる

WaitForMultipleObjects(DWORD nCount, CONST HANDLE *lpHandles, BOOL fWaitAll, DWORD dwMilliseconds)

nCount: スレッドの個数
lpHandles: スレッドのハンドルを配列で
fWaitAll: true(すべてのスレッドがシグナル状態)、 false(どれか1つのスレッドがシグナル状態)
dwMilliseconds: タイムアウト時間
WAIT_OBJECT_ + 0: スレッド0がシグナル状態

XOR

特定のビットを反転するのに用いる

アプリケーションの起動パスの取得

char fullpath[_MAX_PATH], drive[_MAX_DRIVE], dir[_MAX_PATH], fname[_MAX_FNAME], ext[_MAX_EXT];
//起動パスの取得
GetModuleFileName(NULL, fullpath, sizeof(fullpath));
_splitpath(fullpath, drive, dir, fname, ext);

アプリケーション名の変更

// InitInstanceで
free((void*)m_pszAppName);
m_pszAppName=_tcsdup(_T("読影医別依頼状況表示ツール"));

ウィンドウメッセージ

「マウスが押された」、「ウィンドウサイズが変更された」などウィンドウに関連するイベントはウィンドウメッセージによって通知される。

  • WM_ERASEBKGND
    • ウィンドウに無効領域が発生したときに送られる。0を返した場合、無効領域になった部分はウィンドウの背景色で塗りつぶされない

裏画面

CDC m_MemDC;
CBitmap* m_pOldBitmap;
CBitmap* m_pBitmap;   // デストラクタでの処理を忘れずに!
void CFamilyHistoryView::OnInitialUpdate()
{
	CDC *pDC;//通常のデバイスコンテキストを格納するポインタ
	CRect cClient;//クライアント領域
	CBrush cBrush;//ブラシ
	CBrush *pOldBrush;//ブラシのストック変数
	// ビットマップオブジェクトの動的確保
	m_pBitmap = new CBitmap();
	// クライアント領域の取得
	GetClientRect(&cClient);
	// 現在のDCのポインタを取得
	pDC=GetDC();
	// 通常のDCとメモリDCに互換性をつける
	m_MemDC.CreateCompatibleDC(pDC);
	// 通常のDCの互換性のあるビットマップをメモリ上に作成
	m_pBitmap->CreateCompatibleBitmap(pDC,cClient.Width(),cClient.Height());
	//ビットマップとメモリDCの関連付け
	m_pOldBitmap = m_MemDC.SelectObject(m_pBitmap);
	//白のBrushを作成
	cBrush.CreateSolidBrush(RGB(255,255,255));
	//現在のbrushのポインタをpOldBrushとして残しておく
	pOldBrush=m_MemDC.SelectObject(&cBrush);
	// クライアント領域でbitmapをコピー
	m_MemDC.PatBlt(0,0,cClient.Width(),cClient.Height(),PATCOPY);
	//昔のBrushに戻す
	m_MemDC.SelectObject(pOldBrush);
	//DCを解放
	ReleaseDC(pDC);
}
void CFamilyHistoryView::OnDraw(CDC* pDC)
{
   CFamilyHistoryDoc* pDoc = GetDocument();
   ASSERT_VALID(pDoc);
   if (!pDoc)
	return;
   // ここに図形描画
   CRect rect;
   GetClientRect(&rect);
   pDC->BitBlt(0, 0, rect.Width(), rect.Height(), &m_MemDC, 0, 0, SRCCOPY);
}
void CFamilyHistoryView::OnDestroy()
{
	// TODO: ここにメッセージ ハンドラ コードを追加します。
	// ストックしておいたビットマップを割り当てる
	m_MemDC.SelectObject(m_pOldBitmap);
	// ビットマップオブジェクトを削除する
	m_pBitmap->DeleteObject();
	// メモリデバイスコンテキストの削除
	m_MemDC.DeleteDC();
	// 正規のOnDestroyを実行する
	CView::OnDestroy();
}
void CFamilyHistoryView::OnSize(UINT nType, int cx, int cy)
{
	CView::OnSize(nType, cx, cy);
	// TODO: ここにメッセージ ハンドラ コードを追加します。
        // OnInitialUpdate()でやってる処理と同じ
	ViewBackgroundScreen();
       // 表示されてたものをすべて表示
	AllView();
	
	CRect rect;
	GetClientRect(rect);
	m_MemDC.BitBlt(0, 0, rect.Width(), rect.Height(), &m_MemDC, 0, 0, SRCCOPY);
}

参考:http://www.geocities.jp/chiakifujimon/makesoft2/proc3.html

仮想関数

オーバロードされる可能性のあるメンバ関数には、virtualキーワードをつけて仮想関数にする。
基本クラスへのポインタを使って仮想関数を実行したとき、適切なバージョンの関数が実行される(基本型への回帰の回避)

現在時刻を得る

#include <iostream>
#include <boost/date_time/gregorian/gregorian.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
using namespace boost::gregorian;
using namespace boost::posix_time;
const ptime now(second_clock::local_time());
const date d(now.date());
const time_duration time(now.time_of_day());
TFormat("%4d/%2d/%2d/ %2d:%2d:%2d") % d.year() % d.month() % d.day() % time.hours() % time.minutes() % time.seconds()

コピーコンストラクタ

クラスのコピー用。普通のコンストラクタに初期値を設定したり、代入をしても参照渡しなのでダメ(メンバ変数にポインタ等を使ってなければ大丈夫だけど)。

コマンドハンドラ

メニューやボタンのクリックはコマンドとしてコマンドターゲット(CCmdTargetクラス)に送られる

コンマ演算子

(expression1, expression2) 左から順に実行される 優先度が低いので括弧づけしておく コンマ演算子全体の値は最右端の演算の値

サスペンドカウンタ

スレッドオブジェクトが持つ待機と実行を制御するカウンタ
カウンタが0のとき実行し、そうでなければ待機
カウンタをインクリメント: SuspendThread
カウンタをデクリメント: ResumeThread

三項演算子

(式1) ? 式2 : 式3

純粋仮想関数

virtural void show()=0のように「=0」をつける。
抽象クラス(純粋仮想関数を持つクラス)は、その派生クラスを統一的に管理するために存在する。純粋仮想関数を利用することで、実行ファイルサイズを小さくすることができる。

ステータスバーに文字を出力

// メインフレームウィンドウのポインタを取得します
CFrameWnd* pWnd = (CFrameWnd*)AfxGetApp()->m_pMainWnd;
// ステータスバーのポインタを取得します
CStatusBar* pStatusBar = (CStatusBar*)pWnd->GetMessageBar();
// それぞれのペインに文字を出力します
pStatusBar->SetPaneText(0, _T("Pane 0"));

重複includeの回避

C++ Coding Standards 24

  • 常に内部の#includeガードを書こう。決っして外部の#includeガードを書いてはいけない
    // .hppに
    #ifndef INCLUDE_UTIL_HPP
    #define INCLUDE_UTIL_HPP
    // 何かしらの処理
    #endif

データベースへのアクセス

afxdb.hが必要

CDatabaseオブジェクトを構築。その後、OpenExを呼出して接続。
OpenEx(LPCTSTR, DWORD)
 -LPCTSTR: "DSN=SQLSERVER_SOURCE;UID=SA;PWD=abc123"
 -接続に失敗するとCDBExceptionをスロー
close()
 -データベースへの接続を解除。ただし、オブジェクトは破棄されないので再利用可
IsOpen()
 CDatabaseオブジェクトがデータソースに現在接続されているかどうか調べる
CRecordSetオブジェクトを構築。その後、データベースからの読み込み
IsEOF()
 -レコードセットにレコードが存在しない場合、または最終レコードより後にスクロールした場合は0以外の値を返す
GetFieldValue(LPCTSTR, CDBVariant&, short)
 -LPCTSTR: インデックスorフィールドの名前
 -CDBVariant: フィールドの値を保持
MoveNext()
 -現在のレコードを次の行セットの先頭レコードに位置づける
GetODBCFieldCount()
 レコードセットオブジェクト内のフィールドの合計数を取得
GetODBCFieldInfo(nIndex, CODBCFieldInfo&)
 -nIndex: 0から始まるフィールドのインデックス
 -CDBCFieldInfo&: CDBCFieldInfo構造体への参照
 --CString m_strName: フィールド名
 --SWORD m_nSQLType: フィールドのSQLデータ型
 --UDWORD m_nPrecision: フィールドの最大有効桁数
 --SWORD m_nScazle: フィールドのスケール
 --SWORD m_nNullability: フィールドにNULL値を仕様できるかどうか示す

デバイスコンテキスト

ディスプレイやプリンタなどの表示デバイスを出力する際に必要な描画情報を保持するメモリ領域

デフォルト引数

関数の引数にデフォルト値を設定できる

// プロトタイプ宣言
void hoge(int i=0;)
// 実装
void hoge::hoge(int i /* =0 */)

ファイルダイアログのオープン

try
{
  // 「名前をつけて保存」ダイアログの作成
  CFileDialog dlg(FALSE, _T("*.*"), _T("default.csv"), 
	           OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT,
			_T("csv (*.csv)|*.csv|すべて (*.*)|*.*||"), this);
  dlg.m_ofn.lpstrInitialDir = _T("c:\")
  // 「ファイルを開く」ダイアログの作成
  CFileDialog dlg(TRUE, _T("*.*"), _T("default.csv"), 
	           OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT,
			_T("csv (*.csv)|*.csv|すべて (*.*)|*.*||"), this);
OFN_ALLOWMULTISELECT複数ファイルの選択を可能にする
OFN_FILEMUSTEXIST存在しないファイル名を指定した場合、警告を表示し、ダイアログを終了しない。このフラグを指定するとOFN_PATHNUSTEXISTも有効になる
OFN_PATHMUSTEXIST存在しないパスを指定した場合、警告を表示し、ダイアログを終了しない
OFN_NODEREFERENCELINKSショートカットを選択したとき、直接そのファイル名を返す。指定しないと、ショートカットが指すファイル名を返す
OFN_NONETWORKBUTTON[ネットワーク]ボタンを表示しない
OFN_SHOWHELP[ヘルプ]ボタンを表示する
OFN_OVERWRITEPROMPT選択されたファイルがすでに存在するなら、 ファイルに上書きするべきかどうか確認する
OFN_CREATEPROMPT指定ファイルが存在しない時、新規作成するかどうかを確認します。
OFN_READONLY読み取り専用ファイルとして開く(R)を最初からオンに選択させます。
OFN_HIDEREADONLY読み取り専用ファイルとして開く(R)をオンに選択させません
// 指定されたファイルのフルパス名を取得
CFileDialog::GetPathName();
// 選択されたファイルのファイル名を返す
CFileDialog::GetFileName();
// 選択されたファイルの拡張子を返す
CFileDialog::GetFileExt();
// 選択されたファイルのタイトルを返す
CFileDialog::GetFileTitle();
// ファイルの複数選択
POSITION pos = dialog.GetStartPosition();
while (pos != NULL)
   AfxMessageBox(dialog.GetNextPathName(pos));
// ファイルリスト中の最初のファイル名の位置を取得。1つもファイル名が選択されていない場合はNULL
CFileDialog::GetStartPosition
// ファイル名を1つずつ取得する。ファイル名が残されていない場合にはNULLを返す。フルパス名を返す
CFileDialog::GetNextPathName(POSITION& pos);
  // 「ファイルを開く」ダイアログを開く
  if( dlg.DoModal() == IDOK) {
	// 選択されたファイルパス名を表示
	TString FileName = dlg.GetPathName();
	TString Item = _T("\"病院コード\",\"病院グループコード\",\"病院名\",\"依頼科\",\"読影医名\",");
	CStdioFile TxtFile;
       // オープン時のモードの設定により、エラーが発生するので注意!
	BOOL FileOpened = TxtFile.Open(FileName.c_str(), CFile::modeCreate | CFile::modeWrite);
	if(FileOpened)
	{
		TxtFile.WriteString(Item.c_str());
		TxtFile.WriteString(results.c_str());
	        TxtFile.Close();
	}
  } else
  {
	::AfxMessageBox( Msg::ERR_OPEN_FILE );
	return;
  }
}
catch( CFileException& ex )
{
  string msg = io::str( format( Msg::ERR_OPEN_FILE_DIALOG ) % ex.m_cause );
  theApp.GetLogger()->writeLog( Logger::L_ERROR, msg );
  ::AfxMessageBox( msg.c_str() );
}

フォルダ内のファイル検索

// Cドライブのすべてのファイルを検索
SearchFile(_T("C:"));
void SearchFile(CString strFolder)
{ 
   CFileFind FileFind;
   
   // すべてのファイルを検索
   CString strSearchFile = strFolder + _T("\\*.*");
   
   if(!FileFind.FindFile(strSearchFile)) 
       return; 
   
   BOOL bContinue = TRUE;
   while(bContinue){ 
       
       bContinue = FileFind.FindNextFile();
       
       // ドット("." , "..")の場合 無視
       if(FileFind.IsDots()) 
           continue; 
       
       // ディレクトリの場合、そのディレクトリ内を検索するため再起呼び出し
       if(FileFind.IsDirectory()) 
           SearchFile(FileFind.GetFilePath()); 
       else 
           // ファイルの場合
           TRACE("%s\n",FileFind.GetFilePath()); 
   }; 
}

キー入力検知

void CFamilyHistoryView::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)
{
  // TODO: ここにメッセージ ハンドラ コードを追加するか、既定の処理を呼び出します。
  if (nChar != VK_CONTROL)
  {
	// Ctrl-
       if(::GetKeyState(VK_CONTROL)<0)
	{
               // c
		if (nChar == 0x43)
		{
		}
               // v
		if (nChar == 0x56)
		{
		}
               // x
		if (nChar == 0x58)
		{
		}
               // z
		if (nChar == 0x5a)
		{
		}
       }
   }
   CView::OnKeyDown(nChar, nRepCnt, nFlags);

}

コントロールのフォントを変更する

HFONT    hFont;
int fontsize = lexical_cast<int>(m_fontSize);
hFont = CreateFont(fontsize, 0, 0, 0,
			FALSE, FALSE, FALSE, 0,
			SHIFTJIS_CHARSET, OUT_DEFAULT_PRECIS,
			CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY,
			FIXED_PITCH | FF_MODERN, m_fontName.c_str());
SendDlgItemMessage(IDC_EDIT_SAMPLE, WM_SETFONT, (WPARAM)hFont, 0L );

ツールチップの表示

m_ToolTip1.Create(this, TTS_ALWAYSTIP | TTS_BALLOON ); // ダイアログ上のボタンを指定        
m_ToolTip1.AddTool((CButton *)GetDlgItem(IDC_BTN1),_T("あいうえお")); 
BOOL CTheDlg::PreTranslateMessage(MSG* pMsg) 
{
       switch(pMsg->message){
           case WM_LBUTTONDOWN:            
           case WM_LBUTTONUP:              
           case WM_MOUSEMOVE:
           m_ToolTip1.RelayEvent(pMsg);
           m_ToolTip2.RelayEvent(pMsg);
       }
       return CDialog::PreTranslateMessage(pMsg);
}

四捨五入

d = floor(d+0.5);

テンプレート

template <class T> void swap(T& x, T& y)
{
  T tmp = x;
  x = y;
  y = tmp;
};

閉じるボタンを無効に

CMenu* pMenu = GetSystemMenu(FALSE);
ASSERT(pMenu);
pMenu->EnableMenuItem(SC_CLOSE, MF_GRAYED);

ドキュメントとビュー

// ViewからDocへの参照
CXXXDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
pDoc->YYY
// DocからViewへの参照
POSITION pos = GetFirstViewPosition();
CXXXView* pView = (CXXXView*)this->GetNextView(pos);
pView->YYY
// DocとViewの関連づけ
CXXXDoc->AddView(CXXXView);

ファイルの存在チェック

// 存在しているならtrue
bool DoesFileExist( TString FileName )
{
   bool bRet = false;
   WIN32_FIND_DATA	FindData;
   HANDLE hFile = FindFirstFile( FileName.c_str(), &FindData );
   if ( hFile != INVALID_HANDLE_VALUE )
       bRet = true;
   FindClose( hFile );
   return bRet;
}

フォント取得

CFont *pFont;
LOGFONT logFont;
pFont = GetFont();
pFont->GetLogFont(&logFont);
// フォントをポイントサイズで取得
// マッピングモードがMM_TEXTの場合
int pointSize = -MulDiv(logFont.lfHeight, GetDeviceCaps(GetDC()->GetSafeHdc(), LOGPIXELSY), 72);

参考URL: http://support.microsoft.com/kb/74299/ja http://72.14.235.104/search?q=cache:fubrRw54nm0J:www2.ocn.ne.jp/~mizu/api/c/c0002-2.htm+lfHeight+-11&hl=ja&ct=clnk&cd=7&gl=jp&lr=lang_ja&client=firefox

太字(通常の線種でないとき)

LOGBRUSH logBrush;
logBrush.lbColor = color;
logBrush.lbHatch = 0;
logBrush.lbStyle = BS_SOLID;
// 点線
CPen pen(PS_DASH | PS_GEOMETRIC | PS_ENDCAP_FLAT, width, &logBrush);
CPen* pOldPen = pDC->SelectObject(&pen);
pDC->SelectObject(&pen);

ヘルプをつけるには

  • プロジェクト生成時に、「状況依存のッヘルプ」にチェックを入れておく。
  • FXCORE.RTF、AFXPRINT.RTFのファイルが作成されるので、Wordなどで編集する。

変数の初期化

C++ Coding Standards 19 変数は必ず初期化しよう Exceptional C++ 項目42 変数の初期化 T t(u); // T T=u;の代わりに

ボタンにBitmapをはりつけ

void DigestSelectBtn::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)
{
// TODO:  指定された項目を描画するためのコードを追加してください。
	CRect rect;
	rect.CopyRect(&lpDrawItemStruct->rcItem);
	CDC *pDC = CDC::FromHandle(lpDrawItemStruct->hDC);
	UINT nState = lpDrawItemStruct->itemState; 
	
	HBITMAP hBitmap = (HBITMAP)::LoadImage(NULL, _T("res\\Erase.bmp"),IMAGE_BITMAP,0,0,LR_LOADFROMFILE );
	CBitmap* pBitmap = CBitmap::FromHandle(hBitmap);
	CDC OB;
	CBitmap *pOld;
	OB.CreateCompatibleDC( pDC );
	pOld = OB.SelectObject( pBitmap );
	BITMAP bm;
	pBitmap->GetBitmap(&bm);
	/* bitmapの貼り付け */
	pDC->SetStretchBltMode(HALFTONE);
	pDC->StretchBlt(rect.left, rect.top, rect.Width(), rect.Height(), &OB, 0, 0, bm.bmWidth, bm.bmHeight, SRCCOPY);
	/* 縁の描画 */
	if (nState & ODS_SELECTED)
	{
		pDC->DrawEdge(rect,EDGE_SUNKEN,BF_RECT);
	} else
	{
		pDC->DrawEdge(rect,EDGE_RAISED,BF_RECT);
	}

右クリックメニュー

// メニュー押下に対するメッセージ関数を用意しておかないと、表示が無効になったままになるので注意!!!
void CFamilyHistoryView::OnContextMenu(CWnd *pWnd, CPoint pos)
{
  CMenu Menu;
  CMenu* pMenu;
  // 右クリックメニューの追加
  Menu.LoadMenu(IDR_RIGHT_MENU);
  ASSERT(Menu);
  pMenu = Menu.GetSubMenu(0);
  ASSERT(pMenu);
  pMenu->TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON, pos.x, pos.y, AfxGetMainWnd());
}

メニュー項目

// メニュー項目を有効に
pCmdUI->Enable();

// メニュー項目のチェック
if (自分のメニューなら)
 pCmdUI->SetCheck(1);
else
 pCmdUI->SetCheck(0);

メモリリークの検出

// .cpp
// include文より後ろに挿入
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
// プログラムの先頭に;
_CrtSetBreakAlloc(1329)

文字コード

モードレスダイアログの作成

  • ダイアログの作成(IDをIDD_DLG)
  • ダイアログを管理するクラスを作成(Dlg.h, Dlg.cpp)
  • CDlg1.hに以下の変数を追加
    CWnd* m_pParent;
    int m_nID;
  • コンストラクタ内に以下を追加
    m_pParent = pParent;
    m_nID = CDlg1::IDD;
  • クラスウィザードからCreate関数を追加し、引数を消去。関数内の引数は以下のように変更
    return CDialog::Create( m_nID, m_pParent);
  • 表示させたいときに、
    Dlg* pDlg = new Dlg(this);
    pDlg->Create();
    pDlg->ShowWindow(SW_SHOW);

矢印

	CPoint startPos, endPos;
	startPos.x = m_rect.left;
	startPos.y = m_rect.top;
	endPos.x = m_rect.right;
	endPos.y = m_rect.bottom;
	
	pDC->MoveTo(startPos);
	pDC->LineTo(endPos);
	double x, y;
	x = endPos.x - startPos.x;
	y = endPos.y - startPos.y;
	double r = atan2(y, x);
	POINT arrowHead[2], newArrowHead[2];
	arrowHead[0].x = -wingLength;
	arrowHead[0].y = -wingLength;
	arrowHead[1].x = -wingLength;
	arrowHead[1].y =  wingLength;
	for(int j = 0; j < 2; j++)
	{
		newArrowHead[j].x = (int)(arrowHead[j].x * cos(r) - arrowHead[j].y * sin(r));
		newArrowHead[j].y = (int)(arrowHead[j].x * sin(r) + arrowHead[j].y * cos(r));
	}
	pDC->MoveTo(endPos);
	pDC->LineTo(endPos + newArrowHead[0]);
	pDC->MoveTo(endPos);
	pDC->LineTo(endPos + newArrowHead[1]);

ラジオボタン

ラジオボタンをグループ化するためには、

  • ラジオボタン、グループボックスの順にタブオーダーを設定する。
  • タブオーダーが最初のラジオボタンプロパティにおいて、グループを「true」に設定する。

最新の20件

2007-03-05 2008-07-30
  • VC++/C++
2007-05-24 2007-05-09 2007-04-12 2007-03-20 2007-03-18 2007-02-20 2007-02-18 2007-02-04 2006-12-25 2006-09-22 2006-05-02 2005-12-09 2005-05-13 2005-04-28 2005-04-22