-
August 20th, 2015, 11:24 AM
#1
[RESOLVED] Basic Window wrapper
All the basic programs I've written are for a console. What I am working on is creating a basic window that appears to be a console. Just one window for the time being with a black background with white text and a fixed pitched font (8x8).
I have created a class CApp() and placed everything in it as a best effort, and I am a beginner with windows.
The problem I am having is that the program will only run once, when you close the window app the IDE (code blocks) tells me that the compiler/app is still running and I have to close and reboot.
I want to point out that I have been researching this (google) and I have learned that you can create a Window application using main() instead of WinMain(), so that is what I've done. Either this is the issue or I am not processing a quit message?
Here is what I've done so far:
Code:
// CApp.h
#ifndef WINCON_CAPP_H
#define WINCON_CAPP_H
#if defined(UNICODE) && !defined(_UNICODE)
#define _UNICODE
#elif defined(_UNICODE) && !defined(UNICODE)
#define UNICODE
#endif
#include <windows.h>
namespace WinCon {
class CApp
{
public:
CApp();
~CApp();
int Create();
void Show();
HINSTANCE GetInstance() const { return m_sWinClass.hInstance; }
LPCSTR GetClassName() const { return m_sWinClass.lpszClassName; }
HWND GetWindowHandle() const { return m_hWindow; }
static LRESULT CALLBACK WinProc(HWND hwnd , UINT message,
WPARAM wParam, LPARAM lParam);
protected:
void SetInstance();
int RegisterClass(WNDCLASSEX *winClass);
private:
HWND m_hWindow;
WNDCLASSEX m_sWinClass;
};
} // namespace WinCon
#endif // WINCON_CAPP_H
Code:
// CApp.cpp
#include "CApp.h"
using namespace WinCon;
CApp::CApp() : m_hWindow(NULL)
{
SetInstance();
m_sWinClass.lpszClassName = "WinCon";
m_sWinClass.lpfnWndProc = WinProc;
m_sWinClass.style = CS_DBLCLKS;
m_sWinClass.cbSize = sizeof(WNDCLASSEX);
m_sWinClass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
m_sWinClass.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
m_sWinClass.hCursor = LoadCursor(NULL, IDC_ARROW);
m_sWinClass.lpszMenuName = NULL;
m_sWinClass.cbClsExtra = 0;
m_sWinClass.cbWndExtra = 0;
m_sWinClass.hbrBackground = (HBRUSH) COLOR_BACKGROUND; // black ?
RegisterClass(&m_sWinClass);
}
CApp::~CApp() {}
void CApp::SetInstance()
{
if((m_sWinClass.hInstance = GetModuleHandle(NULL)) == NULL) {
MessageBox(NULL, TEXT("Unable to obtain the program instance."),
TEXT("WinCon Error - CApp::SetInstance()"),
MB_ICONSTOP | MB_OK | MB_TASKMODAL);
}
}
int CApp::RegisterClass(WNDCLASSEX *winClass)
{
if(!RegisterClassEx(winClass)) {
MessageBox(NULL, TEXT("Window registration failed."),
TEXT("WinCon Error - CApp::RegisterClass()"),
MB_ICONSTOP | MB_OK | MB_TASKMODAL);
return 1;
}
return 0;
}
int CApp::Create()
{
m_hWindow = CreateWindowEx(
0, // Extended window style
GetClassName(), // Pointer to registered class name
TEXT("WinCon App"), // Pointer to window name
WS_OVERLAPPEDWINDOW, // Window style
CW_USEDEFAULT, // Horizontal position of window
CW_USEDEFAULT, // Vertical position of window
544, // Window width
375, // Window height
HWND_DESKTOP, // Handle to parent or owner window
NULL, // Handle to menu, or child-window identifier
GetInstance(), // Handle to program instance
NULL // Pointer to window-creation data
);
if(!m_hWindow) {
MessageBox(NULL, TEXT("Window creation failed."),
TEXT("WinCon Error - CApp::Create()"),
MB_ICONSTOP | MB_OK | MB_TASKMODAL);
return 1;
}
return 0;
}
void CApp::Show()
{
ShowWindow(m_hWindow, SW_SHOWDEFAULT);
UpdateWindow(m_hWindow);
}
LRESULT CALLBACK CApp::WinProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch(message) {
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hwnd, message, wParam, lParam);
}
return 0;
}
And main like this:
Code:
#include "CApp.h"
using namespace WinCon;
int main()
{
CApp myConsole;
myConsole.Create();
myConsole.Show();
MSG msg;
while(GetMessage(&msg, myConsole.GetWindowHandle(), 0, 0)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return (int) msg.wParam;
}
I hope someone will explain what I've done wrong and how I can resolve this. Any further advice is welcome.
What the mind can conceive it can achieve.
-
August 21st, 2015, 02:53 AM
#2
Re: Basic Window wrapper
PostQuitMessage function
Remarks
The PostQuitMessage function posts a WM_QUIT message to the thread's message queue and returns immediately; the function simply indicates to the system that the thread is requesting to quit at some time in the future.
When the thread retrieves the WM_QUIT message from its message queue, it should exit its message loop and return control to the system. The exit value returned to the system must be the wParam parameter of the WM_QUIT message.
But you pump your window messages only. Try use NULL instead of myConsole.GetWindowHandle().
EDIT: Ah, and please make sure WM_DESTROY is really received.
Last edited by Igor Vartanov; August 21st, 2015 at 03:04 AM.
Best regards,
Igor
-
August 21st, 2015, 02:58 AM
#3
Re: Basic Window wrapper
Besides,
Code:
while(GetMessage(&msg, myConsole.GetWindowHandle(), 0, 0)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
This does not handle situations when GetMessage() returns -1. A very typical beginner's miss.
Should be something like this:
Code:
while(0 < GetMessage(&msg, NULL, 0, 0)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
Last edited by Igor Vartanov; August 21st, 2015 at 03:05 AM.
Best regards,
Igor
-
August 21st, 2015, 04:35 AM
#4
Re: Basic Window wrapper
I can't thank you enough, it works fine now. I understand your changes in the message loop and I've been looking up the functions and reading about the return values and remarks, don't understand all of it at this time however.
As far as I can see I have handled WM_DESTROY correctly? Have I missed something?
Code:
LRESULT CALLBACK CApp::WinProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch(msg) {
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hwnd, msg, wParam, lParam);
}
return 0;
}
I have made a couple of changes to the code. In function RegisterClass() I have changed the return value order so it looks like all the other examples I have seen.
Code:
int CApp::RegisterClass(WNDCLASSEX *winClass)
{
if(!RegisterClassEx(winClass)) {
MessageBox(NULL, TEXT("Window registration failed."),
TEXT("WinCon Error - CApp::RegisterClass()"),
MB_ICONSTOP | MB_OK | MB_TASKMODAL);
return 0;
}
return 1;
}
The issue I have is that I never use the return value so could I get away with making this function void and not return anything? Or is the return 0 going somewhere else?
Likewise I changed Create() to return 0 on failure and the same thought as with RegisterClass() comes to mind?
Code:
// The bit in Create() I've changed.....
if(!m_hWindow) {
MessageBox(NULL, TEXT("Window creation failed."),
TEXT("WinCon Error - CApp::Create()"),
MB_ICONSTOP | MB_OK | MB_TASKMODAL);
return 0;
}
return 1;
}
I'm sure you see my point here?
Last edited by Gerald Bates; August 21st, 2015 at 09:57 AM.
What the mind can conceive it can achieve.
-
August 22nd, 2015, 06:30 AM
#5
Re: Basic Window wrapper
I have tested this and it does appear to be working so I am leaving the code as it is. Sorry for the silly questions but I really don't understand much about windows programming.
My next issue is trying to get "Hello World!" displayed on the screen, the text should be in white on a black background but I am getting a window background in black but for the length of the string only I get a white background and black text?
In the CApp() c'tor I have done this:
Code:
m_sWinClass.hbrBackground = (HBRUSH) GetStockObject(BLACK_BRUSH);
In CApp.cpp I've added this:
Code:
HDC hDc;
HBRUSH hBrush;
switch(msg) {
case WM_CREATE:
hDc = GetDC(hwnd);
hBrush = (HBRUSH) GetStockObject(ANSI_FIXED_FONT);
SetTextColor(hDc, RGB(255, 255, 255)); // White text.
SelectObject(hDc, hBrush);
DeleteObject(hBrush);
ReleaseDC(hwnd, hDc);
break;
In my main.cpp I have done this:
Code:
#include "CApp.h"
#include <cstring>
#include <cstdio>
using namespace WinCon;
int main()
{
CApp myConsole;
myConsole.Create();
myConsole.Show();
MSG msg;
char str[255];
HDC hDc = GetDC(myConsole.GetWindowHandle());
sprintf(str, "Hello World!");
TextOut(hDc, 10, 10, str, strlen(str));
ReleaseDC(myConsole.GetWindowHandle(), hDc);
while(0 < GetMessage(&msg, NULL, 0, 0)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}
Why is the text colour and background wrong? Have I got a fixed pitch font properly
or should I use another function?
What the mind can conceive it can achieve.
-
August 23rd, 2015, 04:06 AM
#6
Re: Basic Window wrapper
I have decided to study a bit more and write simple window programs without using classes. Many thanks for the advice given, it is appreciated.
What the mind can conceive it can achieve.
Posting Permissions
- You may not post new threads
- You may not post replies
- You may not post attachments
- You may not edit your posts
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|