Here''s a fairly simple C++ Win32 program i just finished writing, and i was wondering if anyone could give me any tips, suggestions and bits of info about it. It consists of the Main.cpp where my main stuff is located, ScreenBuffer.h and ScreenBuffer.cpp which is a wrapper class for DCs, and ThreadStuff.h and ThreadStuff.cpp which has three classes for threads, mutexes and critical sections.
Main.cpp
#define WIN32_LEAN_AND_MEAN //Gets rid of rarly used stuff
#include <windows.h> //Win32 API header file
#include <windowsx.h> //Win32 API Extensions header file
#include "resource.h" //Resource IDs, the icon and the cursor that doesn''t work(??)
#include "ScreenBuffer.h" //My ScreenBuffer class
#include "ThreadStuff.h" //My Thread classes
//Message Handler prototype
LRESULT CALLBACK MsgHandler(
HWND hwnd, //Window Handle
UINT msg, //Message Identifier (WM_ constants)
WPARAM wparam, //Message parameter
LPARAM lparam //Message parameter
);
DWORD WINAPI Raster(LPVOID Param); //Drawing function declaration
HWND hWnd; //Window Handle
ScreenBuffer Screen; //Front screenbuffer
ScreenBuffer Canvas; //Back screenbuffer
//Thread that does the animation,
Thread ThreadRaster(&Raster, //Drawing function
CREATE_SUSPENDED); //Starts off suspended.
//Main Function
int WINAPI WinMain(HINSTANCE hInstance, //Application Instance
HINSTANCE hPrewInstance, //Instance of calling application
LPSTR lpCmdLine, //Pointer to command line parameters
int nShowCmd) //Info on how to show window (SW_ constants)
{
WNDCLASSEX TestClass; //Window Descriptor
MSG Msg; //Message variable
//Fill in Window Descriptor
TestClass.cbClsExtra=0; //Extra class info
TestClass.cbSize=sizeof(WNDCLASSEX); //Size of window descriptor
TestClass.cbWndExtra=0; //Extra window info
TestClass.hbrBackground=NULL; //How to paint the background on refresh/repaint
TestClass.hCursor=LoadCursor(hInstance, "IDC_CURSOR1"); //Application Cursor, doesn''t work for some reason
TestClass.hIcon=LoadIcon(hInstance, "IDI_ICON1"); //Application Icon
TestClass.hIconSm=LoadIcon(hInstance, "IDI_ICON1"); //Small icon in top corner
TestClass.hInstance=hInstance; //Application Instance
TestClass.lpfnWndProc=MsgHandler; //Location of Message Handler
TestClass.lpszClassName="Test Class"; //Window Name
TestClass.lpszMenuName=NULL; //Menu Name, if there is one
TestClass.style=CS_DBLCLKS|CS_OWNDC|CS_HREDRAW|CS_VREDRAW; //Info on Window Style (CS_ constants)
RegisterClassEx(&TestClass); //Register window
//Create window, and set hwnd to its handle
hWnd=CreateWindowEx(NULL, //Extended window styles (WS_EX_ constants)
"Test Class", //Window Name
"Test Window", //Window Title
WS_OVERLAPPEDWINDOW|WS_VISIBLE, //Window Style (WS_ constants)
CW_USEDEFAULT, CW_USEDEFAULT, //Window x,y coordinates
308, 334, //Window width and hight in pixels
NULL, //Parent window handle
NULL, //Menu Handle
hInstance, //Application Instance
NULL); //Used for making things like MDIs
Screen.GetBuffer(hWnd); //Initalize front buffer
Canvas.CopyBuffer(Screen); //Make Canvas a copy of Screen
ThreadRaster.Resume(); //Start drawing animation thread now that everything is initalized
//Main program loop
while(true)
{
/*
Prototype for PeekMessage function that checks if there are any pending messages in the message queue
BOOL PeekMessage(
LPMSG lpMsg, Pointer to MSG type variable that contains message info
HWND hWnd, Window Handle for the message queue you want to check
UINT wMsgFilterMin, First message to check
UINT wMsgFilterMax, Last message to check
UINT wRemoveMsg Removal flags, takes either: PM_REMOVE to remove the message from the queue after handling or
PM_NOREMOVE to keep the message in the queue after handling
);
*/
if(PeekMessage(&Msg, 0, 0, 0, PM_REMOVE)) //Check for messages
{
if(Msg.message==WM_QUIT) //Check if it''s time to quit
break; //Leave main loop
TranslateMessage(&Msg); //Prepares message for handeling
DispatchMessage(&Msg); //Sends the message to the message handler
}
else
WaitMessage(); //Wait for a new message
}
DestroyWindow(hWnd); //Destroy the window
UnregisterClass("Test Class", hInstance); //Unregister window class
return 0; //End program
}
//Message Handler function
LRESULT WINAPI MsgHandler(HWND hwnd, UINT Msg, WPARAM wParam, LPARAM lParam)
{
//Put code to handle anything you want to handle manually here, usually in a big switch statement.
//Return 0 if message was handled correctly.
switch(Msg)
{
case WM_KEYDOWN: //If a key was pressed
switch(wParam)
{
case VK_ESCAPE: //If escape key was pressed
PostQuitMessage(0); //End program
break;
}
return 0;
break;
case WM_DESTROY: // any shutdown functions could go here
PostQuitMessage(0); //End program
return 0;
break;
case WM_SIZE:
switch(wParam)
{
case SIZE_MAXIMIZED: //If window is maximized or resized
case SIZE_RESTORED:
Screen.Size.right=LOWORD(lParam); //Set the front buffer''s new size
Screen.Size.bottom=HIWORD(lParam);
Canvas.Resize(Screen.Size.right, Screen.Size.bottom); //Resize the back buffer
ThreadRaster.Resume(); //Resume drawing if stopped
break;
case SIZE_MINIMIZED: //If window is minimized
ThreadRaster.Suspend(); //Stop drawing
break;
}
return 0;
break;
case WM_PAINT: //If it''s time to repaint
PAINTSTRUCT PS;
BeginPaint(hwnd, &PS);
//Do any static drawings here
EndPaint(hwnd, &PS);
return 0;
break;
}
return DefWindowProc(hwnd, Msg, wParam, lParam); //Send unhandled messages to the default windows Message Handler
}
//Draw frame to back buffer function
void DoFrame()
{
static int Change=0; //Direction of lines
static int Pos=0; //Position of lines
static int Change2=0; //Direction of window
static double Pos2=0; //Position of window
//Collision check lines with window edges
if(Pos>Canvas.Size.right-100) //If lines hit the sides
{
Change=1; //Change direction
Pos=Canvas.Size.right-100; //Reset position
}
else if(Pos>Canvas.Size.bottom-100) //If lines hit the bottom
{
Change=1; //Change direction
Pos=Canvas.Size.bottom-100; //Reset position
}
else if(Pos<0) //If lines hit the top
{
Change=0; //Change direction
Pos=0; //Reset position
}
if(Pos2>1) //If window reached max size
{
Change2=1; //Change direction
Pos2=1; //Reset position
}
else if(Pos2<0) //If window reached minimum size
{
Change2=0; //Change direction
Pos2=0; //Reset position
}
for(int i=0; i<100; i++) //Draw lines to back buffer
{
SetPixel(Canvas.hDC, i+Pos, i+Pos, RGB(255, 0, 0)); //Draw first line
SetPixel(Canvas.hDC, -i+Canvas.Size.right-Pos, i+Pos, RGB(255, 0, 0)); //Draw second line
}
//Create and set window''s next shape
//Create a rectangle the size of the whole window
HRGN temp=CreateRectRgn(0, 0, Screen.Size.right+8, Screen.Size.bottom+34);
//Cut out the inside of the window, not the boarders and title bar
CombineRgn(temp, temp, CreateRectRgn(4, 30, Screen.Size.right+4, Screen.Size.bottom+30), RGN_XOR);
//Add on the animated circle
CombineRgn(temp, temp, CreateEllipticRgn(Pos2/4*Screen.Size.right+4,
Pos2/4*Screen.Size.bottom+30,
Screen.Size.right-Pos2/6*Screen.Size.right+4,
Screen.Size.bottom-Pos2/6*Screen.Size.bottom+30), RGN_OR);
SetWindowRgn(hWnd, temp, true); //Set region to window
DeleteObject(temp); //Delete temp
if(Change==0) //Check how the lines'' position should change, and change it
Pos+=4;
else
Pos-=4;
if(Change2==0) //Check how the window''s shape should change, and change it
Pos2+=0.02;
else
Pos2-=0.02;
}
//Draw function
DWORD WINAPI Raster(LPVOID Param)
{
int StartTime=0;
//Main drawing loop
while(true)
{
StartTime=GetTickCount(); //Get frame start time
DoFrame(); //Draw to back buffer
Canvas.CopyTo(Screen); //Copy back buffer to front
Canvas.Erase(); //Clear back buffer
Sleep(33+GetTickCount()-StartTime); //Wait for next frame
}
return 0;
}
ScreenBuffer.h
#ifndef SCREENBUFFER_H
#define SCREENBUFFER_H
//Include Win32 API headers
#include <windows.h>
#include <windowsx.h>
//Define ScreenBuffer class
class ScreenBuffer
{
public:
HDC hDC; //DC handle
RECT Size; //DC size Note: RECT.Right==Width, RECT.Bottom==Height, RECT.left==X, RECT.top==Y.
COLORREF BGColour; //Erase colour
ScreenBuffer(HWND hWnd, COLORREF BkColour=0); //Create from window constuctor
ScreenBuffer(ScreenBuffer& a); //Copy constuctor
ScreenBuffer(); //Default constuctor
BOOL GetBuffer(HWND hWnd, COLORREF BkColour=0); //Initalize from window
BOOL CopyBuffer(ScreenBuffer& a); //Copy from another ScreenBuffer
~ScreenBuffer(); //Destuctor
BOOL Resize(int Width, int Height); //Resize ScreenBuffer
BOOL CopyTo(ScreenBuffer &a); //Copy ScreenBuffer contents to another ScreenBuffer
BOOL Erase(); //Clear ScreenBuffer
};
#endif
ScreenBuffer.cpp
#include "ScreenBuffer.h"
BOOL ScreenBuffer::Resize(int Width, int Height)
{
Size.right=Width; //Set new size
Size.bottom=Height;
//Create a new bitmap of specified size, and set it to the DC
return DeleteObject(SelectObject(hDC, CreateCompatibleBitmap(hDC, Width, Height)));
}
BOOL ScreenBuffer::CopyTo(ScreenBuffer &a)
{
//Copy DC contents to ScreenBuffer a
return BitBlt(a.hDC, 0, 0, Size.right, Size.bottom, hDC, 0, 0, SRCCOPY);
}
BOOL ScreenBuffer::Erase()
{
//Set the DC bitmap to background colour
return FillRect(hDC, &Size, CreateSolidBrush(BGColour));
}
ScreenBuffer::ScreenBuffer(HWND hWnd, COLORREF BackGroundColour)
{
hDC=GetDC(hWnd); //Get the DC from the window
BGColour=BackGroundColour; //Set the background colour
GetClientRect(hWnd, &Size); //Get the DC''s size
Size.left=0; //Reset the position to (0, 0)
Size.top=0;
}
ScreenBuffer::ScreenBuffer(ScreenBuffer& a)
{
hDC=CreateCompatibleDC(a.hDC); //Create a copy of a''s DC
BGColour=a.BGColour; //Set the background colour to a''s
Size.left=a.Size.left; //Set the DC position and size to a''s
Size.top=a.Size.top;
Size.right=a.Size.right;
Size.bottom=a.Size.bottom;
//Create a compaible bitmap the same size as a''s, and set it to the DC
DeleteObject(SelectObject(hDC, CreateCompatibleBitmap(a.hDC, Screen.Size.right, Screen.Size.bottom)));
}
BOOL ScreenBuffer::GetBuffer(HWND hWnd, COLORREF BackGroundColour)
{
hDC=GetDC(hWnd); //Get the DC from the window
if(hDC==NULL) //Check if it was successful
return FALSE;
BGColour=BackGroundColour; //Set the background colour
GetClientRect(hWnd, &Size); //Get the DC''s size
Size.left=0; //Reset the position to (0, 0)
Size.top=0;
return TRUE;
}
BOOL ScreenBuffer::CopyBuffer(ScreenBuffer& a)
{
hDC=CreateCompatibleDC(a.hDC); //Create a copy of a''s DC
if(hDC==NULL) //Check if it was successful
return FALSE;
BGColour=a.BGColour; //Set the background colour to a''s
Size.left=a.Size.left; //Set the DC''s position and size to a''s
Size.top=a.Size.top;
Size.bottom=a.Size.bottom;
Size.right=a.Size.right;
//Create a compaible bitmap the same size as a''s, and set it to the DC
return DeleteObject(SelectObject(hDC, CreateCompatibleBitmap(a.hDC, Screen.Size.right, Screen.Size.bottom)));
}
ScreenBuffer::ScreenBuffer()
{
hDC=NULL; //Set the DC to Null
Size.top=0; //Set the DC''s position and size to 0
Size.left=0;
Size.right=0;
Size.bottom=0;
BGColour=0; //Set the background colour to 0 or black.
}
ScreenBuffer::~ScreenBuffer()
{
DeleteDC(hDC); //Delete the DC
}
ThreadStuff.h
#ifndef THREADSTUFF_H
#define THREADSTUFF_H
//Include Win32 API headers
#include <windows.h>
#include <windowsx.h>
//Define Thread class
class Thread
{
public:
HANDLE hThread; //Thread handle
DWORD ThreadID; //Thread ID
//Thread constuctor
Thread(LPTHREAD_START_ROUTINE ThreadFunction, DWORD StartStatus=0, LPVOID Parameter=0, DWORD StackSize=0);
Thread(); //Default constuctor
~Thread(); //Thread destuctor
//Initalize thread
BOOL Initalize(LPTHREAD_START_ROUTINE ThreadFunction, LPVOID Parameter=0, DWORD StartStatus=0, DWORD StackSize=0);
DWORD Suspend(); //Suspend thread
DWORD Resume(); //Resume thread
void Pause(DWORD Milliseconds); //Sleep thread
};
//Define Mutex class
class Mutex
{
public:
HANDLE hMutex; //Mutex handle
LPCTSTR Name; //Mutex name
Mutex(BOOL StartLocked, LPCTSTR MutexName); //Mutex constuctor
Mutex(); //Default constuctor
~Mutex(); //Mutex destuctor
BOOL Unlock(); //Unlock Mutex
DWORD WaitToLock(DWORD Milliseconds=INFINITE); //Wait for Mutex to unlock, then lock it
BOOL Open(LPCTSTR MutexName); //Open this Mutex to another one
};
//Define CriticalSection
class CriticalSection
{
public:
CRITICAL_SECTION hCriticalSection; //CriticalSection handle
CriticalSection(); //CriticalSection constuctor
~CriticalSection(); //CriticalSection destuctor
void WaitToLock(); //Wait for CriticalSection to unlock, then lock it
void Unlock(); //Unlock CriticalSection
};
#endif
ThreadStuff.cpp
#include "ThreadStuff.h"
Thread::Thread(LPTHREAD_START_ROUTINE ThreadFunction, DWORD StartStatus, LPVOID Parameter, DWORD StackSize)
{
//Create the thread
hThread=CreateThread(NULL, //No security atributes (what are they for?)
StackSize, //The stack size
ThreadFunction,//Thread''s main function
Parameter, //Fuction parameter
StartStatus, //Start suspended or not
&ThreadID); //Address of where the thread ID will be stored
}
Thread::Thread()
{
hThread=NULL; //Set thread handle to nothing
ThreadID=0; //Set the thread''s ID to nothing
}
Thread::~Thread()
{
CloseHandle(hThread); //Delete the thread
}
DWORD Thread::Suspend()
{
return SuspendThread(hThread); //Suspend thread execution
}
DWORD Thread::Resume()
{
return ResumeThread(hThread); //Resume thread execution
}
void Thread::Pause(DWORD Milliseconds)
{
Sleep(Milliseconds); //Stop the thread excution for givin number of milliseconds
}
Mutex::Mutex(BOOL StartLocked, LPCTSTR MutexName)
{
Name=MutexName; //Set the mutex name
//Create the mutex
hMutex=CreateMutex(NULL, //No secutity attibutes (what are they for?)
StartLocked, //Initally locked or not
MutexName); //The name the mutex will have
}
Mutex::Mutex()
{
Name=NULL; //Set name to nothing
hMutex=NULL; //Set the mutex handle to nothing
}
Mutex::~Mutex()
{
Name=NULL; //Set the name to nothing
CloseHandle(hMutex); //Close the mutex
}
BOOL Mutex::Unlock()
{
return ReleaseMutex(hMutex); //Unlock the mutex
}
DWORD Mutex::WaitToLock(DWORD Milliseconds)
{
//Pause the calling thread''s execution until the mutex unlocks, then lock it.
//If the givin time limit is reached, then funtion returns with a fail.
return WaitForSingleObject(hMutex, Milliseconds);
}
BOOL Mutex::Open(LPCTSTR MutexName)
{
//Make a new mutex, and check if it was a success
if((hMutex=OpenMutex(MUTEX_ALL_ACCESS, FALSE, MutexName))==NULL)
{
Name=NULL; //If not, set the name to nothing
return FALSE; //Return fail
}
else
{
Name=MutexName; //Otherwise, set the name
return TRUE; //Return success
}
}
CriticalSection::CriticalSection()
{
//Create the cirtical section
InitializeCriticalSection(&hCriticalSection);
}
CriticalSection::~CriticalSection()
{
//Delete the critical section
DeleteCriticalSection(&hCriticalSection);
}
void CriticalSection::WaitToLock()
{
//Suspend calling thread''s execution until the critacal section unlocks, then lock it
EnterCriticalSection(&hCriticalSection);
}
void CriticalSection::Unlock()
{
//Unlock the critical section
LeaveCriticalSection(&hCriticalSection);
}
[s] [/s]
I can see the fnords.