WhyCan Forum

人过留名,雁过留声,感谢各位朋友不离不弃地支持。 QQ: 516333132, 微信: whycan_cn (哇酷网/挖坑网/填坑网) admin@whycan.cn

您尚未登录。

#1 2019-11-28 16:40:23

win32prog
会员
注册时间: 2019-11-28
累计积分: 71

发现一个不错的 win32 api 入门教程

离线

#2 2019-11-28 16:45:11

szchen2006
会员
注册时间: 2019-10-09
累计积分: 70

Re: 发现一个不错的 win32 api 入门教程

谢谢分享!

离线

#3 2019-11-28 17:51:43

win32prog
会员
注册时间: 2019-11-28
累计积分: 71

Re: 发现一个不错的 win32 api 入门教程

#include <stdio.h>
#include <windows.h>

const wchar_t g_szClassName[] = L"myWindowClass";

void OnPaint(HWND hWnd)
{
    PAINTSTRUCT ps;
    HDC hdc = BeginPaint(hWnd,&ps);
    MoveToEx(hdc,0,0,0);
    LineTo(hdc,100,100);

    Ellipse(hdc, 100, 100, 200, 200);
    EndPaint(hWnd,&ps);
    return;
}
void OnPaint2(HWND hWnd)
{
    PAINTSTRUCT ps;
    HDC hdc = BeginPaint(hWnd, &ps);
    HPEN hPen = CreatePen(PS_DASHDOTDOT, 2, NULL);
    SelectObject(hdc, hPen);
    Ellipse(hdc, 100, 200, 400, 400);
    Ellipse(hdc, 300, 300, 500, 510);

    DeleteObject(hPen);
    EndPaint(hWnd, &ps);
}

// Step 4: the Window Procedure
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
    switch(msg)
    {
		case WM_ERASEBKGND:
            printf("erase back\n");
            fflush(stdout);
			return DefWindowProc(hwnd, msg, wParam, lParam);
        case WM_MOVE:
            printf("move\n");
            fflush(stdout);
        case WM_PAINT:
			OnPaint(hwnd);
            //MessageBoxW(hwnd, L"painting ...", L"p", MB_OK);
            printf("painting...\n");
            fflush(stdout);
            //return DefWindowProc(hwnd, msg, wParam, lParam);
        break;
        case WM_LBUTTONDOWN:
            //wchar_t szFileName[MAX_PATH];
            //HINSTANCE hInstance = GetModuleHandle(NULL);
            //GetModuleFileNameW(hInstance, szFileName, MAX_PATH);
            //MessageBoxW(hwnd, szFileName, L"This program is:", MB_OK | MB_ICONINFORMATION);
			break;
        case WM_CLOSE:
            DestroyWindow(hwnd);
        break;
        case WM_DESTROY:
            PostQuitMessage(0);
        break;
        default:
            return DefWindowProc(hwnd, msg, wParam, lParam);
    }
    return 0;
}

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
    LPSTR lpCmdLine, int nCmdShow)
{
    WNDCLASSEXW wc;
    HWND hwnd;
    MSG Msg;

    //Step 1: Registering the Window Class
    wc.cbSize        = sizeof(WNDCLASSEX);
    wc.style         = 0;
    wc.lpfnWndProc   = WndProc;
    wc.cbClsExtra    = 0;
    wc.cbWndExtra    = 0;
    wc.hInstance     = hInstance;
    wc.hIcon         = LoadIcon(NULL, IDI_APPLICATION);
    wc.hCursor       = LoadCursor(NULL, IDC_ARROW);
    wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
    wc.lpszMenuName  = NULL;
    wc.lpszClassName = g_szClassName;
    wc.hIconSm       = LoadIcon(NULL, IDI_APPLICATION);

    if(!RegisterClassExW(&wc))
    {
        MessageBoxW(NULL, L"Window Registration Failed!", L"Error!",
            MB_ICONEXCLAMATION | MB_OK);
        return 0;
    }

    // Step 2: Creating the Window
    hwnd = CreateWindowExW(
        WS_EX_CLIENTEDGE,
        g_szClassName,
        L"The title of my window",
        WS_OVERLAPPEDWINDOW,
        CW_USEDEFAULT, CW_USEDEFAULT, 640, 480,
        NULL, NULL, hInstance, NULL);

    if(hwnd == NULL)
    {
        MessageBoxW(NULL, L"Window Creation Failed!", L"Error!",
            MB_ICONEXCLAMATION | MB_OK);
        return 0;
    }

    ShowWindow(hwnd, nCmdShow);
    UpdateWindow(hwnd);

    // Step 3: The Message Loop
    while(GetMessage(&Msg, NULL, 0, 0) > 0)
    {
        TranslateMessage(&Msg);
        DispatchMessage(&Msg);
    }
    return (int)Msg.wParam;
}


mingw 编译:  gcc -o test1 test1.c -luser32 -lgdi32
msvc 编译: cl  test1.c gdi32.lib user32.lib

2019-11-28_175132.png

离线

#4 2019-11-28 17:55:48

微凉VeiLiang
会员
注册时间: 2018-10-28
累计积分: 181

Re: 发现一个不错的 win32 api 入门教程

搞不动windows的驱动

离线

#5 2019-11-29 17:07:44

win32prog
会员
注册时间: 2019-11-28
累计积分: 71

Re: 发现一个不错的 win32 api 入门教程

手动撸的一个定时器更新 gdi 的demo:

#include <windows.h>

#define RECT_WIDTH 200
#define RECT_HEIGHT 200
// x and y are the x- and y-locations of the mouse cursor upon release
void drawRectangle(HWND hwnd, const int x, const int y)
{
    // obtain a handle to the device context
    HDC hdc = GetDC(hwnd);

    // RECT_WIDTH and RECT_HEIGHT are elsewhere defined
    // draw rectangle
    Rectangle(hdc, x - RECT_WIDTH / 2, y - RECT_HEIGHT / 2, x + RECT_WIDTH / 2, y + RECT_HEIGHT / 2);

    // release the DC
    ReleaseDC(hwnd, hdc);
}

LRESULT APIENTRY WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    static int x, y;
    PAINTSTRUCT ps;

    switch (message)
    {
		case WM_CREATE:
        {
			SetTimer(hwnd, 0, 200, NULL);
			break;
        }
		case WM_TIMER:
		{
			RECT rect;

			do
			{
                x = rand();
			}
			while(x < 0 || x > 500);

			do
			{
                y = rand();
			}
			while(y < 0 || y > 500);

			GetClientRect(hwnd, &rect);
			InvalidateRect(hwnd, &rect, 1);
			break;
		}

		case WM_PAINT:
		{
            BeginPaint(hwnd, &ps);

			// draw the rectangle
			drawRectangle(hwnd, x, y);

			EndPaint(hwnd, &ps);
			return 0;
		}
		case WM_CLOSE:
			DestroyWindow(hwnd);
			break;
		case WM_DESTROY:
			PostQuitMessage(0);
			break;
		default:
			return DefWindowProc(hwnd, message, wParam, lParam);
    }
    return DefWindowProc(hwnd, message, wParam, lParam);
}

const wchar_t g_szClassName[] = L"myWindowClass";
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
    LPSTR lpCmdLine, int nCmdShow)
{
    WNDCLASSEXW wc;
    HWND hwnd;
    MSG Msg;

    srand(0);
    //Step 1: Registering the Window Class
    wc.cbSize        = sizeof(WNDCLASSEX);
    wc.style         = 0;
    wc.lpfnWndProc   = WndProc;
    wc.cbClsExtra    = 0;
    wc.cbWndExtra    = 0;
    wc.hInstance     = hInstance;
    wc.hIcon         = LoadIcon(NULL, IDI_APPLICATION);
    wc.hCursor       = LoadCursor(NULL, IDC_ARROW);
    wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
    wc.lpszMenuName  = NULL;
    wc.lpszClassName = g_szClassName;
    wc.hIconSm       = LoadIcon(NULL, IDI_APPLICATION);

    if(!RegisterClassExW(&wc))
    {
        MessageBoxW(NULL, L"Window Registration Failed!", L"Error!",
            MB_ICONEXCLAMATION | MB_OK);
        return 0;
    }

    // Step 2: Creating the Window
    hwnd = CreateWindowExW(
        WS_EX_CLIENTEDGE,
        g_szClassName,
        L"The title of my window",
        WS_OVERLAPPEDWINDOW,
        CW_USEDEFAULT, CW_USEDEFAULT, 640, 480,
        NULL, NULL, hInstance, NULL);

    if(hwnd == NULL)
    {
        MessageBoxW(NULL, L"Window Creation Failed!", L"Error!",
            MB_ICONEXCLAMATION | MB_OK);
        return 0;
    }

    ShowWindow(hwnd, nCmdShow);
    UpdateWindow(hwnd);

    // Step 3: The Message Loop
    while(GetMessage(&Msg, NULL, 0, 0) > 0)
    {
        TranslateMessage(&Msg);
        DispatchMessage(&Msg);
    }
    return (int)Msg.wParam;
}

win32_test2.gif

参考: https://stackoverflow.com/questions/28925178/drawing-rectangle-in-c-using-functions

离线

#6 2019-11-29 17:13:52

win32prog
会员
注册时间: 2019-11-28
累计积分: 71

Re: 发现一个不错的 win32 api 入门教程

#include "Piece.h"
#include "Game.h"
#include <windows.h>
#include <iostream>

using namespace std;

const int PX_PER_BLOCK = 25;    // Cell size in pixels
const int SCREEN_WIDTH = 10;    // Level width in cells
const int SCREEN_HEIGHT = 20;   // Level height in cells
const int GAME_SPEED = 33;      // Update the game every GAME_SPEED millisecs (= 1/fps)
const int TIMER_ID = 1;

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

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
                   PSTR szCmdLine, int iCmdShow)
{

    static TCHAR szAppName[] = TEXT("tetris");
    HWND hwnd;
    MSG msg;
    WNDCLASSEX wc;

    // We need to repaint a lot, using CS_OWNDC is more efficient
    wc.cbSize = sizeof(WNDCLASSEX);
    wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
    wc.lpfnWndProc = WndProc;
    wc.cbClsExtra = 0;
    wc.cbWndExtra = 0;
    wc.hInstance = hInstance;
    wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
    wc.hCursor = LoadCursor(NULL, IDC_ARROW);
    wc.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
    wc.lpszMenuName = NULL;
    wc.lpszClassName = szAppName;
    wc.hIconSm = NULL;

    if (!RegisterClassEx(&wc))
    {
        MessageBox(NULL, TEXT("Program requires Windows NT!"),
                   szAppName, MB_ICONERROR);
        return 0;
    }

    hwnd = CreateWindow(szAppName,
                        TEXT("Eliang's Tetris"),
                        WS_MINIMIZEBOX | WS_SYSMENU,  // No window resizing
                        CW_USEDEFAULT,
                        CW_USEDEFAULT,
                        SCREEN_WIDTH * PX_PER_BLOCK + 156,
                        SCREEN_HEIGHT * PX_PER_BLOCK + 25,
                        NULL,
                        NULL,
                        hInstance,
                        NULL);

    ShowWindow(hwnd, iCmdShow);
    UpdateWindow(hwnd);

    while (GetMessage(&msg, NULL, 0, 0))
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }

    return msg.wParam;
}

LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    HDC hdc;
    PAINTSTRUCT ps;
    static Game *game;
    static DrawEngine *de;

    switch (message)
    {
        case WM_CREATE:
            hdc = GetDC(hwnd);

            de = new DrawEngine(hdc, hwnd, PX_PER_BLOCK);
            game = new Game(*de);
            SetTimer(hwnd, TIMER_ID, GAME_SPEED, NULL);

            ReleaseDC(hwnd, hdc);
            return 0;

        case WM_KEYDOWN:
            game->keyPress(wParam);
            return 0;

        case WM_TIMER:
            game->timerUpdate();
            return 0;

        case WM_KILLFOCUS:
            KillTimer(hwnd, TIMER_ID);
            game->pause(true);
            return 0;

        case WM_SETFOCUS:
            SetTimer(hwnd, TIMER_ID, GAME_SPEED, NULL);
            return 0;

        case WM_PAINT:
            hdc = BeginPaint(hwnd, &ps);
            game->repaint();
            EndPaint(hwnd, &ps);
            return 0;

        case WM_DESTROY:
            delete de;
            delete game;
            KillTimer(hwnd, TIMER_ID);
            PostQuitMessage(0);
            return 0;

    }

    return DefWindowProc(hwnd, message, wParam, lParam);
}

https://github.com/eliangcs/tetris-win32

https://github.com/eliangcs/tetris-win32/blob/master/src/main.cpp

68747470733a2f237265656e76e67.png

仅用 win32 api 做的俄罗斯方块。

离线

#7 2019-11-30 09:49:32

win32prog
会员
注册时间: 2019-11-28
累计积分: 71

Re: 发现一个不错的 win32 api 入门教程

找到一个更精简的 俄罗斯方块: https://github.com/VincentJYZhang/tetris-game/tree/master/Source%20Code

TetrisGame_zjy.cpp

// TetrisGame_zjy.cpp
// by 张钧洋
// 2018.4.10

#include <windows.h>
#include <stdio.h>
#include <time.h>
#include "Shapes.h"

#define ID_TIMER  1
#define TIME_INTERVAL 1000   // 下落时间间隔1秒

LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
VOID    CALLBACK TimerProc(HWND, UINT, UINT, DWORD);

/*---------------宏-------------------*/
#define BOARD_WIDTH 180
#define BOARD_HEIGHT 400
#define LONG_SLEEP 300

#define COLS 15  // 列数
#define ROWS 30  // 行数
#define EXTENDED_COLS 23  // 包括不显示区域的列数
#define EXTENDED_ROWS 34  // 包括不显示区域的行数

// 游戏界面实际的方格位置
#define BOARD_LEFT 4
#define BOARD_RIGHT 18
#define BOARD_TOP 0
#define BOARD_BOTTOM 29
/*-----------------------------------*/


/*-------------参数声明---------------*/
// static int shapes[7][4][4];
static int shape[4][4];
static int score = 0;

static int shape_row = 0;  // 当前形状所在行
static int shape_col = EXTENDED_COLS / 2 - 2; // 当前形状所在列

static int **gBoard;

static int lattices_top = 40;   // 上面留白
static int lattices_left = 20;  // 左侧留白
static int width = BOARD_WIDTH / COLS;                    //每个格子的宽度
static int height = (BOARD_HEIGHT - lattices_top) / ROWS; //每个格子的高度

static HBRUSH grey_brush = CreateSolidBrush(RGB(210, 210, 210));
static HBRUSH white_brush = CreateSolidBrush(RGB(255, 255, 255));
static HBRUSH red_brush = CreateSolidBrush(RGB(255, 0, 0));
static HBRUSH blue_brush = CreateSolidBrush(RGB(0, 0, 255));
static HPEN hPen = CreatePen(PS_SOLID, 1, RGB(147, 155, 166));

static bool gIsPause = false;  // 判断是否暂停
/*-----------------------------------*/

/*-------------函数声明---------------*/

void InitGame(HWND);
void InitData();

void TypeInstruction(HWND);

void RandShape();  // 随机选择一个图形

void AddScore();   // 清空一行后加100分

void UpdateShapeRect(HWND hwnd); // 更新下落形状矩形区域
void UpdateAllBoard(HWND hwnd);  // 更新游戏范围

void FallToGround();
void MoveDown(HWND hwnd);   // 下降一格
void RePaintBoard(HDC hdc); // 重绘游戏界面
void PaintCell(HDC hdc, int x, int y, int color); // 绘制指定一个格子
void ClearFullLine();       // 清空满行

void RotateShape(HWND hwnd);  // 图形变形
void MoveHori(HWND hwnd, int direction);  // 水平移动
void RotateMatrix();          // 逆时针翻转图形
void ReRotateMatrix();        // 顺时针翻转图形
bool IsLegel();               // 检测图形是否超出范围

void RespondKey(HWND hwnd, WPARAM wParam); // 响应按键

void PauseGame(HWND hwnd); // 暂停游戏
void WakeGame(HWND hwnd);  // 继续游戏


bool JudgeLose();          // 判断是否输
void LoseGame(HWND hwnd);  // 游戏输了之后处理
void ExitGame(HWND hwnd);  // 游戏结束
/*-----------------------------------*/



// 程序入口 WinMain
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
	PSTR szCmdLine, int iCmdShow)
{
	static TCHAR szAppName[] = TEXT("TetrisGame_Zjy");
	HWND         hwnd;
	MSG          msg;
	WNDCLASS     wndclass;

	wndclass.style = CS_HREDRAW | CS_VREDRAW;
	wndclass.lpfnWndProc = WndProc;
	wndclass.cbClsExtra = 0;
	wndclass.cbWndExtra = 0;
	wndclass.hInstance = hInstance;
	wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
	wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
	wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
	wndclass.lpszMenuName = NULL;
	wndclass.lpszClassName = szAppName;

	if (!RegisterClass(&wndclass))
	{
		MessageBox(NULL, TEXT("Program requires Windows NT!"),
			szAppName, MB_ICONERROR);
		return 0;
	}

	// 这里将窗口设置为无法调节大小并且不能最大化
	hwnd = CreateWindow(szAppName, TEXT("Tetris Game"),
		WS_OVERLAPPEDWINDOW ^ WS_THICKFRAME ^ WS_MAXIMIZEBOX,
		CW_USEDEFAULT, CW_USEDEFAULT,
		BOARD_WIDTH + 220, BOARD_HEIGHT + 70,
		NULL, NULL, hInstance, NULL);

	ShowWindow(hwnd, iCmdShow);
	UpdateWindow(hwnd);

	// 打印说明
	TypeInstruction(hwnd);

	while (GetMessage(&msg, NULL, 0, 0))
	{
		TranslateMessage(&msg);
		DispatchMessage(&msg);
	}
	return msg.wParam;
}

// 窗口过程
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
	static HDC hdc;
	static HDC hdcBuffer;
	static HBITMAP hBitMap;
	static PAINTSTRUCT ps;

	switch (message)
	{
	case WM_CREATE:
		SetTimer(hwnd, ID_TIMER, TIME_INTERVAL, TimerProc);
		InitGame(hwnd);
		TypeInstruction(hwnd);
		return 0;

	// 最小化恢复后需要重绘说明
	case WM_SIZE:
		TypeInstruction(hwnd);
		return 0;

	case WM_KEYDOWN:
		RespondKey(hwnd, wParam);
		return 0;

	case WM_PAINT:
		hdc = BeginPaint(hwnd, &ps);
		RePaintBoard(hdc);
		EndPaint(hwnd, &ps);
		return 0;

	case WM_DESTROY:
		KillTimer(hwnd, ID_TIMER);
		PostQuitMessage(0);
		return 0;
	}
	return DefWindowProc(hwnd, message, wParam, lParam);
}

// 计时器响应事件
VOID CALLBACK TimerProc(HWND hwnd, UINT message, UINT iTimerID, DWORD dwTime)
{
	// 计时器每秒向下移动
	MoveDown(hwnd);
}

// 初始化游戏
void InitGame(HWND hwnd) {

	gBoard = new int*[EXTENDED_ROWS];
	for (int i = 0; i < EXTENDED_ROWS; i++) {
		gBoard[i] = new int[EXTENDED_COLS];
	}

	srand(time(0));

	InitData();

	UpdateAllBoard(hwnd);
}

// 初始化游戏数据
void InitData() {

	// 将游戏面板清零
	for (int i = 0; i < EXTENDED_ROWS; i++) {
		for (int j = 0; j < EXTENDED_COLS; j++) {
			gBoard[i][j] = 0;
		}
	}

	// 将外围填充1,为了判断是否超出范围
	for (int i = 0; i < EXTENDED_ROWS; i++) {
		for (int j = 0; j < BOARD_LEFT; j++) {
			gBoard[i][j] = 1;
		}
	}
	for (int i = 0; i < EXTENDED_ROWS; i++) {
		for (int j = BOARD_RIGHT + 1; j < EXTENDED_COLS; j++) {
			gBoard[i][j] = 1;
		}
	}
	for (int i = BOARD_BOTTOM + 1; i < EXTENDED_ROWS; i++) {
		for (int j = 0; j < EXTENDED_COLS; j++) {
			gBoard[i][j] = 1;
		}
	}

	gIsPause = false;

	// 初始化分数
	score = 0;

	// 随机生成图形
	RandShape();

	return;
}

// 打印说明
void TypeInstruction(HWND hwnd) {

	TEXTMETRIC  tm;
	int cxChar, cxCaps, cyChar, cxClient, cyClient, iMaxWidth;

	HDC hdc = GetDC(hwnd);

	// 保存行高字宽信息
	GetTextMetrics(hdc, &tm);
	cxChar = tm.tmAveCharWidth;
	cxCaps = (tm.tmPitchAndFamily & 1 ? 3 : 2) * cxChar / 2;
	cyChar = tm.tmHeight + tm.tmExternalLeading;

	int startX = 180;
	int startY = 40;

	TCHAR Instruction[100];

	// 打印说明
	wsprintf(Instruction, TEXT("INSTRUCTION "));
	TextOut(hdc, startX + 40, startY, Instruction, lstrlen(Instruction));

	wsprintf(Instruction, TEXT("↑       Change Shape"));
	TextOut(hdc, startX + 40, startY + cyChar * 3, Instruction, lstrlen(Instruction));

	wsprintf(Instruction, TEXT("←       Move Left"));
	TextOut(hdc, startX + 40, startY + cyChar * 5, Instruction, lstrlen(Instruction));

	wsprintf(Instruction, TEXT("→       Move Right"));
	TextOut(hdc, startX + 40, startY + cyChar * 7, Instruction, lstrlen(Instruction));

	wsprintf(Instruction, TEXT("↓       Move Down"));
	TextOut(hdc, startX + 40, startY + cyChar * 9, Instruction, lstrlen(Instruction));

	wsprintf(Instruction, TEXT("Space Pause the game"));
	TextOut(hdc, startX + 40, startY + cyChar * 11, Instruction, lstrlen(Instruction));

	wsprintf(Instruction, TEXT("Esc     Exit the game"));
	TextOut(hdc, startX + 40, startY + cyChar * 13, Instruction, lstrlen(Instruction));

	wsprintf(Instruction, TEXT("©   2018.4   张钧洋"));
	TextOut(hdc, startX + 40, startY + cyChar * 18, Instruction, lstrlen(Instruction));

	ReleaseDC(hwnd, hdc);
}

// 随机选中一个图形
void RandShape() {

	int shape_num = rand() % 7;

	for (int i = 0; i < 4; i++)
		for (int j = 0; j < 4; j++)
			shape[i][j] = shapes[shape_num][i][j];

}

// 更新整个游戏界面
void UpdateAllBoard(HWND hwnd) {

	static RECT rect;

	rect.left = lattices_left;
	rect.right = lattices_left + COLS * width + width;
	rect.top = lattices_top - 30;
	rect.bottom = lattices_top + ROWS * height;

	// 这个矩形包括了游戏界面方格,但不包括右侧的说明
	InvalidateRect(hwnd, &rect, false);

}

// 更新下落形状所在矩形区域内
void UpdateShapeRect(HWND hwnd) {

	static RECT rect;

	rect.left = lattices_left;
	rect.right = lattices_left + COLS * width + width;
	rect.top = lattices_top + (shape_row - 1) * height;
	rect.bottom = lattices_top + (shape_row + 4) * height;

	InvalidateRect(hwnd, &rect, false);
}

// 重绘游戏界面
void RePaintBoard(HDC hdc) {

	SetBkColor(hdc, RGB(255, 255, 255));
	SelectObject(hdc, hPen);   //选用画笔
	TCHAR score_str[50];

	// 绘制当前分数
	wsprintf(score_str, TEXT("Score: %5d "), score);
	TextOut(hdc, 20, 15, score_str, lstrlen(score_str));


	// 绘制游戏界面背景
	for (int i = BOARD_TOP; i <= BOARD_BOTTOM; i++) {
		for (int j = BOARD_LEFT; j <= BOARD_RIGHT; j++) {
			PaintCell(hdc, i, j, gBoard[i][j]);
		}
	}

	// 绘制正在下降的图形
	for (int i = 0; i < 4; i++) {
		for (int j = 0; j<4; j++) {
			if (shape[i][j] == 1)
				PaintCell(hdc, shape_row + i, shape_col + j, shape[i][j]);
		}
	}
}

// 打印指定位置指定颜色的方格
void PaintCell(HDC hdc, int x, int y, int color) {

	// 超出范围直接结束
	if (x < BOARD_TOP || x > BOARD_BOTTOM ||
		y < BOARD_LEFT || y > BOARD_RIGHT) {
		return;
	}

	x -= BOARD_TOP;
	y -= BOARD_LEFT;

	// 将坐标换算为实际的像素点
	int _left = lattices_left + y * width;
	int _right = lattices_left + y * width + width;
	int _top = lattices_top + x * height;
	int _bottom = lattices_top + x * height + height;

	// 绘制边框
	MoveToEx(hdc, _left, _top, NULL);
	LineTo(hdc, _right, _top);
	MoveToEx(hdc, _left, _top, NULL);
	LineTo(hdc, _left, _bottom);
	MoveToEx(hdc, _left, _bottom, NULL);
	LineTo(hdc, _right, _bottom);
	MoveToEx(hdc, _right, _top, NULL);
	LineTo(hdc, _right, _bottom);


	if (color == 0) {
		SelectObject(hdc, white_brush);
	}
	else if (color == 1) {
		SelectObject(hdc, blue_brush);
	}
	else if (color == 2) {
		SelectObject(hdc, red_brush);
	}

	// 填充
	Rectangle(hdc, _left, _top, _right, _bottom);
}

// 响应按键
void RespondKey(HWND hwnd, WPARAM wParam) {

	if (wParam == VK_ESCAPE) {//ESC退出
		ExitGame(hwnd);
		return;
	}
	if (wParam == VK_SPACE) {//空格暂停
		gIsPause = !gIsPause;
		if (gIsPause == true) {
			PauseGame(hwnd);
			return;
		}
		else {
			WakeGame(hwnd);
			return;
		}
	}

	// 如果处于暂停状态下就不响应这些移动操作
	if (!gIsPause) { 
		if (wParam == VK_UP) {
			RotateShape(hwnd);
			return;
		}
		if (wParam == VK_DOWN) {
			MoveDown(hwnd);
			return;
		}
		if (wParam == VK_LEFT) {
			MoveHori(hwnd, 0);
			return;
		}
		if (wParam == VK_RIGHT) {
			MoveHori(hwnd, 1);
			return;
		}
	}
}

// 停止计数器
void PauseGame(HWND hwnd) {
	KillTimer(hwnd, ID_TIMER);
}

// 重启计数器
void WakeGame(HWND hwnd) {
	SetTimer(hwnd, ID_TIMER, TIME_INTERVAL, TimerProc);
}

// 退出游戏
void ExitGame(HWND hwnd) {

	// 先暂停游戏
	SendMessage(hwnd, WM_KEYDOWN, VK_SPACE, 0);

	// 是否退出
	int flag = MessageBox(NULL, TEXT("Do you want exit?"), TEXT("EXIT"), MB_YESNO);

	if (flag == IDYES) {
		SendMessage(hwnd, WM_DESTROY, NULL, 0);
	}
	else if (flag == IDNO) {
		return;
	}

}

// 图形变形
void RotateShape(HWND hwnd) {

	RotateMatrix();

	if (!IsLegel()) {
		ReRotateMatrix();
	}

	UpdateShapeRect(hwnd);

	return;
}

// 判断形状是否在游戏界面中
bool IsLegel() {

	for (int i = 0; i<4; i++)
		for (int j = 0; j<4; j++)
			if (shape[i][j] == 1 && 
				(gBoard[shape_row + i][shape_col + j] == 1 || 
					gBoard[shape_row + i][shape_col + j] == 2))
				return false;

	return true;
}

// 逆时针旋转当前下落的形状
void RotateMatrix() {

	int(*a)[4] = shape;

	int s = 0;

	for (int n = 4; n >= 1; n -= 2) {
		for (int i = 0; i < n - 1; i++) {
			int t = a[s + i][s];
			a[s + i][s] = a[s][s + n - i - 1];
			a[s][s + n - i - 1] = a[s + n - i - 1][s + n - 1];
			a[s + n - i - 1][s + n - 1] = a[s + n - 1][s + i];
			a[s + n - 1][s + i] = t;
		}
		s++;
	}

}

// 如果超出范围,将形状恢复(顺时针旋转)
void ReRotateMatrix() {
	int(*a)[4] = shape;
	int s = 0;
	for (int n = 4; n >= 1; n -= 2) {
		for (int i = 0; i<n - 1; i++) {
			int t = a[s + i][s];
			a[s + i][s] = a[s + n - 1][s + i];
			a[s + n - 1][s + i] = a[s + n - i - 1][s + n - 1];
			a[s + n - i - 1][s + n - 1] = a[s][s + n - i - 1];
			a[s][s + n - i - 1] = t;
		}
		s++;
	}
}

// 下落形状下降一格
void MoveDown(HWND hwnd) {

	shape_row++;

	if (!IsLegel()) {
		shape_row--;

		if (JudgeLose()) {
			LoseGame(hwnd);
			return;
		}
		FallToGround();
		ClearFullLine();
		UpdateAllBoard(hwnd);

		// 重置下落形状位置
		shape_row = 0;
		shape_col = EXTENDED_COLS / 2 - 2;

		RandShape();
	}

	UpdateShapeRect(hwnd);
}

// 判断是否输了
bool JudgeLose() {

	if (shape_row == 0)
		return true;

	return false;

}

// 游戏结束
void LoseGame(HWND hwnd) {

	SendMessage(hwnd, WM_KEYDOWN, VK_SPACE, 0);

	TCHAR words[100];
	wsprintf(words, TEXT("You lose the Game. Your score is %d. \nDo you want try again?"), score);

	int flag = MessageBox(NULL, words, TEXT("EXIT"), MB_YESNO);

	if (flag == IDYES) {
		SendMessage(hwnd, WM_CREATE, NULL, 0);
		return;
	}
	else if (flag == IDNO) {
		SendMessage(hwnd, WM_DESTROY, NULL, 0);
		return;
	}

}

// 图形落地,更新背景数组
void FallToGround() {

	for (int i = 0; i<4; i++) {
		for (int j = 0; j<4; j++) {
			gBoard[shape_row + i][shape_col + j] = shape[i][j] == 1 ? 2 : gBoard[shape_row + i][shape_col + j];
		}
	}
}

// 清除整行的方格
void ClearFullLine() {
	for (int i = shape_row; i <= shape_row + 3; i++) {
		if (i > BOARD_BOTTOM)
			continue;

		bool there_is_blank = false;

		// 判断一行是否有空格
		for (int j = BOARD_LEFT; j <= BOARD_RIGHT; j++) {
			if (gBoard[i][j] == 0) {
				there_is_blank = true;
				break;
			}
		}
		if (!there_is_blank) {
			AddScore();
			for (int r = i; r >= 1; r--) {
				for (int c = BOARD_LEFT; c <= BOARD_RIGHT; c++) {
					gBoard[r][c] = gBoard[r - 1][c];
				}
			}
		}
	}
}

// 清除一行加100分
void AddScore() {
	score += 100;
}

// 下落形状水平方向移动
void MoveHori(HWND hwnd, int direction) {

	int temp = shape_col;

	// direction 为0则左移否则右移
	if (direction == 0)
		shape_col--;
	else
		shape_col++;

	// 如果移动后位置超出边界
	if (!IsLegel()) {
		shape_col = temp;
	}

	UpdateShapeRect(hwnd);

	return;
}

Shapes.h

#ifndef SHAPES_H
#define SHAPES_H

// 存储七种形状
static int shapes[7][4][4] = {
	{
		{ 0, 0, 0, 0 },
		{ 0, 1, 0, 0 },
		{ 1, 1, 1, 0 },
		{ 0, 0, 0, 0 }
	},
	{
		{ 0, 0, 0, 0 },
		{ 0, 1, 1, 0 },
		{ 0, 1, 1, 0 },
		{ 0, 0, 0, 0 }
	},
	{
		{ 0, 1, 0, 0 },
		{ 0, 1, 0, 0 },
		{ 0, 1, 0, 0 },
		{ 0, 1, 0, 0 }
	},
	{
		{ 0, 0, 0, 0 },
		{ 1, 1, 0, 0 },
		{ 0, 1, 1, 0 },
		{ 0, 0, 0, 0 }
	},
	{
		{ 0, 0, 0, 0 },
		{ 1, 0, 0, 0 },
		{ 1, 1, 1, 0 },
		{ 0, 0, 0, 0 }
	},
	{
		{ 0, 0, 0, 0 },
		{ 0, 0, 1, 0 },
		{ 1, 1, 1, 0 },
		{ 0, 0, 0, 0 }
	},
	{
		{ 0, 0, 0, 0 },
		{ 0, 1, 1, 0 },
		{ 1, 1, 0, 0 },
		{ 0, 0, 0, 0 }
	}
};


#endif // !SHAPES_H

2019-11-30_094902.png

离线

#8 2019-11-30 11:04:03

win32prog
会员
注册时间: 2019-11-28
累计积分: 71

Re: 发现一个不错的 win32 api 入门教程

2019-11-30_105913.png

上面代码用 mingw 编译还有点坑, 要 notepad++ 转码一下


g++ -o test TetrisGame_zjy.c  -lgdi32 -luser32 -DUNICODE

咦, 为什么背后还要启动一个黑窗口呢?

2019-11-30_110337.png

离线

#9 2019-11-30 11:16:46

夏雨夜寐
会员
注册时间: 2019-08-23
累计积分: 27

Re: 发现一个不错的 win32 api 入门教程

启动了控制台调试吧?

离线

#10 2019-11-30 11:26:46

win32prog
会员
注册时间: 2019-11-28
累计积分: 71

Re: 发现一个不错的 win32 api 入门教程

夏雨夜寐 说:

启动了控制台调试吧?

g++ -o test TetrisGame_zjy.c  -lgdi32 -luser32 -DUNICODE


这个编译指令要加点什么吗?

离线

#11 2019-11-30 13:01:03

明月心惜
会员
注册时间: 2018-08-19
累计积分: 22

Re: 发现一个不错的 win32 api 入门教程

优秀 围观

离线

#12 2019-11-30 15:52:59

win32prog
会员
注册时间: 2019-11-28
累计积分: 71

Re: 发现一个不错的 win32 api 入门教程

#include <stdio.h>
#include <windows.h>

#define ID_TIMER	1

const wchar_t g_szClassName[] = L"myWindowClass";

void OnTimer(HWND hWnd)
{
    printf("on timer...\n");
    fflush(stdout);

}

void OnPaint(HWND hWnd)
{
    PAINTSTRUCT ps;
    HDC hdc = BeginPaint(hWnd,&ps);

    HDC memdc  = CreateCompatibleDC(hdc);
    HBITMAP membmp =CreateCompatibleBitmap(hdc, ps.rcPaint.right, ps.rcPaint.bottom);
    HGDIOBJ oldBitmap=SelectObject(memdc, membmp);

    //SetMapMode(memdc, GetMapMode(hdc));
    const RECT rect = {10, 10, 300, 100};
    //SetBkColor(memdc, RGB(0xFF, 0xFF, 0xFF));
    FillRect(memdc, &ps.rcPaint, CreateSolidBrush(RGB(255,255,255)));
    FillRect(memdc, &rect, CreateSolidBrush(RGB(255, 0, 0)));
    LineTo(memdc, 100, 100);
    Ellipse(memdc, 150, 150, 250, 200);

    BitBlt(hdc,0,0,ps.rcPaint.right, ps.rcPaint.bottom,memdc,0,0,SRCCOPY);

    DeleteObject(SelectObject(memdc, oldBitmap));
    DeleteDC(memdc);
    DeleteDC(hdc);

    EndPaint(hWnd,&ps);


    return;

}

void OnPaint1(HWND hWnd)
{
    PAINTSTRUCT ps;
    HDC hdc = BeginPaint(hWnd,&ps);

    const RECT rect = {10, 10, 300, 100};
    FillRect(hdc, &rect, CreateSolidBrush(RGB(255, 0, 0)));
    MoveToEx(hdc,0,0,0);
    LineTo(hdc, 100, 100);

    Ellipse(hdc, 100, 100, 200, 200);
    EndPaint(hWnd,&ps);
    return;

}
void OnPaint2(HWND hWnd)
{
    PAINTSTRUCT ps;
    HDC hdc = BeginPaint(hWnd, &ps);
    HPEN hPen = CreatePen(PS_DASHDOTDOT, 2, NULL);
    SelectObject(hdc, hPen);
    Ellipse(hdc, 100, 200, 400, 400);
    Ellipse(hdc, 300, 300, 500, 510);

    DeleteObject(hPen);
    EndPaint(hWnd, &ps);
}

// Step 4: the Window Procedure
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
    switch(msg)
    {
    case WM_CREATE:
        //SetTimer(hwnd, ID_TIMER, 2000, NULL);
        break;
    case WM_TIMER:
        OnTimer(hwnd);
        break;
    case WM_ERASEBKGND:
        printf("erase back\n");
        fflush(stdout);
        return DefWindowProc(hwnd, msg, wParam, lParam);
    case WM_MOVE:
        printf("move\n");
        fflush(stdout);
    case WM_PAINT:
        OnPaint(hwnd);
        //MessageBoxW(hwnd, L"painting ...", L"p", MB_OK);
        printf("painting...\n");
        fflush(stdout);
        //return DefWindowProc(hwnd, msg, wParam, lParam);
        break;
    case WM_LBUTTONDOWN:
        //wchar_t szFileName[MAX_PATH];
        //HINSTANCE hInstance = GetModuleHandle(NULL);
        //GetModuleFileNameW(hInstance, szFileName, MAX_PATH);
        //MessageBoxW(hwnd, szFileName, L"This program is:", MB_OK | MB_ICONINFORMATION);
        break;
    case WM_CLOSE:
        DestroyWindow(hwnd);
        break;
    case WM_DESTROY:
        PostQuitMessage(0);
        break;
    default:
        return DefWindowProc(hwnd, msg, wParam, lParam);
    }

    return 0;
}

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
    LPSTR lpCmdLine, int nCmdShow)
{
    WNDCLASSEXW wc;
    HWND hwnd;
    MSG Msg;

    //Step 1: Registering the Window Class
    wc.cbSize        = sizeof(WNDCLASSEX);
    wc.style         = 0;
    wc.lpfnWndProc   = WndProc;
    wc.cbClsExtra    = 0;
    wc.cbWndExtra    = 0;
    wc.hInstance     = hInstance;
    wc.hIcon         = LoadIcon(NULL, IDI_APPLICATION);
    wc.hCursor       = LoadCursor(NULL, IDC_ARROW);
    wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
    wc.lpszMenuName  = NULL;
    wc.lpszClassName = g_szClassName;
    wc.hIconSm       = LoadIcon(NULL, IDI_APPLICATION);

    if(!RegisterClassExW(&wc))
    {
        MessageBoxW(NULL, L"Window Registration Failed!", L"Error!",
            MB_ICONEXCLAMATION | MB_OK);
        return 0;
    }

    // Step 2: Creating the Window
    hwnd = CreateWindowExW(
        WS_EX_CLIENTEDGE,
        g_szClassName,
        L"The title of my window",
        WS_OVERLAPPEDWINDOW,
        CW_USEDEFAULT, CW_USEDEFAULT, 640, 480,
        NULL, NULL, hInstance, NULL);

    if(hwnd == NULL)
    {
        MessageBoxW(NULL, L"Window Creation Failed!", L"Error!",
            MB_ICONEXCLAMATION | MB_OK);
        return 0;
    }

    ShowWindow(hwnd, nCmdShow);
    UpdateWindow(hwnd);

    // Step 3: The Message Loop
    while(GetMessage(&Msg, NULL, 0, 0) > 0)
    {
        TranslateMessage(&Msg);
        DispatchMessage(&Msg);
    }
    return (int)Msg.wParam;
}

用双缓冲画图 OK

void OnPaint(HWND hWnd)
{
    PAINTSTRUCT ps;
    HDC hdc = BeginPaint(hWnd,&ps);

    HDC memdc  = CreateCompatibleDC(hdc);
    HBITMAP membmp =CreateCompatibleBitmap(hdc, ps.rcPaint.right, ps.rcPaint.bottom);
    HGDIOBJ oldBitmap=SelectObject(memdc, membmp);

    //SetMapMode(memdc, GetMapMode(hdc));
    const RECT rect = {10, 10, 300, 100};
    //SetBkColor(memdc, RGB(0xFF, 0xFF, 0xFF));
    FillRect(memdc, &ps.rcPaint, CreateSolidBrush(RGB(255,255,255)));
    FillRect(memdc, &rect, CreateSolidBrush(RGB(255, 0, 0)));
    LineTo(memdc, 100, 100);
    Ellipse(memdc, 150, 150, 250, 200);

    BitBlt(hdc,0,0,ps.rcPaint.right, ps.rcPaint.bottom,memdc,0,0,SRCCOPY);

    DeleteObject(SelectObject(memdc, oldBitmap));
    DeleteDC(memdc);
    DeleteDC(hdc);
    
    EndPaint(hWnd,&ps);
    
    return;
}

离线

#13 2019-11-30 15:57:08

win32prog
会员
注册时间: 2019-11-28
累计积分: 71

Re: 发现一个不错的 win32 api 入门教程

win32prog 说:

g++ -o test TetrisGame_zjy.c  -lgdi32 -luser32 -DUNICODE


这个编译指令要加点什么吗?

终于搞定,

g++ -o test TetrisGame_zjy.c  -lgdi32 -luser32 -DUNICODE -mwindows

这样就没有黑窗口了。


https://stackoverflow.com/questions/13100785/mingw-build-gui-application-with-console

离线

#14 2019-11-30 16:26:31

win32prog
会员
注册时间: 2019-11-28
累计积分: 71

Re: 发现一个不错的 win32 api 入门教程

定时器调用 InvalidateRect() 使客户区域无效,gui系统会自动发出 WM_PAINT 消息,

窗口消息处理函数收到WM_PAINT消息自动显示随机颜色。

void OnTimer(HWND hWnd)
{
    printf("on timer...\n");
    fflush(stdout);
    RECT rect;
    GetClientRect(hWnd, &rect);
    InvalidateRect(hWnd, &rect, FALSE);
}
void OnPaint(HWND hWnd)
{
    PAINTSTRUCT ps;
    HDC hdc = BeginPaint(hWnd,&ps);

    HDC memdc  = CreateCompatibleDC(hdc);
    HBITMAP membmp =CreateCompatibleBitmap(hdc, ps.rcPaint.right, ps.rcPaint.bottom);
    HGDIOBJ oldBitmap=SelectObject(memdc, membmp);


    //SetMapMode(memdc, GetMapMode(hdc));
    const RECT rect = {10, 10, 300, 100};
    //SetBkColor(memdc, RGB(0xFF, 0xFF, 0xFF));
    FillRect(memdc, &ps.rcPaint, CreateSolidBrush(RGB(255,255,255)));
    FillRect(memdc, &rect, CreateSolidBrush(RGB(rand()%0xFF, rand()%0xFF, rand()%0xFF)));
    LineTo(memdc, 100, 100);
    Ellipse(memdc, 150, 150, 250, 200);

    BitBlt(hdc,0,0,ps.rcPaint.right, ps.rcPaint.bottom,memdc,0,0,SRCCOPY);

    DeleteObject(SelectObject(memdc, oldBitmap));
    DeleteDC(memdc);
    DeleteDC(hdc);

    EndPaint(hWnd,&ps);

    return;
}

离线

#15 2019-11-30 21:46:02

jiangming1399
会员
注册时间: 2018-06-14
累计积分: 63

Re: 发现一个不错的 win32 api 入门教程

感觉现在已经很少有人裸写win32 api gui了,都是用一些界面库来实现了

离线

#16 2019-11-30 23:02:20

win32prog
会员
注册时间: 2019-11-28
累计积分: 71

Re: 发现一个不错的 win32 api 入门教程

jiangming1399 说:

感觉现在已经很少有人裸写win32 api gui了,都是用一些界面库来实现了

为了修改公司的一个祖传MFC软件, 不得不学习一下win32 基础编程.

离线

#17 2019-12-09 14:37:30

win32prog
会员
注册时间: 2019-11-28
累计积分: 71

Re: 发现一个不错的 win32 api 入门教程

https://docs.microsoft.com/en-us/windows/win32/controls/create-toolbars

https://docs.microsoft.com/en-us/windows/win32/api/commctrl/nf-commctrl-imagelist_create

HIMAGELIST g_hImageList = NULL;

HWND CreateSimpleToolbar(HWND hWndParent)
{
    // Declare and initialize local constants.
    const int ImageListID    = 0;
    const int numButtons     = 3;
    const int bitmapSize     = 16;
    
    const DWORD buttonStyles = BTNS_AUTOSIZE;

    // Create the toolbar.
    HWND hWndToolbar = CreateWindowEx(0, TOOLBARCLASSNAME, NULL, 
                                      WS_CHILD | TBSTYLE_WRAPABLE, 0, 0, 0, 0, 
                                      hWndParent, NULL, g_hInst, NULL);
        
    if (hWndToolbar == NULL)
        return NULL;

    // Create the image list.
    g_hImageList = ImageList_Create(bitmapSize, bitmapSize,   // Dimensions of individual bitmaps.
                                    ILC_COLOR16 | ILC_MASK,   // Ensures transparent background.
                                    numButtons, 0);

    // Set the image list.
    SendMessage(hWndToolbar, TB_SETIMAGELIST, 
                (WPARAM)ImageListID, 
                (LPARAM)g_hImageList);

    // Load the button images.
    SendMessage(hWndToolbar, TB_LOADIMAGES, 
                (WPARAM)IDB_STD_SMALL_COLOR, 
                (LPARAM)HINST_COMMCTRL);

    // Initialize button info.
    // IDM_NEW, IDM_OPEN, and IDM_SAVE are application-defined command constants.
    
    TBBUTTON tbButtons[numButtons] = 
    {
        { MAKELONG(STD_FILENEW,  ImageListID), IDM_NEW,  TBSTATE_ENABLED, buttonStyles, {0}, 0, (INT_PTR)L"New" },
        { MAKELONG(STD_FILEOPEN, ImageListID), IDM_OPEN, TBSTATE_ENABLED, buttonStyles, {0}, 0, (INT_PTR)L"Open"},
        { MAKELONG(STD_FILESAVE, ImageListID), IDM_SAVE, 0,               buttonStyles, {0}, 0, (INT_PTR)L"Save"}
    };

    // Add buttons.
    SendMessage(hWndToolbar, TB_BUTTONSTRUCTSIZE, (WPARAM)sizeof(TBBUTTON), 0);
    SendMessage(hWndToolbar, TB_ADDBUTTONS,       (WPARAM)numButtons,       (LPARAM)&tbButtons);

    // Resize the toolbar, and then show it.
    SendMessage(hWndToolbar, TB_AUTOSIZE, 0, 0); 
    ShowWindow(hWndToolbar,  TRUE);
    
    return hWndToolbar;
}

借鉴微软这段代码, 自己写了一个:

#include "stdafx.h"

#include <stdio.h>
#include <windows.h>
#include <commctrl.h>

const wchar_t g_szClassName[] = L"myWindowClass";

HIMAGELIST g_hImageList = NULL;

#define IDM_NEW 100
#define IDM_OPEN 101
#define IDM_SAVE 102

HINSTANCE gInstance;

HWND CreateSimpleToolbar(HWND hWndParent)
{
	// Declare and initialize local constants.
	const int ImageListID = 0;
	const int numButtons = 3;
	const int bitmapSize = 16;

	const DWORD buttonStyles = BTNS_AUTOSIZE;

	// Create the toolbar.
	HWND hWndToolbar = CreateWindowEx(0, TOOLBARCLASSNAME, NULL,
		WS_CHILD | TBSTYLE_WRAPABLE, 0, 0, 0, 0,
		hWndParent, NULL, gInstance, NULL);

	if (hWndToolbar == NULL)
		return NULL;

	// Create the image list.
	g_hImageList = ImageList_Create(bitmapSize, bitmapSize,   // Dimensions of individual bitmaps.
		ILC_COLOR16 | ILC_MASK,   // Ensures transparent background.
		numButtons, 0);

	// Set the image list.
	SendMessage(hWndToolbar, TB_SETIMAGELIST,
		(WPARAM)ImageListID,
		(LPARAM)g_hImageList);

	// Load the button images.
	SendMessage(hWndToolbar, TB_LOADIMAGES,
		(WPARAM)IDB_STD_SMALL_COLOR,
		(LPARAM)HINST_COMMCTRL);

	// Initialize button info.
	// IDM_NEW, IDM_OPEN, and IDM_SAVE are application-defined command constants.

	TBBUTTON tbButtons[numButtons] =
	{
		{ MAKELONG(STD_FILENEW,  ImageListID), IDM_NEW,  TBSTATE_ENABLED, buttonStyles, {0}, 0, (INT_PTR)L"New" },
		{ MAKELONG(STD_FILEOPEN, ImageListID), IDM_OPEN, TBSTATE_ENABLED, buttonStyles, {0}, 0, (INT_PTR)L"Open"},
		{ MAKELONG(STD_FILESAVE, ImageListID), IDM_SAVE, 0,               buttonStyles, {0}, 0, (INT_PTR)L"Save"}
	};

	// Add buttons.
	SendMessage(hWndToolbar, TB_BUTTONSTRUCTSIZE, (WPARAM)sizeof(TBBUTTON), 0);
	SendMessage(hWndToolbar, TB_ADDBUTTONS, (WPARAM)numButtons, (LPARAM)&tbButtons);

	// Resize the toolbar, and then show it.
	SendMessage(hWndToolbar, TB_AUTOSIZE, 0, 0);
	ShowWindow(hWndToolbar, TRUE);

	return hWndToolbar;
}

void OnPaint(HWND hWnd)
{
	PAINTSTRUCT ps;
	HDC hdc = BeginPaint(hWnd, &ps);
	MoveToEx(hdc, 0, 0, 0);
	LineTo(hdc, 100, 100);

	Ellipse(hdc, 100, 100, 200, 200);
	EndPaint(hWnd, &ps);
	return;
}
void OnPaint2(HWND hWnd)
{
	PAINTSTRUCT ps;
	HDC hdc = BeginPaint(hWnd, &ps);
	HPEN hPen = CreatePen(PS_DASHDOTDOT, 2, NULL);
	SelectObject(hdc, hPen);
	Ellipse(hdc, 100, 200, 400, 400);
	Ellipse(hdc, 300, 300, 500, 510);

	DeleteObject(hPen);
	EndPaint(hWnd, &ps);
}

// Step 4: the Window Procedure
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
	switch (msg)
	{
	case WM_CREATE:
		CreateSimpleToolbar(hwnd);
	case WM_ERASEBKGND:
		printf("erase back\n");
		fflush(stdout);
		return DefWindowProc(hwnd, msg, wParam, lParam);
	case WM_MOVE:
		printf("move\n");
		fflush(stdout);
	case WM_PAINT:
		OnPaint(hwnd);
		//MessageBoxW(hwnd, L"painting ...", L"p", MB_OK);
		printf("painting...\n");
		fflush(stdout);
		//return DefWindowProc(hwnd, msg, wParam, lParam);
		break;
	case WM_LBUTTONDOWN:
		//wchar_t szFileName[MAX_PATH];
		//HINSTANCE hInstance = GetModuleHandle(NULL);
		//GetModuleFileNameW(hInstance, szFileName, MAX_PATH);
		//MessageBoxW(hwnd, szFileName, L"This program is:", MB_OK | MB_ICONINFORMATION);
		break;
	case WM_CLOSE:
		DestroyWindow(hwnd);
		break;
	case WM_DESTROY:
		PostQuitMessage(0);
		break;
	default:
		return DefWindowProc(hwnd, msg, wParam, lParam);
	}
	return 0;
}

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
	LPSTR lpCmdLine, int nCmdShow)
{
	WNDCLASSEXW wc;
	HWND hwnd;
	MSG Msg;
	gInstance = hInstance;
	//Step 1: Registering the Window Class
	wc.cbSize = sizeof(WNDCLASSEX);
	wc.style = 0;
	wc.lpfnWndProc = WndProc;
	wc.cbClsExtra = 0;
	wc.cbWndExtra = 0;
	wc.hInstance = hInstance;
	wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
	wc.hCursor = LoadCursor(NULL, IDC_ARROW);
	wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
	wc.lpszMenuName = NULL;
	wc.lpszClassName = g_szClassName;
	wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION);

	if (!RegisterClassExW(&wc))
	{
		MessageBoxW(NULL, L"Window Registration Failed!", L"Error!",
			MB_ICONEXCLAMATION | MB_OK);
		return 0;
	}

	// Step 2: Creating the Window
	hwnd = CreateWindowExW(
		WS_EX_CLIENTEDGE,
		g_szClassName,
		L"The title of my window",
		WS_OVERLAPPEDWINDOW,
		CW_USEDEFAULT, CW_USEDEFAULT, 640, 480,
		NULL, NULL, hInstance, NULL);

	if (hwnd == NULL)
	{
		MessageBoxW(NULL, L"Window Creation Failed!", L"Error!",
			MB_ICONEXCLAMATION | MB_OK);
		return 0;
	}

	ShowWindow(hwnd, nCmdShow);
	UpdateWindow(hwnd);

	// Step 3: The Message Loop
	while (GetMessage(&Msg, NULL, 0, 0) > 0)
	{
		TranslateMessage(&Msg);
		DispatchMessage(&Msg);
	}
	return (int)Msg.wParam;
}

2019-12-09_143156.png

离线

#18 2019-12-09 14:53:58

win32prog
会员
注册时间: 2019-11-28
累计积分: 71

Re: 发现一个不错的 win32 api 入门教程

#include "stdafx.h"

#include <stdio.h>
#include <windows.h>
#include <commctrl.h>

const wchar_t g_szClassName[] = L"myWindowClass";

HIMAGELIST g_hImageList = NULL;

#define IDM_NEW 100
#define IDM_OPEN 101
#define IDM_SAVE 102

HINSTANCE gInstance;

HWND CreateSimpleToolbar(HWND hWndParent)
{
	// Declare and initialize local constants.
	const int ImageListID = 0;
	const int numButtons = 3;
	const int bitmapSize = 16;

	const DWORD buttonStyles = BTNS_AUTOSIZE;

	// Create the toolbar.
	HWND hWndToolbar = CreateWindowEx(0, TOOLBARCLASSNAME, NULL,
		WS_CHILD | TBSTYLE_WRAPABLE, 0, 0, 0, 0,
		hWndParent, NULL, gInstance, NULL);

	if (hWndToolbar == NULL)
		return NULL;

	// Create the image list.
	g_hImageList = ImageList_Create(bitmapSize, bitmapSize,   // Dimensions of individual bitmaps.
		ILC_COLOR16 | ILC_MASK,   // Ensures transparent background.
		numButtons, 0);

	// Set the image list.
	SendMessage(hWndToolbar, TB_SETIMAGELIST,
		(WPARAM)ImageListID,
		(LPARAM)g_hImageList);

	// Load the button images.
	SendMessage(hWndToolbar, TB_LOADIMAGES,
		(WPARAM)IDB_STD_SMALL_COLOR,
		(LPARAM)HINST_COMMCTRL);

	// Initialize button info.
	// IDM_NEW, IDM_OPEN, and IDM_SAVE are application-defined command constants.

	TBBUTTON tbButtons[numButtons] =
	{
		{ MAKELONG(STD_FILENEW,  ImageListID), IDM_NEW,  TBSTATE_ENABLED, buttonStyles, {0}, 0, (INT_PTR)L"New" },
		{ MAKELONG(STD_FILEOPEN, ImageListID), IDM_OPEN, TBSTATE_ENABLED, buttonStyles, {0}, 0, (INT_PTR)L"Open"},
		{ MAKELONG(STD_FILESAVE, ImageListID), IDM_SAVE, 0,               buttonStyles, {0}, 0, (INT_PTR)L"Save"}
	};

	// Add buttons.
	SendMessage(hWndToolbar, TB_BUTTONSTRUCTSIZE, (WPARAM)sizeof(TBBUTTON), 0);
	SendMessage(hWndToolbar, TB_ADDBUTTONS, (WPARAM)numButtons, (LPARAM)&tbButtons);

	// Resize the toolbar, and then show it.
	SendMessage(hWndToolbar, TB_AUTOSIZE, 0, 0);
	ShowWindow(hWndToolbar, TRUE);

	return hWndToolbar;
}

void OnPaint(HWND hWnd)
{
	PAINTSTRUCT ps;
	HDC hdc = BeginPaint(hWnd, &ps);
	MoveToEx(hdc, 0, 0, 0);
	LineTo(hdc, 100, 100);

	Ellipse(hdc, 100, 100, 200, 200);
	EndPaint(hWnd, &ps);
	return;
}
void OnPaint2(HWND hWnd)
{
	PAINTSTRUCT ps;
	HDC hdc = BeginPaint(hWnd, &ps);
	HPEN hPen = CreatePen(PS_DASHDOTDOT, 2, NULL);
	SelectObject(hdc, hPen);
	Ellipse(hdc, 100, 200, 400, 400);
	Ellipse(hdc, 300, 300, 500, 510);

	DeleteObject(hPen);
	EndPaint(hWnd, &ps);
}

// Step 4: the Window Procedure
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
	switch (msg)
	{
	case WM_CREATE:
		CreateSimpleToolbar(hwnd);
		break;
	case WM_COMMAND:
	{
		int wmId = LOWORD(wParam);
		int wmEvent = HIWORD(wParam);
		// Parse the menu selections:
		switch (wmId)
		{
		case IDM_NEW:
			MessageBox(hwnd, _TEXT("点击了new"), _TEXT("提示"), 0);
			break;
		case IDM_OPEN:
			MessageBox(hwnd, _TEXT("点击了open"), _TEXT("提示"), 0);
			break;
		default:
			return DefWindowProc(hwnd, msg, wParam, lParam);
		}
	}

		break;
	case WM_ERASEBKGND:
		printf("erase back\n");
		fflush(stdout);
		return DefWindowProc(hwnd, msg, wParam, lParam);
	case WM_MOVE:
		printf("move\n");
		fflush(stdout);
	case WM_PAINT:
		OnPaint(hwnd);
		//MessageBoxW(hwnd, L"painting ...", L"p", MB_OK);
		printf("painting...\n");
		fflush(stdout);
		//return DefWindowProc(hwnd, msg, wParam, lParam);
		break;
	case WM_LBUTTONDOWN:
		//wchar_t szFileName[MAX_PATH];
		//HINSTANCE hInstance = GetModuleHandle(NULL);
		//GetModuleFileNameW(hInstance, szFileName, MAX_PATH);
		//MessageBoxW(hwnd, szFileName, L"This program is:", MB_OK | MB_ICONINFORMATION);
		break;
	case WM_CLOSE:
		DestroyWindow(hwnd);
		break;
	case WM_DESTROY:
		PostQuitMessage(0);
		break;
	default:
		return DefWindowProc(hwnd, msg, wParam, lParam);
	}
	return 0;
}

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
	LPSTR lpCmdLine, int nCmdShow)
{
	WNDCLASSEXW wc;
	HWND hwnd;
	MSG Msg;
	gInstance = hInstance;
	//Step 1: Registering the Window Class
	wc.cbSize = sizeof(WNDCLASSEX);
	wc.style = 0;
	wc.lpfnWndProc = WndProc;
	wc.cbClsExtra = 0;
	wc.cbWndExtra = 0;
	wc.hInstance = hInstance;
	wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
	wc.hCursor = LoadCursor(NULL, IDC_ARROW);
	wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
	wc.lpszMenuName = NULL;
	wc.lpszClassName = g_szClassName;
	wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION);

	if (!RegisterClassExW(&wc))
	{
		MessageBoxW(NULL, L"Window Registration Failed!", L"Error!",
			MB_ICONEXCLAMATION | MB_OK);
		return 0;
	}

	// Step 2: Creating the Window
	hwnd = CreateWindowExW(
		WS_EX_CLIENTEDGE,
		g_szClassName,
		L"The title of my window",
		WS_OVERLAPPEDWINDOW,
		CW_USEDEFAULT, CW_USEDEFAULT, 640, 480,
		NULL, NULL, hInstance, NULL);

	if (hwnd == NULL)
	{
		MessageBoxW(NULL, L"Window Creation Failed!", L"Error!",
			MB_ICONEXCLAMATION | MB_OK);
		return 0;
	}

	ShowWindow(hwnd, nCmdShow);
	UpdateWindow(hwnd);

	// Step 3: The Message Loop
	while (GetMessage(&Msg, NULL, 0, 0) > 0)
	{
		TranslateMessage(&Msg);
		DispatchMessage(&Msg);
	}
	return (int)Msg.wParam;
}

2019-12-09_145245.png

添加了工具栏 toolbar wm_command 消息响应代码.

离线

#19 2019-12-11 22:25:28

hzqlz
会员
注册时间: 2018-03-23
累计积分: 32

Re: 发现一个不错的 win32 api 入门教程

多谢分享

离线

页脚