Thursday, February 21, 2008

時間表示プログラム

Chapter 4:
GetLocalTime(
  • LPSYSTEMTIME lpSystemTime
);
この関数で時間情報をシステムから取得し,構造体SystemTimeで保持する.
SystemTime構造:
typedef struct _SYSTEMTIME{
  • WORD wYear;
  • WORD wMonth;
  • WORD wDayOfWeek;
  • WORD wDay;
  • WORD wHour;
  • WORD wMinute;
  • WORD Second;
  • WORD wMilliseconds;
} SYSTEMTIME, *PSYSTEMTIME;
時間取得するにはWindowsは駆動型だからシステムから定期的にあるメッセージが送られれてきて,このメッセージが来たら,時間を取得するという仕組みになっている.この定期的なメッセージが来るようにするにはSetTimer()関数を使用.
UINT_PTR SetTimer(
  • HWND hWnd,
  • UINT_PTR nIDEvent, // タイマID
  • UINT uElapse, // タイムアウト値 単位はミリセコンド
  • TIMERPROC lpTimerFunc //タイマのプロシージャ
);
最後のパラメータはNULLにするとhWndのプロシージャで処理することになる.
プロシージャへ送られるメッセージは副メッセージもやってくる.その副メッセージはプロシージャ引数の最後の2つであるWPARAM, LPARAMである.
WM_TIMERのときはwParamにはタイマID,lParamにはタイマのプロシージャのアドレス(SetTimer関数の第4引数)が入る.
タイマが不要になったらKillTimer()関数を使用.
BOOL KillTimer(
  • HWND hWnd,
  • UINT_PTR uIDEvent
);

Wednesday, February 20, 2008

Windowsプログラミングの厄介な型のまとめ

Windowsプログラミングではたくさんのデータ型がある.慣れるしかないな~
Windowsのデータ型まとめ:




LPCSTR(pointer const string??) => const CHAR *
LPCWSTR => const WCHAR *
CHAR => char
TCHAR => WCHAR => wchar_t -> Unicode
WORD => unsigned short
DWORD => unsigned long



Windowsのハンガリー記述法まとめ:




c char
by, b BYTE
n short, int
b,f BOOL(int)
w WORD or UINT
l LONG
dw DWORD
fn pointer to function
s string
sz ASCII string
p,lp pointer




Unicodeの文字はワイドCHARで,C言語ではこれ表すがたはwchar_t(2bytes)
C言語でwchar_tの使い方は:

#include 
#include

int main(void)
{
wchar_t waidomoji[10] = L"漢字";//Lマクロに注意

setlocale(LC_ALL, "japanese");
wprintf(L"%s\n", waidomoji);
return 0;
}
WindowsではTEXT("...")マクロとTCHARを一緒に使うとUnicodeになる.
TEXT(quote) => __TEXT(quote) =>
Lquote
次の使い方もある
(LPCWSTR)L"Wide Char Message"
 
 

Saturday, January 05, 2008

3.ウィンドウの作成

RegisterClassEx()関数で定義したウィンドウクラスをシステムに登録し終わったら,次にウィンドウを作成する.CreateWindow()関数またはCreateWindowEx()関数を使用:(後者は拡張スタイルも使用できる点だけ前者と異なる.)

HWND CreateWindow(

  • LPCTSTR lpClassName, // クラス名
  • LPCTSTR lpWindowName, // ウィンドウ名,タイトル
  • DWORD dwStyle, // ウィンドウスタイル
  • int x, // x位置
  • int y, // y位置
  • int nWidth, // 幅
  • int nHeight, // 高さ
  • HWND hWndParrent, // 親ウィンドウのハンドル
  • HMENU hMenu, // メニューハンドルまたは子ウィンドウID
  • HINSTANCE hInstance, // インスタンスハンドル
  • LPVOID lpParam // ウィンドウ作成データ

);

まず,...
lpClassNameはWNDCLASSEX構造体のlpszClassNameメンバに指定したウィンドウクラス名を指定.自分で登録したウィンドウクラス以外に,システムで定義されたクラスを使うことができる.(後述)

続いて,...
lpWindowNameはウィンドウの名前,タイトル

続いて,...
dwStyleはウィンドウスタイルを指定.サイズ変更可能,タイトルバーにコントロールメニューボックス,最大化,最小化ボタンを持つ一般的なオーバーラップウィンドウであるWS_OVERLAPPEDWINDOWを指定.

続いて,...
x, yはウィンドウが表示される座標を指定.

続いて,...
nWidth, nHeightはウィンドウの幅,高さ.x,y,nWidth,nHeightそれぞれCW_USEDEFAULTを指定することができる.そうすると適当な位置とサイズをシステムが決めてくれる.

続いて,...
hWndParrentには親ウィンドウのウィンドウハンドルを指定.親がないときはNULL.

続いて,...
hMenuにはメニューを指定.そのほかの使い方もあるが後述.

続いて,...
hInstanceにはインスタンスハンドルを指定.Windows NT/2000/XPは無視される.

続いて,...
lpParamはいろいろ面白い使い方があるが後述.ここではNULL.気になる~

これで登録を行い失敗したらNULLが返ってくる.成功するとウィンドウのハンドルを返される.以後,このウィンドウを操作するにはこのハンドルをいじる

登録が終わるとウィンドウが表示されない.表示するにはShowWindow()関数を使用:

ShowWindow(

  • HWND hWnd, // ウィンドウハンドル
  • int nCmdShow // 表示状態

);

nCmdShowは次の値をとる:

オプション 意味
SW_HIDE 非表示
SW_MAXIMIZE 最大表示
SW_MINIMIZE 最小表示
SW_RESTORE 最大化または最小化されたウィンドウを元のサイズに戻す
SW_SHOW ウィンドウをアクティブにして,現在の位置とサイズで表示
SW_SHOWNORMAL ウィンドウをアクティブにして表示.初めてウィンドウを表示するときはこれを指定.

UpdateWindow()関数はウィンドウを更新する.

BOOL UpdateWindow(

  • HWND hWnd;

);
この関数はどのような役割をもつのかな?プログラムをこの部分をコメントアウトしてもウィンドウは普通に表示された.

その3.p28~p31

2.ウィンドウクラスの内部

  1. WNDCLASSEX構造体のメンバー指定
  2. RegisterClassex関数で登録

typedef struct WNDCLASSEX, *PWNDCLASSEX{

  • UINT cbSize; // 構造体のサイズ
  • UNIT style;   // クラスのスタイル
  • WNDPROC lpfnWndProc; // ウィンドウプロシージャ
  • int cbClsExtra; // 補助メモリ
  • int cbWndExtra; // 補助メモリ
  • HINSTANCE hInstance; // インスタンスハンドル
  • HICON hIcon; // アイコン
  • HCURSOR hCursor; // カーソル
  • HBRUSH hbrBackground; // 背景ブラシ
  • LPCTSTR lpszMenuName; // メニュー名
  • LPCTSTR lpszClassName; // クラス名
  • HICON hIconSm; // 小さいアイコン

}

指定方法:
WNDCLASSEX wc;

まず...
wc.cbSize = sizeof(WNDCLASSEX);

続いて...
wc.style = CS_HREDRAW | CS_VREDRAW;
「CS_??」はClass Styleの略.CS_HREDRAWはクライアント領域の横が変わったときにウィンドウ全体を再描画する.H-> Horizon, V -> Vertical.ほかにwinuser.hに多数定義してある.CS_??はただの数字.winuser.hの中に
#define CS_* 0x???
...

続いて,...
wc.lpfnWndProc = ウィンドウのプロシージャ関数のアドレス
これはウィンドウプロシージャ関数アドレスを指定(関数の名前そのもの)

続いて,...
hIcon(大きいアイコン)やhIconSm(小さいアイコン)にはアイコンを指定.hIconSmがNULLであるとシステムはhIconの値を検索する.アイコンをロードする方法は
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
しかし,LoadIcon関数は現在LoadImage関数に取って代わられた

LoadImage関数:
HANDLE LoadImage{

  • HINSTANCE hinst, // インスタンスのハンドル
  • LPCTSTR lpszName, // イメージの名前または識別子
  • UINT uType, // イメージタイプ
  • int cxDesired, // 希望する幅
  • int cyDesired, // 希望する高さ
  • UINT fuLoad // ロードのオプション

};

hinst:インスタンスハンドルを指定する.システムで定義されたアイコンを使う場合はNULLを指定

lpszName:にはアイコンの名前または識別子を使う.識別子で指示するときは

  • MAKEINTRESOURCEマクロ

を使用する

uType:はイメージのタイプを指定する.アイコンならIMAGE_ICONとなる.

LoadImage関数はアイコンだけでなく,マウスカーソルやビットマップもロードできる.カーソルのときはIMAGE_CURSOR,ビットマップはIMAGE_BITMAP,を指定.

cxDesired,cyDesiredはイメージの希望サイズを指定するが,これを0にして,fuLoadパラメータにLR_DEFAULTSIZEを指定するとシステムで定義されたサイズになる.またfuLoadLR_SHAREDも指定する必要がある.このフラグを指定した場合不要なリソースはシステムによって自動的に破棄される.ウィンドウクラスの定義では必ずLR_SHAREDを入れておく!

その2.p23~p26

~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*

LoadImage()関数はカーソルやアイコンを設定できるという話のつづき...
アイコンとカーソルの指定は共通でLoadImage()関数で行うことができるが,異なる点はMAKEINTRESOURCEマクロの設定は

  • MAKEINTRESOURCE(IDC_APPLICATION)->ICONか
    MAKEINTRESOURCE(IDC_ARROW) ->CURSORの点が異なると
  • uTypeの指定はIMAGE_ICONかIMGAE_CURSORかの点で異なる

でした.具体的に,もっと詳細で書くとプログラム内でカーソルの設定の部分は以下のようになる(カーソルはHCURSORでキャッシュしアイコンはHICONでキャッシュしている所に注意!):

wc.hCursor = (HCURRSOR)LoadImage(

  • NULL,
  • MAKEINTRESOURCE(IDV_ARROW),
  • IMAGE_CURSOR,
  • 0,
  • 0,
  • LR_DEFAULTSIZE | LR_SHARED

);

続いて,...
hbrBackgroundには背景を塗りつぶすブラシを指定.(これは後述).サンプルでは:

wc.hbBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);

GetStockObject()関数はHGDIOBJ型を返す関数がhbBackgroundはHBRUSH型であるためキャッシュする必要がある.めちゃめちゃキャッシュしてるやなぁ~.こりゃ大変.APIのプログラミングではキャッシュは無数あるらしい...
GetStockObject()関数は定義済み(ストック)オブジェクトのハンドルを取得.戻り値の型はHGDIOBJである(GDIオブジェクトのハンドル).WHITE_BRUSH, GRAY_BRUSH, BLACK_BRUSH...など指定してみた^^

続いて,... 
lpszMenuNameにはメニューの名前を指定.サンプルはメニューがないためNULLを指定した.

続いて,...
lpzClassNameにはクラスの名前を指定.サンプルでは"sample01"とか指定してある.

これでウィンドウクラスの定義が完了!次にはRegisterClassEx()関数でシステムに登録する

ATOM RegisterClassEx(CONST WNDCLASSEX *lpwcx);

ATOM型は後述
登録が終わったらウィンドウの作成...

その2.p27~p28

Saturday, December 29, 2007

1.猫はWindowsプログラミングがわからん

DDL:Dynamic Link Library
WindowsシステムのAPI関数の実際の実行コードはgdi32.dllやkernel32.dllやuser32.dllに含まれている.

メッセージ駆動型プログラミング:プログラムはシステムからどのようなメッセージが送られてきたら何をすれば指定するプログラミング
イベント駆動型プログラミング:どのイベントが発生したら何を実行するか?

Win32APIで使われているデータ型:

データ型 意味
BOOL True or False
BYTE バイト(8ビットデータ)
CHAR 8ビットANSIキャラクタ
DWORD 32ビット符号なし整数
INT 32ビット符号付きの整数
LONG 32ビット符号付きの整数
WORD 16ビット符号なし整数

基本的なWindowsプログラムであれば,多くの場合,結合するライブラリを指定しなくてもリンカが自動でやってくれる.しかしツールバーやステータスバーなどを持つプログラムは特別にライブラリを指定する必要がある.

メニューやダイヤボックス(これらはリソースという)を持つプログラムでははリソーススクリプトを作成して,リソースコンパイラでコンパイルし,リンカで結合する必要がある.

WindowsプログラムはWinMain関数から出発.
CALLBACK修飾子が付いている関数は自分のプログラムにどの場所に出てこないこともあるが,これはシステムから呼ばれるものである.コールバック関数あるいはウィンドウプロシージャという.

int WINAPI WinMain(HINSTANCE hCurInst,
HINSTANCE hPrevInst,
LPSTR lpsCmdLine, int nCmdShow)

HINSTANCE:インスタンスハンドルと呼ばれ,インスタンスとはメモリ上のプログラムのこと.インスタンスハンドルはシステムがインスタンスを識別するための番号です.
hCurInst: Current instance
hPrevInst: Previous instance.Windowsでは同じプログラムを複数起動できる.16ビット時代はこの引数を見て,すでに自分自身が起動されているかどうかを知ることができたが,Win32 APでは常にNULL.互換性維持のため,無視してよし.

LPSTR lpsCmdLine
コマンドライン引数が格納される.ARGV...と同じ

int nCmdShow
ウィンドウの表示状態を指定する.WinMain開始,システムが表示状態を決定する(?),そのままメインウィンドウを作った後
ShowWindow(hWnd, nCmdShow);

WinMain関数の中身:

  • ウィンドウクラスの定義
  • ウィンドウクラスの登録
  • 登録したウィンドウクラスを元に,親ウィンドウを作成
  • メッセージループの作成

自分で作ったウィンドウに対してはウィンドウプロシージャと呼ばれる関数が必要.複数のウィンドウに対して同じウィンドウプロシージャを使うことができる.

実はWinMain関数はどのようなプログラムもほとんど同じ.プログラムのメインの部分はウィンドウプロシージャにある.ここでイベントが起きたときのプログラムの反応を書くからである.イベントが起きるとメッセージが届く.メッセージ処理ということになる.

その1.