FC2ブログ

まったり開発日誌

embossの工具箱(J2EE Java2 Linux Zaurus C++)

WindowsMobileではじめるWin32APIプログラミング入門

  1. スポンサーサイト(--/--)
  2. 021:子ウィンドウを作る(02/10)
  3. 020:WindowsMobileらしい全画面ダイアログを作る(02/09)
  4. [コラム]DoxyCommentでC++でもコメントを自動生成(05/17)
  5. 019:モードレスダイアログを作る (11/20)
  6. 018:モーダイルダイアログを作る(10/19)
次のページ

スポンサーサイト

上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。
  1. --/--/--(--) --:--:--|
  2. スポンサー広告

021:子ウィンドウを作る

親ウィンドウの中に子ウィンドウを作成してみましょう。
親ウィンドウと同じサイズの子ウィンドウを2つ作成して、表示、非表示を切り替える事で、アプリケーション内での画面遷移を実現してみましょう。

子ウィンドウの作成は、親ウィンドウと同じくCreateWindow関数を使用します。

HWND CreateWindow(
  LPCTSTR lpClassName,  // 登録されているクラス名
  LPCTSTR lpWindowName, // ウィンドウ名
  DWORD dwStyle,        // ウィンドウスタイル
  int x,                // ウィンドウの横方向の位置
  int y,                // ウィンドウの縦方向の位置
  int nWidth,           // ウィンドウの幅
  int nHeight,          // ウィンドウの高さ
  HWND hWndParent,      // 親ウィンドウまたはオーナーウィンドウのハンドル
  HMENU hMenu,          // メニューハンドルまたは子ウィンドウ ID
  HINSTANCE hInstance,  // アプリケーションインスタンスのハンドル
  LPVOID lpParam        // ウィンドウ作成データ
);

子ウィンドウを作成するには、親ウィンドウのWM_CREATE時に、CreateWindow関数でウィンドウを生成します。
第3引数のdwStyleには、WS_CHILDスタイルを与えます。
このとき第8引数のhWndParentに親ウィンドウのハンドルを指定します。今までは親ウィンドウの生成でしたので、NULLにしていましたね。

GetWindowRect関数で親ウィンドウのサイズを取得して子ウィンドウにも同じサイズを指定します。

BOOL GetWindowRect(
  HWND hWnd,      // ウィンドウのハンドル
  LPRECT lpRect   // ウィンドウの座標値
);

GetWindowRect関数はウィンドウのハンドルで指定したウィンドウのサイズを、RECT構造体に格納します。この関数より取得したサイズで、子ウィンドウを作成すれば、親ウィンドウと同じサイズの子ウィンドウができます。

親ウィンドウのウィンドウプロシージャWndProc内では、ウィンドウの初期化時にWM_CREATEメッセージが送られてきます。ここで子ウィンドウA、子ウィンドウBを生成しています。


親ウィンドウの「OPEN_A」,「OPEN_B」ボタンを押すとそれぞれ子ウィンドウA、子ウィンドウBを表示します。
子ウィンドウに配置した「CLOSE」ボタンを押すと、親ウィンドウへ戻ります。これは子ウィンドウを非表示にすることで実現しています。

親ウィンドウプロシージャ内の記述としては
 「OPEN_A」が押されたら子ウィンドウAを表示状態にする。
 「OPEN_B」が押されたら子ウィンドウBを表示状態にする。
子ウィンドウプロシージャ内の記述としては
 「CLOSE」が押されたら、自ウィンドウを非表示にする。(親ウィンドウが表示される)。

とすれば実現できますが、今回は、画面遷移の処理をすべて親ウィンドウに集めてみましょう。

親ウィンドウプロシージャ内の記述としては
 「OPEN_A」が押されたら子ウィンドウAを表示状態にする。
 「OPEN_B」が押されたら子ウィンドウBを表示状態にする。
 「CLOSE」が押されたら、子ウィンドウAが表示状態なら、子ウィンドウAを非表示にする。
 子ウィンドウBが表示状態なら、子ウィンドウBを非表示にする。
子ウィンドウプロシージャ内の記述としては
 「CLOSE」ボタンが押されたら、親ウィンドウに対してメッセージを送る。

とすることで、画面遷移の処理を親ウィンドウに集めることができそうです。

// ChildWindow.cpp
//
// リージョンの結合

#include <windows.h
>


#define BUTTON_ID   1000
#define CHILD_ID_A  5000
#define CHILD_ID_B  5001
#define BUTTON_ID_OPEN_A 6000
#define BUTTON_ID_OPEN_B 6001




LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM
);
LRESULT CALLBACK ChildWindowProc(HWND , UINT , WPARAM , LPARAM 
);
ATOM InitApp(HINSTANCE
);
HWND InitInstance(HINSTANCE, int
);
HINSTANCE hInst
;

TCHAR szClassName[] = _T("ParentWindow"); // ウィンドウクラス。UNICODEとしての文字列定数

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine,int nShowCmd
)
{
   MSG msg
;
   BOOL bRet
;
   HWND hWnd
;

   hInst = hInstance
;

   if (!InitApp(hInstance
))
       return FALSE
;
   if (!(hWnd = InitInstance(hInstance,nShowCmd
)))
       return FALSE
;
   while((bRet = GetMessage(&msg, NULL, 0, 0)) != 0) 
{
       if (bRet == -1
){
           break
;
       } else 
{
           TranslateMessage(&msg
);
           DispatchMessage(&msg
);
       
}
   
}
   return (int)msg.wParam
;
}

// ウィンドウクラスの登録

ATOM InitApp(HINSTANCE hInst
)
{
   WNDCLASS wc
;
   wc.style        = CS_HREDRAW|CS_VREDRAW
;
   wc.lpfnWndProc  = WndProc;  // プロシージャ名
   wc.cbClsExtra   = 0
;
   wc.cbWndExtra   = 0
;
   wc.hInstance    = hInst
;
   wc.hIcon        = NULL;     // 未サポート
   wc.hCursor      = NULL;     // 未サポート
   wc.hbrBackground= (HBRUSH) COLOR_WINDOW
;
   wc.lpszMenuName = NULL;     // 未サポート
   wc.lpszClassName=(LPCTSTR) szClassName
;

   return (RegisterClass(&wc
));
}

// ウィンドウの生成
HWND InitInstance(HINSTANCE hInst, int nShowCmd
)
{
   HWND hWnd
;

   hWnd = CreateWindow
(
       szClassName,_T("ChildWindowサンプル"),
       WS_CLIPCHILDREN,    // ウィンドウの種類
       CW_USEDEFAULT,      // x座標
       CW_USEDEFAULT,      // y座標
       CW_USEDEFAULT,      // 幅
       CW_USEDEFAULT,      // 高さ
       NULL,               // 親ウィンドウのハンドル。親を作るのでNULL
       NULL,               // メニューハンドルまたは子ウィンドウID
       hInst,              // インスタンスハンドル
       NULL
);
   if (!hWnd
)
       return FALSE
;
   ShowWindow(hWnd, nShowCmd
);
   UpdateWindow(hWnd
);
   return hWnd
;
}
// ウィンドウクラスの登録
void CreateWindowClass(HINSTANCE hInst, LPCTSTR szClassName, WNDCLASSW &wc
)
{
   wc.style  = CS_HREDRAW|CS_VREDRAW
;
   wc.lpfnWndProc = ChildWindowProc ; // プロシージャ名
   wc.cbClsExtra = 0
;
   wc.cbWndExtra = 0
;
   wc.hInstance = hInst
;
   wc.hIcon  = NULL
;
   wc.hCursor  = NULL
;
   wc.hbrBackground= reinterpret_cast<HBRUSH>(GetStockObject(GRAY_BRUSH)); //グレーにする
   wc.lpszMenuName = NULL;  // 未サポート
   wc.lpszClassName=(LPCWSTR) szClassName
;
}

// 子ウィンドウの生成
HWND CreateChildWindow(HINSTANCE hInst, int nShowCmd,LPTSTR ClassName,HMENU hMenuChildId,HWND hParent
)
{
   HWND hWnd
;

   // 親ウィンドウのサイズを取得
   RECT rect
;
   GetWindowRect(hParent, (LPRECT)&rect
);

   hWnd = CreateWindow
(
       ClassName,
       NULL,
       WS_CHILD,
       0,                      //親ウィンドウと同じサイズ
       0,
       rect.right - rect.left,
       rect.bottom - rect.top,
       hParent,        //親ウィンドウのハンドル
       (HMENU)hMenuChildId,    // 子ウィンドウを判別するためのID
       hInst,          //インスタンスハンドル
       NULL
);
   if (!hWnd
)
       return FALSE
;
   ShowWindow(hWnd, nShowCmd
);
   UpdateWindow(hWnd
);
   return hWnd
;
}
// ウィンドウプロシージャ
LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp
)
{
   PAINTSTRUCT ps
;
   HDC hdc
;

   TCHAR buf[256
];
   size_t size;        // 文字列のサイズを格納する

   WNDCLASSW wc_A
;
   WNDCLASSW wc_B
;
   static HWND hChildWnd_A
;
   static HWND hChildWnd_B
;

   static HWND hButton
;

   switch (msg
){
       case WM_CREATE
:

           // 子ウィンドウAの生成
           CreateWindowClass(hInst,_T("ChildWindow_A"),wc_A
);
           RegisterClassW(&wc_A
);
           hChildWnd_A = CreateChildWindow(hInst,SW_HIDE,_T("ChildWindow_A"),(HMENU)CHILD_ID_A,hWnd
);

           // 子ウィンドウBの生成
           CreateWindowClass(hInst,_T("ChildWindow_B"),wc_B
);
           RegisterClassW(&wc_B
);
           hChildWnd_B = CreateChildWindow(hInst,SW_HIDE,_T("ChildWindow_B"),(HMENU)CHILD_ID_B,hWnd
);

           // プッシュボタンを作成する
           hButton = CreateWindow
(
               _T("BUTTON"),                            // ウィンドウクラス名
               _T("OPEN A"),                            // キャプション
               WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON,   // スタイル指定
               50, 50,                                  // 座標
               60, 40,                                  // サイズ
               hWnd,                                    // 親ウィンドウのハンドル
               (HMENU)BUTTON_ID_OPEN_A,                 // メニューハンドル
               hInst,                                   // インスタンスハンドル
               NULL                                     // その他の作成データ
               
);

           // プッシュボタンを作成する
           hButton = CreateWindow
(
               _T("BUTTON"),                            // ウィンドウクラス名
               _T("OPEN B"),                            // キャプション
               WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON,   // スタイル指定
               50, 100,                                 // 座標
               60, 40,                                  // サイズ
               hWnd,                                    // 親ウィンドウのハンドル
               (HMENU)BUTTON_ID_OPEN_B,                 // メニューハンドル
               hInst,                                   // インスタンスハンドル
               NULL                                     // その他の作成データ
               
);

           break
;
       case WM_COMMAND
:
           GetClassName(hWnd, buf, 255
);
           NKDbgPrintfW(_T("%s\n"),buf
);
           switch(LOWORD(wp) 
){
           case BUTTON_ID_OPEN_A
:
               // 親ウィンドウの「OPEN_A」ボタン押下時の処理
               // 子ウィンドウAを表示する
               ShowWindow(hChildWnd_A,SW_SHOW
);
               UpdateWindow(hChildWnd_A
);

               return (DefWindowProc(hWnd, msg, wp, lp
));
               break
;
           case BUTTON_ID_OPEN_B
:
               // 親ウィンドウの「OPEN_B」ボタン押下時の処理
               // 子ウィンドウBを表示する
               ShowWindow(hChildWnd_B,SW_SHOW
);
               UpdateWindow(hChildWnd_B
);

               return (DefWindowProc(hWnd, msg, wp, lp
));
               break
;

           case BUTTON_ID
:
               // 子ウィンドウの「CLOSE」ボタン押下字の処理
               if( IsWindowVisible(hChildWnd_A) 
){
                   ShowWindow(hChildWnd_A,SW_HIDE
);
               }else
{
                   ShowWindow(hChildWnd_B,SW_HIDE
);
               
}

               break
;
           default
:
               return (DefWindowProc(hWnd, msg, wp, lp
));
           
}

           break
;
       case WM_PAINT
:
           hdc = BeginPaint(hWnd,&ps);     // 描画処理を開始します。

           SetBkMode(hdc, TRANSPARENT);    // 背景を透過モードにします

           GetClassName(hWnd, buf, 255);   // クラス名を取得

           StringCchLength(buf,255,&size); // 文字列長の取得

           ExtTextOut
(
               hdc,    // デバイスコンテキストのハンドル
               0,      // 開始位置(基準点)の x 座標
               20,     // 開始位置(基準点)の y 座標
               NULL,   // 長方形領域の使い方のオプション
               NULL,   // 長方形領域の入った構造体へのポインタ
               buf,    // 文字列
               size,   // 文字数
               NULL    // 文字間隔の入った配列
               
);

           EndPaint(hWnd,&ps);             // 描画処理を終了します。

           break
;
       case WM_DESTROY
:
           PostQuitMessage(0
);
           break
;
       default
:
           return (DefWindowProc(hWnd, msg, wp, lp
));
   
}
   return 0
;
}



LRESULT CALLBACK ChildWindowProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp
)
{
   PAINTSTRUCT ps
;
   HWND hButton
;
   HDC hdc
;
   COLORREF bkColor
;
   TCHAR buf[256
];
   size_t size;        // 文字列のサイズを格納する


   switch (msg
){
       case WM_CREATE
:
           // プッシュボタンを作成する
           hButton = CreateWindow
(
               _T("BUTTON"),                            // ウィンドウクラス名
               _T("CLOSE"),                             // キャプション
               WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON,   // スタイル指定
               100, 200,                                // 座標
               60, 40,                                  // サイズ
               hWnd,                                    // 親ウィンドウのハンドル
               (HMENU)BUTTON_ID,                        // メニューハンドル
               hInst,                                   // インスタンスハンドル
               NULL                                     // その他の作成データ
               
);
           break
;
       case WM_PAINT
:
           hdc = BeginPaint(hWnd,&ps);     // 描画処理を開始します。

           SetBkMode(hdc, TRANSPARENT);    // 背景を透過モードにします

           GetClassName(hWnd, buf, 255);   // クラス名を取得

           StringCchLength(buf,255,&size); // 文字列長の取得

           ExtTextOut
(
               hdc,    // デバイスコンテキストのハンドル
               0,      // 開始位置(基準点)の x 座標
               20,     // 開始位置(基準点)の y 座標
               NULL,   // 長方形領域の使い方のオプション
               NULL,   // 長方形領域の入った構造体へのポインタ
               buf,    // 文字列
               size,   // 文字数
               NULL    // 文字間隔の入った配列
               
);

           EndPaint(hWnd,&ps
);

           break
;
       case WM_COMMAND
:
           GetClassName(hWnd, buf, 255
);
           NKDbgPrintfW(_T("%s\n"),buf
);
           switch(LOWORD(wp) 
){
           case BUTTON_ID
:

               // 親ウィンドウへメッセージ伝播。処理は親に任せる。
               SendMessage(GetParent(hWnd),msg,wp,lp
);

               // 自ウィンドウを非表示にする
               //ShowWindow(hWnd,SW_HIDE);
               //UpdateWindow(hWnd);

               break
;
           default
:
               return (DefWindowProc(hWnd, msg, wp, lp
));
           
}

           break
;
       case WM_DESTROY
:
           PostQuitMessage(0
);
           break
;
       default
:
           return (DefWindowProc(hWnd, msg, wp, lp
));
   
}
   return 0
;
}

親ウィンドウにメッセージを送るには、SendMessage関数を使います。
子ウィンドウの「CLOSE」ボタンが押下されると、
子ウィンドウのウィンドウプロシージャChildWindowProcにWM_COMMANDメッセージが通知されます。ここでは

    // 親ウィンドウへメッセージ伝播
    SendMessage(GetParent(hWnd),msg,wp,lp);

としているだけです。

LRESULT SendMessage(
  HWND hWnd,      // 送信先ウィンドウのハンドル
  UINT Msg,       // メッセージ
  WPARAM wParam,  // メッセージの最初のパラメータ
  LPARAM lParam   // メッセージの 2 番目のパラメータ
);

hWnd 送信先ウィンドウハンドルには、親ウィンドウを指定します。Msg,wParam,lParamには、子ウィンドウのウィンドウプロシージャが受け取った値をそのままセットします。

これにより、親ウィンドウで一括してボタン押下時の処理を任せることができます。
親ウィンドウのウィンドウプロシージャでは、子ウィンドウAが表示されていれば、子ウィンドウAを非表示、子ウィンドウBが表示されていれば、子ウィンドウBを非表示にします。

これにより、子ウィンドウの管理を親ウィンドウに任せることができるようになりました。

 

 

スポンサーサイト

テーマ:Windows Mobile - ジャンル:コンピュータ

  1. 2010/02/10(水) 06:00:09|
  2. WindowsMobileではじめるWin32APIプログラミング入門
  3. | トラックバック:0
  4. | コメント:3

020:WindowsMobileらしい全画面ダイアログを作る

通常のパソコンで行うような、たくさんのダイアログを切り替えて作業する、といった事は小さな携帯画面では操作もしずらく、あまり現実的ではありません。
WindowsMobileアプリケーションでは、ウインドウであれダイアログであれ、全画面表示にするのが一般的です。その方が使い勝手もよく、他のソフトウェアともインターフェースを統一できるのでお勧めです。

Windows Mobile6 Standardでは、主にナビゲーションバーにOKボタンを表示したフルスクリーンダイアログボックスが使用されます。完了ボタンは視覚的にフルスクリーンのダイアログボックスで隠されてOKボタンに置き換わるため、「ダイアログのOKボタンである」ということが理解しやすいからです。ダイアログのボタンを完了ボタン([×]ボタン)にしていると、親画面の完了ボタン([×]ボタン)なのか、ダイアログの完了ボタンなのか区別がつかず、ユーザの誤動作を招くことになります。

ではダイアログも全画面表示にしてみましょう。

前回のダイアログ「SampleDialog002」を全画面ダイアログになるように変更します。

全画面ダイアログを表示するには、WM_INITDIALOG:でSHInitDialog()を使用します。

SH~()関数と頭にSHのつく関数は、WindowsMobile特有の関数で主にUIの部分に関連する関数です。

このSHInitDialog()関数はSHINITDLGINFO構造体にパラーメータを指定することで、ダイアログボックスのサイズをSIPに合わせて変更します。

SHInitDialog()関数を使用するにはaygshell.hをインクルードします。

■SHInitDialog()

ダイアログの状態を指定するSHINITDLGINFO構造体に値をセットしてSHInitDialog()関数に渡します。

SHINITDLGINFO構造体
typedef struct tagSHINITDLGINFO
{
    DWORD dwMask;
    HWND  hDlg;
    DWORD dwFlags;
} SHINITDLGINFO, *PSHINITDLGINFO;

dwMask
SHINITDLGINFO構造でどのメンバーが有効であるかを示すビットフィールドで、SHIDIM_FLAGSを指定します。
hDlg
ダイアログへのハンドルです。必須項目です。
dwFlags
ダイアログの動作を決定するフラグです。SHIDIM_FLAGSフラグが設定されてなければ無視されます。

SHIDIF_DONEBUTTON
ナビゲーションバーにOKボタンを表示します。
SHIDIF_EMPTYMENU
下部に空のメニューを作成します。
SHIDIF_FULLSCREENNOMENUBAR
ダイアログボックスを入力パネルの位置に関係なく、フルスクリーン表示に設定します。
SHIDIF_SIPDOWN
ダイアログ初期化時に入力パネルが開いていたら閉じます。
SHIDIF_SIZEDLG
ダイアログボックスはSIPの邪魔にならないサイズで最大化されます。
SHIDIF_SIZEDLGFULLSCREEN
ダイアログボックスを入力パネルの位置に関係なく、フルスクリーン表示に設定します。
SHIDIF_CANCELBUTTON
[×]ボタン表示しダイアログを閉じると同時にキャンセル(IDCANCEL)を発行します。
SHIDIF_WANTSCROLLBAR
ダイアログが画面に収まらない場合にスクロールバーを表示します。

ソースコードは次のとおりです。


// SampleDialog003.cpp
//
// ダイアログを全画面表示にする

#include <windows.h
>
#include <aygshell.h
>
#include
"resource1.h"

#define ID_BUTTON1 (0)             
// ボタンのID

LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM
);
BOOL CALLBACK DlgProc(HWND, UINT, WPARAM, LPARAM
);

ATOM InitApp(HINSTANCE
);
HWND InitInstance(HINSTANCE, int
);
HWND hDlg;          
// モードレスダイアログボックスのハンドル
HINSTANCE hInst;    
// アプリケーションインスタンスハンドル
TCHAR szClassName[] = _T("SampleDialog003"
);
                   
// ウィンドウクラス。UNICODEとしての文字列定数
TCHAR szStr[4];     
// ダイアログとのデータ受け渡し用。4文字確保(うち1つはNULLポインタ用)

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine,int nShowCmd
)
{
   MSG msg
;
   BOOL bRet
;
   HWND hWnd
;

   hInst = hInstance;
// アプリケーションインスタンスハンドルをグローバル変数へ格納

   if (!InitApp(hInstance
))
       return FALSE
;
   if (!(hWnd = InitInstance(hInstance,nShowCmd
)))
       return FALSE
;
   while((bRet = GetMessage(&msg, NULL, 0, 0)) != 0)
{
       if (bRet == -1
){
           break
;
       } else
{
           
//ダイアログからのメッセージを処理する。
           if(!IsDialogMessage(hDlg,&msg
)){
               
// ダイアログで処理されなかったメッセージは
               
// ウィンドウプロシージャで処理する。
               TranslateMessage(&msg);
// 仮想キーメッセージを文字メッセージに変換
               DispatchMessage(&msg);  
// メッセージをウィンドウプロシージャに送る
           
}
       
}
   
}
   return (int)msg.wParam
;
}

// ウィンドウクラスの登録

ATOM InitApp(HINSTANCE hInst
)
{
   WNDCLASS wc
;
   wc.style        = CS_HREDRAW|CS_VREDRAW
;
   wc.lpfnWndProc  = WndProc;  
// プロシージャ名
   wc.cbClsExtra   = 0
;
   wc.cbWndExtra   = 0
;
   wc.hInstance    = hInst
;
   wc.hIcon        = NULL;     
// 未サポート
   wc.hCursor      = NULL;     
// 未サポート
   wc.hbrBackground= (HBRUSH) COLOR_WINDOW
;
   wc.lpszMenuName = NULL;     
// 未サポート
   wc.lpszClassName=(LPCTSTR) szClassName
;

   return (RegisterClass(&wc
));
}

// ウィンドウの生成
HWND InitInstance(HINSTANCE hInst, int nShowCmd
)
{
   HWND hWnd
;

   hWnd = CreateWindow(szClassName,_T("モードレス"),
       WS_CLIPCHILDREN,    
// ウィンドウの種類
       CW_USEDEFAULT,      
// x座標
       CW_USEDEFAULT,      
// y座標
       CW_USEDEFAULT,      
// 幅
       CW_USEDEFAULT,      
// 高さ
       NULL,               
// 親ウィンドウのハンドル。親を作るのでNULL
       NULL,               
// メニューハンドルまたは子ウィンドウID
       hInst,              
// インスタンスハンドル
       NULL
);
   if (!hWnd
)
       return FALSE
;
   ShowWindow(hWnd, nShowCmd
);
   UpdateWindow(hWnd
);
   return hWnd
;
}

// ウィンドウプロシージャ
LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp
)
{
   PAINTSTRUCT ps
;
   HDC hdc
;
   size_t size;        
// 文字列のサイズを格納する
   HWND hButton
;
   HWND hDlg
;

   switch (msg
){
       case WM_CREATE:
// 初期化処理開始

           
// モードレスダイアログを開くボタン
           hButton = CreateWindow
(
               _T("BUTTON"),                           
// ウィンドウクラス名
               _T("DIALOG"),                           
// キャプション
               WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON,  
// スタイル指定
               50, 50,                                 
// 座標
               60, 40,                                 
// サイズ
               hWnd,                                   
// 親ウィンドウのハンドル
               HMENU(ID_BUTTON1),                      
// メニューハンドル
               hInst,                                  
// インスタンスハンドル
               NULL                                    
// その他の作成データ
               
);

           break
;

       case WM_PAINT
:

           hdc = BeginPaint(hWnd,&ps);     
// 描画処理を開始

           StringCchLength(szStr,STRSAFE_MAX_CCH,&size);
// 安全な文字列長取得

           ExtTextOut
(
               hdc,    
// デバイスコンテキストのハンドル
               0,      
// 開始位置(基準点)の x 座標
               20,     
// 開始位置(基準点)の y 座標
               NULL,   
// 長方形領域の使い方のオプション
               NULL,   
// 長方形領域の入った構造体へのポインタ
               szStr,  
// 文字列
               size,   
// 文字数
               NULL    
// 文字間隔の入った配列
           
);
           EndPaint(hWnd,&ps
);

           break
;

       case WM_COMMAND
:
           switch (LOWORD(wp
)){
               case ID_BUTTON1
:
                   
// モードレスダイアログウィンドウを開く
                   hDlg = CreateDialog
(
                       hInst,      
// アプリケーションのインスタンスのハンドル
                       MAKEINTRESOURCE(IDD_DIALOG1),
                                   
// ダイアログボックステンプレートを指定
                       hWnd,       
// 親ウィンドウのハンドル
                       DlgProc     
// ダイアログボックスプロシージャへのポインタ
                   
);
                   ShowWindow(hDlg,SW_SHOW
);
           
}
           break
;
       case WM_DESTROY
:
           PostQuitMessage(0
);
           break
;
       default
:
           return (DefWindowProc(hWnd, msg, wp, lp
));
   
}
   return 0
;
}

// ダイアログプロシージャ
BOOL CALLBACK DlgProc(HWND hDlg, UINT msg, WPARAM wp, LPARAM lp
)
{
   static HWND hParent;    
// 親ウィンドウのハンドル
   int copyCount
;

   switch(msg
){
       case WM_INITDIALOG:
// ダイアログの初期化処理
           
{
               SHINITDLGINFO shidi
;

               hParent = GetParent(hDlg);
// 親ウィンドウハンドル

               
// Create a Done button and size it.
               shidi.dwMask = SHIDIM_FLAGS;                
// SHINITDLGINFO構造でどのメンバーが有効であるかを示すビットフィールドです。
                                                           
// SHIDIM_FLAGSを指定します。
               shidi.dwFlags = SHIDIF_SIZEDLGFULLSCREEN    
// ダイアログボックスを入力パネルの位置に関係なく、フルスクリーン表示に設定します。
                               | SHIDIF_EMPTYMENU          
// 下部に空のメニューを作成します
                               | SHIDIF_WANTSCROLLBAR      
// ダイアログが画面に収まらない場合にスクロールバーを表示します
                               | SHIDIF_DONEBUTTON         
// ナビゲーションバーにOKボタンを表示します。
                               
;
               shidi.hDlg = hDlg;                          
// ダイアログのハンドル。必須です。
               SHInitDialog(&shidi
);

               return TRUE
;
           
}
       case WM_COMMAND:    
// ダイアログのボタンが押されたときの処理
           switch (LOWORD(wp
)){
               case IDOK
:

                   
// エディットコントロールの値を取得
                   copyCount = GetDlgItemText(hDlg,IDC_EDIT1,szStr,4
);

                   
// デバッグプリント
                   NKDbgPrintfW(_T("szStr :バイト数: %d 文字数:%d コピーした文字数:%d"
)
                       ,sizeof(szStr),lstrlen(szStr),copyCount
);

                   DestroyWindow(hDlg);    
// ダイアログを破棄
                   return TRUE
;

               case IDCANCEL
:
                   DestroyWindow(hDlg);    
// ダイアログを破棄
                   return TRUE
;

           
}
           return FALSE
;
   
}
   return FALSE
;



}


コンパイル時に
error LNK2019: 未解決の外部シンボル

といったエラーが出る場合、前回はpragmaを使用し、#pragma comment( lib, "aygshell.lib" ) としていたと思います。

これは.dllをリンクする必要があればリンクしなさいという命令です。今回はaygshell.libファイルをリンカ入力として追加します。

プロジェクトを右クリックし[プロパティ]からプロジェクトのプロパティウィンドウを開きます。
[構成]プルダウンリストより[すべての構成]を選択します。
[プラットフォーム]プルダウンリストより[すべてのプラットフォーム]を選択します。
[構成プロパティ]-[リンカ]-[入力]を選択します。
[追加の依存ファイル]プロパティにaygshell.libを追加します。

テーマ:Windows Mobile - ジャンル:コンピュータ

  1. 2010/02/09(火) 04:30:16|
  2. WindowsMobileではじめるWin32APIプログラミング入門
  3. | トラックバック:0
  4. | コメント:0

[コラム]DoxyCommentでC++でもコメントを自動生成

DoxyCommentでC++でもコメントを自動生成

JavaにはJavadocというコメントから自動的にドキュメントを生成する標準的な機能がありますが、Visual C++には標準ツールはありません。
お勧めなのはdoxygenというドキュメント生成ツールです。ソースファイルのコメントから文書を抜き出し、HTMLをはじめとするさまざまなフォーマットのドキュメントを生成することができます。

DoxygenはQtスタイル及びJavaDocスタイルのコメン トを認識してくれます。
私はお仕事ではJavaプログラマーなのでJavaDocスタイルのコメントに慣れていますのでJavaDoc形式のコメントは助かります。

さて、今回インストールするDoxyCommentですが、そのdoxygen形式のコメントを自動生成してくれるツールです。Visual Studioにアドイン(add-in)して使用します。

別にDoxygenでドキュメント作らないよーという場合でも、ソースにコメントは入れると思います。コメント作成の作業をちょっと楽にしてくれるお勧め便利ツールです。

インストール

プロジェクトのサイト
http://sourceforge.net/projects/doxycomment/
よりインストーラをダウンロードしてインストールしてみました。

Visual Studio2005 用と2008用があります。ご自分の環境にあったファイルをダウンロードしてください。
※現在2008用はベータバージョンのようです。

Visual Studio2005の場合
ダウンロードした、doxycomment_0_4_3_setup.msi をインストールします。

Visual Studioを起動すると画像のようなツールバーがでます。

Add Code Commentをクリックすると、コメントが生成されます。

カスタムコメントプロバイダで自分好みのコメントを生成する

さて、DoxygenのデフォルトではQt形式のタグになっており、JavaDoc形式のコメントになりません。[ツール]-[オプション]のDoxyCommentで設定すればコメントブロックだけはJavaDoc形式にできますが、\authorや\versionなどのコマンドの接頭辞は\(バックスラッシュ(¥マーク))のままです。ここはやはり@で記述してほしいところです。

DoxyCommentにはコメントプロバイダというDLLを作成することで、コメントの生成を自分好みにカスタマイズすることができます。
これを使ってJavaDoc風のコメントにしてみましょう。

[ファイル]-[新しいプロジェクト]-[Visual C#]
より、クラスライブラリを選択します。
プロジェクト名:JavaDocComment
OKを押します。

参照設定に

EnvDTE(.NETライブラリ)
Microsoft.VisualStudio.VCCodeModel(.NETライブラリ)
DoxyComment(デフォルトではC:\Program Files\SourceForge.net\DoxyComment add-in for Visual Studio 2005\DoxyComment.dllにあります。)

を追加します。
DoxyComment.ICommentProviderインターフェースを実装する新しいパブリッククラスを作成してください。
ICommentProviderインターフェースのすべての方法を実装してください。
DoxyCommentのインストールフォルダにTest Providerフォルダがあります。これを参考にすると良いでしょう。
C:\Program Files\SourceForge.net\DoxyComment add-in for Visual Studio 2005\Test Provider


using System;
using System.Collections
;
using DoxyComment
;
using EnvDTE
;
using System.ComponentModel
;
using Microsoft.VisualStudio.VCCodeModel
;

namespace JavaDocComment
{
   [CommentProviderFriendlyName("JavaDocComment"
)]
   public class JavaDocComment : DoxyComment.ICommentProvider
   
{
       [CommentProviderProperty
]
       private string firstLineTag = "/**"
;
       [CommentProviderProperty
]
       private string normalLineTag = " * "
;
       [CommentProviderProperty
]
       private string lastLineTag = " */"
;
       [CommentProviderProperty
]
       private string commandPrefix = "@"
;

       public JavaDocComment
()
       
{
       
}

       [Category("コメントブロック概観"),
       Description("コメントブロックの先頭行の接頭辞."
)]
       public string FirstLineTag
       
{
           get
           
{
               return firstLineTag
;
           
}
           set
           
{
               firstLineTag = value
;
           
}
       
}

       [Category("コメントブロック概観"),
       Description("コメントブロックの行の接頭辞."
)]
       public string NormalLineTag
       
{
           get
           
{
               return normalLineTag
;
           
}
           set
           
{
               normalLineTag = value
;
           
}
       
}

       [Category("コメントブロック概観"),
       Description("コメントブロックの最終行の接頭辞."
)]
       public string LastLineTag
       
{
           get
           
{
               return lastLineTag
;
           
}
           set
           
{
               lastLineTag = value
;
           
}
       
}
       [Category("コマンド接頭辞"),
       Description("コマンドの接頭辞です。\\や@を指定します."
)]
       public string CommandPrefix
       
{
           get
           
{
               return commandPrefix
;
           
}
           set
           
{
               commandPrefix = value
;
           
}
       
}

       #region ICommentProvider implementation

       private ArrayList CreateCommentHeader(VCCodeElement codeElem
)
       
{
           ArrayList rv = new ArrayList
();

           if (FirstLineTag.Length > 0
)
           
{
               rv.Add(FirstLineTag
);
           
}

           rv.Add(NormalLineTag + CommandPrefix +"brief   ここに" + codeElem.Name + " の要約を記載."
);
           rv.Add(NormalLineTag
);
           return rv
;
       
}

       private void AppendCommentFooter(VCCodeElement codeElem, ArrayList buffer
)
       
{
           buffer.Add(NormalLineTag + "ここに " + codeElem.Name + " の詳細を記載."
);
           buffer.Add(NormalLineTag
);
           buffer.Add(NormalLineTag + CommandPrefix +"remarks ここに" + codeElem.Name + " の備考を記載."
);
           buffer.Add(NormalLineTag
);
           buffer.Add(NormalLineTag + CommandPrefix +"see     "
);

           
// Does the comment provider require a last line tag?
           if (LastLineTag.Length > 0
)
           
{
               buffer.Add(LastLineTag
);
           
}
       
}

       public string[] CreateFileComment(Document doc
)
       
{
           ArrayList rv = new ArrayList
();
           DateTime now = DateTime.Now
;

           
// Begin tag?
           if (FirstLineTag.Length > 0
)
           
{
               rv.Add(FirstLineTag
);
           
}

           rv.Add(NormalLineTag + CommandPrefix +"file    " + doc.Name
);
           rv.Add(NormalLineTag + CommandPrefix +"brief   "
);
           rv.Add(NormalLineTag
);
           rv.Add(NormalLineTag + CommandPrefix +"author  "
);
           rv.Add(NormalLineTag + CommandPrefix +"date    " + now.ToString("yyyy/MM/dd"
));
           rv.Add(NormalLineTag + CommandPrefix +"version "
);

           
// End tag?
           if (LastLineTag.Length > 0
)
           
{
               rv.Add(LastLineTag
);
           
}

           return (string[])rv.ToArray(typeof(string
));
       
}

       public string[] CreateTypeDefComment(VCCodeTypedef codeElem
)
       
{
           ArrayList rv
;

           rv = CreateCommentHeader((VCCodeElement)codeElem
);
           AppendCommentFooter((VCCodeElement)codeElem, rv
);

           return (string[])rv.ToArray(typeof(string
));
       
}

       public string[] CreateUnionComment(VCCodeUnion codeElem
)
       
{
           ArrayList rv
;

           rv = CreateCommentHeader((VCCodeElement)codeElem
);
           AppendCommentFooter((VCCodeElement)codeElem, rv
);

           return (string[])rv.ToArray(typeof(string
));
       
}

       public string[] CreateMacroComment(VCCodeMacro codeElem
)
       
{
           ArrayList rv
;

           rv = CreateCommentHeader((VCCodeElement)codeElem
);
           if ((codeElem.Parameters.Count > 0
))
           
{
               foreach (VCCodeParameter curParam in codeElem.Parameters
)
               
{
                   rv.Add(NormalLineTag + CommandPrefix +"param   " + curParam.Name
                       + " パラメータ  " + curParam.Name + " の説明を記載."
);
                   rv.Add(NormalLineTag
);
               
}
           
}
           AppendCommentFooter((VCCodeElement)codeElem, rv
);

           return (string[])rv.ToArray(typeof(string
));
       
}

       public string[] CreateStructComment(VCCodeStruct codeElem
)
       
{
           ArrayList rv
;

           rv = CreateCommentHeader((VCCodeElement)codeElem
);
           AppendCommentFooter((VCCodeElement)codeElem, rv
);

           return (string[])rv.ToArray(typeof(string
));
       
}

       public string[] CreateNamespaceComment(VCCodeNamespace codeElem
)
       
{
           ArrayList rv
;

           rv = CreateCommentHeader((VCCodeElement)codeElem
);
           AppendCommentFooter((VCCodeElement)codeElem, rv
);

           return (string[])rv.ToArray(typeof(string
));
       
}

       public string[] CreateFunctionComment(VCCodeFunction codeElem
)
       
{
           ArrayList rv
;

           rv = CreateCommentHeader((VCCodeElement)codeElem
);

           
// Create /param sections for each parameters in the function
           if (codeElem.Parameters.Count > 0
)
           
{
               foreach (VCCodeParameter curParam in codeElem.Parameters
)
               
{

                   rv.Add(NormalLineTag + CommandPrefix +"param   " + curParam.Name
                       + " パラメータ " + curParam.Name + " の説明を記載."
);
                   rv.Add(NormalLineTag
);
               
}
           
}

           
// Create /returns section
           if ((codeElem.TypeString.Length > 0)
&
               (codeElem.TypeString.ToLower() != "void"
))
           
{

               rv.Add(NormalLineTag + CommandPrefix +
"returns "
                   + "ここに戻り値の説明を記載."
);
               rv.Add(NormalLineTag
);
           
}

           
// Create /throws section
           rv.Add(NormalLineTag + CommandPrefix +"throws <exception class>"
);
           rv.Add(NormalLineTag + "    この例外を投げるための基準の説明を記載."
);
           rv.Add(NormalLineTag
);

           AppendCommentFooter((VCCodeElement)codeElem, rv
);

           return (string[])rv.ToArray(typeof(string
));
       
}

       public string[] CreateEnumValueComment(VCCodeVariable codeElem
)
       
{
           ArrayList rv = new ArrayList
();

           if (FirstLineTag.Length > 0
)
           
{
               rv.Add(FirstLineTag
);
           
}

           rv.Add(NormalLineTag + CommandPrefix +"brief   ここに " + codeElem.Name + " の要約を記載."
);

           
// End tag required?
           if (LastLineTag.Length > 0
)
           
{
               rv.Add(LastLineTag
);
           
}

           return (string[])rv.ToArray(typeof(string
));
       
}

       public string[] CreateEnumComment(VCCodeEnum codeElem
)
       
{
           ArrayList rv
;

           rv = CreateCommentHeader((VCCodeElement)codeElem
);
           AppendCommentFooter((VCCodeElement)codeElem, rv
);

           return (string[])rv.ToArray(typeof(string
));
       
}

       public string[] CreateVariableComment(VCCodeVariable codeElem
)
       
{
           ArrayList rv
;

           rv = CreateCommentHeader((VCCodeElement)codeElem
);
           AppendCommentFooter((VCCodeElement)codeElem, rv
);

           return (string[])rv.ToArray(typeof(string
));
       
}

       public string[] CreateClassComment(VCCodeClass codeElem
)
       
{
           ArrayList rv
;

           
// Header
           rv = CreateCommentHeader((VCCodeElement)codeElem
);

           
// Template parameters?
           if ((codeElem.IsTemplate
))
           
{
               foreach (VCCodeParameter curTemplateParam in codeElem.Templatizations
)
               
{
                   string typeStr
;
                   if ((curTemplateParam.Name.Length != 0
))
                   
{
                       typeStr = curTemplateParam.Name
;
                   
}
                   
else
                   
{
                       int typeIdx
;

                       typeIdx = curTemplateParam.TypeString.LastIndexOf(" "
);
                       typeStr = curTemplateParam.TypeString.Substring(typeIdx + 1
);
                   
}

                   rv.Add(NormalLineTag + CommandPrefix +"param   " + typeStr
);
                   rv.Add(NormalLineTag + "パラメータ " + typeStr + " の説明を記載."
);
                   rv.Add(NormalLineTag
);
               
}
           
}

           AppendCommentFooter((VCCodeElement)codeElem, rv
);

           return (string[])rv.ToArray(typeof(string
));
       
}
using System
;
using System.Collections
;
using DoxyComment
;
using EnvDTE
;
using System.ComponentModel
;
using Microsoft.VisualStudio.VCCodeModel
;

namespace JavaDocComment
{
   [CommentProviderFriendlyName("JavaDocComment"
)]
   public class JavaDocComment : DoxyComment.ICommentProvider
   
{
       [CommentProviderProperty
]
       private string firstLineTag = "/**"
;
       [CommentProviderProperty
]
       private string normalLineTag = " * "
;
       [CommentProviderProperty
]
       private string lastLineTag = " */"
;
       [CommentProviderProperty
]
       private string commandPrefix = "@"
;
       [CommentProviderProperty
]
       private string author =""
;

       public JavaDocComment
()
       
{
       
}

       [Category("コメントブロック概観"),
       Description("コメントブロックの先頭行の接頭辞です."
)]
       public string FirstLineTag
       
{
           get
           
{
               return firstLineTag
;
           
}
           set
           
{
               firstLineTag = value
;
           
}
       
}

       [Category("コメントブロック概観"),
      Description("コメントブロックの行の接頭辞です."
)]
       public string NormalLineTag
       
{
           get
           
{
               return normalLineTag
;
           
}
           set
           
{
               normalLineTag = value
;
           
}
       
}

       [Category("コメントブロック概観"),
      Description("コメントブロックの最終行の接頭辞です."
)]
       public string LastLineTag
       
{
           get
           
{
               return lastLineTag
;
           
}
           set
           
{
               lastLineTag = value
;
           
}
       
}
       [Category("コマンド接頭辞"),
       Description("コマンドの接頭辞です。\\や@を指定します."
)]
       public string CommandPrefix
       
{
           get
           
{
               return commandPrefix
;
           
}
           set
           
{
               commandPrefix = value
;
           
}
       
}
       [Category("制作者"),
       Description("制作者を指定します."
)]
       public string Author
       
{
           get
           
{
               return author
;
           
}
           set
           
{
               author = value
;
           
}
       
}
       #region ICommentProvider implementation

       private ArrayList CreateCommentHeader(VCCodeElement codeElem
)
       
{
           ArrayList rv = new ArrayList
();

           if (FirstLineTag.Length > 0
)
           
{
               rv.Add(FirstLineTag
);
           
}

           rv.Add(NormalLineTag + "ここに" + codeElem.Name + "の要約を記載."
);
           rv.Add(NormalLineTag + "ここに" + codeElem.Name + "の詳細を記載."
);
           return rv
;
       
}

       private void AppendCommentFooter(VCCodeElement codeElem, ArrayList buffer
)
       
{
           buffer.Add(NormalLineTag + CommandPrefix +"remarks ここに" + codeElem.Name + "の備考を記載."
);

           
// Does the comment provider require a last line tag?
           if (LastLineTag.Length > 0
)
           
{
               buffer.Add(LastLineTag
);
           
}
       
}

       public string[] CreateFileComment(Document doc
)
       
{
           ArrayList rv = new ArrayList
();
           DateTime now = DateTime.Now
;

           
// Begin tag?
           if (FirstLineTag.Length > 0
)
           
{
               rv.Add(FirstLineTag
);
           
}

           rv.Add(NormalLineTag + "ここに" + doc.Name + "の概要を記載."
);
           rv.Add(NormalLineTag + CommandPrefix + "file    " + doc.Name
);
           rv.Add(NormalLineTag + CommandPrefix + "author  " + Author
);
           rv.Add(NormalLineTag + CommandPrefix + "date    " + now.ToString("yyyy/MM/dd"
));
           rv.Add(NormalLineTag + CommandPrefix + "version "
);

           
// End tag?
           if (LastLineTag.Length > 0
)
           
{
               rv.Add(LastLineTag
);
           
}

           return (string[])rv.ToArray(typeof(string
));
       
}

       public string[] CreateTypeDefComment(VCCodeTypedef codeElem
)
       
{
           ArrayList rv
;

           rv = CreateCommentHeader((VCCodeElement)codeElem
);
           AppendCommentFooter((VCCodeElement)codeElem, rv
);

           return (string[])rv.ToArray(typeof(string
));
       
}

       public string[] CreateUnionComment(VCCodeUnion codeElem
)
       
{
           ArrayList rv
;

           rv = CreateCommentHeader((VCCodeElement)codeElem
);
           AppendCommentFooter((VCCodeElement)codeElem, rv
);

           return (string[])rv.ToArray(typeof(string
));
       
}

       public string[] CreateMacroComment(VCCodeMacro codeElem
)
       
{
           ArrayList rv
;

           rv = CreateCommentHeader((VCCodeElement)codeElem
);
           if ((codeElem.Parameters.Count > 0
))
           
{
               foreach (VCCodeParameter curParam in codeElem.Parameters
)
               
{
                   rv.Add(NormalLineTag + CommandPrefix +"param   " + curParam.Name
                       + " パラメータ" + curParam.Name + "の説明を記載."
);
               
}
           
}
           AppendCommentFooter((VCCodeElement)codeElem, rv
);

           return (string[])rv.ToArray(typeof(string
));
       
}

       public string[] CreateStructComment(VCCodeStruct codeElem
)
       
{
           ArrayList rv
;

           rv = CreateCommentHeader((VCCodeElement)codeElem
);
           AppendCommentFooter((VCCodeElement)codeElem, rv
);

           return (string[])rv.ToArray(typeof(string
));
       
}

       public string[] CreateNamespaceComment(VCCodeNamespace codeElem
)
       
{
           ArrayList rv
;

           rv = CreateCommentHeader((VCCodeElement)codeElem
);
           AppendCommentFooter((VCCodeElement)codeElem, rv
);

           return (string[])rv.ToArray(typeof(string
));
       
}

       public string[] CreateFunctionComment(VCCodeFunction codeElem
)
       
{
           ArrayList rv
;

           rv = CreateCommentHeader((VCCodeElement)codeElem
);

           
// Create /param sections for each parameters in the function
           if (codeElem.Parameters.Count > 0
)
           
{
               foreach (VCCodeParameter curParam in codeElem.Parameters
)
               
{

                   rv.Add(NormalLineTag + CommandPrefix +"param   " + curParam.Name
                       + " パラメータ" + curParam.Name + "の説明を記載."
);
               
}
           
}
           rv.Add(NormalLineTag + CommandPrefix + "see     "
);
           
// Create /returns section
           if ((codeElem.TypeString.Length > 0)
&
               (codeElem.TypeString.ToLower() != "void"
))
           
{

               rv.Add(NormalLineTag + CommandPrefix +
"return  "
                   + "ここに戻り値の説明を記載."
);
           
}

           
// Create /throws section
           rv.Add(NormalLineTag + CommandPrefix +"throws <exception class> この例外を投げるための基準の説明を記載."
);

           AppendCommentFooter((VCCodeElement)codeElem, rv
);

           return (string[])rv.ToArray(typeof(string
));
       
}

       public string[] CreateEnumValueComment(VCCodeVariable codeElem
)
       
{
           ArrayList rv = new ArrayList
();

           if (FirstLineTag.Length > 0
)
           
{
               rv.Add(FirstLineTag
);
           
}

           rv.Add(NormalLineTag + CommandPrefix +"brief   ここに " + codeElem.Name + " の要約を記載."
);

           
// End tag required?
           if (LastLineTag.Length > 0
)
           
{
               rv.Add(LastLineTag
);
           
}

           return (string[])rv.ToArray(typeof(string
));
       
}

       public string[] CreateEnumComment(VCCodeEnum codeElem
)
       
{
           ArrayList rv
;

           rv = CreateCommentHeader((VCCodeElement)codeElem
);
           AppendCommentFooter((VCCodeElement)codeElem, rv
);

           return (string[])rv.ToArray(typeof(string
));
       
}

       public string[] CreateVariableComment(VCCodeVariable codeElem
)
       
{
           ArrayList rv
;

           rv = CreateCommentHeader((VCCodeElement)codeElem
);
           AppendCommentFooter((VCCodeElement)codeElem, rv
);

           return (string[])rv.ToArray(typeof(string
));
       
}

       public string[] CreateClassComment(VCCodeClass codeElem
)
       
{
           ArrayList rv
;

           
// Header
           rv = CreateCommentHeader((VCCodeElement)codeElem
);

           
// Template parameters?
           if ((codeElem.IsTemplate
))
           
{
               foreach (VCCodeParameter curTemplateParam in codeElem.Templatizations
)
               
{
                   string typeStr
;
                   if ((curTemplateParam.Name.Length != 0
))
                   
{
                       typeStr = curTemplateParam.Name
;
                   
}
                   
else
                   
{
                       int typeIdx
;

                       typeIdx = curTemplateParam.TypeString.LastIndexOf(" "
);
                       typeStr = curTemplateParam.TypeString.Substring(typeIdx + 1
);
                   
}

                   rv.Add(NormalLineTag + CommandPrefix +"param   " + typeStr + " パラメータ" + typeStr + "の説明を記載."
);
               
}
           
}

           AppendCommentFooter((VCCodeElement)codeElem, rv
);

           return (string[])rv.ToArray(typeof(string
));
       
}

       
#endregion
   
}
}

       
#endregion
   
}
}

[ビルド]-[JavaDocCommentのビルド]を選択してDLLを作成します。

JavaDocComment.dll
が生成されるので、これをあなたがDoxyCommentをインストールしたフォルダに「Custom Providers」という名のサブフォルダを作ってそこへコピーしてください。
デフォルトのインストール先であれば

C:\Program Files\SourceForge.net\DoxyComment add-in for Visual Studio 2005\Custom Providers

です。

Visual Studio 2005を再度起動すればカスタムコメントプロバイダがロードされます。

JavaDocCommentプロバイダを使用するように設定します。

[ツール]-[オプション]よりオプションウィンドウを開き、ツリー内のDoxyComment-Generalを選択します。
Active comment provider:JavaDocComment を設定します。

次にDoxyComment-Providerを選択します。


Comment provider:JavaDocComment を選択し、コマンド接頭辞やコメントブロック概観を好みのスタイルに設定してください。

さらにカスタマイズすれば、自分好みのコメントを自動生成できて、便利に使えるでしょう

テーマ:プログラミング - ジャンル:コンピュータ

  1. 2009/05/17(日) 22:53:51|
  2. WindowsMobileではじめるWin32APIプログラミング入門
  3. | トラックバック:0
  4. | コメント:0

019:モードレスダイアログを作る

モードレスダイアログを作る 

ダイアログボックスの場合も、考え方は今まで作ってきたウィンドウのプログラムと同じです。

今まではウインドウに発生した色々な処理をウィンドウプロシージャに記述し処理していました。 ダイアログボックスの場合も同じです。ダイアログプロシージャを作成し、ダイアログに発生したいろいろな処理をダイアログプロシージャで受け取り、適切に処理します。

ではサンプルを見てみましょう。
 
 

// SampleDialog002.cpp
//
// モードレスダイアログを作る

#include <windows.h
>
#include
"resource.h"

#define ID_BUTTON1 (0)             
// ボタンのID

LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM
);
BOOL CALLBACK DlgProc(HWND, UINT, WPARAM, LPARAM
);

ATOM InitApp(HINSTANCE
);
HWND InitInstance(HINSTANCE, int
);
HWND hDlg;          
// モードレスダイアログボックスのハンドル
HINSTANCE hInst;    
// アプリケーションインスタンスハンドル
TCHAR szClassName[] = _T("SampleDialog002"
);
                   
// ウィンドウクラス。UNICODEとしての文字列定数
TCHAR szStr[4];     
// ダイアログとのデータ受け渡し用。4文字確保(うち1つはNULLポインタ用)

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine,int nShowCmd
)
{
   MSG msg
;
   BOOL bRet
;
   HWND hWnd
;

   hInst = hInstance;
// アプリケーションインスタンスハンドルをグローバル変数へ格納

   if (!InitApp(hInstance
))
       return FALSE
;
   if (!(hWnd = InitInstance(hInstance,nShowCmd
)))
       return FALSE
;
   while((bRet = GetMessage(&msg, NULL, 0, 0)) != 0)
{
       if (bRet == -1
){
           break
;
       } else
{
           
//ダイアログからのメッセージを処理する。
           if(!IsDialogMessage(hDlg,&msg
)){
               
// ダイアログで処理されなかったメッセージは
               
// ウィンドウプロシージャで処理する。
               TranslateMessage(&msg);
// 仮想キーメッセージを文字メッセージに変換
               DispatchMessage(&msg);  
// メッセージをウィンドウプロシージャに送る
           
}
       
}
   
}
   return (int)msg.wParam
;
}

// ウィンドウクラスの登録

ATOM InitApp(HINSTANCE hInst
)
{
   WNDCLASS wc
;
   wc.style        = CS_HREDRAW|CS_VREDRAW
;
   wc.lpfnWndProc  = WndProc;  
// プロシージャ名
   wc.cbClsExtra   = 0
;
   wc.cbWndExtra   = 0
;
   wc.hInstance    = hInst
;
   wc.hIcon        = NULL;     
// 未サポート
   wc.hCursor      = NULL;     
// 未サポート
   wc.hbrBackground= (HBRUSH) COLOR_WINDOW
;
   wc.lpszMenuName = NULL;     
// 未サポート
   wc.lpszClassName=(LPCTSTR) szClassName
;

   return (RegisterClass(&wc
));
}

// ウィンドウの生成
HWND InitInstance(HINSTANCE hInst, int nShowCmd
)
{
   HWND hWnd
;

   hWnd = CreateWindow(szClassName,_T("モードレス"),
       WS_CLIPCHILDREN,    
// ウィンドウの種類
       CW_USEDEFAULT,      
// x座標
       CW_USEDEFAULT,      
// y座標
       CW_USEDEFAULT,      
// 幅
       CW_USEDEFAULT,      
// 高さ
       NULL,               
// 親ウィンドウのハンドル。親を作るのでNULL
       NULL,               
// メニューハンドルまたは子ウィンドウID
       hInst,              
// インスタンスハンドル
       NULL
);
   if (!hWnd
)
       return FALSE
;
   ShowWindow(hWnd, nShowCmd
);
   UpdateWindow(hWnd
);
   return hWnd
;
}

// ウィンドウプロシージャ
LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp
)
{
   PAINTSTRUCT ps
;
   HDC hdc
;
   size_t size;        
// 文字列のサイズを格納する
   HWND hButton
;
   HWND hDlg
;

   switch (msg
){
       case WM_CREATE:
// 初期化処理開始

           
// モードレスダイアログを開くボタン
           hButton = CreateWindow
(
               _T("BUTTON"),                           
// ウィンドウクラス名
               _T("DIALOG"),                           
// キャプション
               WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON,  
// スタイル指定
               50, 50,                                 
// 座標
               60, 40,                                 
// サイズ
               hWnd,                                   
// 親ウィンドウのハンドル
               HMENU(ID_BUTTON1),                      
// メニューハンドル
               hInst,                                  
// インスタンスハンドル
               NULL                                    
// その他の作成データ
               
);

           break
;

       case WM_PAINT
:

           hdc = BeginPaint(hWnd,&ps);     
// 描画処理を開始

           StringCchLength(szStr,STRSAFE_MAX_CCH,&size);
// 安全な文字列長取得

           ExtTextOut
(
               hdc,    
// デバイスコンテキストのハンドル
               0,      
// 開始位置(基準点)の x 座標
               20,     
// 開始位置(基準点)の y 座標
               NULL,   
// 長方形領域の使い方のオプション
               NULL,   
// 長方形領域の入った構造体へのポインタ
               szStr,  
// 文字列
               size,   
// 文字数
               NULL    
// 文字間隔の入った配列
           
);
           EndPaint(hWnd,&ps
);

           break
;

       case WM_COMMAND
:
           switch (LOWORD(wp
)){
               case ID_BUTTON1
:
                   
// モードレスダイアログウィンドウを開く
                   hDlg = CreateDialog
(
                       hInst,      
// アプリケーションのインスタンスのハンドル
                       MAKEINTRESOURCE(IDD_DIALOG1),
                                   
// ダイアログボックステンプレートを指定
                       hWnd,       
// 親ウィンドウのハンドル
                       DlgProc     
// ダイアログボックスプロシージャへのポインタ
                   
);
                   ShowWindow(hDlg,SW_SHOW
);
           
}
           break
;
       case WM_DESTROY
:
           PostQuitMessage(0
);
           break
;
       default
:
           return (DefWindowProc(hWnd, msg, wp, lp
));
   
}
   return 0
;
}

// ダイアログプロシージャ
BOOL CALLBACK DlgProc(HWND hDlg, UINT msg, WPARAM wp, LPARAM lp
)
{
   static HWND hParent;    
// 親ウィンドウのハンドル
   int copyCount
;

   switch(msg
){
       case WM_INITDIALOG:
// ダイアログの初期化処理
           hParent = GetParent(hDlg);
// 親ウィンドウハンドル

           return TRUE
;

       case WM_COMMAND:    
// ダイアログのボタンが押されたときの処理
           switch (LOWORD(wp
)){
               case IDOK
:

                   
// エディットコントロールの値を取得
                   copyCount = GetDlgItemText(hDlg,IDC_EDIT1,szStr,4
);

                   
// デバッグプリント
                   NKDbgPrintfW(_T("szStr :バイト数: %d 文字数:%d コピーした文字数:%d"
)
                       ,sizeof(szStr),lstrlen(szStr),copyCount
);

                   InvalidateRect(hParent,NULL,TRUE);  
// 親ウィドウに再描画を指示
                   return TRUE
;

               case IDCANCEL
:
                   DestroyWindow(hDlg);    
// ダイアログを破棄
                   return TRUE
;

           
}
           return FALSE
;
   
}
   return FALSE
;



}


動作イメージは次のようになります。
起動するとメインウィンドウが表示されます。
ボタンをクリックするとダイアログが表示されます。
OKを押すと、入力した内容がメインウィンドウに反映されます。
キャンセルでダイアログを閉じます。
 
今回は、メインウィンドウを作成後、ダイアログウィンドウを作成します。
メインウィンドウにはウィンドウプロシージャ、ダイアログにはダイアログプロシージャをそれぞれ用意しています。
メインウィンドウの作成は今までと全く同じですので問題ないでしょう。
ウィンドウプロシージャを見てください。
ウィンドウを作成するときの初期化処理として、WM_CREATEメッセージがきたら、ウィンドウにボタンを表示しています。
よく見てください。ボタンの生成にCreateWindowを使っています。メインウィンドウと同じですよね。実はボタンやエディットコントロール、ラジオボタンといったよく使われるコントロールは皆、特殊なウィンドウなのです。ウィンドウですからCreateWindowで作成します。
 
HWND CreateWindow(
  LPCTSTR lpClassName,  // 登録されているクラス名
  LPCTSTR lpWindowName, // ウィンドウ名
  DWORD dwStyle,        // ウィンドウスタイル
  int x,                // ウィンドウの横方向の位置
  int y,                // ウィンドウの縦方向の位置
  int nWidth,           // ウィンドウの幅
  int nHeight,          // ウィンドウの高さ
  HWND hWndParent,      // 親ウィンドウまたはオーナーウィンドウのハンドル
  HMENU hMenu,          // メニューハンドルまたは子ウィンドウ ID
  HINSTANCE hInstance,  // アプリケーションインスタンスのハンドル
  LPVOID lpParam        // ウィンドウ作成データ
);
 

いままではCreateWindow関数の第1引数lpClassNameにはウィンドウクラス名を定義していました。ここに定義済みのウィンドウクラス名を指定することが出来ます。
今回の例ではウィンドウクラス名に_T("BUTTON")を指定して、ボタンのコントロールを生成しています。
第3引数dwStyleに、BS_PUSHBUTTONを指定していますので、いわゆるコマンドボタンになります。この第3引数にBS_CHECKBOXを指定するとチェックボックス、BS_GROUPBOXを指定するとグループボックスになります。チェックボックスもグループボックスも「ボタン」の一種ってのがちょっと不思議に感じられるかも知れません。
dwStyleに指定できるスタイルはウィンドウクラスによって異なってきます。詳しくはMSDNを参照してください。
また第8引数hWndParentに親ウィンドウのハンドルを指定します。メインウィンドウのハンドルを指定しましたので、作成するボタンは、メインウィンドウの子ウィンドウになります。
第9引数hMenuのメニューハンドルには、このボタンを識別するコードを設定します。あとでこのボタンからのメッセージであることを識別するのに使います。
今回は識別用に
#define ID_BUTTON1 (0)             // ボタンのID
を作りました。
 
ボタンが押されたときの処理は、ウィンドウプロシージャにWM_COMMANDメッセージが届いたときの処理に記述します。LOWORD(wp)がID_BUTTON1であれば、ボタンが押されたということです。
このときにモードレスダイアログを開くようにします。
モードレスダイアログはCreateDialogマクロで作成し、DestroyWindow関数でダイアログを破棄します。
 
CreateDialogマクロ
ダイアログボックステンプレートリソースから、モードレスダイアログボックスを作成します。
HWND CreateDialog(
  HINSTANCE hInstance,  // モジュールのハンドル
  LPCTSTR lpTemplate,   // ダイアログボックステンプレートの名前
  HWND hWndParent,      // オーナーウィンドウのハンドル
  DLGPROC lpDialogFunc  // ダイアログボックスプロシージャ
);
hInstance にはアプリケーションハンドルを指定します。
lpTemplate にはダイアログボックステンプレートを指定します。指定にはMAKEINTRESOURCEマクロを使用します。
hWndParent には親ウィンドウのハンドルを指定します。
lpDialogFunc にはダイアログボックスプロシージャを指定します。
 
DestroyWindow関数
指定されたウィンドウを破棄します。
BOOL DestroyWindow(
  HWND hWnd   // 破棄するウィンドウのハンドル
);
 
DlgProc関数がモードレスダイアログボックスのプロシージャです。
プロシージャ内で最初に呼ばれるのはWM_INITDIALOGメッセージです。ダイアログが初期化されるときにWM_INITDIALOGメッセージが送られてきます。このメッセージが来たら、ダイアログボックスで必要な初期化処理を記述しておけばよいわけです。
ここでは、親ウィンドウの再描画処理のために親ウィンドウのハンドルが必要となりますので取得しておきます。
親ウィンドウハンドルの取得にはGetParent関数を使います。
 
GetParent関数
親ウィンドウハンドルを返します。
HWND GetParent(
  HWND hWnd   // 子ウィンドウのハンドル
);
 
ダイアログのボタンが押されると、WM_COMMANDメッセージが送られてきます。どのボタンが押されたのか判定するにはWPARAMの下位バイトを見ればよかったですよね。

OKボタン(IDOK)が押されたらエディットコントロールに入力された値を取得して、グローバル変数に格納します。
エディットコントロールから文字列を取得するにはGetDlgItemText関数を使います。

 
GetDlgItemText関数
ダイアログボックス内の指定されたコントロールに関連付けられているタイトルまたはテキストを取得します。
UINT GetDlgItemText(
  HWND hDlg,       // ダイアログボックスのハンドル
  int nIDDlgItem,  // コントロールの識別子
  LPTSTR lpString, // テキストを受け取るバッファへのポインタ
  int nMaxCount    // 文字列の最大サイズ
);
hDlg にダイアログボックスのハンドルを指定します。
nIDDlgItem には取得したいコントロールの識別子を指定します。
lpString には文字列格納用の領域を指定します。ここでは親ウィンドウに文字列を渡したいのでグローバル変数を指定しています。
nMaxCount  には文字列の長さをTCHAR単位で指定します。 
格納したら親ウィンドウに再描画を指示します。すると親ウィンドウはグローバル変数に格納された文字列を、自分のウィンドウ内に描画します。 再描画にはInvalidateRect関数を使います。

 

InvalidateRect関数
指定されたウィンドウの更新リージョン(再描画しなければならない部分)に 1 個の長方形を追加します。 
BOOL InvalidateRect(
  HWND hWnd,           // ウィンドウのハンドル
  CONST RECT *lpRect,  // 長方形の座標
  BOOL bErase          // 消去するかどうかの状態
);
 
InvalidateRect関数を使って無効領域(更新領域)を発生させます。
無効領域とは、画面が他のウィンドウなどで隠れてしまうことです。通常は、無効領域が発生するとWM_PAINTが発生して、再描画する仕組みになっています。
しかし、プログラムの中で状態を変化させ、それを画面に反映したい場合もあると思います。
そのような場合に、InvalidateRect関数を実行して無効領域を発生させるわけです。
意図的に無効領域を発生させると、WM_PAINTが発生します。
つまり結果的に、親ウィドウに再描画を指示することが出来るというわけです。
 
ダイアログプロシージャの中に、NKDbgPrintfW関数という見慣れないものがありますね。これはデバッグ出力ストリーム(出力ウィンドウ)に文字列を出力できる関数です。デバッグには重宝します。

NKDbgPrintfW関数
デバッグ出力ストリームに文字列を出力します。
void WINAPIV NKDbgPrintfW(
  LPCWSTR lpszFmt,
);
引数lpszFmtにはprintfスタイルの書式を指定します。デバッグには結構便利な関数です。 
 
関数がたくさん出てきましたね。 
今日はここまでです。
 

 

テーマ:Windows Mobile - ジャンル:コンピュータ

  1. 2008/11/20(木) 23:28:42|
  2. WindowsMobileではじめるWin32APIプログラミング入門
  3. | トラックバック:0
  4. | コメント:0

018:モーダイルダイアログを作る

モーダルダイアログを作る

今まで、ウィンドウを使ったプログラムを作成してきました。でもちょっとした情報の表示や設定を行いたいだけの場合には、ダイアログが便利です。
また、ダイアログの場合は、VisualC++の「リソースエディタ」を用いて、WYSIWYGにダイアログを作成することが可能ですので、ちょっとしたアプリケーションの作成に向いています。

ダイアログリソースを作成する

まずダイアログリソースの作成を行います。
[ソリューション エクスプローラ]の中の、[リソースファイル]を右クリックします。
メニューから[追加(D)]-[リソース(R)...]を選択します。

[リソースの追加]ウィンドウが開くのでDialogを選択し[新規作成(N)]ボタンをクリックします。

OKとキャンセルのボタンがデフォルトで表示されています。ここにCheck Box、Static Text、Radio Button、Edit Controlを貼り付けてみます。

実行してみましょう。ダイアログの生成方法は、Windowsの場合と同じです。
モーダルダイアログ(ダイアログボックスを閉じるまで、他の操作が出来ない)で表示するソースです。

// SampleDialog001.cpp
// モーダルダイアログを作成する

#include <windows.h>
#include "resource.h"

BOOL DlgProc(HWND hDlg,UINT uMsg, WPARAM wParam,LPARAM lParam);

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLine,int nShowCmd)
{
   DialogBox(hInstance,MAKEINTRESOURCE(IDD_DIALOG1),NULL,DlgProc);

}

// ダイアログプロシージャ
BOOL DlgProc(HWND hDlg,UINT uMsg, WPARAM wParam,LPARAM lParam)
{
   switch (uMsg){
   case WM_COMMAND:
       switch( LOWORD(wParam) ) {
       case IDOK:
           EndDialog(hDlg,IDOK);
           break;
       case IDCANCEL:
           EndDialog(hDlg,IDCANCEL);
           break;
       }
       break;
   case WM_CLOSE:
       DestroyWindow(hDlg);
       break;
   }
   return FALSE;
}

 

リソースエディタでの表示と、WindowsMobile上での表示が異なっていますね。チェックボックスとラジオボタンの上下か切れてしまっています。



これを修正するには、ダイアログのフォントをWindowsMobileにデフォルトで導入されているフォントに変更します。
では、フォントをTahomaにかえてサイズを9ポイントに設定して実行してみましょう。

このように、正しく表示されました。

なぜダイアログではこのような事が起こるのでしょう。実はダイアログではフォントのサイズを基にして、ダイアログの幅、高さ、オブジェクトの幅、高さを決めているのです。ダイアログにデフォルトで設定されているフォント "MS Shell Dlg"がWindowsMobileには存在しないため、ダイアログやオブジェクトの幅が正しく設定されず、文字が切れたり、チェックボックスやラジオボタンの上下が切れてしまったのです。

ダイアログボックスには、今回作成したモーダルダイアログボックスの他に、モードレスダイアログボックスというものがあります。

モーダルダイアログボックスダイアログボックスを閉じるまで、他の操作が出来ません。通常のアプリケーションではよくこれを使いますね。
モードレスダイアログボックスダイアログボックスを開いている間にも他の操作が出来ます。ダイアログボックスを開いたまま、ブラウザを開いたり、電卓を開いたりすることができます。Excelの検索ダイアログがこれにあたりますね。Excelでは検索ダイアログを開いたまま操作ができますよね。
 
 

では、今回のプログラムの説明です。

モーダルダイアログを作るには、DialogBox関数を呼び出します。ダイアログボックスを閉じるときにはEndDialog関数を呼び出します。

DialogBox関数
モーダルダイアログを表示します。

int DialogBox(
  HINSTANCE
hInstance,      // インスタンスハンドル
  LPCTSTR lpTemplate,       // ダイアログボックステンプレート
  HWND hWndParent,          // 親ウィンドウのハンドル
  DLGPROC lpDialogFunc      // ダイアログプロシージャのポインタ
);

EndDialog関数
モーダルダイアログボックスを破棄し、そのダイアログボックスに関係するすべての処理を終了します。

BOOL EndDialog(
  HWND
hDlg,        // ダイアログボックスのハンドル
  INT_PTR nResult   // 返したい値
);

WinMain関数を見てください。今までのプログラムとは違い、メッセージループがありません。これは、DialogBox関数の処理はEndDialog関数が呼び出されるまで終了しないためです。

DialogBox関数のlpTemplateにはダイアログリソースを指定します。リソース識別子を指定する場合、上位ワードに 0 を、下位ワードに識別子を指定しなければなりません。MAKEINTRESOURCEマクロを使用すれはリソース識別子を作成できます。

lpDialogFuncにはダイアログプロシージャを指定します。

ダイアログプロシージャDlgProcを見てみましょう。ダイアログでは、ボタンが押されるなどのイベントが発生すると、WM_COMMANDメッセージが届きます。これだけでは、どのボタンが押されたのかわかりませんね。追加の情報がwParamに格納されています。どのボタンか判断するにはLOWORD(wParam)とします。これで押されたボタンのIDがわかります。
LOWORDは特定の値の下位ワードを取り出すマクロです。つまりwParamの下位ワードに押されたボタンのIDが格納されているのです。

サンプルでは、IDOKとIDCANCELの処理を別々に書いていますが、ダイアログプロシージャの中での処理が特にない場合はまとめて下のように書きます。EndDialogの第2引数にLOWORD(wParam)を指定するのがポイントです。

        switch( LOWORD(wParam) ) {
        case IDOK:
        case IDCANCEL:
            EndDialog(hDlg,LOWORD(wParam));
            break;
        }

今日はここまでです。

テーマ:Windows Mobile - ジャンル:コンピュータ

  1. 2008/10/19(日) 17:07:29|
  2. WindowsMobileではじめるWin32APIプログラミング入門
  3. | トラックバック:0
  4. | コメント:0
次のページ

RSSフィード

カレンダー

08 | 2018/09 | 10
- - - - - - 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 - - - - - -

カテゴリー

最近の記事

最近のコメント

最近のトラックバック

月別アーカイブ

ブロとも申請フォーム

この人とブロともになる

ブログ内検索

リンク

このブログをリンクに追加する

メールフォーム

名前:
メール:
件名:
本文:

上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。