noocyte のプログラミング研究室 〜プログラムは楽しげに走らねばならない♪〜

Windows Icon Windows Programming Tips & Memos

公開:2006/09/21(木)
最終更新:2017/07/23(日)

生の Windows API (および関連 API) を C/C++ で使用するために調べたことのメモおよび Tips 集です.随時追加します.

目次

  1. 実行環境バージョン指定マクロ (Windows Kits 10, SdkDdkVer.h)
  2. ウインドウリサイズ時のちらつきを抑える.
  3. ウインドウの特徴
  4. ウインドウメッセージ
  5. ダイアログ
  6. コントロールのウインドウクラス名一覧
  7. ToolBar
  8. GDI
  9. ゴミ箱
  10. その他
  11. 参考図書
  12. 外部へのリンク
  13. 更新履歴

実行環境バージョン指定マクロ (Windows Kits 10, SdkDdkVer.h)

最低限必要な Windows バージョン
Windows NTDDI_VERSION
Windows 10 V1903
(SDK 10.0.18362.0)
≧NTDDI_WIN10_19H1
Windows 10 V1809
(SDK 10.0.17763.0)
≧NTDDI_WIN10_RS5
Windows 10 V1803
(SDK 10.0.17134.0)
≧NTDDI_WIN10_RS4
Windows 10 V1709
(SDK 10.0.16299.0)
≧NTDDI_WIN10_RS3
Windows 10 V1703
(SDK 10.0.15063.0)
≧NTDDI_WIN10_RS2
Windows 10 V1607
(SDK 10.0.14393.0)
≧NTDDI_WIN10_RS1
Windows 10 V1511
(SDK 10.0.10586.0)
≧NTDDI_WIN10_TH2
Windows 10
(SDK 10.0.10240.0)
≧NTDDI_WIN10
Windows 8.1 ≧NTDDI_WINBLUE
Windows 8 ≧NTDDI_WIN8
Windows 7 ≧NTDDI_WIN7
Server 2008 SP4 ≧NTDDI_WS08SP4
Server 2008 SP3 ≧NTDDI_WS08SP3
Server 2008 SP2 ≧NTDDI_WS08SP2
Server 2008 ≧NTDDI_WS08
Vista SP4 ≧NTDDI_VISTASP4
Vista SP3 ≧NTDDI_VISTASP3
Vista SP2 ≧NTDDI_VISTASP2
Vista SP1 ≧NTDDI_VISTASP1
Vista ≧NTDDI_VISTA
Server 2003 SP4 ≧NTDDI_WS03SP4
Server 2003 SP3 ≧NTDDI_WS03SP3
Server 2003 SP2 ≧NTDDI_WS03SP2
Server 2003 SP1 ≧NTDDI_WS03SP1
Server 2003 ≧NTDDI_WS03
XP SP4 ≧NTDDI_WINXPSP4
XP SP3 ≧NTDDI_WINXPSP3
XP SP2 ≧NTDDI_WINXPSP2
XP SP1 ≧NTDDI_WINXPSP1
XP ≧NTDDI_WINXP
2000 SP4 ≧NTDDI_WIN2KSP4
2000 SP3 ≧NTDDI_WIN2KSP3
2000 SP2 ≧NTDDI_WIN2KSP2
2000 SP1 ≧NTDDI_WIN2KSP1
2000 ≧NTDDI_WIN2K
最低限必要な IE バージョン
IE _WIN32_IE
IE 10.0 ≧0x0A00
IE 9.0 ≧0x0900
IE 8.0 ≧0x0800
IE 7.0 ≧0x0700
IE 6.0 SP2 ≧0x0603
IE 6.0 SP1 ≧0x0601
IE 6.0 ≧0x0600
IE 5.5 ≧0x0550
IE 5.01 ≧0x0501
IE 5.0 / 5.0a / 5.0b ≧0x0500
IE 4.01 ≧0x0401
IE 4.0 ≧0x0400
IE 3.02 ≧0x0302
IE 3.0 / 3.01 ≧0x0300
IE 2.0 ≧0x0200
最低限必要な Windows バージョン
Windows WINVER _WIN32_WINNT _WIN32_WINDOWS
Windows 10 ≧0x0A00 ≧_WIN32_WINNT_WIN10
Windows 8.1 ≧0x0603 ≧_WIN32_WINNT_WINBLUE
Windows 8 ≧0x0602 ≧_WIN32_WINNT_WIN8
Windows 7 ≧0x0601 ≧_WIN32_WINNT_WIN7
Vista /
Server 2008
≧0x0600 ≧_WIN32_WINNT_{VISTA,WS08}
XP SP2 /
Server 2003 SP1
≧0x0502 ≧_WIN32_WINNT_WS03
XP /
Server 2003
≧0x0501 ≧_WIN32_WINNT_WINXP
2000 ≧0x0500 ≧_WIN32_WINNT_WIN2K
NT4.0 ≧0x0400 ≧_WIN32_WINNT_NT4
Me ≧0x0490
≧0x0490
98 ≧0x0410
≧0x0410
95 ≧0x0400
≧0x0400

参考

_MSC_VER

Visual C/C++
Version
Compiler
Version
Tools
Version
_MSC_VER _MSC_FULL_VER
(自分の環境で確認した値)
出典
2003 13.10 ? 1310 未定義 Predefined Macros (Visual Studio .NET 2003)
2005 14.00 ? 1400 未定義 Predefined Macros (Visual Studio 2005)
2008 15.00.nnnnn.nn 3.5? 1500 1500nnnnn
(150030729)
Predefined Macros (Visual Studio 2008)
2010 16.00.nnnnn.nn 4.0 1600 1600nnnnn
(未確認)
Predefined Macros (Visual Studio 2010)
2012 17.00.nnnnn.nn 4.0 1700 1700nnnnn
(170061030)
Predefined Macros (Visual Studio 2012)
2013 18.00.nnnnn.nn 12.0 1800 1800nnnnn
(未確認)
Predefined Macros (Visual Studio 2013)
VS 2013
Community
18.00.nnnnn.nn 12.0 1800 1800nnnnn
(180031101)
2015
Community
19.00.nnnnn.nn 14.0 1900 1900nnnnn
(190023026)
Predefined Macros (Visual Studio 2015)
2017
Community
19.1x.nnnnn 14.1
15.0
1910
1913
191nnnnnn
(191025019
191326129)
Predefined Macros
2019
Community
19.22.27905 14.2 1922 1922nnnnn
(192227905)
Predefined Macros

参考


ウインドウの特徴 (Window Features)

ウインドウ種別 (Window Types)

Overlapped Window (WS_OVERLAPPED,WS_OVERLAPPEDWINDOW)

アプリケーションのメインウインドウとして使用するためのトップレベル・ ウインドウ.タイトルバー,境界,クライアントエリアを持つ. ウインドウメニュー,最大化および最小化ボタン, スクロールバーを持つこともできる.

ウインドウスタイル:

  • WS_OVERLAPPED:タイトルバーと境界を持つ.
  • WS_OVERLAPPEDWINDOW:次の要素を持つ.
    • タイトルバー (WS_CAPTION)
    • サイズ変更可能境界 (WS_THICKFRAME (=WS_SIZEBOX))
    • ウインドウメニュー (WS_SYSMENU)
    • 最小化ボタン (WS_MINIMIZEBOX)
    • 最大化ボタン (WS_MAXIMIZEBOX)
    // WinUser.h
    #define WS_OVERLAPPEDWINDOW (WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | \
                                 WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX)
    
Pop-up Window (WS_POPUP)

Overlapped window の一種で, アプリケーションのメインウインドウの外に表示されるダイアログボックス, メッセージボックス,ツールチップ, その他の一時的なウインドウとして用いられる. タイトルバーがオプションである点を除いて WS_OVERLAPPED と同じ.

CreateWindowEx() で WS_POPUP を指定する場合, hwndParent には親ではなくオーナー (または NULL) を指定する. ポップアップウインドウの親はデスクトップウインドウになる.(実験で確認)

ウインドウスタイル:

  • WS_POPUP:ポップアップ・ウインドウ.
  • WS_POPUPWINDOW:WS_POPUP に加え,境界 (WS_BORDER) とウインドウメニュー (WS_SYSMENU) を持つ.
    // WinUser.h
    #define WS_POPUPWINDOW      (WS_POPUP | WS_BORDER | WS_SYSMENU)
    
Child Window (WS_CHILD)

通常,子ウインドウはクライアントエリアのみを持つが, 明示的に指定すれば次の要素を持つこともできる.

  • タイトルバー (WS_CAPTION)
  • ウインドウメニュー (WS_SYSMENU)
  • 最小化ボタン (WS_MINIMIZEBOX)
  • 最大化ボタン (WS_MAXIMIZEBOX)
  • 境界 (WS_BORDER)
    指定しない場合は境界のないウインドウを作成する. これは親ウインドウのクライアント領域を, 見えない境界で分割するのに使用できる.
  • スクロールバー (WS_HSCROLL,WS_VSCROLL)
  • メニュー (不可)
    CreateWindow() の hMenu 引数の説明からわかるように, メニューハンドルと子ウインドウ ID の一方しか指定できないので, 子ウインドウはメニューを持つことができないのだろう.
Layered Window (WS_EX_LAYERED)

レイヤード・ウインドウ. 次のような視覚効果を持つトップレベル・ウインドウ (子ウインドウは不可) を,ちらつかずに高速表示する. Windows 8 では子ウインドウも可 (出典:SetLayeredWindowAttributes function).

  • 複雑な形状 (アニメーションも可)
  • アルファブレンド

参考

Message-Only Window

メッセージを受信するためだけのウインドウ.不可視であり,Z-order はなく,列挙できない.また,ブロードキャストメッセージは受信しない.

参考


ウインドウメッセージ

ウインドウメッセージ番号 (WM_*) の範囲

番号範囲 説明 ヘッダファイル
0x0000WM_USER−1 (0x03FF) システム定義済または予約. WinUser.h
(Windows.h が include する.)
WM_USER (0x0400) 〜 WM_APP−1 (0x7FFF) WM_USER+n: ウインドウクラス内のプライベート・メッセージ.
(コモンコントロール固有メッセージなど)
CommCtrl.h,CommDlg.h など
WM_APP (0x8000) 〜 0xBFFF WM_APP+n:アプリケーション定義のプライベート・メッセージ. -
0xC0000xFFFF RegisterWindowMessage() が動的に割り当てる.アプリケーション間の通信用.

2013/11/17(日) 追記
RegisterWindowMessage() が返す値は global atom だろうと思っていたが,そうではないようだ. GlobalGetAtomName(atom1) が返した文字列を RegisterWindowMessage() に渡すと,atom1 とは異なる値が返ってくる.(実験で確認)

-
0x10000 システム予約. -

■Memo

DestroyWindow() の処理手順 (WM_DESTROY,WM_NCDESTROY)

下記のマニュアルの項目から推測した DestroyWindow(hwnd) の処理手順.

  1. 拡張ウインドウスタイル WS_EX_NOPARENTNOTIFY が指定されていなければ, すべての祖先ウインドウに WM_PARENTNOTIFY を send する.
  2. ウインドウを非表示 (!IsWindowVisible()) にする.
  3. WM_DESTROY を send する.
    ⇒ アプリケーションは hwnd に関連付けられているメモリを解放すべき.
    また,このウインドウが (SetClipboardViewer() で設定された) clipboard viewer chain の一部の場合は,ChangeClipboardChain() で削除しなければならない.
  4. 子孫ウインドウを破棄する.
  5. WM_NCDESTROY を send し,hwnd が使用していたメモリを解放する.
    したがってこの時点で hwnd が無効になる.つまり,hwnd が最後に受け取るメッセージは WM_NCDESTROY.

つまり WM_DESTROY は子孫ウインドウを破棄する,WM_NCDESTROY は子孫ウインドウを破棄したに send される.


参考

(2009/03/14(土))

マウスメッセージ

マウス入力メッセージ

Msg
No.
Message Symbol wParam lParam
(カーソル位置(*1))
Windows
Version
備考
HIWORD LOWORD HIWORD LOWORD
0x00A0 WM_NCMOUSEMOVE HitTest(*2) Screen-Y Screen-X
0x00A1 WM_NCLBUTTONDOWN
0x00A2 WM_NCLBUTTONUP
0x00A3 WM_NCLBUTTONDBLCLK
0x00A4 WM_NCRBUTTONDOWN
0x00A5 WM_NCRBUTTONUP
0x00A6 WM_NCRBUTTONDBLCLK
0x00A7 WM_NCMBUTTONDOWN
0x00A8 WM_NCMBUTTONUP
0x00A9 WM_NCMBUTTONDBLCLK
0x00AA (未定義)
0x00AB WM_NCXBUTTONDOWN XBUTTON[12] HitTest(*2) Screen-Y Screen-X 2000
以降
0x00AC WM_NCXBUTTONUP
0x00AD WM_NCXBUTTONDBLCLK

0x0200 WM_MOUSEMOVE - KeyState Client-Y Client-X
0x0201 WM_LBUTTONDOWN
0x0202 WM_LBUTTONUP
0x0203 WM_LBUTTONDBLCLK
0x0204 WM_RBUTTONDOWN
0x0205 WM_RBUTTONUP
0x0206 WM_RBUTTONDBLCLK
0x0207 WM_MBUTTONDOWN
0x0208 WM_MBUTTONUP
0x0209 WM_MBUTTONDBLCLK
0x020A WM_MOUSEWHEEL ホイール
回転量(*3)
KeyState Screen-Y Screen-X 98/NT4.0
以降
0x020B WM_XBUTTONDOWN XBUTTON[12] KeyState Client-Y Client-X 2000
以降
0x020C WM_XBUTTONUP
0x020D WM_XBUTTONDBLCLK
0x020E WM_MOUSEHWHEEL ホイール
回転量(*3)
KeyState Screen-Y Screen-X Vista
以降

(*1) マルチモニタ環境ではカーソル座標が負になる場合があるので,lParam からカーソル座標を取得するには LOWORD(),HIWORD() ではなく GET_X_LPARAM(), GET_Y_LPARAM() を使用すること.
(*2) HitTest:DefWindowProc()WM_NCHITTEST メッセージの処理結果として返すヒットテスト値.
(*3) ホイール回転量:
  • GET_WHEEL_DELTA_WPARAM(wParam) で取得する.
  • 回転量の符号は回転方向を表す.
    • WM_MOUSEWHEEL:回転方向が前方 (指先が手から遠ざかる) ならば+,後方 (手に近づく) ならば−.
    • WM_MOUSEHWHEEL:回転方向が右ならば+,左ならば−.
  • 普通は WHEEL_DELTA (=120) の倍数.WHEEL_DELTA は回転の1ノッチ (刻み) に相当する.ただし高分解能ホイールやノッチのないホイールでは,WHEEL_DELTA より小さい回転量の WM_MOUSE(H)WHEEL を高頻度で発生する可能性がある.

参考

(2012/11/23(金))

その他のマウス関連メッセージ

Msg
No.
Message Symbol wParam lParam
(カーソル位置(*1))
Windows
Version
備考
HIWORD LOWORD HIWORD LOWORD
0x0020 WM_SETCURSOR カーソルを含む
ウインドウ
マウス
メッセージID
HitTest(*2) 95/NT3.1
以降
ウインドウがメニューモードのときは HIWORD(lParam)=0.
0x0021 WM_MOUSEACTIVATE アクティブにされるトップ
レベルの親ウインドウ
ボタン押下時に発生したマウス
メッセージ
HitTest(*2)
0x0215 WM_CAPTURECHANGED - マウス入力を獲得する
ウインドウのハンドル
9x/Me/NT4.0
/2000/XP/
Server2003
以降

0x02A0 WM_NCMOUSEHOVER HitTest(*2) Screen-Y Screen-X 98/2000
以降
事前に TrackMouseEvent() の呼び出しが必要.
0x02A1 WM_MOUSEHOVER - KeyState Client-Y Client-X 98/NT4.0
以降
0x02A2 WM_NCMOUSELEAVE 0 0 98/2000
以降
0x02A3 WM_MOUSELEAVE 98/NT4.0
以降
(2012/11/23(金))

ダブルクリック・メッセージ (WM_xBUTTONDBLCLK) を使用するには

(2008/04/23(水))

TrackMouseEvent(),WM_(NC)MOUSEHOVER,WM_(NC)MOUSELEAVE

(2009/07/20(月))

ComboBox のメッセージ

ComboBox のメッセージの一部に, マニュアルの内容から予想されるのと異なる動作があったので実験で確認してみた.
(Windows XP SP3 + comctl32.dll 5.82.2900.5512 (2004/08/05))

(2009/03/21(土))

ダイアログ

ダイアログの座標系 (ダイアログ (テンプレート) 単位とダイアログベース単位)

ダイアログでは,座標の単位として画素数ではなく 「ダイアログテンプレート単位 (dialog template units,ダイアログ単位 (DLU) ともいう)」を用いる. リソースファイル (*.rc) の中のダイアログ定義データに含まれる座標はこれである. ダイアログテンプレート単位は「ダイアログベース単位 (dialog base units)」 を用いて次のように定義される.

TemplateUnitX = BaseUnitX / 4
TemplateUnitY = BaseUnitY / 8

ダイアログベース単位は, そのダイアログで使用するフォントのサイズにより次のように定義される.

BaseUnitX = <ダイアログのフォントの平均幅>
BaseUnitY = <ダイアログのフォントの高さ>

したがってダイアログ (テンプレート) 単位は次のようになる.

TemplateUnitX = <ダイアログのフォントの平均幅> / 4
TemplateUnitY = <ダイアログのフォントの高さ> / 8

2013/10/20(日) 追記

BaseUnitX は「フォントの平均幅」と定義されているが,TEXTMETRIC::tmAveCharWidth とは必ずしも一致しない.
(実験で確認.他方,BaseUnitY は TEXTMETRIC::tmHeight と一致する.)

後述する MapDialogRect() では,どうやらこのページのサンプルにあるように, 英字 [A-Za-z] の平均幅 (端数四捨五入) を使用しているらしい.(数種類のフォントとサイズについて実験で確認.)

要するにダイアログベース単位は, GetTextExtentPoint32("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz") の横幅を 1/52 にしたサイズに等しいはず.(端数四捨五入,高さはそのまま.)

GetDialogBaseUnits() は使えない.

ダイアログベース単位を取得する API 関数として, GetDialogBaseUnits() がある.この関数は引数なしである. つまり特定のダイアログのベース単位を返すのではなく,(Windows 95 時代の?) システムフォント (8ポイントの "System") を用いたダイアログのベース単位を返す. そのためそれ以外のフォントを使用するダイアログでは使えない. 困ったことに,Visual Studio.NET 2003 のダイアログエディタでは, ダイアログのデフォルトフォントは "MS Shell Dlg" であって "System" ではない. だから使えない. (ダイアログエディタでは "MS Shell Dlg" の方を「システムフォント」と呼んでいる.)

GetDialogBaseUnits() の代わりに MapDialogRect() を使う.

ダイアログテンプレート単位の座標を画素座標に変換するには MapDialogRect() を用いる.この関数は,RECT のX座標 (left および right) およびY座標 (top および bottom) をテンプレート単位から画素単位に変換する. テンプレート単位の座標を (Tx, Ty),画素座標を (Px, Py) とすると変換式は次のとおり.

Px = MulDiv(Tx, BaseUnitX, 4)
Py = MulDiv(Ty, BaseUnitY, 8)

この式において,Tx=4,Ty=8 とすれば, Px=BaseUnitX,Py=BaseUnitY となる. つまり使えない GetDialogBaseUnits() の代わりに,MapDialogRect() を用いて実際のダイアログベース単位を求めることができる. 次にその例を示す.

/*─────────────────────────────────────
機能  :ダイアログ hDialog の実際のダイアログベース単位を取得する.
        GetDialogBaseUnits() はシステムフォント (8ポイントの "System") を使
        用するダイアログでしか使えないが,この関数は hDialog が使用している
        フォントに基づいて実際のダイアログベース単位を返す.
入力  :hDialog:ダイアログのウインドウハンドル.
出力  :*baseUnit:hDialog の実際のダイアログベース単位.
戻り値:取得成功のときそのときに限り真.
2006/12/24(日) 作成
─────────────────────────────────────*/
BOOL GetActualDialogBaseUnits(HWND hDialog, SIZE *baseUnit)
{
  RECT rect;
  BOOL result;

  rect.left = 4;
  rect.top = 8;
  if(result = MapDialogRect(hDialog, &rect)) {
    baseUnit->cx = rect.left;
    baseUnit->cy = rect.top;
  }
  return result;
}

■実行結果

GetDialogBaseUnits() で求めたベース単位:(8, 18)
・ダイアログのフォントが "System" (サイズ:8ポイント) の場合
  GetActualDialogBaseUnits() で求めた実際のベース単位:(8, 18)
・ダイアログのフォントが "MS Shell Dlg" (サイズ:8ポイント) の場合
  GetActualDialogBaseUnits() で求めた実際のベース単位:(6, 13)

参考

2006/12/24(日) 初版
2007/01/08(月) 誤記訂正
2013/06/15(土) 参考リンク追加
2013/10/20(日) ダイアログベース単位について追記

(1つ以上の) モードレスダイアログで TAB が効かない!

この項目は,そもそも昨年12月に複数のモードレスダイアログを使おうとして TAB が効かなかったので追加したんだけど, リンクだけ紹介して中身を書くのをサボっていた. しかしついさっき「モードレスダイアログ  複数」で検索してきた人がいるのでこの機会に書くことにした. (2007/03/20(火) 13:40)

ちなみに「モーレス」だと勘違いしている人が多いみたいだけど「モーレス (modeless)」だよ!!
(「モーダル (modal)」とごっちゃになってる.(笑))

モードレスダイアログで TAB が使えるようにする方法は下のリンク先にあるとおりだが, 複数のモードレスダイアログの場合については書かれていなかった. そこで自分で試した結果, メッセージループを次のようにするとうまくいった.

HWND Dialog[NDIALOGS];  // モードレスダイアログのハンドルの配列
HACCEL hAccelTable = LoadAccelerators(hInstance, (LPCTSTR)IDR_xxxx);
MSG msg;
UINT i;

while(GetMessage(&msg, NULL, 0, 0)) {
  for(i = 0;  ;  i++) {
    if(i >= NDIALOGS) {
      // Dialog[*] 宛ではないメッセージの場合
      if(!TranslateAccelerator(msg.hwnd, hAccelTable, &msg)) {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
      }
      break;
    }
    // Dialog[i] またはそのコントロール宛のメッセージか?
    // そうならば処理する.
    if(IsDialogMessage(Dialog[i], &msg)) break;
  }
}

なお,モードレスダイアログの親 (または祖先) がモーダルダイアログだとダメなので, 親 (祖先) もモードレスにする必要がある. これはモーダルダイアログが自分専用のメッセージループを持っており, 同じスレッドに属する他のウインドウへの入力 (マウス,キーボード) メッセージを握りつぶしてしまうため.

つまり,モーダルダイアログが開いている間は, 同じスレッドに属する他のウインドウ (モーダルおよびモードレスダイアログを含む) をマウスやキーボードで操作することはできない.

また,上記のコードはすべてのウインドウがモードレスダイアログ (最大4個) であるアプリケーションでうまく動いたが, 数が多くなると非効率なので,下記の Microsoft の技術サポート記事を参考にする方がよい.


■参考リンク
2006/12/11(月) リンクのみ掲載
2007/03/20(火) 本文作成
2012/07/30(月) 本文ちょっと改訂

WM_INITDIALOG

(2009/03/20(金))

2013/10/20(日) 追記

ダイアログプロシージャは,WM_INITDIALOG より先にいくつかのメッセージを受信する.実験で確認したところ,次の順番になった.

  1. WM_SETFONT (フォントが指定されている場合のみ?)
  2. WM_NOTIFYFORMAT (ない場合もある.)
  3. WM_QUERYUISTATE (ない場合もある.)
  4. その他 (実験で確認したものは WM_CHANGEUISTATE,WM_UPDATEUISTATE,WM_NOTIFYFORMAT など.)
  5. WM_INITDIALOG

コントロールのウインドウクラス名一覧

コントロールのクラス名は,CommCtrl.h の中で次のように定義されている.
(どうしてこんなに名前の付け方がバラバラなんだ.)


コントロール名 クラス名 クラス名定義マクロ 備考
Animate SysAnimate32 ANIMATE_CLASS[AW]
Button Button WC_BUTTON[AW]
ComboBox ComboBox WC_COMBOBOX[AW]
ComboBoxEx ComboBoxEx32 WC_COMBOBOXEX[AW]
DateTimePicker SysDateTimePick32 DATETIMEPICK_CLASS[AW]
Edit Edit WC_EDIT[AW]
Header SysHeader32 WC_HEADER[AW]
HotKey msctls_hotkey32 HOTKEY_CLASS[AW]
IPAddress SysIPAddress32 WC_IPADDRESS[AW]
ListBox ListBox WC_LISTBOX[AW]
ListView SysListView32 WC_LISTVIEW[AW]
MonthCalendar SysMonthCal32 MONTHCAL_CLASS[AW]
NativeFont NativeFontCtl WC_NATIVEFONTCTL[AW]
PageScroller SysPager WC_PAGESCROLLER[AW]
RichEdit 4.1 RICHEDIT50W MSFTEDIT_CLASS Msftedit.dll
RichEdit 2.0/3.0 RichEdit20W RICHEDIT_CLASS[AW] Riched20.dll
Progress msctls_progress32 PROGRESS_CLASS[AW]
Rebar ReBarWindow32 REBARCLASSNAME[AW]
ScrollBar ScrollBar WC_SCROLLBAR[AW]
Static Static WC_STATIC[AW]
StatusBar msctls_statusbar32 STATUSCLASSNAME[AW]
SysLink SysLink WC_LINK (Unicode のみ) XP 以降
Tab SysTabControl32 WC_TABCONTROL[AW]
ToolBar ToolbarWindow32 TOOLBARCLASSNAME[AW]
ToolTips tooltips_class32 TOOLTIPS_CLASS[AW]
TrackBar msctls_trackbar32 TRACKBAR_CLASS[AW]
TreeView SysTreeView32 WC_TREEVIEW[AW]
UpDown msctls_updown32 UPDOWN_CLASS[AW]
Dialog MAKEINTATOM(0x8002) WC_DIALOG WinUser.h
TaskDialog

Vista 以降

■マニュアル

2006/09/21(木) 作成
2009/01/20(火) SysLink を追加
2010/02/13(土) マニュアルへのリンクを追加

ToolBar

ToolBar のボタンの種類 (機能別分類)

プッシュボタン (BTNS_BUTTON)
  • ToolBar ボタンのデフォルトスタイル.
  • 押すと WM_COMMAND を通知する.
チェックボタン (BTNS_CHECK)
  • 押すたびに ON/OFF が反転する.(チェックボックスと同等)
  • 押すと WM_COMMAND を通知する.
  • ON/OFF 状態は TBSTATE_CHECKED フラグで取得できる.
  • ボタンが ON になるときは押した瞬間に表示に反映されるのに対し, OFF になるときは WM_COMMAND の処理が終わってから表示が更新されるので, 処理に時間がかかると表示が変に見える.(実験で確認)
チェックグループ (BTNS_CHECKGROUP)
  • グループ内の0または1個のボタンだけが ON になる. (ラジオボタンのグループと同等)
  • グループの定義:BTNS_GROUP または BTNS_CHECKGROUP スタイルのボタンが連続 (隣接) する範囲が一つのグループとなる. (グループ間はセパレータで区切る.)
  • 押すと WM_COMMAND を通知する.
  • ON/OFF 状態は TBSTATE_CHECKED フラグで取得できる.
  • 押したボタン以外のボタンが OFF の表示になるのは,WM_COMMAND の処理が終わってからなので,処理に時間がかかると表示が変に見える.(実験で確認)
ドロップダウンボタン (BTNS_DROPDOWN,BTNS_WHOLEDROPDOWN)
  • ボタンを押すと選択肢のリストが表示される.
    (ドロップダウンリストスタイルの ComboBox と同等.ただしリストはアプリケーションが表示すべき.)
  • BTNS_WHOLEDROPDOWN スタイル
    ボタンの右端に小さなドロップダウンアロー [▼] を表示する.ボタンを押すと TBN_DROPDOWN を通知する.
  • BTNS_DROPDOWN スタイル
    ToolBar スタイル TBSTYLE_EX_DRAWDDARROWS が
    • 指定されていない場合:[▼] は表示されないが,ボタンを押すと WM_COMMAND ではなく TBN_DROPDOWN を通知する.
    • 指定されている場合:ボタンの右に [▼] を表示する. これはボタン本体とは別のボタンであり,ボタン本体を押すと WM_COMMAND を,[▼] を押すと TBN_DROPDOWN を通知する.(スプリットボタンと同等)
      Windows classic style では,TBSTYLE_FLAT も指定しないとちょっと見栄えが悪い.(ボタン本体と [▼] ボタンで右下の影の色が異なる.)
セパレータ (BTNS_SEP)
  • ボタングループ間に小さな隙間を挿入する.(実測で8画素幅)
  • ユーザ入力には反応しない.
2013/03/19(火) 作成

ToolBar の表示スタイル

以下はマニュアルに書いてある内容そのままではなく,自分で実験した結果を含んでいる. 正確・網羅的に調べたわけではないので間違いがあるかもしれない.
(Vista Home Premium SP2,Windows 7 Home Premium SP1,ComCtl32.dll version:6.16.7601.2)

リスト表示 (TBSTYLE_LIST)

ボタン画像の右にテキストを表示する.(OFF の場合は下に表示.)

フラット表示 (TBSTYLE_FLAT)
  • Windows Classic Style:ボタンの 3D 表示 / フラット表示を切り替える. フラット表示では,セパレータは凹んだ縦線 (|) として表示される. またボタンが複数行の場合,行間は凹んだ横線で区切られる.
  • Aero Basic/Glass Style:TBSTYLE_FLAT にかかわらずフラット表示されるが,Classic Style と同様,TBSTYLE_FLAT が ON の場合のみセパレータと行間の横線が表示される.OFF ならばこれらは表示されない.
透明背景 (TBSTYLE_TRANSPARENT)

Windows classic style の場合,ツールバーの背景を透明にする.

  • TBSTYLE_FLAT が OFF の場合:ボタンの背景は不透明 (COLOR_3DFACE) なので,親ウインドウの背景色を COLOR_3DFACE にしないと見栄えが悪い.
  • TBSTYLE_FLAT が ON の場合:ボタンの背景も透明になる. 背景色に応じてセパレータの縦線と行間の横線の色を設定した方がよい. (TB_SETCOLORSCHEME を使用)
複数行表示 (TBSTYLE_WRAPABLE)

ボタンが1行に収まらない場合,複数行で表示する. 改行は行の右端のセパレータの位置で行われる. セパレータがなければボタン間で改行される.

Windows classic style では,セパレータ位置で改行された場合に限り, 行間にスペースが入る.(TBSTYLE_FLAT が ON の場合は8画素,OFF ならば5画素.(実測))

ツールバー上部の境界線 (CCS_NODIVIDER)

CCS_NODIVIDER が OFF ならば,ツールバー上部に高さ2画素 (マニュアルに記載あり,実測でも確認) の横線を描く. (実験で確認したところ,この境界線は, ツールバーウインドウの非クライアント領域となっている.)

Windows classic style では,境界線を表示すると, (TBSTYLE_EX_DOUBLEBUFFER を指定していても) ウインドウのリサイズ時にツールバーのちらつきが大きい.(Aero Basic/Glass style では,CCS_NODIVIDER にかかわらずちらつきが大きい.)

ダブルバッファリング (TBSTYLE_EX_DOUBLEBUFFER)

ちらつき防止のため,ダブルバッファリングを行う. 実験では,次の条件を両方満たした場合にのみ, ウインドウをリサイズしてもツールバーのちらつきが発生しなかった.

  • Windows classic style
  • CCS_NODIVIDER を ON にする.
    (CCS_NODIVIDER を OFF にした場合はちらつきがひどい. しかも,TBSTYLE_EX_DOUBLEBUFFER が勝手にリセットされる. 境界線が非クライアント領域なので,ダブルバッファリングと両立しないのか?
    「境界線を表示したいけど,リサイズ時のちらつきは嫌だ」という場合は, リサイズ中のみ境界線を非表示にするという手もある. (WM_ENTERSIZEMOVE で CCS_NODIVIDER を ON にし,WM_EXITSIZEMOVE で OFF に戻せばできるはず.))

Aero Basic/Glass style では CCS_NODIVIDER の設定によらずちらつく.

ツールチップでボタンの説明表示 (TBSTYLE_TOOLTIPS)

ツールチップでボタンの説明テキストを表示する.

画像ボタンとテキストボタンの混合表示 (TBSTYLE_EX_MIXEDBUTTONS)

このフラグが ON の場合,BTNS_SHOWTEXT が ON のボタンにだけテキストが表示される.(TBSTYLE_LIST も ON にすること.)

部分的に隠れるボタンの非表示 (TBSTYLE_EX_HIDECLIPPEDBUTTONS)

部分的に隠れるボタンを表示しない.(Rebar で使用する場合に ON にする.)

ハイライトと影の色 (TB_SETCOLORSCHEME)

次の部分のハイライトと影の色を設定する.

  • ボタン上部および行間の横線 (Classic,Aero Basic/Glass いずれの場合も有効)
  • ボタンの境界線およびセパレータ (Classic かつ TBSTYLE_FLAT の場合のみ)
    ただしボタンの境界線はホットトラック時のみ表示される.
2013/03/29(金) 作成
2013/03/30(土) 追記

GDI

DC のマッピングモード

Mapping Mode 1論理単位 X軸
方向
Y軸
方向
デバイス
依存性
等方性
(*1)
備考
MM_TEXT 1画素 デバイス
依存
デフォルトのマッピングモード
MM_LOMETRIC 0.1mm メートル法 (低解像度)
MM_HIMETRIC 0.01mm メートル法 (高解像度)
MM_LOENGLISH 0.01inch
(約 0.254mm)
英国単位 (低解像度)
MM_HIENGLISH 0.001inch
(約 0.0254mm)
英国単位 (高解像度)
MM_TWIPS 1/1440 inch
(約 0.0176mm)
1/20 ポイント
(Twentieth of an Inch Point)
MM_ISOTROPIC ユーザ定義 (等方座標系) SetWindowExtEx()SetViewportExtEx()
座標軸の向きとスケールを設定する.
等方座標系になるように自動調整される.
MM_ANISOTROPIC ユーザ定義 (非等方座標系) 座標系
依存
SetWindowExtEx()SetViewportExtEx()
座標軸の向きとスケールを設定する.

(*1) 等方性 (isotropy):どちらの方向を向いても数学的・物理的性質が等しいこと. 特に2DグラフィックスではX軸方向とY軸方向の1論理単位の (デバイス上での物理的な) 長さが等しいこと. 論理座標空間で正方形や円を描くと,デバイス上でも正方形や円になる. 非等方 (異方) 座標系ではデバイス上で長方形や楕円になる.


(2012/05/06(日))

閉曲線・多角形の塗りつぶしモード (ALTERNATE/WINDING,EvenOdd/Nonzero)
〜 点が閉曲線の内部にあるかどうかを判定する方法 〜

Windows GDI では多角形や閉じたパスの塗りつぶしモードとして,ALTERNATE および WINDING の2種類がある.これらは次の API (や MFC のメソッド) で使用できる.

Direct2D1 (D2D1) にも同様の塗りつぶしモード (D2D1_FILL_MODE) がある.

.NET Framework や Silverlight の FillRule 列挙体では,EvenOddNonzero という名前になっている.

ALTERNATE (EvenOdd) と WINDING (Nonzero) とは何かというと, どちらも閉曲線の内部と外部を区別 (定義) するための規則である. 閉曲線を塗りつぶすには,当然ながら内部と外部を区別する必要がある. 閉曲線が単純 (数学用語で「曲線がそれ自身と交差・接触しない」) ならば,その内部と外部の区別は明らかだが, 単純閉曲線でない場合はあいまいになる場合がある

ALTERNATE/EvenOdd (交互ルール,偶奇ルール)

     ┏━━━━━━━━━━━━━━━━━┓
     ┃ Y               ┃
     ┃ ┏━━━┓   ┏━━┓    ┃
L    ┃ ┃ P ┃   ┃  ┃    ┃
──・→─╂─╂─・ ┃   ┃  ┃    ┃C
  Q  ┃ ┃   ┃   ┃  ┃    ┃
    W┗━╋━━━┛X  ┃  ┃    ┃
       ┃       ┃  ┃    ┃
       ┗━━━━━━━┛  ┃    ┃
       Z          ┃    ┃
                  ┗━━━━┛

上図で点Pが閉曲線Cの内部にあるかどうかを判定したい場合, Pから無限遠に半直線Lを引き,それがCを何回横切るかを数える. 奇数回ならばPはCの内部,偶数回ならば外部にあると定義する. 上図の場合は2回なので,PはCの外部ということになる.

別の言い方をすると,L上の点Qを無限遠からPに近づけるとき, QがCを横切るたびに外部と内部が交互に (alternate) 現れる.

WINDING/Nonzero (巻数ルール)

閉曲線C上の点QがCを1周するとき, 点Pのまわりを何回まわるか (巻数,winding number) により内外を定義する方法.

(1) Pが単純閉曲線Cの内部にある場合

  ┏━━━━━┓C
  ┃  P  ┃
  ┃  ・  ┃
  ┃     ・Q
  ┗━━━━━┛

  QがCを1周すると,Pのまわりを1回まわる.つまり巻数は1.


(2) Pが閉曲線Cの「明らかに」外部にある場合

  ┏━━━━━━━┓C
  ┃ ┏━━━┓ ┃
  ┃ ┃   ┃ ・Q
  ┗━┛   ┃ ┃         ・P
     ┏━━╋━┛
     ┃  ┃
     ┗━━┛

  QがCを何周しようが,Pからみれば8時の方向と10時の方向の間をウロウロ
  するだけで,Pのまわりを1周もすることはない.つまり巻数は0.

そこでPの巻数が0でないとき内部と定義すれば, 最初の ALTERNATE の図のPは,

なお .NET Framework / Silverlight の Nonzero の説明には「ある点から任意の方向に無限に伸びる射線を…」と書かれているので一見 EvenOdd と紛らわしいが,曲線がその射線を右回りに横切る回数から左回りに横切る回数を引いているので, これは巻数 (右回りが+) を求めていることになる.
(図解:方法 : 複合図形の塗りつぶしを制御する)

2007/06/16(土) 作成
2013/02/09(土) Direct2D1 追記
2016/11/05(土) .NET Framework /
Silverlight 追記

参考リンク


ごみ箱

ファイルをごみ箱に移動する.

ごみ箱は Windows95 以降のシェルアプリケーションの機能です. したがってごみ箱用の API は Windows API ではなく,シェル API であり, 次の3つがあります.

API 名 機能
SHFileOperation() ファイルまたはディレクトリをごみ箱に移動する.
(ごみ箱以外の機能もあり.)
SHEmptyRecycleBin() ごみ箱を空にする.
SHQueryRecycleBin() ごみ箱内にあるオブジェクトの個数と合計サイズを取得する.

ここでは,SHFileOperation() を用いてファイルやディレクトリをごみ箱に送る方法を説明します. といっても,私は SHFileOperation() の動作についてまだ十分理解しているわけではないので, 色々試行錯誤しながら理解したことや注意点を書きます. 間違いや補足があればご指摘ください.

SHFileOperation() は,次の構造体を使って必要なパラメータを受け取ります.

typedef struct {
  HWND         hwnd;
  UINT         wFunc;
  LPCTSTR      pFrom;
  LPCTSTR      pTo;
  FILEOP_FLAGS fFlags;
  BOOL         fAnyOperationsAborted;
  LPVOID       hNameMappings;
  LPCTSTR      lpszProgressTitle; // only used if FOF_SIMPLEPROGRESS
} SHFILEOPSTRUCT;

この構造体のメンバのうち,注意が必要なのは (というより,私がつまずいたのは (^^;)) 次の2つです.

pFrom
  • pFrom の最後は2個の '\0' で終端する.
    pFrom は複数のパス名を指定できる仕様になっており, 次の形式の文字列を受け取ります.
    <パス名1>\0<パス名2>\0\0<パス名N>\0\0
  • フルパス名でなければならない.
    … さもなくば,ごみ箱行きではなく, 本当に削除されてしまう,とマニュアルには書かれています.(動作未確認)

  • ディレクトリの区切り文字に '/' は不可.

    私がつまづいたのはこの点.マニュアルには書かれていないし, SHFileOperation() を説明している他のサイトにも書かれていません.
    (そもそも,Windows でパス名の区切りに '/' を使おうとする人自体,非常に少ないんだろうけど.(^^;)
    私は (少なくとも日本語環境では) 見やすいから Unix 流の '/' の方が好き.)

    多くの (すべての?) Windows API は,パス名の区切りとして '\\' の代わりに '/' を使っても,あるいは両者を混在させてもかまいません. しかし SHFileOperation() は Windows API ではなくシェル API であるせいか,そうはなっていないようです. この点にハマってしまいました.

    パス名の区切りとして '/' を用いたファイル名を指定したところ, ごみ箱には移動されるのですが, ごみ箱の中身を表示した際の「名前」が空文字列に, 「元の場所」が "D:" になってしまいました. また,「ファイル削除の確認」ダイアログに表示されるファイル名は, 単一の '"' だけになっていました. どうやらパス名の最初の '/' 以後の部分が無視されてしまったようです. しかし,ごみ箱のディレクトリ内にあるごみ箱管理ファイル "INFO2" をダンプしてみたところ, そのようなファイルでも元のパス名がちゃんと記録されており, ごみ箱から「元に戻す」こともできました. どうやら表示だけの問題のようです.

    2007/08/18(土) 追記

    パス名を \\?\ で始めると,Windows API でも '/' をディレクトリ区切り文字として使用できなくなるらしい. (参考:下記 外部へのリンク → Windowsパス名の落とし穴 → サービス機能の不活性化)

hwnd

NULL で大丈夫です.GUI アプリケーションだけでなく,hwnd に NULL を渡さざるを得ないコンソール・アプリケーションでも動きます. ただしコンソール・アプリケーションの場合はなぜか ERROR_INVALID_HANDLE がセットされますが,ごみ箱への移動はちゃんとできているようなので, このエラーコードは無視してよさそうです.
(ついでに言うと,fFlags に FOF_NOCONFIRMATION や FOF_NOERRORUI を指定しなければ,コンソール・アプリケーションであっても 削除確認ダイアログやエラーダイアログが表示されます.)

いやむしろ,NULL 以外の値として何を渡せばよいのか, マニュアルを見てもさっぱりわかりません. マニュアルの hwnd の説明には次のように書かれています.

「ファイル操作の状態に関する情報を表示するダイアログボックスのウインドウハンドル」(拙訳)

しかし,どんなコントロールをどのように配置すればいいのか?  全く謎です. テキトーにダミーのダイアログを作ってそのハンドルを渡してみたり, アプリケーションで別の目的に使用しているダイアログのハンドルを渡してみたりしましたが, ERROR_INVALID_HANDLE になり,ファイルはごみ箱に送られませんでした. 他のサイトのサンプルコードでは,当たり前のようにハンドルを渡しており, 疑問を持っている人はいないようです. ひょっとして,私はなにか大きな勘違いをしているのでしょうか?

現時点ではどんなダイアログのハンドル渡したらいいのかわからないし,NULL で動くので NULL を渡しています.


あと,ごみ箱に移動できないファイルがあると, なぜかそのようなファイルごとに数秒程度時間がかかります. SHFILEOPSTRUCT::fFlags に FOF_NOCONFIRMATION と FOF_NOERRORUI を指定していない場合,削除確認ダイアログはすぐに表示されるものの, それに「はい」と答えると約5秒後にエラーダイアログが出ました. なぜこんなに時間がかかるんだろう?

ファイルまたはディレクトリをごみ箱に送る関数の例を次に示します.

#include <ShellAPI.h>
#include <tchar.h>
/* その他のヘッダは省略 */

/* fullPathName はフツーの '\0' 終端文字列.
 * ただしフルパス名で,ディレクトリの区切りに '/' は不可.
 */
int MoveFileToRecycleBin(const TCHAR *fullPathName, HWND hwnd, FILEOP_FLAGS flags)
{
  SHFILEOPSTRUCT fileOp;
  const TCHAR *src = fullPathName;
  TCHAR *dest;

  /* ファイルのフルパス名を2つの _T('\0') で終端する必要があるので,
   * fullPathName[] を fileOp.pFrom[] にコピーし,2個目の _T('\0') を追加する.
   */
  fileOp.pFrom = dest = alloca(sizeof(*dest) * (_tcslen(fullPathName) + 2));
  while((*dest++ = *src++) != _T('\0')) {}
  *dest = _T('\0');     /* もう1個必要 */

  fileOp.hwnd = hwnd;
  fileOp.wFunc = FO_DELETE;
  fileOp.pTo = NULL;
  fileOp.fFlags = FOF_ALLOWUNDO | flags;
  fileOp.fAnyOperationsAborted = FALSE;
  fileOp.hNameMappings = NULL;
  fileOp.lpszProgressTitle = NULL;
  return SHFileOperation(&fileOp);
}
(2006/10/14(土))

ごみ箱の構造 (Windows XP Pro SP2 の場合)

まだ調査中です.

ごみ箱フォルダのパス名

ごみ箱フォルダのパス名は,各ドライブの <drive>:\RECYCLER\<OwnerSID> (隠しフォルダ).

<drive> はドライブ文字 (A〜Z), <OwnerSID> はユーザの SecurityID で,例えば次のような文字列.

"S-1-5-21-1234567890-123456789-123456789-1234"

したがって複数ユーザが使用している PC では, ドライブごと,ユーザごとにごみ箱フォルダが作られる (はず).

●参考

削除されたファイルのパス名

ごみ箱フォルダの中には,削除されたファイルが名前を変えて入れられる. そのファイル名は次のとおり.

D<drive><number>.<元の拡張子>

ここで <drive> はドライブ文字 (小文字), <number> はファイル番号 (削除された順に1から).

例えば,E: ドライブで5番目に削除された *.txt ファイルは, De5.txt という名前になる.

ファイルを「元に戻す」と,そのファイル番号は欠番になる.

INFO2 ファイルのフォーマット

ごみ箱フォルダ内の隠しファイル INFO2 には, ごみ箱内の削除ファイルの情報が含まれている. INFO2 の先頭20バイトはヘッダ部.その後に, ごみ箱内のファイルの情報が必要個数繰り返される.
(ファイルはごみ箱フォルダと同じドライブのものだけで, 「元に戻した」ものを含む.)

// INFO2 ファイル全体の構造
typedef struct {
  Info2Header_t header;         // ヘッダ (20バイト)
  Info2FileData_t fileInfo[N];  // ファイル情報 (各800バイト)
} INFO2_t;
調べた範囲では,どのドライブのごみ箱も,ヘッダは全く同じ内容だった (下記16進ダンプ).このため色々条件を変えて内容の変化を調べ, 各部の意味を推定するという手が使えない.orz

// ヘッダ部の16進ダンプ
00000000 05 00 00 00 00 00 00 00-00 00 00 00 20 03 00 00
00000010 00 00 00 00

よくあるパターンだが,ファイル先頭の数バイトはおそらくバージョン番号だろう. 途中の 20 03 00 00 は,sizeof(Info2FileData_t) と思われる.

// ヘッダ部の構造 (20バイト)
typedef struct {
  BYTE unknown1[12];  // 不明 (最初の数バイトは INFO2 ファイルのバージョンか?)
  DWORD fileInfoSize; // sizeof(Info2FileData_t) か?
  BYTE unknown2[4];   // 0固定?
} Info2Header_t;
// ごみ箱内の各ファイルの情報
typedef struct {
  // 削除前のフルパス名 (マルチバイト文字列).
  // ・余白は '\0' で埋める.
  // ・ファイルを元に戻した場合,最初の1バイトが '\0' になる.
  char ansiPathName[MAX_PATH];

  DWORD fileNo;     // ファイル番号? (1から始まる連番)
  DWORD driveNo;    // ドライブ番号? (A:0,B:1,…,Z:25)
  BYTE unknown[12]; // 未確認.削除時刻と属性フラグか?

  // 削除前のフルパス名 (UTF-16LE 文字列).
  // ・余白は L'\0' で埋める.
  // ・ファイルを元に戻しても変更されない.
  wchar_t unicodePathName[MAX_PATH];
} Info2FileData_t;

■参考リンク
(2007/06/29(金))

ウインドウリサイズ時のちらつきを抑える.

全面改訂中

ウインドウクラスを登録する際,スタイルに CS_HREDRAW | CS_VREDRAW を指定しておくと,ウインドウがリサイズされるたびに再描画が行われるが, それが頻繁すぎてちらつきが気になる場合がある. これは,次のようにすると低減することができる場合が多い (ちらつきを減らすのであって,完全になくせるわけではない).

CS_HREDRAW | CS_VREDRAW を指定するのをやめ, ウインドウプロシージャの WM_SIZE の処理で InvalidateRect(hwnd, NULL, FALSE) を行うようにする.

この方法が効果がある理由は次のとおり.(前半は推測)

CS_HREDRAW | CS_VREDRAW を指定した場合,ウインドウをリサイズするたびに WM_PAINT メッセージが (たぶん) send され,非常に頻繁に再描画が行われる. (いまいち確信なし)

これに対し,WM_SIZE の処理で InvalidateRect を行う方法では次のようになる.

このため再描画が行われる回数は激減する. リサイズが行われている間は WM_SIZE などが繰り返しディスパッチされ続け, WM_PAINT はほとんどディスパッチされないのに対し,リサイズが (一瞬でも) 停止して 他のメッセージがなくなると WM_PAINT が (1回だけ) ディスパッチされて再描画が行われる.

(2007/05/06(日))

■参考リンク (とりあえずメモ,未整理)


その他

Windows のエラーメッセージ文字列を取得する.

2006/10/29(日) 作成
2009/03/25(水) 改定

Windows のエラーメッセージは FormatMessage() で取得できるが, 引数が多いので自由度が高い反面,使うのが面倒. そこでエラー番号だけを指定すればエラーメッセージ文字列を取得できる, 次のような関数を用意しておくと簡単に使えて便利.

#include <windows.h>
#include <tchar.h>

TCHAR *WinErrorMessage(DWORD errorCode)
{
  TCHAR *message;
  DWORD n = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
                          FORMAT_MESSAGE_IGNORE_INSERTS |
                          FORMAT_MESSAGE_FROM_SYSTEM,
                          NULL, errorCode, LANG_USER_DEFAULT,
                          (TCHAR*)&message, 0, NULL);
  return (n > 0) ? message : NULL;
}

この関数は,必要な文字列バッファを自分で確保するので, 不要になったら LocalFree() で解放する必要がある.
(注意:このため,メモリ不足に陥った場合, そのメモリ不足を知らせるメッセージを取得できない可能性がある.)

この関数は Windows API を直接呼び出す場合だけでなく, C標準ライブラリ関数を呼び出した後にも (仕様として保証されているわけではないが) 事実上使用できる. (ライブラリ関数の中で Windows API を呼んでいるため.)

C標準ライブラリでエラーメッセージを取得するには strerror(errno) を使うが, これは英語だけなので,日本語表示が必要な場合には WinErrorMessage() や FormatMessage() の方が便利.また FormatMessage() の dwLanguageId 引数に言語識別子を指定すれば, 他言語のメッセージを取得できる.

Windows の基本的なエラーメッセージは kernel32.dll のリソース (メッセージテーブル) で定義されており,Windows 日本語版では日本語と英語のメッセージテーブルが定義されている.

メッセージテーブルの内容は,Resource Hacker などのリソース編集ツールで見ることができる.

使用例

TCHAR *fileName, *message, buf[1024];
FILE *in;

if((in = _tfopen(fileName, _T("r"))) == NULL) {
  message = WinErrorMessage(GetLastError());
  _stprintf(buf, _T("\"%s\" をオープンできません。\n%s"), fileName, message);
  LocalFree(message);
  MessageBox(NULL, buf, AppName, MB_ICONERROR);
  return -1;
}

注意:FormatMessage() が返すメッセージの一部には, 末尾に余分な空白や改行がついているものがあり, これらが邪魔になる場合がある.


Modifier Keys

Modifier Keys (SHIFT,CTRL,ALT など) を指定するための定数. いずれも WinUser.h で定義されている.


ATOM

■ATOM とは何か,なぜそういう名前なのか?
(たぶん間違っていない個人的推測 ― 以前回答したページに今更リンク.)


■各種コントロールの ATOM の値 (ATOM values for various control classes)

各種コントロールについて, テストプログラムを作って実際の値を調べてみると次のようになった.
(I wrote a test code to confirm the ATOM values, and the result is as follows.)

DLL Class ATOM Remarks
System-defined
Controls
(User32.dll?)
Dialog 0x8002
(WC_DIALOG)
WinUser.h で定数として定義されている.
(Defined in WinUser.h)
Button 0xC017 DLGITEMTEMPLATEEX Structure には, これらのクラスはシステム定義と書かれている.
すると ATOM は (事実上) 定数か?
ATOM の値は上記のページに書かれている windowClass の値に 0xBF97 を加算したものに
なっている.

("DLGITEMTEMPLATEEX Structure" says these controls are predefined system classes, and the ATOM values seem to be (DLGITEMTEMPLATEEX::windowClass + 0xBF97).)
Edit 0xC018
Static 0xC019
ListBox 0xC01A
ScrollBar 未確認だが
0xC01B のはず
(Not Tested,
but should be 0xC01B)
ComboBox 0xC01C
Common Controls
(ComCtl32.dll)
DLL Version 5.82.2900.2 6.16.7601.2
ComboBoxEx 0xC04A 0xC0B6
0xC0E2
ATOM の値は定数ではないので, 動的に割り当てられていると思われる.

(These ATOM values do NOT seem to be constant, so they should be assigned dynamically.)
(ComboLBox) Not Tested 0xC01E
ListView Not Tested 0xC098
StatusBar 0xC03E 0xC075
0xC076
TabControl Not Tested 0xC0D6
ToolBar Not Tested 0xC072
0xC075
TrackBar Not Tested 0xC077
TreeView Not Tested 0xC0D4
UpDown Not Tested 0xC0AE
その他
(Others)
Not Tested Not Tested

InitCommonControlsEx() のエラー

INITCOMMONCONTROLSEX::dwICC に ICC_STANDARD_CLASSES または ICC_LINK_CLASS が含まれているとなぜかエラーになる.
(Windows XP SP3 + comctl32.dll 5.82.2900.5512 (2004/08/05))

■参考

GetLastError() で ERROR_ALREADY_EXISTS が返るが, 上記のフラグの代わりに未定義のビット (0x00010000 以上) をセットしても同じ結果になるので, このエラーコードには意味がなさそうである.

(2009/03/21(土))

実行ファイルのフルパス名を取得する.

GetModuleFileName() の第1引数 (hModule) に NULL を渡すと, 現在のプロセスに対応する実行ファイルのフルパス名を取得できる.

#include <windows.h>
#include <tchar.h>

TCHAR ExeFileName[MAX_PATH];

GetModuleFileName(NULL, ExeFileName, MAX_PATH);
(2006/09/21(木))

参考図書

プログラミングWindows第5版〈上〉Win32 APIを扱う開発者のための決定版! (Microsoft Programming Series)
チャールズ ペゾルド
アスキー
売り上げランキング: 97738
おすすめ度の平均: 4.0
4 Windowsプログラマのバイブル本!
5 初版で勉強しました。
4 基本から確実に理解したいなら
4 詳しいが、少しバランスが!
5 硬派なWindowsプログラマーを志すならば

プログラミングWindows第5版〈下〉Win32 APIを扱う開発者のための決定版! (Microsoft Programming Series)
チャールズ ペゾルド
アスキー
売り上げランキング: 208637
おすすめ度の平均: 4.0
4 Windowsプログラマのバイブル本!
5 初版で勉強しました。
4 基本から確実に理解したいなら
4 詳しいが、少しバランスが!
5 硬派なWindowsプログラマーを志すならば

著者サイト


Advanced Windows 第5版 上 (マイクロソフト公式解説書)
Jeffrey Richter Christophe Nasarre
日経BPソフトプレス
売り上げランキング: 127753
おすすめ度の平均: 5.0
5 Advanced Windows第5版翻訳本

Advanced Windows 第5版 下 (マイクロソフト公式解説書)
Jeffrey Richter Christophe Nasarre
日経BPソフトプレス
売り上げランキング: 131018



【送料無料】インサイドWindows(上) [ マーク・E.ルシノビッチ ]

楽天で買う
価格:7,980円(税込、送料込)

インサイドWindows 第6版 上 (マイクロソフト公式解説書)
Mark E. Russinovich David A. Solomon Alex Ionescu
日経BP社
売り上げランキング: 82,632
【送料無料】インサイドWindows 第6版 下 [ マーク・E.ルシノビッチ ]

楽天で買う
価格:7,560円(税込、送料込)

インサイドWindows 第6版 下 (マイクロソフト公式解説書)
Mark E. Russinovich David A. Solomon Alex Ionescu
日経BP社
売り上げランキング: 82,761



Microsoft Windows Internals
Mark Russinovich David A. Solomon Alex Ionescu
Microsoft Pr
売り上げランキング: 23,301



Microsoft Windows Internals
Mark E. Russinovich David A. Solomon Alex Ionescu
Microsoft Pr
売り上げランキング: 25,543



C++ユーザーのためのWindowsプログラミングの基礎知識―Visual C++とMFCを利用したプログラミング入門 (Ascii books)
柏原 正三
アスキー
売り上げランキング: 359295
おすすめ度の平均: 3.5
5 この本はいいですよ
1 入門者にはお勧めできない
5 MFCを使ったWindowsプログラミング入門に最適です。



猫でもわかるWindowsプログラミング 第3版 (猫でもわかるプログラミングシリーズ)
粂井 康孝
ソフトバンククリエイティブ
売り上げランキング: 122154
おすすめ度の平均: 3.0
3 普通にわかりません。
2 猫ではわかりません
5 実践重視でテンポよい解説
2 著者はMSDNライブラリを読んでいない
4 Visual C++ 2008対応リニューアル版



Windowsプログラミング逆引きクロス大辞典
佐納 康治 曽我部 雄樹
秀和システム
売り上げランキング: 318690
おすすめ度の平均: 5.0
5 こんな辞書を待っていました



Windowsゲームプログラミング 第2版 Game Developer
赤坂 玲音
ソフトバンククリエイティブ
売り上げランキング: 24726
おすすめ度の平均: 3.5
2 内容はいいんだけど
4 C言語経験者向き
5 Windowsプログラミング



【送料無料】Windowsプログラミングの極意

楽天で買う
価格:3,990円(税込)

日本語のタイトルは誤解を招きやすいが,Windows のプログラミング方法ではなく, 「Windows の○○はなぜそうなっているのか?」を解説した本.

■参考


外部へのリンク


更新履歴

  1. 2006/09/21(木) 公開
  2. 2006/10/14(土) ファイルをごみ箱に移動する.を追加.
  3. 2006/10/29(日) Windows のエラーメッセージ文字列を取得する.を追加.
  4. 2006/12/11(月) (1つ以上の) モードレスダイアログで TAB が効かない! 準備開始.
  5. 2006/12/24(日) ダイアログの座標系 (ダイアログテンプレート単位とダイアログベース単位) を追加.
  6. 2007/01/08(月) ダイアログの座標系 (ダイアログテンプレート単位とダイアログベース単位) の誤記訂正.
  7. 2007/03/20(火) モードレスダイアログで TAB が効かない! ようやく内容作成.
  8. 2007/05/06(日) ウインドウリサイズ時のちらつきを抑える.を追加.
  9. 2007/06/16(土) 閉曲線・多角形の塗りつぶしモード (ALTERNATE と WINDING) 〜 点が閉曲線の内部にあるかどうかを判定する方法 〜 を追加.
  10. 2007/06/29(金) ごみ箱の構造 (Windows XP Pro SP2 の場合) を追加 (まだ調査中).
  11. 2007/08/18(土) 外部へのリンクの「Windowsパス名の落とし穴」にコメントを追記. またそれに関連して,「ファイルをごみ箱に移動する.」の pFrom の説明にも追記.
  12. 2007/11/04(日) 外部へのリンクに「あなたの知らない259文字越えの世界 (Tatsuの開発室)」を追加.
  13. 2009/01/20(火) コントロールのウインドウクラス名一覧に SysLink を追加.
  14. 2009/03/28(土) 下記を追加.
  15. 2009/07/20(月) TrackMouseEvent(),WM_(NC)MOUSEHOVER,WM_(NC)MOUSELEAVE を追加.
  16. 2009/08/11(火) 実行環境バージョン指定マクロ に Windows 7 と IE8 を追加.
  17. 2010/06/22(火) CB_GETCURSEL の説明を少し改定.
  18. 2010/10/09(土) 「ウインドウメッセージ番号 (WM_*) の範囲」を追加.
  19. 2010/10/28(木) WS_POPUP にちょっと追記.
  20. 2011/09/11(日) 「ATOM」を追加.
  21. 2012/01/15(日) 「_MSC_VER」を追加.
  22. 2012/05/06(日) 「DC のマッピングモード」を追加.
  23. 2012/07/30(月) 「(1つ以上の) モードレスダイアログで TAB が効かない!」をちょっと改訂.
  24. 2012/11/23(金)
  25. 2013/02/09(土) 「閉曲線・多角形の塗りつぶしモード」に,Direct2D1 の塗りつぶしモードを追記.
  26. 2013/03/29(金) 「ToolBar」を追加.
  27. 2013/06/15(土) 記事の順序変更.
  28. 2013/09/14(土) 「実行環境バージョン指定マクロ」を Windows Kits 8.1 用に更新.
  29. 2013/10/13(日) 「_MSC_VER」に追記.
  30. 2013/10/19(土) 「各種コントロールの ATOM の値」の表と説明を全面改訂.
  31. 2013/10/20(日) 「ダイアログの座標系」に,ダイアログベース単位の計算方法を追記.
  32. 2013/11/17(日) ウインドウメッセージ 0xC000 〜 0xFFFF についてちょっと追記.
  33. 2014/05/01(木) 「各種コントロールの ATOM の値」に英語を併記.(外国のサイトからリンクされているので.)
  34. 2014/11/22(土) 「_MSC_VER」に VC2015 と ToolsVersion を追記.
  35. 2014/12/06(土) 「_MSC_VER」に Visual Studio 2013 Community を追記.
  36. 2015/08/01(土) 「実行環境バージョン指定マクロ」を Windows Kits 10 用に更新.
  37. 2016/11/05(土) 「閉曲線・多角形の塗りつぶしモード」に,.NET Framework / Silverlight の塗りつぶしモードを追記.
  38. 2017/07/23(日) 「_MSC_VER」に VC2017 Community と ToolsVersion を追記.


Copyright © 2006-2020 noocyte
E-mail: relipmoced (a) yahoo.co.jp
  (" (a) " を半角のアットマークに書き替えてください.)
リンクはご自由に.
「noocyte のプログラミング研究室」トップページに戻る.