Re: Forum for windows programming?

From: Martijn Mulder (i_at_m)
Date: 02/19/05


Date: Sat, 19 Feb 2005 07:10:04 +0100

JoeC wrote:
> I am trying to learn win32 API prograaaming with C++.
> Where can I go to get basic advice and discuss that
> topic? I wrtite my porgram in C++ using the windows.h
> library and my C++ compiler. I am trying to write good
> C++ programs with graphics and GUIs.

Use this code as a basic two-mouse-button drawing tool and hack! Also look at

http://www.relisoft.com/win32/index.htm

for a nice Windows API tutorial.

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

using namespace std;

/* function DebugMSG()
Function DebugMSG() displays debug information about Windows messages like
WM_CREATE, WM_INITMENUPOPUP, WM_COMMAND etc. that are send from Windows
to WindowProc().
*/
void DebugMSG(const string&a,UINT b,WPARAM c,LPARAM d)
{
 cout<<"\nMSG: "<<a<<'('<<b<<')';
 cout<<"\t\t"<<LOWORD(c)<<'-'<<HIWORD(c);
 cout<<'\t'<<LOWORD(d)<<'-'<<HIWORD(d);
}

/* pointer HWND hwnd
Forward declaration of global data member hwnd. It's value is set
in function Window::Create(). There is only one HWND for the whole
program.
*/
static HWND hwnd;

//struct Color
struct Color
{

 //data members red, green, blue
 int red,green,blue;

 //constructor
 Color(int a=0,int b=0,int c=0):red(a),green(b),blue(c)
 {
  red=rand()%256;
  green=rand()%256;
  blue=rand()%256;
 }

 //operator COLORREF
 operator COLORREF()const{return RGB(red,green,blue);}
};

//struct Pen
struct Pen
{

 //data member color
 Color color;

 //data member width
 int width;

 //constructor
 Pen(int a=1):width(a)
 {
  width=rand()%75+1;
 }

 //operator HPEN
 operator HPEN()const{return::CreatePen(PS_SOLID,width,color);}
};

//struct DC
struct DC
{

 //data member paintstruct
 PAINTSTRUCT paintstruct;

 //data member hdc
 HDC hdc;

 //constructor
 DC()
 {
  hdc=::BeginPaint(hwnd,&paintstruct);
  cout<<"\nDC.constructor";
  cout<<"\nPAINTSTRUCT.rcPaint: ";
  cout<<paintstruct.rcPaint.left<<", ";
  cout<<paintstruct.rcPaint.top<<", ";
  cout<<paintstruct.rcPaint.right<<", ";
  cout<<paintstruct.rcPaint.bottom;
 }

 //destructor
 ~DC()
 {
  cout<<"\nDC.destructor";
  ::DeleteObject(::SelectObject(hdc,::GetStockObject(BLACK_PEN)));
  ::EndPaint(hwnd,&paintstruct);
 }
};

//struct BackDC
struct BackDC
{

 //data member hdc
 HDC hdc;

 //data member bitmap
 HBITMAP bitmap;

 //data members width, height
 int width,height;

 //constructor
 BackDC()
 :
 width(::GetSystemMetrics(SM_CXSCREEN)),
 height(::GetSystemMetrics(SM_CYSCREEN))
 {
  cout<<"\nBackDC.constructor";
  HDC a=::GetDC(hwnd);
  hdc=::CreateCompatibleDC(a);
  bitmap=::CreateCompatibleBitmap(a,width,height);
  ::ReleaseDC(hwnd,a);
  ::SelectObject(hdc,bitmap);
  ::SelectObject(hdc,::GetStockObject(WHITE_BRUSH));
  ::PatBlt(hdc,0,0,width,height,PATCOPY);
 }

 //destructor
 ~BackDC()
 {
  cout<<"\nBackDC.destructor";
  ::DeleteObject(::SelectObject(hdc,::GetStockObject(BLACK_PEN)));
  ::DeleteObject(bitmap);
  ::DeleteDC(hdc);
 }

 //clear
 void clear()const{::PatBlt(hdc,0,0,width,height,PATCOPY);}

 //moveTo
 void moveTo(int a,int b)const
 {
  POINT c;
  ::MoveToEx(hdc,a,b,&c);
 }

 //lineTo
 void lineTo(int a,int b)const{::LineTo(hdc,a,b);}

 //selectPen
 void selectPen(const Pen&a)const{::DeleteObject(::SelectObject(hdc,a));}

 //update
 void update()const
 {
  DC dc;
  ::BitBlt(dc.hdc,0,0,width,height,hdc,0,0,SRCCOPY);
 }
};

//struct Point
struct Point
{

 //data members x, y
 long x,y;

 //constructor
 Point(long a=0,long b=0):x(a),y(b){}
};

//struct Line
struct Line
{

 //data member points
 vector<Point>points;

 //data member pen
 Pen pen;

 //constructor
 Line(){}

 //addPoint
 void addPoint(int a,int b)
 {
  points.push_back(Point(a,b));
  InvalidateRect(hwnd,0,false);
 }

 //paint
 void paint(const BackDC&a)
 {
  POINT b;
  a.selectPen(pen);
  a.moveTo(points[0].x,points[0].y);
  for(int c=1;c<points.size();c++)a.lineTo(points[c].x,points[c].y);
 }
};

//struct Drawing
struct Drawing
{

 //data member lines
 vector<Line>lines;

 //enum DRAWINGSTYLE
 enum DRAWINGSTYLE{NONE,DRAW,LINE};

 //drawingstyle
 DRAWINGSTYLE drawingstyle;

 //constructor
 Drawing():drawingstyle(NONE){}

 //addPoint
 void addPoint(int a,int b){lines[lines.size()-1].addPoint(a,b);}

 //addLine
 void addLine(){lines.push_back(Line());}

 //mouseMove
 void mouseMove(int a,int b)
 {
  switch(drawingstyle)
  {
   case NONE:break;
   case LINE:
        lines[lines.size()-1].points[1]=Point(a,b);
        break;
   case DRAW:
        lines[lines.size()-1].addPoint(a,b);
        break;
  }}

 //rButtonDown
 void rButtonDown(int a,int b)
 {
  drawingstyle=LINE;
  addLine();
  addPoint(a,b);
  addPoint(a,b);
 }

 //lButtonDown
 void lButtonDown(int a,int b)
 {
  drawingstyle=DRAW;
  addLine();
  addPoint(a,b);
 }

 //ButtonUp
 void ButtonUp(){drawingstyle=NONE;}

 //paint
 void paint(const BackDC&a)
 {
  a.clear();
  for(int c=0;c<lines.size();c++){lines[c].paint(a);}
  a.update();
 }
};

//global data member drawing
Drawing drawing;

//global data member backdc
BackDC backdc;

//WindowProc
LRESULT CALLBACK WindowProc(HWND a,UINT b,WPARAM c,LPARAM d)
{
 switch(b)
 {

 case WM_CHAR:
         ::DebugMSG("WM_CHAR",b,c,d);
         break;

 case WM_CREATE:
          ::DebugMSG("WM_CREATE",b,c,d);
          break;

  case WM_COMMAND:
          ::DebugMSG("WM_COMMAND",b,c,d);
          break;

 case WM_DESTROY:
         ::DebugMSG("WM_DESTROY",b,c,d);
         ::PostQuitMessage(0);
         break;

 case WM_DRAWITEM:
         ::DebugMSG("WM_DRAWITEM",b,c,d);
         break;

 case WM_ENTERIDLE:
         ::DebugMSG("WM_ENTERIDLE",b,c,d);
         break;

 case WM_ENTERMENULOOP:
         ::DebugMSG("WM_ENTERMENULOOP",b,c,d);
         break;

 case WM_EXITMENULOOP:
         ::DebugMSG("WM_EXITMENULOOP",b,c,d);
         break;

 case WM_INITMENU:
         ::DebugMSG("WM_INITMENU",b,c,d);
         break;

 case WM_INITMENUPOPUP:
         ::DebugMSG("WM_INITMENUPOPUP",b,c,d);
         break;

 case WM_KEYDOWN:
         ::DebugMSG("WM_KEYDOWN",b,c,d);
         break;

 case WM_KEYUP:
         ::DebugMSG("WM_KEYUP",b,c,d);
         break;

 case WM_LBUTTONDOWN:
         ::DebugMSG("WM_LBUTTONDOWN",b,c,d);
         ::SetCapture(hwnd);
  drawing.lButtonDown(LOWORD(d),HIWORD(d));
         break;

 case WM_LBUTTONUP:
         ::DebugMSG("WM_LBUTTONUP",b,c,d);
         ::ReleaseCapture();
  drawing.ButtonUp();
         break;

  case WM_MOUSEMOVE:
          drawing.mouseMove(LOWORD(d),HIWORD(d));
          InvalidateRect(hwnd,0,false);
         break;

 case WM_NOTIFY:
         ::DebugMSG("WM_NOTIFY",b,c,d);
  break;

 case WM_PAINT:
         ::DebugMSG("WM_PAINT",b,c,d);
         drawing.paint(backdc);
         break;

 case WM_RBUTTONDOWN:
         ::DebugMSG("WM_RBUTTONDOWN",b,c,d);
  ::SetCapture(hwnd);
  drawing.rButtonDown(LOWORD(d),HIWORD(d));
         break;

 case WM_RBUTTONUP:
         ::DebugMSG("WM_RBUTTONUP",b,c,d);
  drawing.ButtonUp();
  ::ReleaseCapture();
         break;

 default:return::DefWindowProc(a,b,c,d);

 }
 return 0;
}

//struct Window
struct Window
{

 //data member name
 const char*name;

 //constructor
 Window(const char*a)
 :
 name(a)
 {
  Register();
  Create();
 }

 //Create
 void Create()
 {
  hwnd=::CreateWindow
  (
   name,
   name,
   WS_OVERLAPPEDWINDOW,
   CW_USEDEFAULT,
   CW_USEDEFAULT,
   CW_USEDEFAULT,
   CW_USEDEFAULT,
   0,
   0,
   NULL,//hinstance,
   0
  );
  ::ShowWindow(hwnd,SW_SHOWNORMAL);
  ::UpdateWindow(hwnd);
 }

 //Register
 void Register()
 {
  WNDCLASSEX a=
  {
   sizeof(WNDCLASSEX),
   CS_HREDRAW|CS_VREDRAW|CS_BYTEALIGNCLIENT,
   WindowProc,
   0,
   0,
   NULL,//hinstance,
   NULL,
   LoadCursor(0,IDC_ARROW),
   (HBRUSH)(::GetStockObject(WHITE_BRUSH)),
   name,
   name
  };
  if(!::RegisterClassEx(&a))cout<<"\nRegisterClassEx failed";
}};

//global data member window
static Window window("Minimal Windows Application");

//WinMain
int WINAPI WinMain(HINSTANCE a,HINSTANCE b,char*c,int d)
{
 MSG msg;
 int status;
 while((status=::GetMessage(&msg,0,0,0))!=0)
 {
  if(status==-1)return -1;
 {
  ::TranslateMessage(&msg);
  ::DispatchMessage(&msg);
 }}
 return msg.wParam;
}