1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119
|
LRESULT CALLBACK fnWndProc(HWND hwnd, unsigned int msg, WPARAM wParam, LPARAM lParam)
{
ProgramData* pPD=NULL;
switch(msg)
{
case WM_CREATE: //This message is only received once at program startup.
{ //Here we'll dynamically allocate memory on the heap to
std::wstring* pStr; //store inputs the program will receive in terms of key-
pStr=new std::wstring; //presses, mouse movements, button clicks, etc. We'll
SetWindowLong(hwnd,0,(long)pStr);//store pointers to this memory in 8 bytes we've
pPD=(ProgramData*)GlobalAlloc(GPTR,sizeof(ProgramData));
if(pPD) //allocated in theWNDCLASSEX struct down in WinMain()
{
SetWindowLong(hwnd,4,(long)pPD);
return 0;
}
else
{
return -1;
}
}
case WM_SIZE: //Sent when the Window is first shown or resized. We need
{ //to first retrieve the ProgramData* from the cbWndExtra
pPD=(ProgramData*)GetWindowLong(hwnd,4); //bytes. Then we can retrieve from
pPD->xSize=LOWORD(lParam); //lParam's lo and hi words the width
pPD->ySize=HIWORD(lParam); //and height of the window. Then
InvalidateRect(hwnd,NULL,TRUE); //force a WM_PAINT to redraw the
return 0; //newly acquired info.
}
case WM_CHAR: //Sent when this program has the focus and the user hits
{ //a char on the keypad. Same drill as above; retrieve
std::wstring* pStr; //String pointer though; Then just add the wParam (which
pStr=(std::wstring*)GetWindowLong(hwnd,0); //holds the key code pressed) to the
*pStr+=+wParam; //String and force the repaint as
InvalidateRect(hwnd,NULL,FALSE); //above.
return 0;
}
case WM_MOUSEMOVE: //Sent when user moves mouse and mouse cursor is over this
{ //window. 1st retrieve ProgramData* from cbWndExtra bytes.
pPD=(ProgramData*)GetWindowLong(hwnd,4); //Then extract present mouse coord-
pPD->xMouse=LOWORD(lParam); //inates from lParam's Lo and Hi words.
pPD->yMouse=HIWORD(lParam); //Finally force repaint.
InvalidateRect(hwnd,NULL,TRUE);
return 0;
}
case WM_LBUTTONDOWN: //Sent when user left button mouse clicks over window. In
{ //terms of the rest, you should be getting the idea by now!
pPD=(ProgramData*)GetWindowLong(hwnd,4);
pPD->xButton=LOWORD(lParam);
pPD->yButton=HIWORD(lParam);
InvalidateRect(hwnd,NULL,FALSE);
return 0;
}
case WM_PAINT: //All drawing to a window should be done during a WM_PAINT message.
{ //That is why in all of the above message handling code except that
PAINTSTRUCT ps; //for WM_CREATE there is an InvalidateRect() Api call. That call
std::wstring s1; //will cause Windows to invalidate the client area of the window,
std::wstring s2; //and when this occurs windows will post to the window's message
std::wstring* pStr; //queue a WM_PAINT message. In this code just left we are
TCHAR szBuffer[16]; //allocating a few standard string objects, and a TCHAR
HDC hDC; //buffer. These will support the text we wish to display
hDC=BeginPaint(hwnd,&ps); //using TextOut(). What we first do though is call
pPD=(ProgramData*)GetWindowLong(hwnd,4); //BeginPaint() to get a handle to a
s1=_T("xMouse="); //device context (which is necessary
_stprintf(szBuffer,_T("%d"),pPD->xMouse); //for GDI (Graphics Device Interface)
s2=szBuffer; //function calls, and then call
s1+=s2+_T(" yMouse="); //GetWindowLong() to retrieve our
_stprintf(szBuffer,_T("%d"),pPD->yMouse); //ProgramData pointer from the Window
s2=szBuffer; //Class struct. Having done that we can
s1+=s2; //chug through some string minipulation
TextOut(hDC,0,0,s1.c_str(),s1.length()); //code to compose the messages we want
if(pPD->xButton||pPD->yButton) //to display in our window, which
{ //messages contain the various numeric
s1=_T("xButton="); //information we want to convey. Note
_stprintf(szBuffer,_T("%d"),pPD->xButton); //that _stprintf() is used to convert
s2=szBuffer; //the integral data to a string format
s1+=s2+_T(" yButton="); //so it can be output in a std::string.
_stprintf(szBuffer,_T("%d"),pPD->yButton); //If you know a better way to do it go
s2=szBuffer; //for it. I'm not really expert on the
s1+=s2; //std::string class, as I mostly use my
TextOut //own. Finally, after outputting all
( //the data we want we need to call
hDC, //EndPaint() to release the device
pPD->xButton+12, //context. This is important because
pPD->yButton, //if you don't release memory objects
s1.c_str(), //and resources back to the operating
s1.length() //system you'll cause a memory leak, and
); //your program will start to behave
pPD->xButton=0, pPD->yButton=0; //rather badly. Essentially, .NET
} //is Microsoft's answer to the problem
s1=_T("Width="); //that the average coder can't be trusted
_stprintf(szBuffer,_T("%d"),pPD->xSize); //to do things like this correctly, so
s2=szBuffer; //the framework takes care of it for
s1+=s2+_T(" Height="); //him/her. So you've got to ask yourself,
_stprintf(szBuffer,_T("%d"),pPD->ySize); //"Are you better than the average coder?"
s2=szBuffer; //
s1+=s2; //In WM_DESTROY below we'll release the
TextOut(hDC,0,20,s1.c_str(),s1.length()); //std::string pointer we acquired with
pStr=(std::wstring*)GetWindowLong(hwnd,0); //new by calling delete on it, and we'll
TextOut(hDC,0,40,pStr->c_str(),pStr->length()); //use GlobalFree() on the ProgramData
EndPaint(hwnd,&ps); //pointer we acquired with GlobalAlloc().
return 0;
}
case WM_DESTROY:
{
std::wstring* pStr;
pStr=(std::wstring*)GetWindowLong(hwnd,0);
delete pStr;
pPD=(ProgramData*)GetWindowLong(hwnd,4);
if(pPD)
GlobalFree(pPD); //send the WM_DESTROY. Anyway, what we need to do here is
PostQuitMessage(0);//release our heap allocations and post a Quit message.
return 0;
}
}
return (DefWindowProc(hwnd, msg, wParam, lParam));
}
|