WindowsのGUIプログラムと呼ぶには何かが足りない? そうでした、ウィンドウを利用する際に代表的な操作方法である「メニュー」が抜け落ちていました。
メニューは拡張子が .rc のテキストファイルに、リソーススクリプトを所定の書式で定義してコンパイル、ウィンドウクラスに登録する事で表示されます。(リソースには、メニューやアイコン、ダイアログボックス、文字列などなどが該当します)
試しに、Win32APIでメニューを表示&動作させるだけのサンプルを作ってみました。
<注意点>
・前回のサンプルに、メニューの操作部分を追加しただけです。
「stdio.h」を「cstdio」に変更することで、.cppファイルとしてもコンパイル出来ます。
お試し環境
WindowsXP 32bit Edition
Visual C++ 2008
/*---- Win32API メニュー 追加 --------------- コマンドライン ---------------*/
D:\vc2008\dllchk>rc resource
D:\vc2008\dllchk>cl test.c user32.lib gdi32.lib resource.res
/*----------------------------------------------------------------------------*/
/*---- resource.h -------------------- お試しソース ------------------------*/
// Resource ID
#define IDR_MENU_MAIN 2000
// Menu Item ID
#define IDM_FILE_OPEN 2001
#define IDM_EXIT 2002
#define IDM_SYSINF_ARCH 2003
#define IDM_SYSINF_TYPE 2004
#define IDM_HELP_ABOUT 2005
/*----------------------------------------------------------------------------*/
/*---- resource.rc ------------------- お試しソース ------------------------*/
#include <windows.h>
#include "resource.h"
IDR_MENU_MAIN MENU
begin
popup "ファイル(&F)"
begin
menuitem "開く(&O)...", IDM_FILE_OPEN
menuitem separator
menuitem "終了(&X)", IDM_EXIT
end
popup "ヘルプ(&H)"
begin
popup "システム情報"
begin
menuitem "OS環境(&A)", IDM_SYSINF_ARCH
menuitem "CPU型(&T)", IDM_SYSINF_TYPE
end
menuitem "バージョン情報(&A)", IDM_HELP_ABOUT
end
end
/*----------------------------------------------------------------------------*/
/*---- test.c ------------------------ お試しソース ------------------------*/
#include <stdio.h>
#include <windows.h>
#include <process.h> // _beginthreadex 関数
#include "resource.h"
#define WINCLASS_NAME "Form.003"
#define ID_BUTTON1 1001
#define ID_BUTTON2 1002
#define ID_BUTTON3 1003
#define ID_EDITBOX 1011
unsigned WINAPI subThread1(void *hCtr)
{
int i, len;
char s[] = ", i = ";
for(i = 0; i < 5; i++) {
len = SendMessage((HWND)hCtr, WM_GETTEXTLENGTH, 0, 0);
SendMessage((HWND)hCtr, EM_SETSEL, (WPARAM)len, (LPARAM)len);
sprintf(s, ", i = %d", i);
SendMessage((HWND)hCtr, EM_REPLACESEL, 0, (LPARAM)s);
Sleep(1000);
}
return(0);
}
unsigned WINAPI subThread2(void *hCtr)
{
int j, len;
char s[] = ", j = ";
for(j = 5; j < 15; j++) {
len = SendMessage((HWND)hCtr, WM_GETTEXTLENGTH, 0, 0);
SendMessage((HWND)hCtr, EM_SETSEL, (WPARAM)len, (LPARAM)len);
sprintf(s, ", j = %d", j);
SendMessage((HWND)hCtr, EM_REPLACESEL, 0, (LPARAM)s);
Sleep(500);
}
return(0);
}
unsigned WINAPI subThread3(void *hCtr)
{
int k, len;
char s[] = ", k = ";
_beginthreadex(NULL, 0, subThread2, hCtr, 0, NULL);
for(k = 15; k < 19; k++) {
len = SendMessage((HWND)hCtr, WM_GETTEXTLENGTH, 0, 0);
SendMessage((HWND)hCtr, EM_SETSEL, (WPARAM)len, (LPARAM)len);
sprintf(s, ", k = %d", k);
SendMessage((HWND)hCtr, EM_REPLACESEL, 0, (LPARAM)s);
Sleep(1500);
}
return(0);
}
LRESULT CALLBACK WinProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
static HWND hLbl1, hBtn1, hBtn2, hBtn3, hEdit;
static unsigned short x, y, z;
HINSTANCE hInstance;
int wmid, wmevent;
PAINTSTRUCT ps;
HDC hdc;
char str[] = "X = , Y = , Button = ";
SYSTEM_INFO sysinfo;
switch(uMsg) {
case WM_CREATE :
hInstance = ((LPCREATESTRUCT)lParam)->hInstance;
if((hLbl1 = CreateWindowEx(WS_EX_LEFT, "STATIC", "ラベル1", WS_CHILD | WS_VISIBLE, 200, 120, 150, 20, hWnd, NULL, hInstance, NULL)) == NULL) {
printf("ラベル1コントロールを作成出来ませんでした。\n");
return(FALSE);
}
if((hBtn1 = CreateWindowEx(WS_EX_LEFT, "BUTTON", "ボタン1", WS_CHILD | WS_VISIBLE | BS_DEFPUSHBUTTON, 75, 220, 70, 20, hWnd, (HMENU)ID_BUTTON1, hInstance, NULL)) == NULL) {
printf("ボタン1コントロールを作成出来ませんでした。\n");
return(FALSE);
}
if((hBtn2 = CreateWindowEx(WS_EX_LEFT, "BUTTON", "ボタン2", WS_CHILD | WS_VISIBLE | BS_DEFPUSHBUTTON, 160, 220, 70, 20, hWnd, (HMENU)ID_BUTTON2, hInstance, NULL)) == NULL) {
printf("ボタン2コントロールを作成出来ませんでした。\n");
return(FALSE);
}
if((hBtn3 = CreateWindowEx(WS_EX_LEFT, "BUTTON", "ボタン3", WS_CHILD | WS_VISIBLE | BS_DEFPUSHBUTTON, 245, 220, 70, 20, hWnd, (HMENU)ID_BUTTON3, hInstance, NULL)) == NULL) {
printf("ボタン3コントロールを作成出来ませんでした。\n");
return(FALSE);
}
if((hEdit = CreateWindowEx(WS_EX_LEFT, "EDIT", "エディットボックス1", WS_CHILD | WS_VISIBLE | WS_BORDER | WS_VSCROLL | ES_AUTOVSCROLL | ES_LEFT | ES_MULTILINE, 50, 50, 100, 150, hWnd, (HMENU)ID_EDITBOX, hInstance, NULL)) == NULL) {
printf("エディットボックスコントロールを作成出来ませんでした。\n");
return(FALSE);
}
break;
case WM_COMMAND :
wmid = LOWORD(wParam);
wmevent = HIWORD(wParam);
switch(wmevent) {
case BN_CLICKED :
switch(wmid) {
case ID_BUTTON1 :
EnableWindow(hBtn1, FALSE);
SetWindowText(hBtn1, "押下1");
SetWindowText(hLbl1, "コンパイルエラーが来たぁ!");
break;
case ID_BUTTON2 :
EnableWindow(hBtn2, FALSE);
SetWindowText(hBtn2, "押下2");
SetWindowText(hEdit, "修正漏れが見つかったぞぉ!");
break;
case ID_BUTTON3 :
EnableWindow(hBtn3, FALSE);
SetWindowText(hBtn3, "スレッド");
_beginthreadex(NULL, 0, subThread1, hEdit, 0, NULL);
_beginthreadex(NULL, 0, subThread3, hEdit, 0, NULL);
break;
case IDM_FILE_OPEN :
// To Do List
break;
case IDM_EXIT :
DestroyWindow(hWnd);
break;
case IDM_SYSINF_ARCH :
GetNativeSystemInfo(&sysinfo);
switch(sysinfo.wProcessorArchitecture) {
case PROCESSOR_ARCHITECTURE_INTEL : // x86
MessageBox(NULL, "32ビットです。", "This OS's Version", MB_OK);
break;
case PROCESSOR_ARCHITECTURE_ARM : // ARM
break;
case PROCESSOR_ARCHITECTURE_IA64 : // Intel Itanium-based
break;
case PROCESSOR_ARCHITECTURE_AMD64 : // x64(AMD or Intel)
MessageBox(NULL, "64ビットです。", "This OS's Version", MB_OK);
break;
// case PROCESSOR_ARCHITECTURE_ARM64 : // ARM64
// break;
case PROCESSOR_ARCHITECTURE_UNKNOWN :
default :
break;
}
break;
case IDM_SYSINF_TYPE :
GetNativeSystemInfo(&sysinfo);
switch(sysinfo.dwProcessorType) {
case PROCESSOR_INTEL_386 :
break;
case PROCESSOR_INTEL_486 :
break;
case PROCESSOR_INTEL_PENTIUM :
MessageBox(NULL, "ペンティアム4です。", "This CPU's Version", MB_OK);
break;
case PROCESSOR_INTEL_IA64 :
break;
case PROCESSOR_AMD_X8664 :
MessageBox(NULL, "AMD Ryzen7です。", "This CPU's Version", MB_OK);
break;
// case PROCESSOR_ARM :
default :
break;
}
break;
case IDM_HELP_ABOUT :
// To Do List
break;
default :
break;
}
break;
default :
break;
}
break;
case WM_LBUTTONDOWN :
case WM_RBUTTONDOWN :
x = LOWORD(lParam);
y = HIWORD(lParam);
z = LOWORD(wParam);
InvalidateRect(hWnd, NULL, TRUE);
break;
case WM_PAINT :
hdc = BeginPaint(hWnd, &ps);
sprintf(str, "X = %d, Y = %d, Button = %s", x, y, (z == 1 ? "Left" : "Right") );
TextOut(hdc, 30, 10, str, (int)strlen(str));
EndPaint(hWnd, &ps);
break;
case WM_CLOSE :
if(MessageBox(hWnd, "ウィンドウを閉じます。\nよろしいですか?", "確認", MB_OKCANCEL | MB_ICONWARNING) == IDOK) {
DestroyWindow(hWnd);
} else {
SetWindowText(hLbl1, "ラベル1");
SetWindowText(hBtn1, "ボタン1");
EnableWindow(hBtn1, TRUE);
SetWindowText(hBtn2, "ボタン2");
EnableWindow(hBtn2, TRUE);
SetWindowText(hBtn3, "ボタン3");
EnableWindow(hBtn3, TRUE);
}
break;
case WM_DESTROY :
PostQuitMessage(0);
break;
default :
return DefWindowProc(hWnd , uMsg , wParam , lParam);
}
return(0);
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
HWND hWnd;
WNDCLASSEX wcx;
MSG msg;
int ret;
/* ウィンドウクラスの登録 */
wcx.cbSize = sizeof(WNDCLASSEX);
wcx.style = CS_HREDRAW | CS_VREDRAW;
wcx.lpfnWndProc = WinProc;
wcx.cbClsExtra = 0;
wcx.cbWndExtra = 0;
wcx.hInstance = hInstance;
wcx.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wcx.hCursor = LoadCursor(NULL, IDC_ARROW);
wcx.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
wcx.lpszMenuName = MAKEINTRESOURCE(IDR_MENU_MAIN);
wcx.lpszClassName = WINCLASS_NAME;
wcx.hIconSm = NULL;
if(!RegisterClassEx(&wcx)) {
printf("ウィンドウクラスの登録が出来ませんでした。\n");
return(0);
}
/* 登録したクラスのウィンドウを生成 */
hWnd = CreateWindowEx(WS_EX_LEFT, WINCLASS_NAME, "ウインドウタイトル3", WS_OVERLAPPEDWINDOW, 50, 50, 400, 300, NULL, NULL, hInstance ,NULL);
if(hWnd == NULL) {
printf("ウィンドウが作成出来ませんでした。\n");
return(FALSE);
}
/* ウィンドウの表示 */
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
/* メッセージループ */
while((ret = GetMessage(&msg, NULL, 0, 0)) > 0 ) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
if(ret == -1) {
printf("メッセージの取得に失敗しました。\n");
return(FALSE);
}
return((int)msg.wParam);
}
/*----------------------------------------------------------------------------*/
/*============================================================================*/