This is “ウインドウズプログラミング講座、第1回、 LCC版“
Since: 3/5/2006 11:31:01 AM
Contact
with
今回のソースは、最小限の構成となっている。
つまり、C言語ソースコード1つと、リソース用ヘッダーファイル並びにリソースファイルが1つという、構成である。これは、例えば、BCC版であっても、VCC版であっても変わらず、最小編成である。
ウインドウズプログラムでなければ、あるいは、リソースを用いない場合には、リソースファイルとリソースヘッダーファイルが無い、C言語ソースコードのみ(1つだけ)ということになる。
○初めに、WinMain 関数ありきである。
ついで、WinMain 関数のコールバック関数である、MainWndProc 関数がそれに次ぐ。
残りの関数は、ウインドウズプログラムという観点からは、この二つの関数の補足となっている。
○ 同様の構成を持っているのが、ダイアログ関連のDialogBox関数(ウインドウズAPI関数である)、とそのコールバック関数である、AboutDlg関数である。
今回の例では、ウインドウ関連の精製とコールバック関数はこの2つのみである。
○ちなみに、AboutDlg 関数は、WinMainコールバック関数のMainWndProc関数から、MsgMenuSelect関数、ついで、MainWndProc_OnCommand関数を経て、呼ばれている。
これは、ちょうど、メニュー選択、とその処理、”About”コマンドとその処理の関係である。ウインドウズプログラミングにおける、メニュー処理の典型といえる関係となっていると言えよう。
○ WinMain()関連のユーザー定義初期化関数(view.c で定義されている関数群)については、意見の分かれるところであろう。そのまま、好みの問題といってよい、どーでもいい関数わけとも、いえる、という訳だ。
○ステータスバーの処理なども、興味深いところである。初期化(生成、クリエート)関数は別にして、描画・内容の設定、表示・アップデートの関係は、描画などの処理そのままであり、ウインドウズプログラムの特徴をよく芦原和紙していると言えよう。
大体、ここまで説明すると、残りはAPIの具体的な仕様、入力と出力、並びに処理内容の問題となるといえるだろう。つまりは、マニュアルの勉強の問題である。
という訳で、後は、それぞれの、プログラムの勉強用の本、又は、関数に関する情報元をあたってみてほしい。
LCC付属の、API関連ヘルプなどは、格好のデータベースではあるが、いかんせん、構造を持たない羅列であることから、大変な苦労を伴いそうであるが、…。
定数一覧 今回は省く。
以下にソースコードを掲載する。
/* --- The following code comes from c:\lcc\lib\wizard\stddef.tpl. */
// This are the definitions for all symbols used in menus or string.
#define IDM_OPEN 210
#define IDM_SAVE 220
#define IDM_SAVEAS 230
#define IDM_CLOSE 240
#define IDM_PRINT
250
#define
IDM_PAGESETUP 260
#define IDM_EXIT 300
#define IDM_ABOUT 500
#define IDMAINMENU 600
#define IDAPPLICON [t.k3] 710
#define IDAPPLCURSOR 810
#define IDS_FILEMENU[t.k4] 2000
#define IDS_HELPMENU 2010
#define IDS_SYSMENU 2030
#define IDM_STATUSBAR[t.k5] 3000
/*@@ Wedit generated application. Written Sun Mar 05 09:37:27 2006
@@header: c:\mywork\c\lcc\view\viewres.h
@@resources: c:\mywork\c\lcc\view\view.rc
Do not edit outside the indicated areas */
/*<---------------------------------------------------------------------->*/
/*<---------------------------------------------------------------------->*/
#include <windows.h>
#include <windowsx.h>
#include <commctrl.h>
#include <string.h>
[t.k7] #include "viewres.h"[t.k8]
/*<---------------------------------------------------------------------->*/
HINSTANCE hInst; // Instance handle[t.k9]
HWND hwndMain; //Main window handle[t.k10]
LRESULT CALLBACK MainWndProc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam);[t.k11]
/* --- The following code comes from c:\lcc\lib\wizard\statbar.tpl. */
// Global Variables for the status bar control.
/*------------------------------------------------------------------------
Procedure: UpdateStatusBar ID:1
Purpose: Updates the statusbar control with the appropiate
text
Input: lpszStatusString: Charactar string that will be shown
partNumber: index of the status bar part number.
displayFlags: Decoration flags
Output: none
Errors: none
------------------------------------------------------------------------*/
void UpdateStatusBar(LPSTR lpszStatusString, WORD partNumber, WORD displayFlags)
[t.k13] {
SendMessage(hWndStatusbar,
SB_SETTEXT,
partNumber | displayFlags,
(LPARAM)lpszStatusString);
}
/*------------------------------------------------------------------------
Procedure: MsgMenuSelect ID:1
Purpose: Shows in the status bar a descriptive explaation of
the purpose of each menu item.The message
WM_MENUSELECT is sent when the user starts browsing
the menu for each menu item where the mouse passes.
Input: Standard windows.
Output: The string from the resources string table is shown
Errors: If the string is not found nothing will be shown.
------------------------------------------------------------------------*/
LRESULT MsgMenuSelect(HWND hwnd, UINT uMessage, WPARAM wparam, LPARAM lparam)
[t.k14] {
static char szBuffer[256];
UINT nStringID = 0;
UINT fuFlags = GET_WM_MENUSELECT_FLAGS(wparam, lparam) & 0xffff;
UINT uCmd = GET_WM_MENUSELECT_CMD(wparam, lparam);
HMENU hMenu = GET_WM_MENUSELECT_HMENU(wparam, lparam);
szBuffer[0] = 0; // First reset the buffer
if (fuFlags == 0xffff && hMenu == NULL) // Menu has been closed
nStringID = 0;
else if (fuFlags & MFT_SEPARATOR) // Ignore separators
nStringID = 0;
else if (fuFlags & MF_POPUP) // Popup menu
{
if (fuFlags & MF_SYSMENU) // System menu
nStringID = IDS_SYSMENU;
else
// Get string ID for popup menu from idPopup array.
nStringID = 0;
} // for MF_POPUP
else // Must be a command item
nStringID = uCmd; // String ID == Command ID
// Load the string if we have an ID
if (0 != nStringID)
LoadString(hInst, nStringID, szBuffer, sizeof(szBuffer));
// Finally... send the string to the status bar
UpdateStatusBar(szBuffer, 0, 0);
return 0;
}
/*------------------------------------------------------------------------
Procedure: InitializeStatusBar ID:1
Purpose: Initialize the status bar
Input: hwndParent: the parent window
nrOfParts: The status bar can contain more than one
part. What is difficult, is to figure out how this
should be drawn. So, for the time being only one is
being used...
Output: The status bar is created
Errors:
------------------------------------------------------------------------*/
void InitializeStatusBar(HWND hwndParent,int nrOfParts)
[t.k15] {
const int cSpaceInBetween = 8;
int ptArray[40]; // Array defining the number of parts/sections
RECT rect;
HDC hDC;
/* * Fill in the ptArray... */
hDC = GetDC(hwndParent);
GetClientRect(hwndParent, &rect);
ptArray[nrOfParts-1] = rect.right;
//---TODO--- Add code to calculate the size of each part of the status
// bar here.
ReleaseDC(hwndParent, hDC);
SendMessage(hWndStatusbar,
SB_SETPARTS,
nrOfParts,
(LPARAM)(LPINT)ptArray);
UpdateStatusBar("Ready", 0, 0);
//---TODO--- Add code to update all fields of the status bar here.
// As an example, look at the calls commented out below.
// UpdateStatusBar("Cursor Pos:", 1, SBT_POPOUT);
// UpdateStatusBar("Time:", 3, SBT_POPOUT);
}
/*------------------------------------------------------------------------
Procedure: CreateSBar ID:1
Purpose: Calls CreateStatusWindow to create the status bar
Input: hwndParent: the parent window
initial text: the initial contents of the status bar
Output:
Errors:
------------------------------------------------------------------------*/
static BOOL CreateSBar(HWND hwndParent,char *initialText,int nrOfParts)
[t.k16] {
hWndStatusbar = CreateStatusWindow(WS_CHILD | WS_VISIBLE | WS_BORDER|SBARS_SIZEGRIP,
initialText,
hwndParent,
IDM_STATUSBAR);
if(hWndStatusbar)
{
InitializeStatusBar(hwndParent,nrOfParts);
return TRUE;
}
return FALSE;
}
int GetFileName(char *buffer,int buflen)[t.k17]
{
char tmpfilter[40];
int i = 0;
OPENFILENAME ofn;
memset(&ofn,0,sizeof(ofn));
ofn.lStructSize = sizeof(ofn);
ofn.hInstance = GetModuleHandle(NULL);
ofn.hwndOwner = GetActiveWindow();
ofn.lpstrFile = buffer;
ofn.nMaxFile = buflen;
ofn.lpstrTitle = "Open";
ofn.nFilterIndex = 2;
ofn.lpstrDefExt = "txt";
strcpy(buffer,"*.txt");
strcpy(tmpfilter,"All files,*.*,Text Files,*.txt");
while(tmpfilter[i]) {
if (tmpfilter[i] == ',')
tmpfilter[i] = 0;
i++;
}
tmpfilter[i++] = 0; tmpfilter[i++] = 0;
ofn.Flags = 539678;
ofn.lpstrFilter
= tmpfilter;
return GetOpenFileName(&ofn);
}
/*<---------------------------------------------------------------------->*/
/*@@0->@@*/
static BOOL InitApplication(void)
[t.k18] {
WNDCLASS wc;
memset(&wc,0,sizeof(WNDCLASS));[t.k19]
wc.style = CS_HREDRAW|CS_VREDRAW |CS_DBLCLKS ;
wc.lpfnWndProc = (WNDPROC)MainWndProc;
wc.hInstance = hInst;
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
wc.lpszClassName = "viewWndClass";
wc.lpszMenuName = MAKEINTRESOURCE(IDMAINMENU);
wc.hCursor = LoadCursor(NULL,IDC_ARROW);
wc.hIcon = LoadIcon(NULL,IDI_APPLICATION);
if (!RegisterClass(&wc))
return 0;
/*@@0<-@@*/
// ---TODO--- Call module specific initialization routines here
return 1;
}
/*<---------------------------------------------------------------------->*/
HWND CreateviewWndClassWnd(void)
[t.k20] {
return CreateWindow("viewWndClass","view",
WS_MINIMIZEBOX|WS_VISIBLE|WS_CLIPSIBLINGS|WS_CLIPCHILDREN|WS_MAXIMIZEBOX|WS_CAPTION|WS_BORDER|WS_SYSMENU|WS_THICKFRAME,
CW_USEDEFAULT,0,CW_USEDEFAULT,0,
NULL,
NULL,
hInst,
NULL);
[t.k21] }
/*@@1<-@@*/
/*<---------------------------------------------------------------------->*/
/* --- The following code comes from c:\lcc\lib\wizard\aboutdlg.tpl. */
BOOL _stdcall AboutDlg(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)[t.k22]
{
switch(msg) {
case WM_CLOSE:
EndDialog(hwnd,0);
return 1;
case WM_COMMAND:
switch (LOWORD(wParam)) {
EndDialog(hwnd,1);
return 1;
}
break;
}
return 0;
}
/*<---------------------------------------------------------------------->*/
/* --- The following code comes from c:\lcc\lib\wizard\defOnCmd.tpl. */
/* --- The following code comes from c:\lcc\lib\wizard\aboutcmd.tpl. */
void MainWndProc_OnCommand(HWND hwnd, int id, HWND hwndCtl, UINT codeNotify)[t.k24]
{ char buffer[MAX_PATH];
switch(id) {
// ---TODO--- Add new menu commands here
/*@@NEWCOMMANDS@@*/
case IDM_ABOUT:
DialogBox(hInst,MAKEINTRESOURCE(IDD_ABOUT),
hwndMain,AboutDlg);
break;
case IDM_OPEN:
GetFileName(buffer,sizeof(buffer));
break;
case IDM_EXIT:
PostMessage(hwnd,WM_CLOSE,0,0);
break;
}
}
/*<---------------------------------------------------------------------->*/
/*@@2->@@*/
LRESULT CALLBACK MainWndProc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam)[t.k25]
{
switch (msg) {
/*@@3->@@*/
case WM_SIZE:
SendMessage(hWndStatusbar,msg,wParam,lParam);
InitializeStatusBar(hWndStatusbar,1);[t.k26]
break;
case WM_MENUSELECT:
return MsgMenuSelect(hwnd,msg,wParam,lParam)[t.k27] ;
case WM_COMMAND:
HANDLE_WM_COMMAND(hwnd,wParam,lParam,MainWndProc_OnCommand)[t.k28] ;
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hwnd,msg,wParam,lParam);[t.k29]
}
/*@@3<-@@*/
return 0;
}
/*@@2<-@@*/
/*<---------------------------------------------------------------------->*/
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, INT nCmdShow)[t.k30]
{
MSG msg;
hInst = hInstance;[t.k32]
if (!InitApplication())[t.k33]
return 0;
hAccelTable = LoadAccelerators(hInst,MAKEINTRESOURCE(IDACCEL));[t.k34]
if ((hwndMain = CreateviewWndClassWnd()) == (HWND)0)
return 0;
CreateSBar(hwndMain,"Ready",1);
ShowWindow(hwndMain,SW_SHOW);
[t.k35] while (GetMessage(&msg,NULL,0,0)) {
if (!TranslateAccelerator(msg.hwnd,hAccelTable,&msg)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
[t.k36] }
[t.k37] return msg.wParam;[t.k38]
}
viewer.zip LCCでのフォルダーの内容そのままである。ショートファイルネームでアクセスできるフォルダー[1]に展開するとコンパイル可能になる。
MS-OFFICE :word, 初めとしたお馴染みのツールである。著作権等は、自明であるから省く。
EPTREE.exe: C言語の解析に使用。 出力には、編集を加えている。著作権等は、添付されたreadme.txt ファイルから抜粋。
*******************************************************************************
発 行:エケセテネPON
作 者:ふたばわに
連絡先:バグや追加してほしい機能がありましたらメールまたはHPの掲示板にカキコ
:してください。
メール:aab87010@pop13.odn.ne.jp
HP :http://hp.vector.co.jp/authors/VA019049/
*******************************************************************************
End of contents.
[t.k1]ID+ACCEL 続いて値である。アクセラレーターの定義である。
[t.k7]ウインドウズ用の標準ヘッダーファイルと、文字処理用のヘッダーファイル。いずれも標準ヘッダーファイルである。
[t.k8]上で表示されている、リソースハンドル用のヘッダーファイルである。
[t.k9]インスタンス、変数。グローバル変数として定義されている。
[t.k10]メインとなるウインドウのハンドル。グローバル変数として定義されている。
[t.k12]ステータスバーのハンドル。ウインドウハンドルであるのと、グローバル変数として宣言されているところ。
[t.k13]ステータスバーのアップデート関数
[t.k14]メインウインドウのメニュードライバー関数。リソースファイルを参照のこと。
[t.k15]ステータスバーの初期化関数
[t.k16]ステータスバーのクリエート関数。
[t.k17]コメントが無いが、ファイルオープンのための関数。ほぼ、そのままである。
[t.k18]アプリケーション初期化関数。これについては、詳細を述べる。
[t.k19]Memsetの意味と、WNDCLASS関連のマニュアルを参照のこと。
[t.k20]メインウインドウのクリエート関数。
[t.k21]Return(func());型の関数1つである。意見が分かれるところ、である。
[t.k22]アバウトダイアログのコールバック関数。
[t.k23]ジェネレーターは、バグのある出力を出す。リソースファイルを参照のこと。
[t.k24]メインウインドウのコマンド処理関数。
[t.k25]メインウインドウのコールバック関数。プロトタイプ宣言されていた関数である。
[t.k26]サイズ変更に伴う、ステータスバーのアップデート、である。
[t.k27]メニューをマウスで選択している段階、である。
[t.k28]API,メニュー関係を参照後のこと。
[t.k29]意見が分かれるところである。バグとハングの例も、多い。
[t.k30]WinMain関数である。コンソールアプリケーションではmain関数に相当する。
[t.k31]このオート変数は、初期化の前に作られ、アプリケーションの終わりまで存在している。理由を考えること。
[t.k33]メインウインドウクリエートで使うクラス登録しているだけ、である。省略も可能。
[t.k34]あくセラーレーション、キー入力の変換テーブルの読み込みと設定。省略も可能。
[t.k35]ステータスバーを作って、ウインドウを表示。ウインドウを表示した段階で、アプリケーションの初期が終了である。
[t.k36]システムからのイベントメッセージを待って、アクセラレーターテーブルで変換後、処理。つまり、ここで割り込み機構を使ってコールバック関数が呼ばれる訳である
[t.k37]メインウインドウの生成とそのチェック。アプリケーション起動のチェックともなっている。
[t.k38]アプリケーションの返り値である。結構重要な概念。