I have successfully created a window but it wont update the window to change its shape and color. I have tried to solve this for days an appreciate any help.
The program is meant to show an orange window that can be reshaped. It would also help, if you could check the code by compiling it in Visual Studios.
Here is the code:
#include <Windows.h>
#include "Header.h"
bool running = true;
void *buffer_memory;
int buffer_width;
int buffer_hight;
BITMAPINFO buffer_bitmap_info;
LRESULT CALLBACK windows_callback(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
LRESULT result = 0;
switch (uMsg)
{
case WM_CLOSE:
case WM_DESTROY:
{
running = false;
}
break;
case WM_SIZE:
{
RECT rect;
GetClientRect(hwnd, &rect);
buffer_width = rect.left - rect.right;
buffer_hight = rect.bottom - rect.top;
int buffer_size = buffer_width *buffer_hight* sizeof(unsigned int);
if (buffer_memory) VirtualFree(buffer_memory, 0, MEM_RELEASE);
buffer_memory = VirtualAlloc(0, buffer_size, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
buffer_bitmap_info.bmiHeader.biSize = sizeof(buffer_bitmap_info.bmiHeader);
buffer_bitmap_info.bmiHeader.biWidth = buffer_width;
buffer_bitmap_info.bmiHeader.biHeight = buffer_hight;
buffer_bitmap_info.bmiHeader.biPlanes = 1;
buffer_bitmap_info.bmiHeader.biBitCount = 32;
buffer_bitmap_info.bmiHeader.biCompression = BI_RGB;
}
break;
default:
{
result = DefWindowProc(hwnd, uMsg, wParam, lParam);
}
}
return result;
}
int WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)
{
//compile window
CHAR clsName[] = "test";
WNDCLASSA window_class = {};
window_class.style = CS_HREDRAW | CS_VREDRAW;
window_class.lpszClassName = clsName;
window_class.lpfnWndProc = windows_callback;
//register clases
ATOM atom = RegisterClassA(&window_class);
if (0 == atom)
{
DWORD err = GetLastError();
return 1;
}
// create window
HWND window = CreateWindow(clsName, "game", WS_OVERLAPPEDWINDOW | WS_VISIBLE, CW_USEDEFAULT,
CW_USEDEFAULT, 720, 360, 0, 0, hInstance, 0);
if (NULL == window)
{
DWORD err = GetLastError();
return 1;
}
while (running)
{
HDC hdc = GetDC(window);
// input
// simulate
MSG mesage;
while (PeekMessage(&mesage, window, 0, 0, PM_REMOVE))
{
TranslateMessage(&mesage);
DispatchMessage(&mesage);
}
unsigned int *pixel = (unsigned int *) buffer_memory;
for (int y = 0; y < buffer_hight; y++)
{
for (int x = 0; x < buffer_width; x++)
{
*pixel++ = 0xff5500;
}
}
// render
StretchDIBits(hdc, 0, 0, buffer_width, buffer_hight, 0, 0, buffer_width, buffer_hight,
buffer_memory, &buffer_bitmap_info, DIB_RGB_COLORS, SRCCOPY); {}
}
};
The line: buffer_width = rect.left - rect.right;
=> buffer_width = rect.right- rect.left ;
You should draw in the WM_PAINT message,
case WM_PAINT:
{
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hwnd, &ps);
unsigned int* pixel = (unsigned int*)buffer_memory;
for (int y = 0; y < buffer_hight; y++)
{
for (int x = 0; x < buffer_width; x++)
{
*pixel++ = 0xff5500;
}
}
// render
StretchDIBits(hdc, 0, 0, buffer_width, buffer_hight, 0, 0, buffer_width, buffer_hight,
buffer_memory, &buffer_bitmap_info, DIB_RGB_COLORS, SRCCOPY); {}
EndPaint(hwnd, &ps);
}
break;
Updated:
#include <Windows.h>
//#include "Header.h"
bool running = true;
void* buffer_memory;
int buffer_width;
int buffer_hight;
BITMAPINFO buffer_bitmap_info;
LRESULT CALLBACK windows_callback(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
LRESULT result = 0;
switch (uMsg)
{
case WM_CLOSE:
case WM_DESTROY:
{
PostQuitMessage(0);
}
break;
case WM_SIZE:
{
RECT rect;
GetClientRect(hwnd, &rect);
buffer_width = rect.right - rect.left;
buffer_hight = rect.bottom - rect.top;
int buffer_size = buffer_width * buffer_hight * sizeof(unsigned int);
if (buffer_memory) VirtualFree(buffer_memory, 0, MEM_RELEASE);
buffer_memory = VirtualAlloc(0, buffer_size, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
buffer_bitmap_info.bmiHeader.biSize = sizeof(buffer_bitmap_info.bmiHeader);
buffer_bitmap_info.bmiHeader.biWidth = buffer_width;
buffer_bitmap_info.bmiHeader.biHeight = buffer_hight;
buffer_bitmap_info.bmiHeader.biPlanes = 1;
buffer_bitmap_info.bmiHeader.biBitCount = 32;
buffer_bitmap_info.bmiHeader.biCompression = BI_RGB;
}
break;
case WM_PAINT:
{
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hwnd, &ps);
unsigned int* pixel = (unsigned int*)buffer_memory;
for (int y = 0; y < buffer_hight; y++)
{
for (int x = 0; x < buffer_width; x++)
{
*pixel++ = 0xff5500;
}
}
// render
StretchDIBits(hdc, 0, 0, buffer_width, buffer_hight, 0, 0, buffer_width, buffer_hight,
buffer_memory, &buffer_bitmap_info, DIB_RGB_COLORS, SRCCOPY); {}
EndPaint(hwnd, &ps);
}
break;
default:
{
result = DefWindowProc(hwnd, uMsg, wParam, lParam);
}
}
return result;
}
int WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)
{
//compile window
CHAR clsName[] = "test";
WNDCLASSA window_class = {};
window_class.style = CS_HREDRAW | CS_VREDRAW;
window_class.lpszClassName = clsName;
window_class.lpfnWndProc = windows_callback;
//register clases
ATOM atom = RegisterClassA(&window_class);
if (0 == atom)
{
DWORD err = GetLastError();
return 1;
}
// create window
HWND window = CreateWindow(clsName, "game", WS_OVERLAPPEDWINDOW | WS_VISIBLE, CW_USEDEFAULT,
CW_USEDEFAULT, 720, 360, 0, 0, hInstance, 0);
if (NULL == window)
{
DWORD err = GetLastError();
return 1;
}
MSG msg;
// Main message loop:
while (GetMessage(&msg, nullptr, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
Related
I have been trying to create a Window whose title bar could be in any language. But I am getting something like ▯*. I writing as escape characters as of now. I am attesting the entirity of the code.
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <string>
LRESULT CALLBACK WindowProc(HWND Window, UINT Message, WPARAM WParam, LPARAM LParam) {
switch(Message) {
case WM_KEYDOWN: {
switch(WParam) {
case 'O': {
DestroyWindow(Window);
} break;
}
} break;
case WM_DESTROY: {
PostQuitMessage(0);
} break;
default: {
return DefWindowProc(Window, Message, WParam, LParam);
}
}
return 0;
}
int WINAPI WinMain(HINSTANCE Instance, HINSTANCE PrevInstance, PSTR CmdLine, int CmdShow) {
WNDCLASSW WindowClass = {0};
const wchar_t* ClassName = L"MyWindowClass";
WindowClass.lpfnWndProc = WindowProc;
WindowClass.hInstance = Instance;
WindowClass.lpszClassName = ClassName;
WindowClass.hCursor = LoadCursor(NULL, IDC_CROSS);
MessageBoxW(0, L"\u0906\u092a", L"\u0906\u092a", 0);
if(!RegisterClassW(&WindowClass)) {
MessageBoxW(0, L"RegisterClass failed", 0, 0);
return GetLastError();
}
HWND Window = CreateWindowExW(0, ClassName, L"\u0906\u092a",
WS_OVERLAPPEDWINDOW|WS_VISIBLE,
CW_USEDEFAULT, CW_USEDEFAULT,
CW_USEDEFAULT, CW_USEDEFAULT,
0, 0, Instance, 0);
if(!Window) {
MessageBoxW(0, L"CreateWindowEx failed", 0, 0);
return GetLastError();
}
int Running = 1;
while(Running) {
MSG Message;
while(GetMessageW(&Message, NULL, 0, 0)) {
if(Message.message == WM_QUIT) Running = 0;
TranslateMessage(&Message);
DispatchMessage(&Message);
}
}
return 0;
}
I was expecting the title bar to be something like 'आप'
I am extending an old console application. Trying to add a window( for an animation ). Are able to display first image, but unable to update the window with later images. Have created a minimum application to demonstrate the problem. In this app I have a red window that should change at each update of the window( it is not ). What am I doing wrong ?
#include "pch.h"
#include <iostream>
#include <Windows.h>
using namespace std;
HWND hWindow;
LRESULT __stdcall MyWindowProcedure(HWND hWnd, unsigned int msg, WPARAM wp, LPARAM lp)
{
PAINTSTRUCT ps;
HDC hdc;
HBITMAP hBitmap;
VOID * pvBits;
RGBQUAD *bmiColors;
static int j = 128;
HBITMAP hOldBmp;
BITMAPINFO MyBitmap;
BOOL qRetBlit;
switch (msg)
{
case WM_DESTROY:
std::cout << "\ndestroying window\n";
PostQuitMessage(0);
return 0L;
case WM_LBUTTONDOWN:
std::cout << "\nmouse left button down at (" << LOWORD(lp)
<< ',' << HIWORD(lp) << ")\n";
// fall thru
case WM_PAINT:
hdc = BeginPaint(hWnd, &ps);
#if 1
// Create a device context that is compatible with the window
HDC hLocalDC;
hLocalDC = ::CreateCompatibleDC(hdc);
// Verify that the device context was created
if (hLocalDC == NULL) {
printf("CreateCompatibleDC Failed\n");
// return false;
break;
}
MyBitmap.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
MyBitmap.bmiHeader.biWidth = 256;
MyBitmap.bmiHeader.biHeight = -256;
MyBitmap.bmiHeader.biPlanes = 1;
MyBitmap.bmiHeader.biBitCount = 32;
MyBitmap.bmiHeader.biCompression = BI_RGB;
MyBitmap.bmiHeader.biSizeImage = 256 * 256 * 4;
MyBitmap.bmiHeader.biYPelsPerMeter = 1000;
MyBitmap.bmiHeader.biXPelsPerMeter = 1000;
MyBitmap.bmiHeader.biClrUsed = 0;
MyBitmap.bmiHeader.biClrImportant = 0;
hBitmap = CreateDIBSection(NULL, &MyBitmap, DIB_RGB_COLORS, &pvBits, NULL, NULL);
bmiColors = (RGBQUAD*)pvBits;
// note: BGR
for (int i = 0; i < 256 * 256; i++)
{
bmiColors[i].rgbBlue = 0;
bmiColors[i].rgbGreen = 0;
bmiColors[i].rgbRed = j % 256;
bmiColors[i].rgbReserved = 255;
}
j += 10;
bmiColors[1000].rgbRed;
// Select the bitmap into the device context
hOldBmp = (HBITMAP)::SelectObject(hLocalDC, hBitmap);
if (hOldBmp == NULL) {
printf("SelectObject Failed");
// return false;
break;
}
// Blit the dc which holds the bitmap onto the window's dc
qRetBlit = ::BitBlt(hdc, 0, 0, 256, 256, hLocalDC, 0, 0, SRCCOPY);
if (!qRetBlit) {
printf("Blit Failed");
// return false;
break;
}
// Unitialize and deallocate resources
SelectObject(hLocalDC, hOldBmp);
DeleteDC(hLocalDC);
DeleteObject(hBitmap);
#endif
EndPaint(hWnd, &ps);
break;
default:
std::cout << '.';
break;
}
return DefWindowProc(hWnd, msg, wp, lp);
}
int main()
{
WNDCLASSEX wndclass = { sizeof(WNDCLASSEX), CS_DBLCLKS | CS_HREDRAW, MyWindowProcedure,
0, 0, GetModuleHandle(0), LoadIcon(0,IDI_APPLICATION),
LoadCursor(0,IDC_ARROW), HBRUSH(COLOR_WINDOW + 1),
0, L"myclass", LoadIcon(0,IDI_APPLICATION) };
if (RegisterClassEx(&wndclass))
{
hWindow = CreateWindowEx(0, L"myclass", L"myclass", WS_OVERLAPPEDWINDOW, 1200, 600, 256 + 15, 256 + 38, 0, 0, GetModuleHandle(0), 0);
ShowWindow(hWindow, SW_SHOWDEFAULT);
UpdateWindow(hWindow);
MSG msg;
byte bRet;
while ((bRet = GetMessage(&msg, hWindow, 0, 0)) != 0)
{
if (bRet == -1)
{
return 1;
}
else
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
}
}
As pointed out. You do not want to call WM_PAINT your self. Let the system handle it. So in WM_LBUTTONDOWN do:
case WM_LBUTTONDOWN:
std::cout << "\nmouse left button down at (" << LOWORD(lp)
<< ',' << HIWORD(lp) << ")\n";
InvalidateRect(hWnd, nullptr, FALSE);
return 0;
Do not fall through. Wnen you call RedrawWindow the window is invalidated and then needs to be repainted. I just tested this, the window lightens up on each click.
UPDATE:
Thanks to Remy Lebeau
Difference between InvalidateRect and RedrawWindow
And yes, it is better to let windows use its own schedule for this kind of stuff.
Here's my simple program:
#include "stdafx.h"
#include<Windows.h>
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
void initBackBuffer(HWND hwnd);
HDC hBackDC = NULL;
HBITMAP hBackBitmap = NULL;
const int WIDTH = 512;
const int HEIGHT = 512;
DWORD screenBuffer[WIDTH * HEIGHT];
void draw(HWND hwnd) {
HDC hWinDC = GetDC(hwnd);
SetBitmapBits(hBackBitmap, HEIGHT * WIDTH * sizeof(DWORD), (const void*)(screenBuffer));
BitBlt(hWinDC, 0, 0, WIDTH, HEIGHT, hBackDC, 0, 0, SRCCOPY);
ReleaseDC(hwnd, hWinDC);
}
int WINAPI wWinMain(HINSTANCE hInstace, HINSTANCE hPrevInstace, LPWSTR lpCmdLine, int nCmdShow) {
memset(screenBuffer, 0, sizeof(screenBuffer));
MSG msg = { 0 };
WNDCLASS wnd = { 0 };
wnd.lpfnWndProc = WndProc;
wnd.hInstance = hInstace;
wnd.lpszClassName = L"Window";
if (!RegisterClass(&wnd)) {
return 0;
}
HWND hwnd = CreateWindowEx(NULL, wnd.lpszClassName, L"Window",
WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, WIDTH, HEIGHT, NULL, NULL, hInstace, NULL);
if (!hwnd) {
return 0;
}
ShowWindow(hwnd, nCmdShow);
UpdateWindow(hwnd);
for (int i = 0; i <= 512; i++) {
screenBuffer[i * WIDTH + 0] = 0x00FF0000;
}
while (true) {
if(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
if (msg.message == WM_QUIT) {
break;
}
TranslateMessage(&msg);
DispatchMessage(&msg);
}
draw(hwnd);
}
return msg.wParam;
}
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam){
switch (msg){
case WM_CREATE:
initBackBuffer(hwnd);
break;
case WM_DESTROY:
DeleteDC(hBackDC);
DeleteObject(hBackBitmap);
PostQuitMessage(0);
break;
}
return DefWindowProc(hwnd, msg, wParam, lParam);
}
void initBackBuffer(HWND hwnd) {
HDC hWinDC = GetDC(hwnd);
hBackDC = CreateCompatibleDC(hWinDC);
hBackBitmap = CreateCompatibleBitmap(hWinDC, WIDTH, HEIGHT);
SetBitmapBits(hBackBitmap, HEIGHT * WIDTH * sizeof(DWORD), (const void*)(screenBuffer));
SelectObject(hBackDC, hBackBitmap);
ReleaseDC(hwnd, hWinDC);
}
The output is as expected.
I moved
const int WIDTH = 512;
const int HEIGHT = 512;
DWORD screenBuffer[WIDTH * HEIGHT];
into Global.h and I added #include "Global.h" in my main file.
Main File :
#include "stdafx.h"
#include<Windows.h>
#include "Global.h"
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
void initBackBuffer(HWND hwnd);
HDC hBackDC = NULL;
HBITMAP hBackBitmap = NULL;
void draw(HWND hwnd) {
HDC hWinDC = GetDC(hwnd);
SetBitmapBits(hBackBitmap, HEIGHT * WIDTH * sizeof(DWORD), (const void*)(screenBuffer));
BitBlt(hWinDC, 0, 0, WIDTH, HEIGHT, hBackDC, 0, 0, SRCCOPY);
ReleaseDC(hwnd, hWinDC);
}
int WINAPI wWinMain(HINSTANCE hInstace, HINSTANCE hPrevInstace, LPWSTR lpCmdLine, int nCmdShow) {
memset(screenBuffer, 0, sizeof(screenBuffer));
MSG msg = { 0 };
WNDCLASS wnd = { 0 };
wnd.lpfnWndProc = WndProc;
wnd.hInstance = hInstace;
wnd.lpszClassName = L"Window";
if (!RegisterClass(&wnd)) {
return 0;
}
HWND hwnd = CreateWindowEx(NULL, wnd.lpszClassName, L"Window",
WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, WIDTH, HEIGHT, NULL, NULL, hInstace, NULL);
if (!hwnd) {
return 0;
}
ShowWindow(hwnd, nCmdShow);
UpdateWindow(hwnd);
for (int i = 0; i <= 512; i++) {
screenBuffer[i * WIDTH + 0] = 0x00FF0000;
}
while (true) {
if(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
if (msg.message == WM_QUIT) {
break;
}
TranslateMessage(&msg);
DispatchMessage(&msg);
}
draw(hwnd);
}
return msg.wParam;
}
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam){
switch (msg){
case WM_CREATE:
initBackBuffer(hwnd);
break;
case WM_DESTROY:
DeleteDC(hBackDC);
DeleteObject(hBackBitmap);
PostQuitMessage(0);
break;
}
return DefWindowProc(hwnd, msg, wParam, lParam);
}
void initBackBuffer(HWND hwnd) {
HDC hWinDC = GetDC(hwnd);
hBackDC = CreateCompatibleDC(hWinDC);
hBackBitmap = CreateCompatibleBitmap(hWinDC, WIDTH, HEIGHT);
SetBitmapBits(hBackBitmap, HEIGHT * WIDTH * sizeof(DWORD), (const void*)(screenBuffer));
SelectObject(hBackDC, hBackBitmap);
ReleaseDC(hwnd, hWinDC);
}
Global.h
#pragma once
const int WIDTH = 512;
const int HEIGHT = 512;
DWORD screenBuffer[WIDTH * HEIGHT];
I get a erroneous white window.
I don't understand why this is happening because the compiler will anyway copy the contents of Global.h in to main file, so both variants should produce same results.
What is the cause of this problem ?
There is a bug here:
const int WIDTH = 512;
const int HEIGHT = 512;
DWORD screenBuffer[WIDTH * HEIGHT];
void foo()
{
for (int i = 0; i <= 512; i++) {
screenBuffer[i * WIDTH + 0] = 0x00FF0000;
}
}
This should be should be i < 512. Otherwise it overwrites a random memory location, this can result in an error in a different location, or no error if you are lucky. Debugger may report a nonsensical error, or no error at all. If screenBuffer was created on stack, debugger may give "heap corruption" error.
Consider using std::vector to avoid this problem in future.
vector<int> vec;
vec[vec.size()] = 0;//<- debug error
Side note: SetDIBitsToDevice or StretchDIBits will set bits directly:
void draw(HWND hwnd)
{
BITMAPINFO bi;
bi.bmiHeader.biSize = sizeof(bi.bmiHeader);
bi.bmiHeader.biBitCount = 32;
bi.bmiHeader.biWidth = WIDTH;
bi.bmiHeader.biHeight = HEIGHT;
bi.bmiHeader.biPlanes = 1;
bi.bmiHeader.biCompression = BI_RGB;
HDC hdc = GetDC(hwnd);
SetDIBitsToDevice(hdc, 0, 0, WIDTH, HEIGHT, 0, 0, 0, HEIGHT, screenBuffer,
&bi, DIB_RGB_COLORS);
ReleaseDC(hwnd, hdc);
}
In a short sample I generate a HwndRenderTarget, a Brush, a PathGeometry in this two lines are drawn both starting at the same Point. But in the rendered Frame they don't start at the same point but clearly intersect each other ( they are extended beyond the starting point)
Main.cpp
#include<Windows.h>
#include "Graphics.h"
Graphics* graphics;
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
case WM_DESTROY:
PostQuitMessage(0);
return 0;
//case WM_PAINT:
}
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE prevInstance, LPWSTR cmd, int nCMDShow)
{
WNDCLASSEX windowclass;
ZeroMemory(&windowclass, sizeof(WNDCLASSEX));
windowclass.cbSize = sizeof(WNDCLASSEX);
windowclass.hbrBackground = (HBRUSH)COLOR_WINDOW;
windowclass.hInstance = hInstance;
windowclass.lpfnWndProc = WindowProc;
windowclass.lpszClassName = "MainWindow";
windowclass.style = CS_HREDRAW | CS_VREDRAW;
RegisterClassEx(&windowclass);
RECT rect = { 0,0,564,564 };
AdjustWindowRectEx(&rect, WS_OVERLAPPEDWINDOW, false, WS_EX_OVERLAPPEDWINDOW);
HWND windowhandle = CreateWindowEx(WS_EX_OVERLAPPEDWINDOW,"MainWindow", "Intersection Test", WS_OVERLAPPEDWINDOW, 100, 100,
rect.right - rect.left, rect.bottom- rect.top, NULL, NULL, hInstance, 0);
if (!windowhandle) return -1;
graphics = new Graphics();
if (!graphics->Init(windowhandle))
{
delete graphics;
return -1;
}
ShowWindow(windowhandle, nCMDShow);
graphics->PrepareSpirale();
MSG msg;
msg
.message = WM_NULL;
while (msg.message != WM_QUIT) //
{
if (PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
{
DispatchMessage(&msg);
}
else
{
graphics->BeginDraw();
graphics->ClearScreen(1, 1, 1);
graphics->DrawGraphics();
graphics->EndDraw();
}
}
delete graphics;
return 0;
}
Graphics.h
#pragma once
#include <Windows.h>
#include<d2d1.h>
#include <math.h>
class Graphics
{
ID2D1Factory* factory;
ID2D1HwndRenderTarget* renderTarget;
ID2D1PathGeometry * BorderCCW;
ID2D1GeometrySink * pSink;
ID2D1SolidColorBrush *RedBrush;
public:
Graphics();
~Graphics();
bool Init(HWND windowHandle);
void BeginDraw() { renderTarget->BeginDraw(); }
void EndDraw() { renderTarget->EndDraw(); }
void PrepareSpirale();
void DrawGraphics();
void ClearScreen(float r, float g, float b );
};
Graphics.cpp
#include"Graphics.h"
Graphics::Graphics()
{
factory = NULL;
renderTarget = NULL;
pSink = NULL;
BorderCCW = NULL;
RedBrush = NULL;
}
Graphics::~Graphics()
{
if (factory) factory->Release();
if (renderTarget) renderTarget->Release();
}
bool Graphics::Init(HWND windowHandle)
{
HRESULT res = 0;
// Create renderTarget
if (SUCCEEDED(res))
{
res = D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED, &factory);
RECT rect;
GetClientRect(windowHandle, &rect);
D2D1_SIZE_U size = D2D1::SizeU(
rect.right - rect.left,
rect.bottom - rect.top
);
if (SUCCEEDED(res))
res = factory->CreateHwndRenderTarget(
D2D1::RenderTargetProperties(),
D2D1::HwndRenderTargetProperties(windowHandle, size),
&renderTarget);
FLOAT dpiX, dpiY;
factory->GetDesktopDpi(&dpiX, &dpiY);
// Create Other Resurces
if (SUCCEEDED(res))
{
// Brushes
res = renderTarget->CreateSolidColorBrush(
D2D1::ColorF(1.0f, 0.13f, 0.13f, 1.0f),
&RedBrush);
}
return true;
}
return false;
}
void Graphics::PrepareSpirale()
{
HRESULT res = 0;
if (SUCCEEDED(res))
{
res = factory->CreatePathGeometry(&BorderCCW);
if (SUCCEEDED(res))
{
res = BorderCCW->Open(&pSink);
D2D1_POINT_2F currentLocation = { 281.5f, 281.5f };
pSink->BeginFigure(currentLocation, D2D1_FIGURE_BEGIN_HOLLOW);
pSink->AddLine(D2D1::Point2F(132.5, 432.5));
pSink->EndFigure(D2D1_FIGURE_END_CLOSED);
pSink->BeginFigure(currentLocation, D2D1_FIGURE_BEGIN_HOLLOW);
pSink->AddLine(D2D1::Point2F(132+ 282.5f, 432.5));
pSink->EndFigure(D2D1_FIGURE_END_CLOSED);
}
//}
res = pSink->Close();
pSink->Release();
pSink = NULL;
}
}
void Graphics::DrawGraphics()
{
//renderTarget->SetAntialiasMode(D2D1_ANTIALIAS_MODE_ALIASED);
renderTarget->DrawGeometry(BorderCCW, RedBrush, 2.f);
}
void Graphics::ClearScreen(float r, float g, float b )
{
renderTarget->Clear(D2D1::ColorF(r, g, b));
}
Rendered Lines
As this is my first adventure into C++ any style comments are also most welcome, but them main question is to find an explaination for this strange phenomenon.
ATOM MyRegisterChildClass(void)
{
WNDCLASSEX wcex = {0};
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.lpfnWndProc = ChildProc;
wcex.hInstance = hInst;
wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 8);
wcex.lpszClassName = ChildClassName;
return RegisterClassEx(&wcex);
}
static HFONT newFont;
static HWND hChild[9];
unsigned char k[9] = {0};
char text[] = {' ', 'X', '0'};
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
int i;
static int sx, sy;
switch (message)
{
case WM_CREATE:
MyRegisterChildClass();
for(i = 0; i < 9; i++)
hChild[i] = CreateWindow(ChildClassName, NULL, WS_CHILD |
WS_DLGFRAME | WS_VISIBLE, 0, 0, 0, 0, hWnd, NULL, hInst, NULL);
break;
case WM_SIZE:
if(wParam == SIZE_MINIMIZED)
break;
sx = LOWORD(lParam)/3;
sy = HIWORD(lParam)/3;
if(newFont)
DeleteObject(newFont);
newFont = CreateFont(min(sx, sy), 0, 0, 0, FW_NORMAL, 0, 0, 0,
DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
DEFAULT_QUALITY, DEFAULT_PITCH | FF_DONTCARE, L"Arial");
for(i = 0; i < 9; i++)
{
MoveWindow(hChild[i], (i%3)*sx, (i/3)*sy, sx, sy, TRUE);
UpdateWindow(hChild[i]);
}
break;
case WM_COMMAND:
switch(LOWORD(wParam))
{
case ID_NEW:
for(i = 0; i < 9; i++)
{
k[i] = 0;
InvalidateRect(hChild[i], NULL, TRUE);
UpdateWindow(hChild[i]);
}
break;
case IDM_EXIT:
DestroyWindow(hWnd);
break;
case IDM_ABOUT:
DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
LRESULT CALLBACK ChildProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
PAINTSTRUCT ps;
HDC hDC;
RECT rt;
int s, i;
char *ch;
switch(message)
{
case WM_LBUTTONDOWN:
for(i = 0; hWnd != hChild[i]; i++)
;
if(k[i])
break;
else
k[i] = 1;
InvalidateRect(hWnd, NULL, TRUE);
UpdateWindow(hWnd);
srand(lParam);
for(i = s = 0; i < 9; i++)
if(k[i])
s++;
if(s == 9)
MessageBox(hWnd, L"...",L"...", MB_OK|MB_ICONQUESTION);
else
{
while(true)
{
s = rand()*9/(RAND_MAX+1);
if(k[s])
continue;
k[s] = 2;
InvalidateRect(hChild[s], NULL, TRUE);
UpdateWindow(hChild[s]);
break;
}
}
break;
case WM_PAINT:
for(i = 0; hWnd != hChild[i]; i++);
if(k[i])
{
ch = text+k[i];
hDC = BeginPaint(hWnd, &ps);
GetClientRect(hWnd, &rt);
SelectObject(hDC, newFont);
DrawTextA(hDC, ch, 1, &rt, DT_SINGLELINE | DT_CENTER | DT_VCENTER);
EndPaint(hWnd, &ps);
}
else
DefWindowProc(hWnd, message, wParam, lParam);
break;
default:
DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
I try to create a Tic-Tac-Toe game. Here is the code that I've written by hand (no standard code generated by Visual Studio included). I made 9 child windows. This code runs, but it doesn't show child windows and doesn't react when I push left mouse button. With the help of debugger I saw that messages WM_LBUTTONDOWN and WM_PAINT are never sent to ChildProc function.
What's wrong?
for(i = 0; i < 9; i++)
hChild[i] = CreateWindow(ChildClassName, NULL, WS_CHILD |
WS_DLGFRAME | WS_VISIBLE, 0, 0, 0, 0, hWnd, NULL, hInst, NULL);
You are making a traditional mistake, you are blindly hoping that winapi functions will succeed. That's idle hope, CreateWindow() fails and returns NULL. Something you could also see with the debugger, you'll see the hChild array contain nothing but nulls. Always write defensive code, at the absolute minimum use assert() to backup your assumptions:
for(i = 0; i < 9; i++) {
hChild[i] = CreateWindow(ChildClassName, ...);
assert(hChild[i]);
}
Lots of other places in your code where you should do this. You'll now have to trouble diagnosing failure.
The actual bug is located in ChildProc():
default:
DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
Or in other words, it always return 0. That's not okay, you should only return that value when you processed the message. You didn't process every message. Again use the debugger and set a breakpoint on the switch() statement in ChildProc. You'll see the first message being improperly handled, WM_NCCREATE. Which requires you to return TRUE to continue creation of the window. You don't, you return FALSE. So that's a quick end to the window getting created. You must return the value of DefWindowProc(). Fix:
default:
return DefWindowProc(hWnd, message, wParam, lParam);