§ Основной код

* hInstance        Переданная текущая программа
* hPrevInstance    Программа, которая передала управление
* lpCmdLine        Строка запроса (нулевой символ в конце)
* nShowCmd         Показывает состояние окна
Подробное описание в этой статье.
1@echo off
2g++ -m32 -g3 -static-libgcc -mwindows -lgdi32 main.cpp -o main.exe
3strip main.exe
4main.exe
1#include "demoapp.cpp"
2
3int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)
4{
5    DemoApp app;
6    app.init(hInstance, 1280, 800, "Windows", 50, 4);
7
8    int test = 0;
9    while (app.wait()) {
10
11        // Срабатывает на таймере
12        if (app.is_timer()) {
13
14            test++;
15            for (int y = 0; y < 200; y++)
16            for (int x = 0; x < 320; x++)
17                app.pset(x, y, x*y + test);
18        }
19
20        app.repaint();
21    }
22
23    return 0;
24}

§ Класс-обработчик demoapp.cpp

1// Опции компилятора -static-libgcc -mwindows -lgdi32
2
3// Убрать лишнее из генерируемого файла
4#define WIN32_LEAN_AND_MEAN
5
6#include <windows.h>
7#include <stdio.h>
8#include <stdlib.h>
9
10#include "demoapp.h"
11
12// ---------------------------------------------------------------------------------------
13
14class DemoApp {
15protected:
16
17    HWND            hWnd;
18    INT64           frameMillisecond;
19    int             last_events;
20
21public:
22
23    // Инициализация окна, создание и назначение обработчиков
24    // fps количество кадров в секунду
25    // scale: 0=1x1, 1=2x2, 2=4x4, ...
26    void init(HINSTANCE hInstance, int width, int height, const char* name, int fps, int scale) {
27
28        DWORD dwExStyle = WS_EX_APPWINDOW;
29        DWORD dwStyle   = WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU;
30
31        int x, y, w, h;
32
33        WNDCLASS wc;
34        RECT     rc;
35
36        wc.style            = CS_OWNDC;
37        wc.lpfnWndProc      = MainWndProc;
38        wc.cbClsExtra       = 0;
39        wc.cbWndExtra       = 0;
40        wc.hInstance        = hInstance;
41        wc.hIcon            = LoadIcon(NULL, IDI_APPLICATION);
42        wc.hCursor          = LoadCursor(NULL, IDC_ARROW);
43        wc.hbrBackground    = NULL;
44        wc.lpszMenuName     = NULL;
45        wc.lpszClassName    = TEXT("MainWndEx");
46
47        if (!RegisterClass(&wc)) {
48
49            MessageBox(NULL, TEXT("RegisterClass failed!"), TEXT("Error"), MB_ICONERROR | MB_OK | MB_SETFOREGROUND);
50            return;
51        }
52
53        rc.left   = 0;
54        rc.top    = 0;
55        rc.right  = width;
56        rc.bottom = height;
57
58        window_width  = width;
59        window_height = height;
60
61        win_ws = window_width  / scale;
62        win_hs = window_height / scale;
63
64        if (!AdjustWindowRectEx(&rc, dwStyle, FALSE, dwExStyle)) {
65
66            MessageBox(NULL, TEXT("AdjustWindowRectEx failed!"), TEXT("Error"), MB_ICONERROR | MB_OK | MB_SETFOREGROUND);
67            return;
68        }
69
70        w = width;
71        h = height;
72        x = (GetSystemMetrics(SM_CXSCREEN) - w) / 2;
73        y = (GetSystemMetrics(SM_CYSCREEN) - h) / 2;
74
75        EventAccept      = 0;
76        last_events      = 0;
77        frameMillisecond = 1000 / fps;
78
79        // Выделить память для пиксельного буфера
80        pixels = (COLORREF*) malloc (width * height * sizeof(COLORREF));
81
82        hWnd = CreateWindowEx(dwExStyle, wc.lpszClassName, name, dwStyle, x, y, w, h, NULL, NULL, hInstance, NULL);
83        if (!hWnd) {
84            MessageBox(NULL, TEXT("CreateWindowEx failed."), TEXT("Error"), MB_ICONERROR | MB_OK | MB_SETFOREGROUND);
85            return;
86        }
87
88        bitmapInfo.bmiHeader.biSize     = sizeof(bitmapInfo);
89        bitmapInfo.bmiHeader.biWidth    = width / scale;
90        bitmapInfo.bmiHeader.biHeight   = -height / scale;
91        bitmapInfo.bmiHeader.biPlanes   = 1;
92        bitmapInfo.bmiHeader.biBitCount = 32;
93        bitmapInfo.bmiHeader.biCompression = BI_RGB;
94
95        SetTimer(hWnd, 0, frameMillisecond, NULL);
96        ShowWindow(hWnd, SW_SHOWNORMAL);
97        UpdateWindow(hWnd);
98    }
99
100    // Перерисовка окна
101    void repaint() {
102
103        if (is_timer()) {
104            InvalidateRect(hWnd, NULL, FALSE);
105        }
106    }
107
108    // Сработал таймер
109    int is_timer() {
110        return last_events & MYEVENT_WM_TIMER ? 1 : 0;
111    }
112
113    // Сработала клавиатура
114    int is_keydown() { return last_events & MYEVENT_WM_KEYDOWN ? 1 : 0; }
115    int is_keyup()   { return last_events & MYEVENT_WM_KEYUP   ? 1 : 0; }
116    int kb_key()     { return DataKeyboard; }
117
118    // Обработка сообщений от windows
119    int peek_messages() {
120
121        MSG msg;
122
123        while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
124
125            // Выход из процедуры ожидания
126            if (msg.message == WM_QUIT)
127                return 0;
128
129            TranslateMessage (&msg);
130            DispatchMessage  (&msg);
131        }
132
133        Sleep(1);
134        return 1;
135    }
136
137    // Процедура ожидания
138    int wait() {
139
140        EventAccept = 0;
141        do {
142
143            if (peek_messages() == 0)
144                return 0;
145
146        } while (!EventAccept);
147
148        last_events = EventAccept;
149        return EventAccept;
150    }
151
152    // ==== Графические процедуры ====
153
154    // Поставить точку в буфере
155    void pset(int x, int y, int color) {
156
157        if (x >= 0 && y >= 0 && x < win_ws && y < win_hs) {
158            pixels[win_ws*y + x] = color;
159        }
160    }
161
162     // Нарисовать линию
163    void line(int x1, int y1, int x2, int y2, int color) {
164
165        int deltax = abs(x2 - x1);
166        int deltay = abs(y2 - y1);
167        int signx  = x1 < x2 ? 1 : -1;
168        int signy  = y1 < y2 ? 1 : -1;
169
170        int error = deltax - deltay;
171        int error2;
172
173        pset(x2, y2, color);
174        while (x1 != x2 || y1 != y2)
175        {
176            pset(x1, y1, color);
177            error2 = error * 2;
178
179            if (error2 > -deltay) {
180                error -= deltay;
181                x1 += signx;
182            }
183
184            if (error2 < deltax) {
185                error += deltax;
186                y1 += signy;
187            }
188        }
189    }
190
191    // Очистить весь экран
192    void cls(int color) {
193
194        for (int i = 0; i < win_ws * win_hs; i++)
195            pixels[i] = color;
196    }
197};
198
199// Обработчик событий от Windows
200LRESULT CALLBACK MainWndProc(HWND MyWnd, UINT msg, WPARAM wParam, LPARAM lParam) {
201
202    switch (msg) {
203
204        case WM_CLOSE:
205        case WM_DESTROY:
206
207            PostQuitMessage(0);
208            return 0;
209
210        case WM_ERASEBKGND:
211            return TRUE;
212
213        case WM_KEYDOWN:
214
215            EventAccept |= MYEVENT_WM_KEYDOWN;
216            DataKeyboard = wParam;
217            return 0;
218
219        case WM_KEYUP:
220
221            EventAccept |= MYEVENT_WM_KEYUP;
222            DataKeyboard = wParam;
223            return 0;
224
225        case WM_TIMER:
226
227            EventAccept |= MYEVENT_WM_TIMER;
228            return 0;
229
230        case WM_PAINT:
231
232            PAINTSTRUCT ps;
233            RECT r;
234            HDC  hDC;
235
236            hDC = BeginPaint(MyWnd, &ps);
237            GetClientRect(MyWnd, &r);
238
239            // dstx, dsty, dstw, dsth, srcx, srcy, scrw, scrh
240            StretchDIBits(
241                hDC,
242                0, 0, window_width, window_height,
243                0, 0, win_ws, win_hs,
244                pixels, &bitmapInfo, DIB_RGB_COLORS, SRCCOPY);
245
246            EndPaint(MyWnd, &ps);
247            return 0;
248    }
249
250    return DefWindowProc(MyWnd, msg, wParam, lParam);
251}

§ Заголовочный файл demoapp.h

1// Объявление процедуры обработки данных
2LRESULT CALLBACK  MainWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
3int     WINAPI    WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, INT nCmdShow);
4
5// Глобальные данные
6int         window_width, window_height;
7int         win_ws, win_hs;
8int         EventAccept;
9WPARAM      DataKeyboard;
10
11// Хранение пиксельных данных
12static COLORREF*   pixels;
13static BITMAPINFO  bitmapInfo;
14
15enum Events {
16
17    MYEVENT_WM_TIMER    = 1,
18    MYEVENT_WM_KEYDOWN  = 2,
19    MYEVENT_WM_KEYUP    = 4,
20};