From: Jimbo on
Hello

I am looking for advice on what are the proper practices when coding
an application or a C++ Win32 Application & how to improve how I code
applications.

I have my application I have made below which just shows a map of the
world & a dot on the city we are focused on. If the user clicks
anywhere in the client area, the program will find the nearest city &
select it & the same will happen if you press next or prev.

Some things I am not sure about concerning C++ Win32 app are:
- are windows messages & functions meant to be handled in Winmain or
is it ok to handle them in a class.
For example, if I have some code that grabs text from an edit box, is
it better coding practice to place that code in WinMain or in a Class?

Any advice on improving my app would be really helpful :)
Especially on which functions should be part of main & which functions
should be in a class.

WinMain:
[code]
/*

Application: Displays a world map & a dot at position of the city
we are focused(selected) on

*/

#include <windows.h>
#include <stdio.h>
#include <cmath>
#include <vector>
#include <string>
#include <cstdlib>

#include "conWorldCoord.h"

using namespace std;

#define IDB_NEXT 1
#define IDB_PREV 2
#define IDT_CNAME 3
#define IDB_MAP 4
#define IDB_DOT 5

const char g_szClassName[] = "myWindowClass";
static HINSTANCE gInstance;
controller control;


// Functions List //
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM
lParam);


int WINAPI WinMain(HINSTANCE gInstance, HINSTANCE hPrevInstance, LPSTR
lpCmdLine, int nCmdShow)
{
WNDCLASSEX wc;
HWND hwnd;
MSG Msg;

//Step 1: Registering the Window Class
wc.cbSize = sizeof(WNDCLASSEX);
wc.style = 0;
wc.lpfnWndProc = WndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = gInstance;
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)(DKGRAY_BRUSH);
wc.lpszMenuName = NULL;
wc.lpszClassName = g_szClassName;
wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION);

// if registration of main class fails
if(!RegisterClassEx(&wc))
{
MessageBox(NULL, "Window Registration Failed!", "Error!",
MB_ICONEXCLAMATION | MB_OK);
return 0;
}

// Step 2: Creating the Window
hwnd = CreateWindowEx(
WS_EX_CLIENTEDGE,
g_szClassName,
"Displays the Long & Lat of world cities",
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT, 600, 500,
NULL, NULL, gInstance, NULL);

if(hwnd == NULL)
{
MessageBox(NULL, "Window Creation Failed!", "Error!",
MB_ICONEXCLAMATION | MB_OK);
return 0;
}

ShowWindow(hwnd, nCmdShow);
UpdateWindow(hwnd);

// Step 3: The Message Loop
while(GetMessage(&Msg, NULL, 0, 0) > 0)
{
TranslateMessage(&Msg);
DispatchMessage(&Msg);
}
return Msg.wParam;
}

// Step 4: the Window Procedure
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM
lParam)
{

switch(msg)
{
case WM_CREATE:
{
// Create GUI
control.createGUI
(hwnd,gInstance,IDT_CNAME,IDB_PREV,IDB_NEXT,IDB_MAP,IDB_DOT);
}
break;
case WM_PAINT: // Necessary to draw city focus dot
{

}
break;
case WM_LBUTTONDOWN:
// select city closest to mouse position if not
already selected
if (control.setFocusCity(hwnd,IDT_CNAME,LOWORD
(lParam),HIWORD(lParam))==true) {
control.drawCityBmp(hwnd,IDB_MAP,IDB_DOT); //
call function to draw dot on newly selected city
}
break;
case WM_COMMAND:
{
switch(LOWORD(wParam)) {

case IDB_NEXT:
{
control.setFocusCity
(hwnd,IDT_CNAME,true); // advance focus to next city
control.drawCityBmp
(hwnd,IDB_MAP,IDB_DOT); // call function to draw dot on new city
}
break;
case IDB_PREV:
{
control.setFocusCity
(hwnd,IDT_CNAME,true); // set focus to previous city
control.drawCityBmp
(hwnd,IDB_MAP,IDB_DOT); // call function to draw dot on new city
}
break;
default:
break;
}
}
break;
case WM_CLOSE:
DestroyWindow(hwnd);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default: return DefWindowProc(hwnd, msg, wParam, lParam);
break;
}
}

[/code]

Header file:
[code]
// controller class for Windows App World Coord

#ifndef CONWORLDCOORD_H
#define CONWORLDCOORD_H

#include <windows.h>
#include <vector>
#include <cstdlib>
#include <string>

using namespace std;

struct city
{
string name;
int x;
int y;
int groupPos; // index position in cityList
};

class controller
{
public:
vector <city*> cityList; // store all cities in vector

controller();
void createGUI(HWND hwnd, HINSTANCE gInstance, UINT
cityName, UINT butPrev,
UINT butNext, UINT bmpMap, UINT bmpDot);
void registerCities();
void setFocusCity(HWND hwnd, UINT cityName, bool next);
bool setFocusCity(HWND hwnd, UINT cityName, int mouseX, int
mouseY);
void drawCityBmp(HWND hwnd, UINT bmpMapMsg, UINT bmpDotMsg);
float pointDistance(int x1, int y1, int x2, int y2);
city* instanceNearest(int x, int y);

private:
city *focusCity; // the city we are focused on now
int index; // index of cityList vector
HBITMAP mapImg; // handle to bitmap of world
HBITMAP cityImg; // handle to bitmap of City Dot
BITMAP bm;
HWND stMapImg;
HWND stDotImg;
int xImgOffset, yImgOffset;
string focus;
string cityStr;
string focusStr; // output/record what city we are
currently focused on
};

#endif

[/code]

Implementation file:
[code]
#include <windows.h>
#include <vector>
#include <cstdlib>
#include <string>
#include <cmath>

#include "conWorldCoord.h"

using namespace std;

controller::controller()
{
// Constructor

// Load Bitmaps - World map & dot
mapImg = (HBITMAP)LoadImage(NULL,"worldMapScaled.bmp",IMAGE_BITMAP,
0,0,
LR_CREATEDIBSECTION | LR_DEFAULTSIZE |
LR_LOADFROMFILE);

cityImg = (HBITMAP)LoadImage(NULL,"dot.bmp",IMAGE_BITMAP,0,0,
LR_CREATEDIBSECTION | LR_DEFAULTSIZE
| LR_LOADFROMFILE);
// if load fails
if (cityImg==NULL || mapImg==NULL) {
MessageBox(NULL,"Failed to load bitmaps","Error",MB_OK |
MB_ICONERROR);
}

// get cityBmp offsets
GetObject(cityImg,sizeof(bm),&bm);
xImgOffset = bm.bmWidth/2;
yImgOffset = bm.bmHeight/2;

focus = "City Focus = ";
cityStr = "New York"; // should be cityFocus->name;
index = 0;

registerCities(); // register cities
}

void controller::createGUI(HWND hwnd, HINSTANCE gInstance, UINT
cityName, UINT butPrev,
UINT butNext, UINT bmpMap, UINT bmpDot)
{
// create GUI
// NB check whether we even need the UNIT msgs??
// change window x,y,xW,yH coords to Width+30 etc.
HFONT hfDefault;
hfDefault = (HFONT)GetStockObject(DEFAULT_GUI_FONT); // set font
focusStr = focus+cityStr; // focusStr="City Focus = New York"

HWND stCityFocus = CreateWindowEx(0,"Static",focusStr.c_str
(),WS_BORDER | WS_CHILD | WS_VISIBLE | SS_CENTER,
30,400,150,16,hwnd,(HMENU)
cityName,gInstance,NULL);

HWND btPrev = CreateWindowEx(0,"Button","Prev",WS_BORDER |
WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON,
410,400,70,20,hwnd,(HMENU)
butPrev,gInstance,NULL);

HWND btNext = CreateWindowEx(0,"Button","Next",WS_BORDER |
WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON,
490,400,70,20,hwnd,(HMENU)
butNext,gInstance,NULL);

// draw world map & dot
stMapImg = CreateWindowEx(0,"Static","",WS_CHILD | WS_VISIBLE |
SS_BITMAP,
20,10,540,380,hwnd,(HMENU)
bmpMap,gInstance,NULL);

stDotImg = CreateWindowEx(0,"Static","",WS_CHILD | WS_VISIBLE |
SS_BITMAP,
185-xImgOffset,140-
yImgOffset,CW_USEDEFAULT, CW_USEDEFAULT,hwnd,
(HMENU)bmpDot,gInstance,NULL);

// Set window fonts
SendMessage(stCityFocus,WM_SETFONT,(WPARAM)hfDefault,MAKELPARAM
(FALSE, 0));
SendMessage(btPrev,WM_SETFONT,(WPARAM)hfDefault,MAKELPARAM(FALSE,
0));
SendMessage(btNext,WM_SETFONT,(WPARAM)hfDefault,MAKELPARAM(FALSE,
0));


// Display bitmaps
SendMessage(stMapImg,STM_SETIMAGE,(WPARAM)IMAGE_BITMAP,(LPARAM)
mapImg);
SendMessage(stDotImg,STM_SETIMAGE,(WPARAM)IMAGE_BITMAP,(LPARAM)
cityImg);

}

void controller::registerCities()
{
// Post: Create/Declare & define city data
city *NewYork = new city; // BECAUSE I HAVE USED 'new' HERE DO i
NEED TO 'delete' THEM BEFORE I CLOSE THE APPLICATION???
city *London = new city; // IF I DO CAN YOU EXPLAI HOW & WHERE I
PUT THE DELETE CODE
city *Sydney = new city;
// store cities in global vector
cityList.push_back(NewYork); // ERROR Occurs here Line 79 -
'cityList' undeclared
cityList.push_back(London);
cityList.push_back(Sydney);

NewYork->name = "New York";
NewYork->x = 185; // should be AppWidth-150 etc.
NewYork->y = 140; // should be AppHeight-250 etc.

London->name = "London";
London->x = 288;
London->y = 110;

Sydney->name = "Sydney";
Sydney->x = 490;
Sydney->y = 265;

//set focus city to 1st city
focusCity = cityList.at(0); // ERROR Occurs here Line 96 -
'focusCity' undeclared
}

void controller::setFocusCity(HWND hwnd, UINT cityName, bool next)
{
// Post: Sets cityFocus to next or previous city depending on
bool next value

// If next is true we want to advance our city focus
if (next) {
// make sure index is not > size of cityList vector
if (index < cityList.size()-1) {
index += 1;
}
else index = 0;
}
else if (!next) { // we want to focus on previous city

if (index != 0) {
index -= 1;
}
else index = cityList.size()-1;
}

// append which city we are now focusing on
focusCity = cityList.at(index);
cityStr = focusCity->name;
focusStr = focus+cityStr;
SetDlgItemText(hwnd,cityName,focusStr.c_str());
}

bool controller::setFocusCity(HWND hwnd, UINT cityName, int mouseX,
int mouseY)
{
// Post: finds closest city to mouse position/Coords & selects
it

city* nearestCity = instanceNearest(mouseX,mouseY);

// if the closest city to mouse pos.. is not our focusCity(not
already selected)
if (nearestCity != focusCity) {
focusCity = nearestCity;
cityStr = focusCity->name;
focusStr = focus+cityStr;
SetDlgItemText(hwnd,cityName,focusStr.c_str());
return true;
}
else return false;
}

void controller::drawCityBmp(HWND hwnd, UINT bmpMapMsg, UINT
bmpDotMsg)
{
// Post: Draw dot bmp at location of current focus city

// create bmp coords by compensating for x,y offset
int xPos = (focusCity->x)-xImgOffset;
int yPos = (focusCity->y)-yImgOffset;

// reset city dot bmp position
SetWindowPos(stDotImg,HWND_TOP,xPos,yPos,CW_USEDEFAULT,
CW_USEDEFAULT,SWP_ASYNCWINDOWPOS);

// Redraw world map & city dot
SendMessage(stMapImg,STM_SETIMAGE,(WPARAM)IMAGE_BITMAP,(LPARAM)
mapImg);
SendMessage(stDotImg,STM_SETIMAGE,(WPARAM)IMAGE_BITMAP,(LPARAM)
cityImg);
}

float controller::pointDistance(int x1, int y1, int x2, int y2)
{
return (sqrt( ((x2-x1)*(x2-x1)) + ((y2-y1)*(y2-y1)) ));
}

city* controller::instanceNearest(int x, int y)
{
// Pre: cityList/instance count of object MUST be > 0
// Post: returns the instance closest to specified point

float dist = 99999;
int size = cityList.size();

for (int i=0; i<size; i++) {

float myDist = pointDistance(x,y,cityList.at(i)->x,cityList.at
(i)->y);

if (myDist < dist) {
dist = myDist;
index = i; // record vector cityList index of focus
}
}

return cityList.at(index);
}

[/code]
From: ScottMcP [MVP] on
On Jan 11, 8:08 pm, Jimbo <nill...(a)yahoo.com> wrote:
> Some things I am not sure about concerning C++ Win32 app are:
> - are windows messages & functions meant to be handled in Winmain or
> is it ok to handle them in a class.
>  For example, if I have some code that grabs text from an edit box, is
> it better coding practice to place that code in WinMain or in a Class?
>
> Any advice on improving my app would be really helpful :)
> Especially on which functions should be part of main & which functions
> should be in a class.

Your API-level code represents the way things were about 1990, before C
++ became popular. Rather than asking which functions should be in a
class you should be looking at ways to work entirely in C++, and to
avoid reinventing the wheel with all the mechanisms that are a
standard part of any Windows GUI application. There are several
popular C++ class libraries that make all this much more productive.
They include Microsoft's MFC and ATL, and open source WxWidgets and
Qt.

Another option, which is especially relevant if you will be looking
for employment, is to use C# with WinForms. Most new work in Windows
GUIs is done with this option.