: | 頁内へのリンク | |
: | サイト内の別頁へのリンク | |
: | 外部サイトへのリンク |
【Q】 MSDN には有用なサンプルが有りますが,そういう Web サイトって有りませんか.
【A】 以下はどうでしょう.
・CodeGuru
・MSDN Online Japan
http://www.microsoft.com/japan/developer
・Microsoft Systems Journal Homepage
・VC++によるWin32プログラミングTips
http://www.expertmg.com/html/cti/vctips/
・Belution.com Visual C++ の Tips を公開
http://www.belution.com/worldwide/ja/
【Q】 移植性を高める為に VC++ の独自規格でなく ANSI C/C++ でプログラミングしたいのですが.
【A】 完全には無理ですが,コンパイル オプション /Za で,Microsoft 独自の (ANSI C 標準規格に対する) 拡張機能を無効に出来るようです (或いはプロジェクトの設定で Microsoft 言語拡張機能を無効にする).これではどうでしょうか.
【Q】 MFC 使用のアプリケーションで,別スレッドに CWnd のポインタを渡して処理をしようとした処,アサーションに失敗してしまいます.どうしたら良いでしょうか.
【A】 MFC ではスレッド毎にハンドルと MFC のオブジェクトの対応表を保持しています.即ち別スレッドでは別の対応表を見に行く事に成り,うまく動作しません.
別スレッドにはハンドルを直接渡すようにしましょう.クラスのメンバ関数等を呼び出したい場合には SendMessage が安全です.
【Q】現在 VC++ 6 を使っていますが,昔の VC++ のデベロッパー スタジオのように現在の Cpp ファイルから対応する H ファイルを簡単に開く方法はないでしょうか.
【A】以下のようなマクロを使うのはどうでしょう.
1.「ツール」-「マクロ」で例えば "OpenCppH" という名前でマクロを「編集」
'H ファイルと C/Cpp ファイルの表示切替
Sub OpenCppH()
sn = ActiveDocument.FullName '現在編集中のファイル名
cl = len(sn) '現在のファイル名の文字数
'現在が H なら Cpp を表示
if right(sn, 2) = ".h" then
s2 = left(sn, cl - 2) + ".cpp" 'Cpp ファイル名
Documents.Open s2, "Text" '開く
end if
'現在が Cpp なら H を表示
if right(sn, 4) = ".cpp" then
s2 = left(sn, cl - 4) + ".h" 'H ファイル名
Documents.Open s2, "Text" '開く
end if
End Sub
* 2002/07/10 F山 さん から, 上記ではヘッダーファイル
に対応する cpp ファイルが無い場合等にエラーになるとの御指摘と,改良版のマクロを頂きました.F山 さん
有難う御座いました.御許可を頂いたので以下に改良版を掲載します.
'H ファイルと C/Cpp ファイルの表示切替 (改良版)
Sub OpenCppH()
sn = ActiveDocument.FullName '現在編集中のファイル名
cl = len(sn) '現在のファイル名の文字数
set fs = CreateObject("Scripting.FileSystemObject") 'FileSystemObject
'現在が H なら Cpp を表示
if right(sn, 2) = ".h" then
s2 = left(sn, cl - 2) + ".cpp" 'Cpp ファイル名
if fs.FileExists(s2) = false then
exit Sub 'ファイルが存在しないときは終了
end if
Documents.Open s2, "Text" '開く
end if
'現在が Cpp なら H を表示
if right(sn, 4) = ".cpp" then
s2 = left(sn, cl - 4) + ".h" 'H ファイル名
set fs = CreateObject("Scripting.FileSystemObject") 'FileSystemObject
if fs.FileExists(s2) = false then
exit Sub 'ファイルが存在しないときは終了
end if
Documents.Open s2, "Text" '開く
end if
End Sub
2.「ツール」-「カスタマイズ」-「キーボード」-「マクロ」-「OpenCppH」で御好みのショートカット キーを設定.
* 2003/09/04 Microsoft Visual Studio .NET2003 に移植したバージョンを,casper さんが以下で公開されています.
Microsoft Visual Studio .NET2003用マクロ詰め合わせ
Microsoft Visual Studio .NET2003 に便利と思われる機能を追加するマクロ詰め合わせ
【Q】ダイアログ ボックス ベースのアプリケーションを作成しています.
ところがアクセラレータ テーブルを作成してあるのに,何故か設定したキーが効いてくれません.どうしたら良いでしょうか.
【A】例えば,そのダイアログを CTestDlg とすると,
(1) TranslateAccelerator を行うメンバー関数を追加する
リソースのアクセラレータの ID を IDR_ACCELERATOR1 とすると,
BOOL CTestDlg::TranslateAccelerator(MSG* pMsg)
{
// アクセラレータを一回だけロードする
static HACCEL hAccel = HACCEL(0);
if (hAccel == HACCEL(0)) {
hAccel = ::LoadAccelerators(::AfxGetApp()->m_hInstance, MAKEINTRESOURCE(IDR_ACCELERATOR1));
ASSERT(hAccel != HACCEL(0));
}
// API の TranslateAccelerator を呼ぶ
return ::TranslateAccelerator(GetSafeHwnd(), hAccel, pMsg);
}
(2) 仮想関数 PreTranslateMessage をオーバーライドして先述の関数を呼ぶ
BOOL CTestDlg::PreTranslateMessage(MSG* pMsg)
{
if (TranslateAccelerator(pMsg))
return TRUE;
return CDialog::PreTranslateMessage(pMsg);
}
以上で WM_COMMAND (OnCommand) で受けられるように成ります.
または,次のようにして RegisterHotKey を利用しては如何でしょうか.
この場合は アクセラレータ & OnCommand は使用しません.
(1) 適当に ID を設定
const int ID_TEST = 100;
(2) 開始時に RegisterHotKey
BOOL CTestDlg::OnInitDialog()
{
CDialog::OnInitDialog();
::RegisterHotKey(GetSafeHwnd(), ID_TEST, MOD_CONTROL, UINT('D'));
}
(3) 終了時に UnregisterHotKey
void CTestDlg::OnDestroy()
{
::UnregisterHotKey(GetSafeHwnd(), ID_TEST);
CDialog::OnDestroy();
}
(4) メッセージ ハンドラ (for WM_HOTKEY) を追加
BEGIN_MESSAGE_MAP(CTestDlg, CDialog)
//{{AFX_MSG_MAP(CTestDlg)
ON_MESSAGE(WM_HOTKEY, OnHotKey)
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
LRESULT CTestDlg::OnHotKey(WPARAM wParam, LPARAM lParam)
{
if (int(wParam) == ID_TEST &&
UINT(LOWORD(lParam)) == MOD_CONTROL && UINT(HIWORD(lParam)) == UINT('D')) {
// 目的の処理を行う
}
return LRESULT(0);
}
MFC でドキュメント-ビュー構造 (MDI) の場合のクラス図 (UML) を描いてみました.
Microsoft Visual Modeler を使用しています.
CDocument の更新を CView に通知するには CDocument::UpdateAllViews と CView::OnUpdate を使うのが普通です (Observer パターン) が,この時ユーザー定義の更新データを渡すことが出来ます (Observer パターンの push モデル).
ところが,この時受け渡すのは CObject へのポインタと成っています.CObject から派生していないオブジェクトを渡すのには不便です.
例えば,再描画の為の更新領域を CRect で渡そうとしても CRect は CObject ではないので渡しづらいのです.
virtual void CDocument::UpdateAllViews(CView* pSender, LPARAM lHint = 0L, CObject* pHint = NULL);
virtual void CView::OnUpdate(CView* pSender, LPARAM lHint, CObject* pHint);
そこで,CObject から派生していないクラスのオブジェクトを渡す為のラッパー クラスを作成してみました.
//---------------------------------------------------------------------------
// CObjectWrapper.h
#ifndef CObjectWrapper_h
#define CObjectWrapper_h
#include <afxwin.h>
template <class Type>
class CObjectWrapper : public CObject
{
public:
explicit CObjectWrapper(const Type& object)
: wrapped_(object)
{}
operator const Type&() const
{ return wrapped_; }
private:
Type wrapped_;
};
#endif // CObjectWrapper_h
//---------------------------------------------------------------------------
// CObjectWrapperTestView.h
#ifndef CObjectWrapperTestView_h
#define CObjectWrapperTestView_h
#include "CObjectWrapper.h"
class CCObjectWrapperTestView : public CView
{
DECLARE_DYNCREATE(CCObjectWrapperTestView)
virtual void OnUpdate(CView* pSender, LPARAM lHint, CObject* pHint);
virtual void OnDraw(CDC*) {}
afx_msg void OnTest();
DECLARE_MESSAGE_MAP()
enum // for lHint
{
UPDATE_RECT = 1
};
// Wrapper
typedef CObjectWrapper<CRect> Wrapper;
static void TestResult(const CRect& updateRect);
};
#endif // CObjectWrapperTestView_h
//---------------------------------------------------------------------------
// CObjectWrapperTestView.cpp
#include "CObjectWrapperTestView.h"
#include "resource.h" // for ID_TEST
IMPLEMENT_DYNCREATE(CCObjectWrapperTestView, CView)
BEGIN_MESSAGE_MAP(CCObjectWrapperTestView, CView)
ON_COMMAND(ID_TEST, OnTest)
END_MESSAGE_MAP()
void CCObjectWrapperTestView::OnUpdate(CView* /* pSender */,
LPARAM lHint, CObject* pHint)
{
switch (lHint) {
case UPDATE_RECT:
TestResult(*(Wrapper*)pHint);
break;
}
}
void CCObjectWrapperTestView::OnTest()
{
const CRect updateRect(10, 20, 30, 40); // Dummy Data for Test
// 他のビューへ更新領域を通知するテスト
GetDocument()->UpdateAllViews(this, UPDATE_RECT,
&Wrapper(updateRect));
}
void CCObjectWrapperTestView::TestResult(const CRect& updateRect)
{
// 結果の確認
TRACE(_T("CCObjectWrapperTestView::TestResult(%d, %d, %d, %d)\n"),
updateRect.left , updateRect.top ,
updateRect.right, updateRect.bottom);
}
MFC と C++ の標準関数 と Windows API には良く似た機能のものが有ります.一部を表にしてみます.
MFC (または C++ 関数) | Windows API | |
---|---|---|
ウィンドウ | CWnd とその派生クラス <<クラス>> | CreateWindow 等 <<関数>> |
GDI リソース | CGdiObject とその派生クラス <<クラス>> | CreatePen 等 <<関数>> |
デバイス コンテキスト | CDC とその派生クラス <<クラス>> | BeginPaint, GetDC 等 <<関数>> |
文字列操作 | CString <<クラス>>(_tcscpy, _tcslen, _tcscmp 等 <<関数>>) | lstrcpy, lstrlen, lstrcmp 等 <<関数>> |
メモリー操作 | コンストラクタ <<クラス>> (memset, memcpy 等 <<関数>>) | ZeroMemory, FillMemory, CopyMemory, MoveMemory 等 <<関数>> |
MFC と C++ でも良く似た機能のものが有ります.元々は,C++ の方が標準的なコレクション クラスや型情報,キャストの機能を持っていなかった時期に MFC の方でサポートされたものです.
一部を表にしてみます.
・コレクション クラス等 <<テンプレート クラス>>
MFC | C++ 標準 | |
---|---|---|
配列 | CArray 等 | vector |
リスト | CList 等 | list |
マップ | CMap 等 | map |
文字列 | CString | string |
・型情報クラスとキャスト
MFC | C++ 標準 | |
---|---|---|
型情報型 | COjbect + CRuntimeClass <<クラス>> | type_info <<クラス>> |
型情報生成 | RUNTIME_CLASS <<マクロ>> | typeid <<演算子>> |
静的キャスト | STATIC_DOWNCAST <<マクロ>> | static_cast, const_cast, reinterpret_cast <<演算子>> |
動的キャスト | DYNAMIC_DOWNCAST <<マクロ>> | dynamic_cast <<演算子>> |
必要なオプション | DECLARE_DYNAMIC + IMPLEMENT_DYNAMIC <<マクロ>> |
・例外処理
MFC | C++ 標準 | |
---|---|---|
Try | TRY <<マクロ>> | try <<キーワード>> |
Catch | CATCH, AND_CATCH, END_CATCH, END_CATCH_ALL <<マクロ>> | catch <<キーワード>> |
Throw | THROW, THROW_LAST <<マクロ>> | throw <<キーワード>> |
【Q】 デバッグ時に,Microsoft Developer Studio 等のデバッガに文字を出力したいのですが.
【A】 MFC を使用している場合は,TRACE マクロを使用します.MFC を使っていない場合は,_RPT0 若しくは _RPT1,_RPT2,_RPT3,_RPT4 等のマクロが使えます.
例.
#include <tchar.h>
#include <crtdbg.h> /* _RPT0,_RPT1,_RPT2,_RPT3,_RPT4 には必要 */
/* デバッグ出力 */
/* Just-In-Time (JIT) デバッグが有効な場合はデバッガに文字列を出力 */
/* (C/C++ 用,Microsoft Visual C++ 依存) */
void Trace(const TCHAR* messageText /* デバッグ出力する文字 */)
{
_RPT0(_CRT_WARN, messageText);
}
【Q】 MFC を使用していないアプリケーションのデバッグ時に,メモリ リークを検出したいのですが.
【A】 crtdbg.h というヘッダー ファイルをインクルードし,プログラムの終了時に _CrtDumpMemoryLeaks 関数 を呼ぶか,プログラムの開始時に _CrtSetDbgFlag 関数を使用して _CRTDBG_LEAK_CHECK_DF フラグをオンにしておきます.
すると,アプリケーション終了時にメモリ リークが存在すれば,VC++ の「アウトプット」の「デバッグ」ウィンドウに,ソースのファイル名と行番号付きでダンプされます.
例.
// MemoryLeakTest.h
#ifndef MemoryLeakTest_h
#define MemoryLeakTest_h
#ifdef _DEBUG
#define _CRTDBG_MAP_ALLOC
#include <crtdbg.h>
#endif // _DEBUG
#ifndef DEBUG_NEW
#ifdef _DEBUG
#define DEBUG_NEW ::new(_NORMAL_BLOCK, __FILE__, __LINE__)
#else // _DEBUG
#define DEBUG_NEW new
#endif // _DEBUG
#endif // DEBUG_NEW
#define new DEBUG_NEW
// アプリケーションの開始時に呼ぶ
inline void CheckMemoryLeaksStart()
{
#ifdef _DEBUG
_CrtSetDbgFlag(_CrtSetDbgFlag(_CRTDBG_REPORT_FLAG) | _CRTDBG_LEAK_CHECK_DF);
#endif // _DEBUG
}
#endif // MemoryLeakTest_h
// Main.cpp
#include <iostream>
// 各ソースやヘッダーで "MemoryLeakTest.h" をインクルード
#include "MemoryLeakTest.h"
int Sub();
int main()
{
CheckMemoryLeaksStart();
// …省略…
Sub();
// …省略…
return 0;
}
// Sub.cpp
#include <iostream>
// 各ソースやヘッダーで "MemoryLeakTest.h" をインクルード
#include "MemoryLeakTest.h"
int Sub()
{
// …省略…
}
Copyright © 1997-2008 Sho's Software