HomeC&C++WainTutorialsSamplesTip & TrickTools


Here I will show how to create a magnifying glass.
The basic is a simple window application as the one from the tutorial
This will be the Window Message handler:
LRESULT CALLBACK MainWndProc(HWND hwnd,
                             UINT msg,
                             WPARAM wParam,
                             LPARAM lParam)
{
   switch (msg)
   {
   case WM_DESTROY:
      PostQuitMessage(0);
      break;
   case WM_MOVE:
      HDC Dc;
      Dc = GetDC(hwnd);
      Draw(Dc);
      ReleaseDC(hwnd, Dc);
      break;
   case WM_PAINT:
      PAINTSTRUCT PaintStruct;
      HDC dc;
      dc = BeginPaint(hwnd, &PaintStruct);
      Draw(dc);
      EndPaint(hwnd, &PaintStruct);
      break;
   default:
      return DefWindowProc(hwnd,msg,wParam,lParam);
   }
   return 0;
}
Draw is the funtion which will do the work.
In this first version we will magnify the what is shown at the left hand side of our application, and we will magnify it 4 times.
void Draw(HDC aDc)
{
   RECT R;
   GetWindowRect(MainWindow, &R);
   int Width = (R.right - R.left + 3)/4;
   int Height = (R.bottom - R.top + 3)/4;
   POINT UpperLeft = {R.left - Width, R.top};
First we find the our windows position on the screen, the we calculate the width and height of the source rectangle, that is, the rectangle which we are to show on our window.
UpperLeft is the point at the upper left corner of the source window. Then we get a Device Context for the screen:
   HDC DC = GetDC(0);
Then to copy from the source rectangle to our window is as simple as:
   StretchBlt(aDc,
              0,
              0,
              Width*4,
              Height*4,
              DC,
              UpperLeft.x,
              UpperLeft.y,
              Width,
              Height,
              SRCCOPY);
StretchBlt will copy from source to our window, and enlage it.
Don't forget to release the DC:
   ReleaseDC(0, DC);
And that's all there is to it. The Source

And now a enhancement to the magnifying glass, which also show how to use the system menu.
The system menu is the menu you get when you click on the upper left corner of most windows applications, you can normally also access the menu by typing ALT+Space.
First we define some message ID's which also show which features we are to add:
enum MessageId
{
   DisplayLeftMsgId = 1024,
   DisplayTopMsgId,
   DisplayRightMsgId,
   DisplayBottomMsgId,
   Zoom2MsgId,
   Zoom4MsgId,
   Zoom8MsgId,
   Zoom16MsgId,
};
The first 4 will be used to select what part we are to show on the application, the part on the left, top, right or bottom side of the application.
The last 4 is used to specify the zoom factor, 2,4,8,16.
Now we must get the system menu, in order to modify it:
   HMENU SysMenu = GetSystemMenu(MainWindow, FALSE);
Then we add a seperator (a thin line) and the first items:
   AppendMenu(SysMenu, MF_SEPARATOR, 0 , 0);
   AppendMenu(SysMenu,
              MF_STRING,
              DisplayLeftMsgId,
              "Display Left");
   // etc...
And a seperator and the 4 last items:
   AppendMenu(SysMenu, MF_SEPARATOR, 0 , 0);
   AppendMenu(SysMenu, MF_STRING, Zoom2MsgId, "Zoom * 2");
   // etc...
When the user selects one of our menu items, windows will send a WM_SYSCOMMAND, so we must castch it, in our message handler:
   case WM_SYSCOMMAND:
   {
      switch(wParam)
      {
wParam is the message id, we will handle the first four in one go:
      case DisplayLeftMsgId:
      case DisplayTopMsgId:
      case DisplayRightMsgId:
      case DisplayBottomMsgId:
         ZoomPos = (MessageId )wParam;
         Draw();
         break;
ZoomPos is a variable which will store the current position:
MessageId ZoomPos = DisplayLeftMsgId;
Draw is a function which gets a DC and calls the other Draw function:
void Draw()
{
   HDC Dc;
   Dc = GetDC(MainWindow);
   Draw(Dc);
   ReleaseDC(MainWindow, Dc);
}
The Zoom factor is handled the same way:
      case Zoom2MsgId:
      case Zoom4MsgId:
      case Zoom8MsgId:
      case Zoom16MsgId:
         ZoomFactor = (MessageId )wParam;
         Draw();
         break;
ZoomFactor is defined as:
MessageId ZoomFactor = Zoom4MsgId;
All other WM_SYSCOMMAND messages must be handled by the default window proc, it would not be possible to close the application otherwice:
      default:
         return DefWindowProc(hwnd, msg, wParam, lParam);
Now we must modify the Draw function to use the new parameters, first we convert ZoomFactor, which was some consecutive numbers into 2, 4, 8, 16:
void Draw(HDC aDc)
{
   int Zoom = 1 << (ZoomFactor - Zoom2MsgId + 1);
Then we set the upper-left corner for the rectangle to show on the application:
   RECT R;
   GetWindowRect(MainWindow, &R);
   int Width = (R.right - R.left + Zoom - 1)/Zoom;
   int Height = (R.bottom - R.top + Zoom - 1)/Zoom;

   POINT UpperLeft;
   switch(ZoomPos)
   {
   case DisplayLeftMsgId:
      UpperLeft.x = R.left - Width;
      UpperLeft.y = R.top;
      break;
   case DisplayTopMsgId:
      UpperLeft.x = R.left;
      UpperLeft.y = R.top - Height;
      break;
   case DisplayRightMsgId:
      UpperLeft.x = R.right;
      UpperLeft.y = R.top;
      break;
   case DisplayBottomMsgId:
      UpperLeft.x = R.right - Width;
      UpperLeft.y = R.bottom;
      break;
   }
Then we can copy the bits to our application:
   HDC DC = GetDC(0);
   StretchBlt(aDc,
              0,
              0,
              Width*Zoom,
              Height*Zoom,
              DC,
              UpperLeft.x,
              UpperLeft.y,
              Width,
              Height,
              SRCCOPY);
   ReleaseDC(0, DC);
And we are done. The Source