Member modified by method reverts after it exits - oop

I have a window (Windows), and my wndProc is basically the same as the one on the windows guides. However, even though WM_CLOSE gets passed (and I can use if(msg == WM_CLOSE)), I can't seem to set my shouldClose flag. I've confirmed that I still get the event within my processMessage method. So my question is this: what is going on, and how can I make it work?
Edit: I tried storing the window data as a struct instead of a class, and everything works just fine. Ie. All I changed was the type of the class, and a few errors.
class Win32Window {
this(wstring title, int width, int height) {
immutable wstring className = "glass_def_class_name\0";
auto hInstance = GetModuleHandle(null);
WNDCLASSW wc;
wc.lpfnWndProc = &windowProc;
wc.hInstance = hInstance;
wc.lpszClassName = &className[0];
RegisterClassW(&wc);
handle = CreateWindowExW(
0,
&className[0],
&title[0],
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT,
width, height,
null, null,
hInstance,
cast(void*) this);
ShowWindow(handle, SW_NORMAL);
}
~this() {
DestroyWindow(handle);
}
void processEvents() {
MSG msg;
while (PeekMessage(&msg, handle, 0, 0, PM_REMOVE)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
bool shouldClose;
HWND handle;
private:
LRESULT processMessage(UINT msg, WPARAM wp, LPARAM lp) nothrow {
switch (msg) {
case WM_CLOSE:
shouldClose = true;
return 0;
default:
return DefWindowProc(handle, msg, wp, lp);
}
}
}
private extern (Windows) LRESULT windowProc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp) nothrow {
Win32Window window;
if (msg == WM_CREATE) {
CREATESTRUCT* create = cast(CREATESTRUCT*) lp;
window = cast(Win32Window*) create.lpCreateParams;
SetWindowLongPtr(hwnd, GWLP_USERDATA, cast(LONG_PTR) create.lpCreateParams);
window.handle = hwnd;
}
else {
LONG_PTR ptr = GetWindowLongPtr(hwnd, GWLP_USERDATA);
window = cast(Win32Window* ptr);
}
if (window)
return window.processMessage(msg, wp, lp);
else
return DefWindowProc(hwnd, msg, wp, lp);
}
void main()
{
auto window = new Win32Window("test", 1280, 720);
while(window.shouldClose == false) {
window.processEvents();
}
window.destroy();
}

Member modified by method reverts after it exits
this was when you worked with local copy of object, and make modification to this local copy, but not really to object. I not view another explanations
inside windowProc you do next Win32Window window = *(cast(Win32Window*) ptr); - so you make local copy of your initial object state in windowProc and then do all modification to this local copy - of course all it lost when you exit from windowProc correct code must be next:
private LRESULT windowProc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp) nothrow {
Win32Window* window;
if (msg == WM_NCCREATE) {
CREATESTRUCT* create = (CREATESTRUCT*) lp;
window = (Win32Window*) create.lpCreateParams;
SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR) create.lpCreateParams);
window.handle = hwnd;
}
else {
window = (Win32Window*)GetWindowLongPtr(hwnd, GWLP_USERDATA);
}
return window ? window->processMessage(msg, wp, lp) : DefWindowProc(hwnd, msg, wp, lp);
}

It turns out that you can't actually cast a pointer directly to a reference. An intermediary is necessary (or something to that effect). Thus, the winProc should look something like this:
private extern (Windows) LRESULT windowProc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp) nothrow {
Win32Window window;
if (msg == WM_NCCREATE) {
auto create = cast(CREATESTRUCT*) lp;
window = cast(Win32Window) (cast(void*) create.lpCreateParams);
window.handle = hwnd;
SetWindowLongPtr(hwnd, GWLP_USERDATA, cast(LONG_PTR) create.lpCreateParams);
}
else {
window = cast(Win32Window) (cast(void*) GetWindowLongPtr(hwnd, GWLP_USERDATA));
}
return window ? window.processMessage(msg, wp, lp) : DefWindowProc(hwnd, msg, wp, lp);
}
Note the extra cast(void*) before create.lpCreateParams and GetWindowLongPtr(hwnd, GWLP_USERDATA). I'm not entirely sure why this works as opposed to my original code, but it seems to work, and I'll do some more investigating when I have the time.

Related

Why does my screen starts blinking when I toggle the full screen state?

I'm trying to implement full screen support on my Direct3D11 application, but I've been having a issue with this. I'm using the ALT+ENTER key combination that makes the IDXGISwapChain change the target window to full screen and back. But when I go into full screen my back buffer starts blinking between the color that I have set on the call to ID3D11DeviceContext::ClearRenderTargetView to black.
I also have code in the WinProc function of my window, that when it receives the WM_SIZE message, this code is executed.
If I don't use this code to resize the buffers, the blinking doesn't happen for some reason.
If I call ID3D11DeviceContext::ClearRenderTargetView once after creating the new swap chain, and again after calling IDXGISwapChain::Present, the blinking also doesn't happen.
It's a bit confusing, but I have a theory that maybe, when I go to full screen mode and call IDXGISwapChain::ResizeBuffers it somehow makes my swap chain have more than one buffer, and when I call IDXGISwapChain::Present it rotates to the next buffer, which is on the default color black.
Note that I have also tried to call IDXGISwapChain::SetFullscreenState, but the issue persists.
My code is too big to paste here, so I took the code from this tutorial and changed it a bit to show the behaviour I'm describing:
#include <windows.h>
#include <d3d11.h>
#pragma comment (lib, "d3d11.lib")
#define SCREEN_WIDTH 800
#define SCREEN_HEIGHT 600
// global declarations
IDXGISwapChain* swapchain;
ID3D11Device* dev;
ID3D11DeviceContext* devcon;
ID3D11RenderTargetView* backbuffer;
void InitD3D(HWND hWnd);
void RenderFrame(void);
void CleanD3D(void);
LRESULT CALLBACK WindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
int main()
{
HWND hWnd;
WNDCLASSEX wc;
ZeroMemory(&wc, sizeof(WNDCLASSEX));
wc.cbSize = sizeof(WNDCLASSEX);
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = WindowProc;
wc.hInstance = GetModuleHandle(nullptr);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.lpszClassName = L"WindowClass";
RegisterClassEx(&wc);
RECT wr = { 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT };
AdjustWindowRect(&wr, WS_OVERLAPPEDWINDOW, FALSE);
hWnd = CreateWindowEx(NULL,
L"WindowClass",
L"Our First Direct3D Program",
WS_OVERLAPPEDWINDOW,
300,
300,
wr.right - wr.left,
wr.bottom - wr.top,
NULL,
NULL,
GetModuleHandle(nullptr),
NULL);
ShowWindow(hWnd, SW_SHOW);
InitD3D(hWnd);
MSG msg;
while (TRUE)
{
if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
if (msg.message == WM_QUIT)
break;
}
RenderFrame();
}
CleanD3D();
return msg.wParam;
}
// this is the main message handler for the program
LRESULT CALLBACK WindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_DESTROY:
{
PostQuitMessage(0);
return 0;
} break;
case WM_SIZE: {
if (swapchain)
{
devcon->OMSetRenderTargets(0, 0, 0);
backbuffer->Release();
HRESULT hr;
hr = swapchain->ResizeBuffers(0, 0, 0, DXGI_FORMAT_UNKNOWN, 0);
ID3D11Texture2D* pBuffer;
hr = swapchain->GetBuffer(0, __uuidof(ID3D11Texture2D),
(void**)&pBuffer);
hr = dev->CreateRenderTargetView(pBuffer, NULL,
&backbuffer);
pBuffer->Release();
devcon->OMSetRenderTargets(1, &backbuffer, NULL);
float fColor[] = { 0.0f, 0.2f, 0.4f, 1.0f };
devcon->ClearRenderTargetView(backbuffer, fColor);
DXGI_SWAP_CHAIN_DESC Desc;
ZeroMemory(&Desc, sizeof(DXGI_SWAP_CHAIN_DESC));
swapchain->GetDesc(&Desc);
D3D11_VIEWPORT vp;
vp.Width = Desc.BufferDesc.Width;
vp.Height = Desc.BufferDesc.Height;
vp.MinDepth = 0.0f;
vp.MaxDepth = 1.0f;
vp.TopLeftX = 0;
vp.TopLeftY = 0;
devcon->RSSetViewports(1, &vp);
}
return 1;
}
}
return DefWindowProc(hWnd, message, wParam, lParam);
}
void InitD3D(HWND hWnd)
{
DXGI_SWAP_CHAIN_DESC scd;
ZeroMemory(&scd, sizeof(DXGI_SWAP_CHAIN_DESC));
scd.BufferCount = 1;
scd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
scd.BufferDesc.Width = SCREEN_WIDTH;
scd.BufferDesc.Height = SCREEN_HEIGHT;
scd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
scd.OutputWindow = hWnd;
scd.SampleDesc.Count = 1;
scd.Windowed = TRUE;
scd.Flags = 0;
D3D11CreateDeviceAndSwapChain(NULL,
D3D_DRIVER_TYPE_HARDWARE,
NULL,
NULL,
NULL,
NULL,
D3D11_SDK_VERSION,
&scd,
&swapchain,
&dev,
NULL,
&devcon);
ID3D11Texture2D* pBackBuffer;
swapchain->GetBuffer(0, __uuidof(ID3D11Texture2D), (LPVOID*)&pBackBuffer);
dev->CreateRenderTargetView(pBackBuffer, NULL, &backbuffer);
pBackBuffer->Release();
devcon->OMSetRenderTargets(1, &backbuffer, NULL);
float fColor[] = { 0.0f, 0.2f, 0.4f, 1.0f };
devcon->ClearRenderTargetView(backbuffer, fColor);
D3D11_VIEWPORT viewport;
ZeroMemory(&viewport, sizeof(D3D11_VIEWPORT));
viewport.TopLeftX = 0;
viewport.TopLeftY = 0;
viewport.Width = SCREEN_WIDTH;
viewport.Height = SCREEN_HEIGHT;
devcon->RSSetViewports(1, &viewport);
}
void RenderFrame(void)
{
swapchain->Present(1, 0);
}
void CleanD3D(void)
{
swapchain->SetFullscreenState(FALSE, NULL);
swapchain->Release();
backbuffer->Release();
dev->Release();
devcon->Release();
After messing a bit with the code, I've noticed that when the SampleDesc::Count variable from the DXGI_SWAP_CHAIN_DESC is not equal to 1, the blinking also doesn't happen.

Getting 0xC000041D crash in simple directX12 application

I have a simple Window class and I use a function for WM_PAINT that clears the render target view and presents the final image.so there's not much into it but I get a crash on line FLOAT clearColor[] = { 0.2f, 0.4f, 0.6f, 1.0f }; that says:0xC000041D: An unhandled exception was encountered during a user callback.
here's the window class:
class Win32Window : public WindowsWindow
{
public:
Win32Window(const WindowProps& props);
virtual ~Win32Window();
void OnUpdate() override;
unsigned int GetWidth() const override { return m_Data.Width; }
unsigned int GetHeight() const override { return m_Data.Height; }
void SetEventCallback(const EventCallbackFn& callback) override { m_Data.EventCallback = callback; }
void SetVSync(bool enabled) override;
bool IsVSync() const override;
virtual void* GetNativeWindow() const override { return m_Window; }
private:
HWND m_Window;
RECT m_WindowRect;
HINSTANCE m_hInst;
LRESULT CALLBACK MainWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);
static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);
virtual void Init(const WindowProps& props);
virtual void Shutdown();
};
the definitions:
Win32Window::Win32Window(const WindowProps& props)
{
HZ_PROFILE_FUNCTION();
Init(props);
}
Win32Window::~Win32Window()
{
HZ_PROFILE_FUNCTION();
Shutdown();
}
void Win32Window::Init(const WindowProps& props)
{
m_hInst = GetModuleHandle(0);
m_Data.WideCharacterTitle = props.WideCharacterTitle;
m_Data.Width = props.Width;
m_Data.Height = props.Height;
HZ_CORE_INFO("Creating window {0} ({1}, {2})",props.StringTypeTitle, props.Width, props.Height);
WNDCLASSEXW windowClass = {};
windowClass.cbSize = sizeof(WNDCLASSEX);
windowClass.style = CS_HREDRAW | CS_VREDRAW;
windowClass.lpfnWndProc = &WndProc;
windowClass.cbClsExtra = 0;
windowClass.cbWndExtra = 0;
windowClass.hInstance = m_hInst;
windowClass.hIcon = ::LoadIcon(m_hInst, NULL);
windowClass.hCursor = ::LoadCursor(NULL, IDC_ARROW);
windowClass.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
windowClass.lpszMenuName = NULL;
windowClass.lpszClassName = m_Data.WideCharacterTitle;
windowClass.hIconSm = ::LoadIcon(m_hInst, NULL);
static ATOM atom = ::RegisterClassExW(&windowClass);
assert(atom > 0);
int screenWidth = ::GetSystemMetrics(SM_CXSCREEN);
int screenHeight = ::GetSystemMetrics(SM_CYSCREEN);
RECT windowRect = { 0, 0, static_cast<LONG>(m_Data.Width), static_cast<LONG>(m_Data.Height) };
::AdjustWindowRect(&windowRect, WS_OVERLAPPEDWINDOW, FALSE);
int windowWidth = windowRect.right - windowRect.left;
int windowHeight = windowRect.bottom - windowRect.top;
int windowX = std::max<int>(0, (screenWidth - windowWidth) / 2);
int windowY = std::max<int>(0, (screenHeight - windowHeight) / 2);
m_Window = ::CreateWindowExW(NULL, m_Data.WideCharacterTitle, m_Data.WideCharacterTitle, WS_OVERLAPPEDWINDOW, windowX, windowY, windowWidth, windowHeight, NULL, NULL, m_hInst, this);
assert(m_Window && "Failed to create window");
m_Context = GraphicsContext::Create(m_Window);
m_Context->Init();
::ShowWindow(m_Window, SW_SHOW);
::UpdateWindow(m_Window);
}
LRESULT Win32Window::MainWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_PAINT:
m_Context->RenderWindow();
break;
case WM_DESTROY:
::PostQuitMessage(0);
break;
default:
return ::DefWindowProcW(hwnd, message, wParam, lParam);
}
}
LRESULT Win32Window::WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
Win32Window* instance;
if (message == WM_CREATE)
{
instance = (Win32Window*)(((LPCREATESTRUCT)lParam)->lpCreateParams);
instance->m_Window = hwnd;
SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)instance);
}
else
{
instance = (Win32Window*)GetWindowLongPtr(hwnd, GWLP_USERDATA);
}
if (instance)
{
return instance->MainWndProc(hwnd, message, wParam, lParam);
}
return ::DefWindowProcW(hwnd, message, wParam, lParam);
}
void Win32Window::Shutdown()
{
DestroyWindow(m_Window);
m_Window = nullptr;
}
void Win32Window::OnUpdate()
{
m_Context->Update();
}
void Win32Window::SetVSync(bool enabled)
{
m_Data.VSync = enabled;
}
bool Win32Window::IsVSync() const
{
return m_Data.VSync;
}
m_Context is coming from the parent class, And also WindowProps that has some data for initializing the window .definition of m_Context->RenderWindow():
m_CommnadQueue = D3D12Core::Get().GetCommandQueue(D3D12_COMMAND_LIST_TYPE_DIRECT);
auto m_CommandList = m_CommnadQueue->GetCommandList();
m_CurrentBackBufferIndex = m_SwapChain->GetCurrentBackBufferIndex();
auto m_BackBuffer = D3D12Core::Get().m_BackBuffers[m_CurrentBackBufferIndex];
auto m_RTVDescriptorSize = D3D12Core::Get().GetDevice()->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_RTV);
{
CD3DX12_RESOURCE_BARRIER barrier = CD3DX12_RESOURCE_BARRIER::Transition(m_BackBuffer.Get(), D3D12_RESOURCE_STATE_PRESENT, D3D12_RESOURCE_STATE_RENDER_TARGET);
m_CommandList->ResourceBarrier(1, &barrier);
FLOAT clearColor[] = { 0.2f, 0.4f, 0.6f, 1.0f };
CD3DX12_CPU_DESCRIPTOR_HANDLE rtv(m_RTVDescriptorHeap->GetCPUDescriptorHandleForHeapStart(), m_CurrentBackBufferIndex, m_RTVDescriptorSize);
m_CommandList->ClearRenderTargetView(rtv, clearColor, 0, nullptr);
}
{
CD3DX12_RESOURCE_BARRIER barrier = CD3DX12_RESOURCE_BARRIER::Transition(m_BackBuffer.Get(), D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_PRESENT);
m_CommandList->ResourceBarrier(1, &barrier);
m_CommandList->Close();
ID3D12CommandList* const commandLists[] =
{
m_CommandList.Get()
};
D3D12Core::Get().m_FenceValues[m_CurrentBackBufferIndex] = m_CommnadQueue->ExecuteCommandList(m_CommandList);
UINT syncInterval = m_VSync;
UINT presentFlags = m_TearingSupport && !m_VSync ? DXGI_PRESENT_ALLOW_TEARING : 0;
m_SwapChain->Present(syncInterval, presentFlags);
m_CommnadQueue->WaitForFenceValue(D3D12Core::Get().m_FenceValues[m_CurrentBackBufferIndex]);
}
If there is anything else that I should put in question pls tell me.You can shout at me for my dumbness if you want to but help me pls,thx.
EDIT:
debug layer:
#ifdef _DEBUG
ComPtr<ID3D12Debug> debugInterface;
if (SUCCEEDED(D3D12GetDebugInterface(IID_PPV_ARGS(&debugInterface))))
{
debugInterface->EnableDebugLayer();
}
#endif
WaitForFenceValue after every Present is an extremely slow way to render in DirectX 12. You should generally cue 2-3 frames to the GPU rather than forcing the GPU to stall every frame. It is also highly problematic to have your WndProc block, which is what happens here. Your WndProc should always complete quickly as many hundreds of messages are processed a second for most applications.
Usually Direct3D rendering is not done within WM_PAINT. For a number of examples of common render loops, see GitHub.

Visual-C++ Win32 C++ Application. How do I print variables to the main screen?

I have tried C++11 methods and C methods to convert the string before printing and they either: Returned a string of the same characters or didn't print anything at all. I just wanted to know 3 things really: Is there a fault in the online tutorials and examples? Is there a fault in my interpretation and implementation of the code? What could I do differently to get this working?
// Yu-Gi-Oh! LP Calculator.cpp : Defines the entry point for the application.
//
#include "stdafx.h"
#include "Yu-Gi-Oh! LP Calculator.h"
#define MAX_LOADSTRING 100
#define LP UINT
#define ID CHAR
// Global Variables:
HINSTANCE hInst; // current instance
WCHAR szTitle[MAX_LOADSTRING]; // The title bar text
WCHAR szWindowClass[MAX_LOADSTRING]; // the main window class name
// Global Life Point Variables
struct Player {
LP Lp;
ID Name[MAX_LOADSTRING];
};
struct Player1, Player2, Player3, Player4;
// Forward declarations of functions included in this code module:
BOOL InitInstance(HINSTANCE, int);
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
int APIENTRY wWinMain(_In_ HINSTANCE hInstance,
_In_opt_ HINSTANCE hPrevInstance,
_In_ LPWSTR lpCmdLine,
_In_ int nCmdShow)
{
UNREFERENCED_PARAMETER(hPrevInstance);
UNREFERENCED_PARAMETER(lpCmdLine);
// TEMP: Remove these initializations when preferences are implemented.
Player1.Lp = 8000;
Player2.Lp = 8000;
Player3.Lp = 8000;
Player4.Lp = 8000;
LoadStringA(hInstance, (UINT)"John\0", Player1.Name, MAX_LOADSTRING);
LoadStringA(hInstance, (UINT)"Phil\0", Player2.Name, MAX_LOADSTRING);
LoadStringA(hInstance, NULL, Player3.Name, MAX_LOADSTRING);
LoadStringA(hInstance, NULL, Player4.Name, MAX_LOADSTRING);
// END TEMP
// TODO: Place code here.
// TODO: Load preferences file.
// Initialize global strings
LoadStringW(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
LoadStringW(hInstance, IDC_YUGIOHLPCALCULATOR, szWindowClass, MAX_LOADSTRING);
WNDCLASSEXW wcex;
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = WndProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = hInstance;
wcex.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_YUGIOHLPCALCULATOR));
wcex.hCursor = LoadCursor(nullptr, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
wcex.lpszMenuName = MAKEINTRESOURCEW(IDC_YUGIOHLPCALCULATOR);
wcex.lpszClassName = szWindowClass;
wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));
RegisterClassExW(&wcex);
// Perform application initialization:
if (!InitInstance (hInstance, nCmdShow))
{
return FALSE;
}
HACCEL hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_YUGIOHLPCALCULATOR));
MSG msg;
// Main message loop:
while (GetMessage(&msg, nullptr, 0, 0))
{
if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
return (int) msg.wParam;
}
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
hInst = hInstance; // Store instance handle in our global variable
HWND hWnd = CreateWindowW(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, nullptr, nullptr, hInstance, nullptr);
if (!hWnd)
{
return FALSE;
}
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
return TRUE;
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_CREATE:
break;
case WM_COMMAND:
{
int wmId = LOWORD(wParam);
// Parse the menu selections:
switch (wmId)
{
case IDM_EXIT:
DestroyWindow(hWnd);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
}
break;
case WM_PAINT:
{
PAINTSTRUCT ps;
RECT rect;
HDC hdc = BeginPaint(hWnd, &ps);
// TODO: Add any drawing code that uses hdc here...
GetClientRect(hWnd, &rect);
CHAR b[] = { NULL };
sprintf((char* const)&b, "%s", Player1.Name);
DrawTextA(hdc, b, ARRAYSIZE(b), &rect, DT_SINGLELINE | DT_CENTER | DT_TOP);
//TextOutA(hdc, rect.left, rect.top, s, ARRAYSIZE(Player1.Name));
SelectClipPath(hdc, RGN_AND);
EndPaint(hWnd, &ps);
}
break;
case WM_DESTROY:
case WM_CLOSE:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
By changing:
#define ID CHAR
to:
#define ID LPCSTR
and changing:
ID Name[MAX_LOADSTRING];
to:
ID Name;
I made Player1.Name compatible with the type of the 2nd parameter of the DrawTextA function.
I then changed the 3rd parameter to -1 instead of using ARRAYSIZE(). This means that the function checks the size of the string itself? So the function is called like this:
DrawTextA(hdc, Player1.Name, -1, &rect, DT_SINGLELINE | DT_CENTER | DT_TOP);
All I needed to do then was Initialize the string with my values instead of using LoadStringA so I changed:
LoadStringA(hInstance, (UINT)"John\0", Player1.Name, MAX_LOADSTRING);
to:
Player1.Name = "John";

CreateWindow never triggers WM_CREATE

I have the following bit of code;
#include <windows.h>
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam){
printf("%d\n", message);
return 0;
}
int CALLBACK WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow){
WNDCLASSEX wc = {0};
wc.cbSize = sizeof(WNDCLASSEX);
wc.lpfnWndProc = WndProc;
wc.hInstance = hInstance;
wc.hbrBackground = (HBRUSH)(COLOR_BACKGROUND);
wc.lpszClassName = "oglversionchecksample";
wc.style = CS_OWNDC;
if(!RegisterClassEx(&wc))
return 1;
CreateWindow(wc.lpszClassName, "openglversioncheck", WS_OVERLAPPED, 0, 0, 640, 480, 0, 0, hInstance, 0);
return 0;
}
Calling CreateWindow() triggers message numbers 36 WM_GETMINMAXINFO, 129 WM_NCCREATE, and then 130 WM_NCDESTROY, but message number 1 WM_CREATE is never triggered like it's supposed to be.
What am I doing wrong that's causing WM_CREATE to not be triggered?
It doesn't trigger any message, because message loop is not called yet.
You have to put this after CreateWindow
MSG msg;
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
Also, WndProc should not simply return zero. It should return the following:
return DefWindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
Visual Studio or other IDE's can create C++ -> Win32 project basic project, it sets up all the code.
The created window has no time to receive the messages, it is closed immediately. You should call GetMessage in loop to keep the window alive.
// Step 3: The Message Loop
while(GetMessage(&Msg, NULL, 0, 0) > 0)
{
TranslateMessage(&Msg);
DispatchMessage(&Msg);
}
return Msg.wParam;
See this example: http://www.winprog.org/tutorial/simple_window.html

Window Subclassing terminates the external application

I am trying to subclass the menu of an external application. I am using the SetWindowLong function to subclass the Windows Procedure, it works well, but after doing what I want, it terminates the application, I dont know why.
This is the function I inject:
DWORD __stdcall AddNewMenuItem(){
HWND hwndAna = NULL;
HMENU hMenu = NULL;
hwndAna = FindWindowA("NameOfTheMainWindow,NULL);
if(hwndAna != INVALID_HANDLE_VALUE){
hMenu = GetMenu(hwndAna);
if(hMenu != NULL){
HMENU hMenuFile = CreatePopupMenu();
AppendMenu(hMenuFile, MF_STRING , (UINT_PTR)ID_Load , L"Show Info");
AppendMenu(hMenuFile, MF_STRING , (UINT_PTR)ID_VWS , L"Go to Site");
AppendMenu(hMenu, MF_POPUP, (UINT_PTR)hMenuFile, L"Site");
DrawMenuBar(hwndAna);
OriginalProcedure = SetWindowLongA(hwndAna, GWL_WNDPROC, (LONG)MyProc);
return 1;
}
}
return 0;
}
And this is the My own Windows Procedure:
LRESULT APIENTRY MyProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam){
switch(iMsg)
{
case WM_COMMAND:
switch LOWORD(wParam)
{
case ID_Load:
MessageBoxA(NULL,"this is info", "Information!", MB_OK|MB_ICONINFORMATION);
break;
case ID_VWS:
ShellExecute(NULL, L"Open", L"http://www.gotowebsite.com/", NULL, NULL, SW_SHOWNORMAL);
break;
}
break;
}
return CallWindowProc((WNDPROC)OriginalProcedure, hwnd, iMsg, wParam, lParam);
}
And these are the IDs:
#define ID_VWS 0x8801
#define ID_Load 0x8802
All codes react to the messages, I mean it appends menu successfully, when I click the submenus it shows messagebox etc, but after this, it terminates the application. Somehow it returns WM_CLOSE message after ID messages and I cant manage it. I appreciate your help.