Related
I built a simplest progress bar which shows the progress of my png frame generation. Here is the process
BOOL myProc(HWND hwndParent, HINSTANCE hInst) {
RECT rcClient;
int cyVScroll;
HWND hwndPB;
DWORD cb;
GetClientRect(hwndParent, &rcClient);
cyVScroll = GetSystemMetrics(SM_CYVSCROLL);
hwndPB = CreateWindowEx(0, PROGRESS_CLASS, (LPTSTR) NULL,
WS_CHILD | WS_VISIBLE, rcClient.left,
rcClient.bottom - cyVScroll,
rcClient.right, cyVScroll,
hwndParent, (HMENU) 0, hInst, NULL);
int N = lastFrame;
SendMessage(hwndPB, PBM_SETRANGE, 0, MAKELPARAM(0, N));
SendMessage(hwndPB, PBM_SETSTEP, (WPARAM)1, 0);
for (int i = 0; i < N + 1; i++) {
int frame = create_pngInt(i);
SendMessage(hwndPB, PBM_STEPIT, 0, 0);
}
DestroyWindow(hwndPB);
DestroyWindow(hwndParent);
return TRUE;
}
I want my window to host just this progress bar. When the loop in myProc is done, the host window should be destroyed.
int WINAPI WinMain(HINSTANCE hInst, HINSTANCE PrevInst, LPSTR args, int ncmdshow) {
WNDCLASSW wc = { 0 };
wc.hbrBackground = (HBRUSH)COLOR_WINDOW;
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hInstance = hInst;
wc.lpszClassName = L"GenPng";
wc.lpfnWndProc = WindowProcedure;
wc.hbrBackground = CreateSolidBrush(0x00171c00);
wc.hIcon = hIcon;
if (!RegisterClassW(&wc))
return -1;
hMainWindow = CreateWindowW(L"GenPng", L"Generating pngs", WS_VISIBLE | WS_OVERLAPPEDWINDOW,
200,
100, 300, 58, NULL, NULL, NULL, NULL);
std::thread q(myProc, hMainWindow, hInst);
MSG msg = { 0 };
while (GetMessage(&msg, NULL, NULL, NULL))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return 0;
}
However, the window hMainWindow is not destroyed (!) and the process myProc doesn't terminate by itself (after the loop in myProc is comlete).
It seems I don't understand something important.
I checked. If I don't create a separate thread but just run myProc in WinMain, the window hosting the progress bar destroyed after myProc returns. And this is precisely what I want. But the progress bar freezes after several seconds(. That is why I need a separate thread.
Following your remarks I modified the code like this:
int WINAPI WinMain(HINSTANCE hInst, HINSTANCE PrevInst, LPSTR args, int ncmdshow) {
RECT rect;
WNDCLASSW wc = { 0 };
wc.hbrBackground = (HBRUSH)COLOR_WINDOW;
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hInstance = hInst;
wc.lpszClassName = L"GenPng";
wc.lpfnWndProc = WindowProcedure;
wc.hbrBackground = CreateSolidBrush(0x00171c00);
wc.hIcon = hIcon;
if (!RegisterClassW(&wc))
return -1;
hMainWindow = CreateWindowW(L"GenPng", L"Generating pngs", WS_VISIBLE | WS_OVERLAPPEDWINDOW,
200,
100, 300, 58, NULL, NULL, NULL, NULL);
SetWindowPos(hMainWindow, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
RECT rcClient;
int cyVScroll;
HWND hwndPB;
DWORD cb;
GetClientRect(hMainWindow, &rcClient);
cyVScroll = GetSystemMetrics(SM_CYVSCROLL);
hwndPB = CreateWindowEx(0, PROGRESS_CLASS, (LPTSTR)NULL,
WS_CHILD | WS_VISIBLE, rcClient.left,
rcClient.bottom - cyVScroll,
rcClient.right, cyVScroll,
hMainWindow, (HMENU)0, hInst, NULL);
int N = lastFrame;
SendMessage(hwndPB, PBM_SETRANGE, 0, MAKELPARAM(0, N));
SendMessage(hwndPB, PBM_SETSTEP, (WPARAM)1, 0);
std::thread q(myProc, hMainWindow, hInst, hwndPB);
MSG msg = { 0 };
while (GetMessage(&msg, hMainWindow, NULL, NULL))
{
if (msg.message == WM_QUIT) {
DestroyWindow(hMainWindow);
}
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return 0;
}
However, I know that I haven't handled WM_QUIT event properly, and the whole thing is not destroyed. Could you please, elaborate just a little bit more and if the rest of the code is ok?
The thread which calls CreateWindowEx needs to be the one executing the GetMessage loop.
It won't get destroyed, as there is nothing processing the events and messages for it, including the WM_DESTROY message.
Keep your window creation in your main thread (and that thread only!), and use only PostMessage / SendMessage to send update events and finally a destroy message to the window owned by the main thread.
Ultimately handle a WM_DESTROY to your main window with PostQuitMessage and your are done.
In full:
int WINAPI WinMain(HINSTANCE hInst, HINSTANCE PrevInst, LPSTR args, int ncmdshow) {
RECT rect;
WNDCLASSW wc = { 0 };
wc.hbrBackground = (HBRUSH)COLOR_WINDOW;
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hInstance = hInst;
wc.lpszClassName = L"GenPng";
wc.lpfnWndProc = WindowProcedure;
wc.hbrBackground = CreateSolidBrush(0x00171c00);
wc.hIcon = hIcon;
if (!RegisterClassW(&wc))
return -1;
hMainWindow = CreateWindowW(
L"GenPng", L"Generating pngs", WS_VISIBLE | WS_OVERLAPPEDWINDOW,
200,
100, 300, 58, NULL, NULL, NULL, NULL
);
SetWindowPos(hMainWindow, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
RECT rcClient;
int cyVScroll;
HWND hwndPB;
DWORD cb;
GetClientRect(hMainWindow, &rcClient);
cyVScroll = GetSystemMetrics(SM_CYVSCROLL);
hwndPB = CreateWindowEx(
0, PROGRESS_CLASS, (LPTSTR)NULL,
WS_CHILD | WS_VISIBLE, rcClient.left,
rcClient.bottom - cyVScroll,
rcClient.right, cyVScroll,
hMainWindow, (HMENU)0, hInst, NULL
);
int N = lastFrame;
SendMessage(hwndPB, PBM_SETRANGE, 0, MAKELPARAM(0, N));
SendMessage(hwndPB, PBM_SETSTEP, (WPARAM)1, 0);
std::thread q([hMainWindow, hInst, hwndPB, N]() {
for (int i = 0; i < N + 1; i++) {
SendMessage(hwndPB, PBM_STEPIT, 0, 0);
}
DestroyWindow(hMainWindow);
});
MSG msg = { 0 };
while (GetMessage(&msg, NULL, NULL, NULL))
{
if (msg.message == WM_DESTROY) {
PostQuitMessage(0);
}
TranslateMessage(&msg);
DispatchMessage(&msg);
}
q.join();
// Exit code from PostQuitMessage() is still in msg.param
return msg.param;
}
I was making a program that draws two lines and a circle in the window, for this I used Direct2D.
I was doing a program that draws two lines and a circle in the window. I noticed a problem and that is that when drawing a line of coordinates (100,200), (200,200), that line is not drawn in the pixels (100,200) and ( 200,200). I checked this by reading the coordinates of the mouse in the window and seeing if the line actually has the coordinates that I mentioned.
Do a little more research, and according to Microsoft, direct2d works with dpi and not physical pixels.
So is there a way to work directly with pixels like in Processing or Win32 where the position of the controls is expressed in physical pixels of the window.
#include <d2d1_3.h>
#include <d2d1_3helper.h>
#include <d3d11_1.h>
#include <dxgi1_6.h>
#include <string>
#pragma comment(lib,"d3d11")
#pragma comment(lib,"d2d1")
#pragma comment(lib,"dxgi")
#pragma warning(disable : 4996)
using namespace D2D1;
using namespace std;
template<typename Interface> void SafeRelease(Interface**);
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
int APIENTRY wWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInst
, _In_ LPWSTR lpCmdLine, _In_ int nCmdShow) {
UNREFERENCED_PARAMETER(hPrevInst);
UNREFERENCED_PARAMETER(lpCmdLine);
WNDCLASS wc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hbrBackground = NULL;
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_WINLOGO));
wc.hInstance = hInstance;
wc.lpfnWndProc = WndProc;
wc.lpszClassName = L"Demo_Wnd_Class";
wc.lpszMenuName = NULL;
wc.style = 0;
RegisterClass(&wc);
DWORD dwTopLevelWndStyle = WS_OVERLAPPEDWINDOW ^ (WS_THICKFRAME | WS_MAXIMIZEBOX);
RECT clientRc = { 0,0,640,480 };
AdjustWindowRect(&clientRc, dwTopLevelWndStyle, FALSE);
HWND hWnd = CreateWindow(L"Demo_Wnd_Class", L"Direct2DDemo", dwTopLevelWndStyle, CW_USEDEFAULT, CW_USEDEFAULT
, clientRc.right - clientRc.left, clientRc.bottom - clientRc.top, NULL, NULL, hInstance, NULL);
ShowWindow(hWnd, SW_SHOWDEFAULT);
MSG msg;
ZeroMemory(&msg, sizeof(MSG));
ID3D11Device* d3dDevice;
IDXGIDevice* dxgiDevice = NULL;
D3D_FEATURE_LEVEL featureLevels[] = {
D3D_FEATURE_LEVEL_11_1,
D3D_FEATURE_LEVEL_11_0,
D3D_FEATURE_LEVEL_10_1,
D3D_FEATURE_LEVEL_10_0,
D3D_FEATURE_LEVEL_9_3,
D3D_FEATURE_LEVEL_9_2,
D3D_FEATURE_LEVEL_9_1,
};
HRESULT hr = D3D11CreateDevice(NULL, D3D_DRIVER_TYPE_HARDWARE, NULL, D3D11_CREATE_DEVICE_BGRA_SUPPORT, featureLevels
, 7, D3D11_SDK_VERSION, &d3dDevice, NULL, NULL);
if (SUCCEEDED(hr)) {
OutputDebugString(L"D3D11 Device created successful\n");
hr = d3dDevice->QueryInterface(__uuidof(IDXGIDevice), (void**)&dxgiDevice);
}
ID2D1Device6* d2dDevice = NULL;
ID2D1DeviceContext6* d2dDeviceContext = NULL;
IDXGIFactory2* dxgiFactory = NULL;
IDXGISwapChain1* dxgiSwapChain = NULL;
IDXGISurface *dxgiBackBufferSurface = NULL; // Back buffer
ID2D1Bitmap1* bmpTarget = NULL;
ID2D1SolidColorBrush* shapeBr = NULL;
DXGI_SWAP_CHAIN_DESC1 dscd;
dscd.AlphaMode = DXGI_ALPHA_MODE_IGNORE;
dscd.BufferCount = 2;
dscd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
dscd.Flags = 0;
dscd.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
dscd.Height = 480;
dscd.SampleDesc.Count = 1;
dscd.SampleDesc.Quality = 0;
dscd.Scaling = DXGI_SCALING_NONE;
dscd.Stereo = FALSE;
dscd.SwapEffect = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL;
dscd.Width = 640;
if (SUCCEEDED(hr)) {
OutputDebugString(L"DXGI Device created successful\n");
hr = D2D1CreateDevice(dxgiDevice, CreationProperties(D2D1_THREADING_MODE_SINGLE_THREADED, D2D1_DEBUG_LEVEL_NONE, D2D1_DEVICE_CONTEXT_OPTIONS_NONE), (ID2D1Device**)&d2dDevice);
}
if (SUCCEEDED(hr)) {
OutputDebugString(L"D2D Device created successful\n");
hr = d2dDevice->CreateDeviceContext(D2D1_DEVICE_CONTEXT_OPTIONS_NONE, (ID2D1DeviceContext**)&d2dDeviceContext);
}
if (SUCCEEDED(hr)) {
OutputDebugString(L"D2D Device Context created successful\n");
hr = CreateDXGIFactory2(DXGI_CREATE_FACTORY_DEBUG, __uuidof(IDXGIFactory2), (void**)&dxgiFactory);
}
if (SUCCEEDED(hr)) {
OutputDebugString(L"DXGI Factory created successful\n");
hr = dxgiFactory->CreateSwapChainForHwnd(d3dDevice, hWnd, &dscd, NULL, NULL, &dxgiSwapChain);
}
if (SUCCEEDED(hr)) {
OutputDebugString(L"DXGI Swap Chain created successful\n");
hr = dxgiSwapChain->GetBuffer(0, __uuidof(IDXGISurface), (void**)&dxgiBackBufferSurface);
}
if (SUCCEEDED(hr)) {
hr = d2dDeviceContext->CreateBitmapFromDxgiSurface(dxgiBackBufferSurface, BitmapProperties1(D2D1_BITMAP_OPTIONS_TARGET | D2D1_BITMAP_OPTIONS_CANNOT_DRAW, PixelFormat(DXGI_FORMAT_B8G8R8A8_UNORM, D2D1_ALPHA_MODE_IGNORE),0,0), &bmpTarget);
}
if (SUCCEEDED(hr)) {
OutputDebugString(L"D2D Bitmap created successful\n");
d2dDeviceContext->SetTarget(bmpTarget);
hr = d2dDeviceContext->CreateSolidColorBrush(ColorF(ColorF::White), &shapeBr);
}
if (SUCCEEDED(hr)) {
OutputDebugString(L"D2D Solid Color Brush created successful\n");
d2dDeviceContext->SetUnitMode(D2D1_UNIT_MODE_PIXELS);
d2dDeviceContext->SetTransform(Matrix3x2F::Identity());
d2dDeviceContext->SetAntialiasMode(D2D1_ANTIALIAS_MODE::D2D1_ANTIALIAS_MODE_ALIASED);
}
while (msg.message != WM_QUIT) {
if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
else {
d2dDeviceContext->BeginDraw();
d2dDeviceContext->Clear(ColorF(ColorF::ForestGreen));
d2dDeviceContext->DrawLine(Point2F(400, 0), Point2F(400, 400), shapeBr);
d2dDeviceContext->DrawLine(Point2F(200.0f, 320.0f), Point2F(400.0f, 320.0f), shapeBr);
d2dDeviceContext->DrawEllipse(D2D1::Ellipse(Point2F(300.0f, 300.0f), 10.0f, 10.0f), shapeBr);
POINT cursorPos;
GetCursorPos(&cursorPos);
ScreenToClient(hWnd,&cursorPos);
wstring dbgCursorPos = wstring(L"(MouseX: " + to_wstring(cursorPos.x) + L" MouseY: " + to_wstring(cursorPos.y) + L")\n");
OutputDebugString(dbgCursorPos.c_str());
d2dDeviceContext->EndDraw();
dxgiSwapChain->Present(1, 0);
}
}
SafeRelease(&d3dDevice);
SafeRelease(&dxgiBackBufferSurface);
SafeRelease(&dxgiDevice);
SafeRelease(&dxgiFactory);
SafeRelease(&dxgiSwapChain);
SafeRelease(&d2dDevice);
SafeRelease(&d2dDeviceContext);
SafeRelease(&bmpTarget);
SafeRelease(&shapeBr);
return 0;
}
template<typename Interface> void SafeRelease(Interface** ppInterface) {
if (*ppInterface) {
(*ppInterface)->Release();
(*ppInterface) = NULL;
}
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) {
if (Msg == WM_DESTROY) {
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hWnd, Msg, wParam, lParam);
}
In my code I have a message class that I would like to 'Find' from another process.
class MyWindow : public CWnd
{
public:
MyWindow::MyWindow(LPCTSTR pszClassName)
{
auto wcn = ::AfxRegisterWndClass(NULL);
auto created = this->CreateEx(0, wcn, pszClassName, 0, 0, 0, 0, 0, HWND_MESSAGE, 0);
}
};
Then somewhere in my main app.
...
auto pszClassName = _T("MyWindowClass");
auto wnd = new MyWindow(pszClassName);
auto p = FindWindow(pszClassName, nullptr); // = nullptr
// or using FindWindowExW( ... )
p = FindWindowExW(nullptr, nullptr, pszClassName, nullptr);// = nullptr
p = FindWindowExW(HWND_MESSAGE, nullptr, pszClassName, nullptr);// = nullptr
So, regardless what I do, I never seem to 'Find' the created window.
How can I create a window that can be 'Found' using FindWindow[Ex]
I'm using a VS2013 console app. I've modified your code slightly to create a normal window and a message-only window and find both their handles by class name.
Output:
Normal window=00000000003A06FE Message-only window=00000000001F06CA
FindWindow=00000000003A06FE
FindWindowEx=00000000003A06FE
FindWindowEx(HWND_MESSAGE,...)=00000000001F06CA
Code:
typedef std::basic_string<TCHAR> tstring;
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
class MyWindow //: public CWnd
{
public:
tstring className;
HWND hwnd;
HWND hwndMsgOnly;
HWND find1;
HWND find2;
HWND find3;
MyWindow::MyWindow(LPCTSTR pszClassName)
{
className = pszClassName;
//auto wcn = ::AfxRegisterWndClass(NULL);
//auto created = this->CreateEx(0, wcn, pszClassName, 0, 0, 0, 0, 0, HWND_MESSAGE, 0);
// For a console app, `hInstance` is the instance of the program
HINSTANCE hInstance = GetModuleHandle(0);
WNDCLASSEX windowClass;
windowClass.lpszClassName = pszClassName;
windowClass.cbClsExtra = NULL;
windowClass.cbWndExtra = NULL;
windowClass.cbSize = sizeof(WNDCLASSEX);
windowClass.hbrBackground = (HBRUSH)CreateSolidBrush(RGB(150, 0, 0));
windowClass.hCursor = LoadCursor(NULL, IDC_ARROW);
windowClass.hIcon = LoadIcon(NULL, MAKEINTRESOURCE(IDI_APPLICATION));
windowClass.hIconSm = (HICON)LoadImage(NULL, MAKEINTRESOURCE(IDI_APPLICATION), IMAGE_ICON, 16, 16, NULL);
windowClass.hInstance = hInstance;
windowClass.lpfnWndProc = WindowProc;
windowClass.lpszMenuName = NULL;
windowClass.style = CS_VREDRAW | CS_HREDRAW;
RegisterClassEx(&windowClass);
hwnd = CreateWindowEx(NULL, pszClassName, _T("Basic Window"), WS_OVERLAPPEDWINDOW | WS_VISIBLE, 100, 100, 500, 500, NULL, NULL, hInstance, NULL);
hwndMsgOnly = CreateWindowEx(NULL, pszClassName, _T("Dummy name"), 0, 0, 0, 0, 0, HWND_MESSAGE, NULL, NULL, NULL);
}
};
void window_test(MyWindow & wnd)
{
LPCTSTR pszClassName = wnd.className.c_str();
wnd.find1 = FindWindow(pszClassName, nullptr); // = nullptr for OP version; okay for this version
// or using FindWindowExW( ... )
/**
HWND hwndParent is a handle to the parent window whose child windows are to be searched.
If hwndParent is NULL, the function uses the desktop window as the parent window.The function searches among windows that are child windows of the desktop.
If hwndParent is HWND_MESSAGE, the function searches all message-only windows.
**/
HWND hWndParent = nullptr;
wnd.find2 = FindWindowExW(hWndParent, nullptr, pszClassName, nullptr);// = nullptr for OP version; okay for this version
hWndParent = HWND_MESSAGE;
wnd.find3 = FindWindowExW(hWndParent, nullptr, pszClassName, nullptr);// = nullptr for OP version; finds the message-only window in this version
}
void main()
{
MyWindow wnd(_T("test_window"));
cout << "Normal window=" << wnd.hwnd << " Message-only window=" << wnd.hwndMsgOnly << endl;
window_test(wnd);
cout << "FindWindow=" << wnd.find1 << endl;
cout << "FindWindowEx=" << wnd.find2 << endl;
cout << "FindWindowEx(HWND_MESSAGE,...)=" << wnd.find3 << endl;
}
Alright so I've been sitting here for over 30 mins trying to solve this problem, in "Create Window" it gives me a NULL value unless I have the class name as "LoginClassName" if I use "RegisterClassName" it will return a NULL. I am trying to create a pop-up window and so far its kicking my ass. I create the class the same as LoginClass so I don't really see the problem.
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR szCmdLine, int iCmdShow) {
MSG msg;
WNDCLASSW LoginClass = { 0 };
wchar_t LoginClassName[] = L"LoginWindow";
LoginClass.cbClsExtra = 0;
LoginClass.cbWndExtra = 0;
LoginClass.hbrBackground = HBRUSH(GetStockObject(WHITE_BRUSH));
LoginClass.hCursor = LoadCursor(hInstance, IDC_ARROW);
LoginClass.hIcon = LoadIcon(hInstance, IDI_APPLICATION);
LoginClass.lpfnWndProc = LoginWndProc;
LoginClass.hInstance = hInstance;
LoginClass.lpszClassName = LoginClassName;
LoginClass.lpszMenuName = NULL;
LoginClass.style = CS_VREDRAW | CS_HREDRAW;
if (!RegisterClass(&LoginClass))
{
MessageBox(NULL, L"Error", L"Error", MB_OK | MB_ICONERROR);
return 0;
}
WNDCLASSW RegisterWindowClass = { 0 };
wchar_t RegisterClassName[] = L"Test";
RegisterWindowClass.cbClsExtra = 0;
RegisterWindowClass.cbWndExtra = 0;
RegisterWindowClass.hbrBackground = HBRUSH(GetStockObject(WHITE_BRUSH));
RegisterWindowClass.hCursor = LoadCursor(hInstance, IDC_ARROW);
RegisterWindowClass.hIcon = LoadIcon(hInstance, IDI_APPLICATION);
RegisterWindowClass.lpfnWndProc = RegisterWndProc;
RegisterWindowClass.hInstance = hInstance;
RegisterWindowClass.lpszClassName = RegisterClassName;
RegisterWindowClass.lpszMenuName = NULL;
RegisterWindowClass.style = CS_VREDRAW | CS_HREDRAW;
if (!RegisterClass(&RegisterWindowClass))
{
MessageBox(NULL, L"Error", L"Error", MB_OK | MB_ICONERROR);
return 0;
}
hLoginWindow = CreateWindow(LoginClassName, L"GameLauncher Login", WS_SYSMENU | WS_CAPTION | WS_OVERLAPPED, CW_USEDEFAULT, CW_USEDEFAULT, 350, 200, NULL, NULL, hInstance, NULL);
hRegisterWindow = CreateWindowEx(NULL, RegisterClassName, L"Register Account", WS_SYSMENU | WS_CAPTION | WS_OVERLAPPED, CW_USEDEFAULT, CW_USEDEFAULT, 350, 200, NULL, NULL, hInstance, NULL);
ShowWindow(hLoginWindow, iCmdShow);
UpdateWindow(hLoginWindow);
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}
This is the WndProc of the RegisterClassWindow:
LRESULT CALLBACK RegisterWndProc(HWND hWnd, UINT uMessage, WPARAM wParam, LPARAM lParam) {
switch (uMessage)
{
case WM_CREATE: {
break;
}
case WM_DESTROY:{
PostQuitMessage(0);
break;
}
default:{
DefWindowProc(hWnd, uMessage, wParam, lParam);
}
}
return 0;
}
this is the code that creates a simple window and initializes a simple direct3d device. but every time the program reaches the render() function application terminates. i have no idea why that happens. can somebody explain me this weird behavior? thank you!!
//====================================================================================================
#include <windows.h>
#include <d3d9.h>
//====================================================================================================
HINSTANCE hInst;
HWND wndHandle;
//====================================================================================================
LPDIRECT3D9 pD3D; // the Direct3D object
LPDIRECT3DDEVICE9 pd3dDevice; // the Direct3D device
//====================================================================================================
bool initWindow(HINSTANCE hInstance);
bool initDirect3D(void);
void cleanUp (void);
void render(void);
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
//====================================================================================================
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
if (!initWindow(hInstance)) return false;
if (!initDirect3D()) return false;
MSG msg;
ZeroMemory(&msg, sizeof(msg));
if(PeekMessage(&msg, NULL, 0U, 0U, PM_REMOVE))
{
TranslateMessage (&msg);
DispatchMessage (&msg);
} else {
render(); // i think this is the problem ...
}
return static_cast<int>(msg.wParam);
}
bool initWindow(HINSTANCE hInstance )
{
WNDCLASSEX 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(0, IDI_APPLICATION);
wcex.hCursor = LoadCursor(0, IDC_ARROW);
wcex.hbrBackground = static_cast<HBRUSH>(GetStockObject(WHITE_BRUSH));
wcex.lpszMenuName = 0L;
wcex.lpszClassName = L"DirectXTemplate";
wcex.hIconSm = 0;
RegisterClassEx(&wcex);
wndHandle = CreateWindow(L"DirectXTemplate", L"DirectX Template", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 640, 480, NULL, NULL, hInstance, NULL);
if (!wndHandle) return false;
ShowWindow(wndHandle, SW_SHOW);
UpdateWindow(wndHandle);
return true;
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
}
bool initDirect3D(void)
{
pD3D = NULL;
pd3dDevice = NULL;
// create the DirectX object
if(NULL == (pD3D = Direct3DCreate9(D3D_SDK_VERSION))) return false;
// fill the presentation parameters structure
D3DPRESENT_PARAMETERS d3dpp;
ZeroMemory(&d3dpp, sizeof(d3dpp));
d3dpp.Windowed = TRUE;
d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
d3dpp.BackBufferFormat = D3DFMT_UNKNOWN;
d3dpp.BackBufferCount = 1;
d3dpp.BackBufferHeight = 480;
d3dpp.BackBufferWidth = 640;
d3dpp.hDeviceWindow = wndHandle;
// create a default DirectX device
if (FAILED(pD3D -> CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_REF, wndHandle, D3DCREATE_SOFTWARE_VERTEXPROCESSING, &d3dpp, &pd3dDevice))) return false;
return true;
}
void render(void)
{
// Check to make sure you have a valid Direct3D device
if(NULL == pd3dDevice) return; // clear the back buffer to a blue color
pd3dDevice -> Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0, 0, 255), 1.0f, 0);
// Present the back buffer contents to the display
pd3dDevice -> Present(NULL, NULL, NULL, NULL);
}
void cleanUp (void)
{
// Release the device and the Direct3D object
if (pd3dDevice != NULL) pd3dDevice -> Release();
if (pD3D != NULL) pD3D -> Release();
}
#DuckMaestro is right. Your program is going through the msg/render process once and is then ending. It should only end if the msg is to exit the program. Try putting in a loop like this:
while(msg.message!=WM_QUIT){
if(PeekMessage(&msg, NULL, 0U, 0U, PM_REMOVE))
{
TranslateMessage (&msg);
DispatchMessage (&msg);
} else {
render(); // i think this is the problem ...
}
}
Your...
if(PeekMessage(&msg, NULL, 0U, 0U, PM_REMOVE))
{
TranslateMessage (&msg);
DispatchMessage (&msg);
} else {
render(); // i think this is the problem ...
}
...needs to be in a while loop, no? Step through your code with a debugger, statement by statement. Win32 applications need a while loop to stay alive, so-to-speak.