CS-460/560, Wk1c
Spring, 2000
R. Eckert


EXAMPLE--user moves mouse cursor over a pgm's window area
         and clicks left mouse button.

  Windows decodes HW signals from mouse
  Figures out which pgm user has selected
  Sends a message to pgm:
                   "User has clicked over (X,Y)"
                   "Do something and return control to me"

  Pgm reads message data, does what's needed, returns control to Windows

  (2 main tasks)--

  Initial activities 
  Process messages from Windows (the message loop)


  Initialize variables, memory space

  Create & Show the program's Window

     Fetch any message sent from Windows to this program
     If message is QUIT
        Terminate program, return control to Windows
     If message is something else
        Do appropriate actions based on the message ID and parameters
     Return control to Windows
  End Loop



  A. The WinMain() function--

     0. Include files, variable declarations, initialization, etc.

     1. Register the class from which the program window will be derived.

     2. Create a window based on a registered class.

     3. Show the window and cause it to update (repaint) its client area.

     4. The Message Loop--Get messages from Windows and dispatch back to
        Windows for forwarding to the correct callback message-processing
        function; Messages are usually the result of user actions.

  B. The WndProc() function--The callback function that acts on messages
     from Windows.


  Resource data--Windows static data.

     Separate from code and dynamic data
     Compiled by a separate "Resource Compiler"
     Examples: Keyboard Accelerators, Bitmaps, Cursors, Dialog Box
               Definitions, Fonts, Icons, Menus, String Tables.

     Separation of static resources and program code-->
       Reduced memory demands
       Separate tasks of programmer and designer
       Changes can be made to user interface without touching the code

NOW WE LOOK AT THE DETAILS (Refer to the EXAMPLE application)--


#include <windows.h>        /* window's header file - always included */
                            /* contains constant and function definitions */

  A. THE WinMain() FUNCTION--

  int PASCAL WinMain (HANDLE hInstance, HANDLE hPrevInstance,
                                     LPSTR lpszCmdLine, int nCmdShow);

  Every Windows program must have a WinMain--like main(), starts first.
     -returns an int exit code to Windows which does nothing with it.
     -PASCAL: l-to-r parm passing on stack, faster than C convention.

  4 parameters passed from Windows to WinMain():

   -hinstance: instance handle--an ID # created by Windows when app starts.
    Each instance has a unique handle, identifies application's data.

    [Handle--a pointer to a pointer. Locates an object in memory even though
    Windows moves things around.]

   -hPrevInstance: if another copy of program is started, will contain the
    hInstance value for the last copy started; NULL (0) if no other copy
    running. (Under Win32 this is not used.)

   -lpszCmdLin: pointer to a char string containing the command line
    arguments passed to the program. (like argc, argv in a DOS C program).

   -nCmdShow: an integer passed to the program's ShowWindow() function.
    Windows is telling the application whether its window is to appear
    minimized, as an icon, normal, or maximized when it's first displayed.

  Hungarian Notation--used very commonly in Windows programs:
    -Help to clarify types of variables
    -Precede name with key letters representing its type
    -Named after Hungarian Microsoft programmer, Charles Simonyi

  prefix   data type
  by    BYTE (unsigned char)
  b     BOOL (int, use only TRUE and False, values: 1 and 0)
  c     char
  dw    DWORD (double word, 4-byte unsigned long int)
  fn    function
  h     handle. An ID value Windows uses internally to keep track of memory
        blocks, window ID values, etc.
  i     int (two byte signed)
  l     long (4 bytes)
  n     short (int) near pointer
  p     pointer
  s     character string
  sz    null-terminated character string
  w     word (two bytes)
  can be combined -- lpsz: long pointer to a null-terminated string 


  New windows are created from "classes". All windows of a given class have
  same properties: backgrond color, cursor shape, pass Windows messages to
  the same function. Can use predefined classes (e.g. "BUTTON") or define and
  register a new class.

  There can be many instances of the same class.

  Windows can only be created if their class has been "registered"--

  RegisterClass()--takes one parameter--a ptr to a WNDCLASS structure. The
  program must fill in the members of the class describing the window class
  before calling RegisterClass().

  typedef struct tagWNDCLASS
  UINT    style;        /*bitwise or'd binary flags specify window style*/
  LRESULT CALLBACK lpfnWndProc)();  /*ptr to the msg-processing function*/
  int     cbClsExtra;   /*count of extra bytes after window class, usually 0*/
  int     cbWndExtra;   /*count of extra bytes after window instance, " */
                        /*both could be used to reserve memory for extra data*/
  HINSTANCE  hInstance;    /*creating program's instance handle*/
  HICON   hIcon;        /*handle to the window class icon */
  HCURSOR hCursor;      /*handle to the window class cursor shape*/
  HBRUSH  hBackground;  /*window class background brush*/
  LPSTR   lpszMenuName  /*pointer to resource name of class menu*/
  LPSTR   lpszClassName; /*ptr to name of the window's class*/

  To register the class of our window, we must set up the members of a WNDCLASS 
  variable and call RegisterClass() as follows:

         WNDCLASS wndclass;
         wndclass.style          = CS_HREDRAW | CS_VREDRAW ;
         wndclass.lpfnWndProc    = WndProc ;
         wndclass.cbClsExtra     = 0 ;
         wndclass.cbWndExtra     = 0 ;
         wndclass.hInstance      = hInstance ;
         wndclass.hIcon          = LoadIcon (hInstance, "MyIcon") ;
         wndclass.hCursor        = LoadCursor (NULL, IDC_ARROW) ;
         wndclass.hbrBackground  = GetStockObject (WHITE_BRUSH) ;
         wndclass.lpszMenuName   = "MyMenu" ;
         wndclass.lpszClassName  = "MyClass" ;
         if (!RegisterClass (&wndclass))
               return 0 ;

  If the call to RegisterClass(&wndclass) is successful, a non-zero result will 
  be returned. If not, we should return a 0 to Windows, which causes execution to 

  -wndclass fields for EXAMPLE.C window:

  .style-- CS_HREDRAW|CS_VREDRAW--bitwise or operator==> specifies that
  windows of this class should be redrawn if either the horizontal or
  verticdal size changes.

    CS_HREDRAW = 00000010B
    CS_VREDRAW = 00000001B
    or'd value = 00000011B

  These are examples of binary flags--each bit means something, Bitwise or
  operation is a way to tell Windows that several conditions are to be set.
  Way to specify combinations. (See Help/Search/WNDCLASS).

  .lpfnWndProc--WndProc: the name (address) of the function to be called when
  windows sends messages; could have any name you like, but that name must be
  registered. Here the name used is WndProc. This function must be declared --
  usually at the top of the source file or, more commonly, in a header file
  included at the top of the source file.

  .cbClsExtra & .cbWndExtra--no extra memory allocated for this class.

  .hInstance--specifies which instance the WinProc() lies in.--it's this
  instance (passed as a parameter by Windows to WinMain()). Used as a
  unique identification for the application calling RegisterClass().

  .hIcon, .hCursor--use Windows load functions to use some predefined objects.
  IDI_APPLICATION--constant meaning the std windows icon;
  IDC_ARROW--constant meaning the standard arrow pointer.
  (These are defined in the windows.h file)
  Examples:  LoadIcon (NULL, IDI_APPLICATION);
             LoadCursor (NULL, IDC_ARROW);

  .hbrBackground--use Windows GetStockObject() to obtain a solid white brush
  which paints the background color of the window. This is a handle to a
  brush -- a graphics term refering to the pattern of pixels used to fill
  an area. A brush is an example of a Windows "Graphics Device Interface"
  (GDI) object. Many other GDI objects are used to "paint" on the client
  area of a window.

  .lpszMenuName--"MyMenu": The menu is described in the resource script file.

  .lpszClassName--the name given to this window class; will be used when we
  create a window based on the class.

  After registering the new window class, the program must create the window.
  Any number of windows based on this class can be created.


  CreateWindow() creates the program's window & returns a handle (a unique ID)
  value of type HWND (for the window created)

  Arguments to CreateWindow():
    window class name
    window caption
    window style (Boolean OR of different predefined style masks)
    initial x position in pixels
    initial y position
    initial width
    initial height
    parent window handle (if main window, no parent ==> NULL)
    window menu handle (NULL if no menu or if class menu is to be used)
    program instance handle (passed in from Windows)
    creation parameters (can be used to access extra data, usually NULL)

  HWND    hWnd ;
  hWnd = CreateWindow ("MyClass","Example", WS_OVERLAPPEDWINDOW,
         100, 50, 400, 200, NULL, NULL, hInstance, NULL) ;


    ShowWindow (hWnd,nCmdShow); -- makes window just created visible on screen

    -hWnd: specifies which window to make visible

    -nCmdShow: specifies how (normal, minimized, etc.)
               -set by Windows environment when program is started;
               -value is passed in from Windows;
               -"normal" can be overridden: start program from the program
                 manager "file/run" & select "Run minimized"


     UpdateWindow (hWnd);


  Any time the user interacts with the window, the Windows OS sends a message 
  to the window's WndProc(). The interaction could be mouse movement, a mouse 
  button click, a keyboard key press, a resizing or moving operation that causes 
  some area to be exposed (with a resultant need to be repainted), or any number 
  of other operations. (Windows sends many other messages as well.)

  A message consistgs of some data placed in a block of memory:

  A C structure--

    typedef struct tagMSG
    HWND    hwnd;     /* handle of target window */
    UINT    message;  /* message ID value--always a WM_* constant */
    WPARAM  wParam;   /* a double word of data passed in the message */
    LPARAM  lParam;   /* a second double word of data in the message */
    DWORD   time;     /* time in msec message was sent */
    POINT   pt;       /* mouse cursor (x,y) position when sent */
    }  MSG;


    typedef struct tagPoint
    int   nx;
    int   ny;
    }  POINT;

  Windows fills in all this data before message is sent.

  A Windows program must continually check for incoming messages.
  This is done by using a small program loop called the message loop.
  One possibility: Use GetMessage()

  GetMesssage() function---
    reads the next message from the application's message queue and fills
    the fields of a variable of type MSG.

  We want put our call to GetMessage() in a loop that continually retrieves
  the message:

  while (GetMessage(&msg, NULL, 0, 0))
       { ... }

   -if Windows has sent the program a message, GetMessage() puts all the
    message data into the structure pointed to by msg.

  BOOL GetMessage (lpMsg, hWnd, uFirstMsg, uLastMsg);

    lpMsg--address of structure where Windows should put the message data.

    hWnd--handle of the window from which the message was sent (NULL ==>
    receive messages from all windows belonging to the application that made
    the call to GetMessage().)

    last 2 parameters--specify a range of message values to be retrieved

  -If no messages, Windows retains control of the system and does other stuff
  (with other programs) until a message to the program is generated. Only
  then does GetMessage() return to your program. This is the key to
  cooperative multitasking!

  -For all messages other than WM_QUIT (generated by the WndProc(), as we'll
  see, after user actions like a double click on System menu button or Alt-F4
  keyboard combination), TRUE (non-zero) is returned to the application's
  message loop and the while loop continues.

  -GetMessage() returns 0 if the mesage is a WM_QUIT. This causes the while
  loop to exit. Then the return (msg.wParam) returns control to Windows,
  effectively terminating the application.

  -All well-behaved Windows applications must have a message loop!

  -GetMessage() is one of the few functions that returns control to Windows,
  thus letting other applications run. If a program never yields control to
  Windows, no other programs are allowed to run--very bad!


    while (GetMessage (&msg, NULL, 0, 0))   /* message loop */
        TranslateMessage (&msg) ;   /* translate keyboard messages */
        DispatchMessage (&msg) ;    /* send message to WndProc() */
    return (msg.wParam) ;

  TranslateMessage (&msg)--

   -This function "cooks" keyboard input and converts raw key codes to ANSI
    codes that can be used by the program.
   -Actually it converts WM_KEYDOWN messages (sent when any key goes down)
    to WM_CHAR messages that recognize specific keys and key combinations,
    e.g., SHIFT-anything.
   -These WM_CHAR messages are processed in a well-defined way by the
    default Window procedure.
   -Gives a keyboard alternative to using the mouse to select.
   -Most Windows programs use TranslateMessage() in their message loops.

  DispatchMessage (&msg)--

   -Since message processing will be done in the function WndProc(), the
    program must tell Windows to pass any message data to that function.

   -This is done with DispatchMessage (&msg), which sends the message on to
    Windows. Windows, in turn, forwards it to the function specified in the
    lpfnWndProc member of the WNDCLASS structure--the WndProc().

   -Data is sent along in the msg structure that was filled in by

   -This happens each time a message is received. Messages are continuously
    retrieved from the program's queue and dispatched to its WndProc().


  This is a "callback" function (named so because it is called by Windows).
  It contains a big switch/case statement that looks at the message ID of the
  current message and acts appropriately on any "interesting" messages.

                          WPARAM wParam, LPARAM lParam)

  Parameters--same as first four fields of the MSG structure--
     -the window the message is associated with;
     -what the message is;
     -any data associated with the message (wParam & lParam message
      parameters): this data is specific for each type of message.
        wParam--"word" parameter; (16 bits under Win16)
        lParam--long param (32 bits)
        [This changed under Win32 -- both 32 bits]

  The WndProc() in EXAMPLE.C looks for the following messages:

  WM_COMMAND--User interacted with a menu item, wParam=Menu item ID).

  WM_LBUTTONDOWN--User pressed the left mouse button (lParam contains the
  x,y coordinates).

  WM_RBUTTONDOWN--User pressed the right mouse button.

  WM_CHAR--User pressed a key/key combination that corresponds to a valid
  ANSI code (wParam contains the ANSI code).

  WM_DESTROY--Generated when the user double clicks on the system menu,  
  chooses "Close" from the system menu, or presses ALT-F4. This message means
  that Windows is in the process of removing the window from the screen.

  Any other messages are handled by DefWindowProc(), the default Window

  It is essential that our programs trap the WM_DESTROY message; if not the
  GetMessage() loop will carry on forever, even though the window is gone!

  Response to WM_DESTROY--
   -program calls PostQuitMessage(0).
   -PostQuitMessage() causes Windows to send a WM_QUIT message to the
    program's message queue. Recall that when this is encountered,
    GetMessage() returns a 0 (the only message for which it does that).
   -This causes the program to exit WinMain()'s while loop.
   -It then hits return (msg.wParam).
   -Value returned is that accompanying the WM_QUIT message (0), and
    control goes to Windows (doesn't use the 0), which releases memory used
    by the program.

  If it's some other message, the program calls DefWindowProc()--the default
  procedure. This carries out the default actions for the message received.
  e.g., pressing the left mouse button while cursor is over title bar-->
  default dragging action. (Movement, repainting all done by Windows default
  function.) The DefWindowProc() function is in Windows.

  Our EXAMPLE.C program code overrides default window procedure action for
  WM_DESTROY messages.

C. THE RESOURCE SCRIPT (.RC FILE): adding a menu--

  Add a MENU BAR with "Rectangle", "Circle" and "Quit" items.

  Recall that resources are static data that the linker combines with our
  compiled application. Resources are defined in a script (.rc) file that is
  compiled by a resource compiler into a .res file.

  EXAMPLE.RC--will have a header file included (gives values to named
  constants that identify the menu items).

  Most straight-forward way of setting up the resource script file--use a
  text editor:

  /* EXAMPLE.RC  resource file */

  #include "example.h"

  MyMenu MENU
    MENUITEM "&Circle",             IDM_CIRCLE
    MENUITEM "&Rectangle",          IDM_RECTANGLE
    MENUITEM "Clear &Screen",       IDM_CLEAR 
    MENUITEM "&Quit",               IDM_QUIT

  The resource script file can also be prepared visually using Microsoft's
  Developer Studio resource editors. This is especially useful when many resources (in
  addition to a menu) are to be incorporated in the application.

  Notice that this file has some constants--IDM_CIRCLE, IDM_RECTANGLE, IDM_CLEAR, 

  These are defined in the EXAMPLE.H header file:

  #define IDM_CIRCLE       1
  #define IDM_RECTANGLE    2
  #define IDM_CLEAR        3 
  #define IDM_QUIT         10

  In the .C program file the menu items are referred to by these constant
  names. But they need to have ID numbers so the program can determine which
  item was selected.

  Use of constant names makes program more readable and less prone to using
  the wrong ID value.

  The values and names can be anything (although Microsoft has certain
  conventions when you use the resource workshop visually).

  MyMenu is the name that will be used in the .C program to refer to the menu
  resources that are defined in the .RC file.

  Keyword MENUITEM specifies that the following text in quotes will appear on
  the window's main menu bar.
    -The '&' means that the following character, when used in conjunction
     with ALT from keyboard and 'cooked', will generate a message indicating
     that the item has been selected. The character following the '&' will be
     underlined on the window's menu bar.

  The header file is also included in the .C program file so that the same ID
  values are known both to the C and the resource compiler.

  In the EXAMPLE.C program, the lpszMenuName field of the wndclass structure
  is set to "MyMenu"--the menu described in the resource file--when the
  window class is registered.

  WndProc()--now responds to user interaction with menu items.
    -Whenever a menu item is selected with the mouse or its keyboard
     alternative, Windows sends the application a WM_COMMAND msg;
    -wParam contains the ID number of the menu item selected.
    -we can do a switch/case on wParam to perform the correct action.

Before examining the EXAMPLE.C program, we need to see how graphics and text
output work in Windows.

TEXT AND GRAPHICS OUTPUT -- Displaying something in a window

Under DOS--character modes are fixed size/font

   -Fast, but limited display possibilities

DOS systems have video boards that support several graphics modes, but--

   -Drawing commands may depend on graphics mode.

   -Each program that does graphics has to have different logic for each
     graphics mode==>lots of duplicate code.

   -Program portability problems.

Windows--always runs in a graphics mode.

   -Slower, but more flexible

   -everything (including text) drawn one pixel at a time, so:

   -Any size/shape is possible


Design goal of Windows: Device Independence

   -Same program should work using different hardware without modification

   -Windows takes care of hardware interface

   -Programmer can concentrate on the pgm

How to achieve this--

   -Windows pgms don't send data directly to HW devices (screen, printer)

   -Uses the "Graphics Device Interface" (GDI) as an intermediary

   -Draws on an abstact surface called a "device context" (DC)

Device Context--

   -Associated with a physical device:
        (display screen, printer, bitmap, metafile)

   -Abstracts the physical device it represents

   -Commands to draw on a DC are same regardless of HW (video card, printer)

   -GDI translates these to HW commands to output to the physical device

   -DC is accessed with a "handle to a DC"

   -Must be "gotten" from Windows using GetDC() or BeginPaint()

   -Is specific to a given window ==> app can only draw in its client area

   -DC specifies attribute settings for drawing (e.g., colors)

   -Attribute settings specify HOW drawing primitives will look
       e.g., background color, text color, etc.

   -Advantage: when drawing, don't have to send a whole bunch of parameters

   -Contains drawing objects (pen, brush, bitmap, font, etc.)
       also determine how primitives look (pen--drawing color)

   -Common DCs come from a Windows cache of only 5!
        app should release it when done, or disastrous things could happen!

   -Released with ReleaseDC() or EndPaint()

The GDI--Graphics Device Interface--

   -Part of Windows that converts drawing function calls to HW commands

   -Located in GDI.EXE (a DLL)

   -Has many graphics functions:

      -Functions that draw Graphics/Text primitives

      -Functions to change values of attributes (settings) in a DC

   -Has several drawing "objects" (pens, brushes, bitmaps, fonts)

   -Shared by all running apps ==> a GDI error by one pgm can crash Windows

   -GDI may make use of a device driver pgm for certain devices

   -.DRV pgms assist GDI in converting graphics commands to HW commands

   -Must be provided by mfg of new devices (graphics cards, etc.)


Background color     white           SetBkColor()     color of empty spaces

Background mode      OPAQUE          SetBkMode()      or TRANSPARENT

Brush Origin         (0,0)           SetBrushOrigin() pattern origin

Clipping Region      whole surf.     SelectClipRgn()  where output displayed

Color Palette        DEFAULT_PALETTE SelectPalette()  color palette

Current Position     (0,0)           MoveToEx()       Start coord of line

Drawing Mode         R2COPYPEN       SetROP2()        How to combine w/ bkgnd

Mapping Mode         MM_TEXT         SetMapMode()     units/scaling in DC

Polygon Fill Mode    ALTERNATE       SetPolyFillMode() how polygons filled

Text Char Spacing    0               SetTextCharacterExtra()

Text Color           Black           SetTextColor()   color of text

OBJECT               DEFAULT         FUNCTION

Bitmap               none            SelectObject()   image object

Brush                WHITE_BRUSH     SelectObject()   area fill object

Font                 SYSTEM_FONT     SelectObject()   text font object

Pen                  BLACK_PEN       SelectObject()   line-drawing object

Objects must be created before being selected into a DC! 

Drawing basics (graphics and text): Steps your pgm must perform--

  1. Obtain a DC

  2. Obtain (Create) and select GDI objects, if required (e.g., a pen)

  3. Set drawing attributes, if necessary

  4. Call drawing functions

  5. Deselect and Delete any GDI objects that were created

  6. Release the DC -- in same state in which it was obtained

hDC = GetDC (hWnd); --

   -Retrieves a DC handle for the client area of the specified window

   -Identified by the value returned in hDC

   -This will be used for all subsequent drawing on that DC

   -GetDC() allows app to draw on the DC at any time

Another function that gets a DC: BeginPaint(hWnd, &ps); --

   -Only used in response to a WM_PAINT msg--
       issued when some are of the window has been exposed and thus needs 
       to be repainted

   -Returns a DC for the client area of the window to draw on

   -And a ptr to a paint structure (PAINTSTRUCT)

   -This contains info about the area of the window that needs to be repainted:

      typedef struct tagPAINTSTRUCT
       HDC     hdc;      /* device context handle */
       BOOL    fErase;   /* should background be redrawn? TRUE/FALSE */
       RECT    rcPaint;  /* rectangular area to update */
       BOOL    fRestore; /* reserved for internal use by Windows */
       BOOL    fIncUpdate;       /* reserved */
       BYTE    rgbReserved[16];  /* reserved */

ReleaseDC (hWnd, hDC); --

  -Each DC takes about 800 bytes of memory, can only have a total of 5
   common DCs in memory at a time (one per window at any given time)

  -So you must release the DC as soon as you've done your drawing

  -If not, bad things can happen AFTER app has been running a while

  -Used in conjunction with GetDC()

  -EndPaint() does the equivalent for a DC obtained with BeginPaint()


Uses four-byte numbers to represent colors

Simplest method--direct color:


 |       0      | Blue (0-255) | Green (0-255) | Red (0-255)  |

   ==> RGB color used (default)
   -other bytes specify R, G, B intensities
   -dithering done for colors that don't match system colors

   -other bytes specify an index into a color lookup table (palette)
   -R,G,B values found at that entry in the lookup table
   -indirect color

MACRO RGB() allows us to specify Red, Green Blue intensities.

Generates a COLORREF value (can be used in color-setting ftns) e.g.--

  cr = RGB (0,0,255);   /* blue */

Definition of RGB():

#define RBG(r,g,b)
   ((DWORD)(((BYTE)(r) | ((WORD)(g) << 8)) | (((DWORD)(BYTE(b)) << 16)))

Example use in a program--

  -SetTextColor(hDC,RGB(255,0,0)) changes text drawing color to red

  -SetBkColor(hDC,RGB(0,0,255)) changes the color of the background around
     each character to blue

GDI Objects--pens, brushes, bitmaps, fonts.

    -Used to "draw" or "paint" on a device context.

    -Created with functions like:

           CreatePen (PS_STYLE, nWidth, cColRef);

           CreateSolidBrush (cColRef);

    -There are lots more (see on-line help). 

    -To be used they must be "selected into" the DC with SelectObject():

  HGDIOBJ--handle to a GDI object.
    parameter--handle to new object being selected into the DC
    value returned--handle to object being displaced from DC

When selected, the data associated with the object is made available to the
DC for immediate use with graphics drawing functions:

Some GDI drawing functions:

[In each of the following (x1,y1), (x2,y2) are the coordinates of 
 diagonally opposite corners of the bounding rectangle]

  Arc (hDC,x1,y1,x2,y2,xArcStart,yArcStart,xArcEnd,yArcEnd);
  [draws a portion of an ellipse with the current pen]

  Chord (hDC,x1,y1,x2,y2,xArcStart,yArcStart,xArcEnd,yArcEnd);
  [paints a filled portion of an ellipse bounded by ellipse border & line
   using the current brush to fill the area, current pen for border]

  Ellipse (hDc, x1,y1,x2,y2);
  [paints an ellipse with the current brush]

  MovetoEx (hDC,x1,y1,lpPoint);
  [establish position of start of line]

  LineTo (hDC,x1,y1);
  [draws a line from start point to specified point with current pen]

  Pie (hDC,x1,y1,x2,y2,xArcStart,yArcStart,xArcEnd,yArcEnd);
  [paints a filled area of ellipse bounded by ellipse arc and a wedge
   using the current brush for area, current pen for border]

  Polygon (hDC,points_array,nCount);
  [paints a closed polygon using the current brush and pen]

  Polyline (hDC,points_array,nCount);
  [draws a series of one or more conected lines with the current pen]

  Rectangle (hDC,x1,y1,x2,y2);
  [paints a rectangle with the current brush and pen]

  SetPixel (hDC,x1,y1,colref);
  [Turns the pixel (point) at x1,y1 to the color specified by colref]

There are several more drawing primitives (see on-line help).

When an object is selected, Windows allocates space for the object in the
program's data segment; this spaced is limited, so pgm should delete the 
object when it's done drawing with it--use DeleteObject()

If you don't--they will use up memory after the program that created them 
has terminated! -- if too many undeleted objects, could crash Windows!

But to delete an object--

  -first, object has to be selected out of the DC

  -(trying to delete an object still selected into a DC could crash pgm)

To do this, select the original object back into the DC--

  -displaces former object

  -then former object can be deleted

A typical sequence with objects:

HPEN    hOldPen, hNewPen;
HDC     hDC;

hDC = GetDC(hWnd);                   /* Get a device context to draw on */

hNewPen = CreatePen(PS_SOLID, 3, RGB(0,0,7)); /*Create pen to draw with */

hOldPen = SelectObject(hDC, hNewPen);       /* Select new pen into DC ..*/
                                            /* & save handle to old one*/

SelectObject(hDC,hOldPen);                  /* Displace NewPen from DC */
                                            /* Now we can delete it*/
DeleteObject(hNewPen);                      /* Delete the new pen */

ReleaseDC(hWnd,hDC);                       /* Get rid of device context */

Stock objects--predefined in Windows; obtain with GetStockObject();

GetStockObject() retrieves a handle to a predefined stock pen/brush/font--

  -Stock objects are maintained by Windows

  -Should not be deleted!


SelectObject (hDc, GetStockObject(BLACK_PEN));

Object Type    Choices

               NULL_BRUSH, WHITE_BRUSH


ANSI_FIXED_FONT useful for tables w/ characters that need to line up.

ANSI_VAR_FONT--smallest of the stock fonts (good for limited space)

An object can be displaced out of the DC for deletion by selecting a stock
object into the DC; i.e. replace last 3 lines of code above with:

SelectObect(hDC, GetStockObject(BLACK_PEN));
ReleaseDC(hWnd, hDC);


WM_COMMAND (menu item clicked)--

    wParam==IDM_CIRCLE (User clicked on "Circle" menu item) ==>
    Get a device context, create a blue pen for the outline and a
    crosshatched magenta brush for the interior of the circle, select
    these objects into the device context, and call the Ellipse() ftn
    to draw the circle. After that, displace the pen and brush from
    the device context, delete them, and release the device context.

    wParam==IDM_RECTANGLE (user clicked on "Rectangle" menu item) ==>
    Get a CD, create a red pen and a solid cyan brush, select them
    into the DC, call the Rectangle() ftn, select the objects out of
    the DC, delete them, and release the DC. 

    wParam==IDM_CLEAR (User clicked on "Clear Screen" menu item) ==>
    call InvalidateRect() which causes Windows to send a WM_PAINT message.
    This message means that the client area needs to be repainted. (It is
    also generated any time the window is exposed.) The Default Window
    Procedure responds to this message by repainting the client area with
    the class background brush, effectively erasing the window's client

    wParam==IDM_QUIT (User clicked on "Quit") ==> program calls
    DestroyWindow(), which causes Windows to destroy the window.

WM_LBUTTONDOWN (Left mouse button pressed) ==>
   -Get x,y coordinates of cursor from lParam w/ LOWORD & HIWORD macros;
   -Get a device context to draw on;
   -Output the letter "L" at (x,y) on the device context w/ TextOut();
   -Release the device context.

WM_RBUTTONDOWN (Right mouse button pressed) ==>
   -Same as above, but outputs the letter "R".

WM_CHAR (A key or key combination was pressed that corresponds to an ANSI
         character) ==>
   -Get a device context to write on;
   -copy the character from the wParam into cBuf;
   -Output it to the upper left hand corner of the window's client area w/
   -Release the device context.

WM_DESTROY (User double clicked on System menu or hit Alt-F4 ==> 
   -Post a WM_QUIT message to the application's queue
   -This will cause the program to exit the event loop and return to Windows
    as described above. 



  1. From Windows (NT or 95) click 'Start' on Task Bar

  2. Select 'Programs | Microsoft Visual C++ | Microsoft Visual C++5.0'

  3. Close the "Tip of the Day" box (if it comes up)

  You should now have a window containing three subwindows:
    left: the Project Workspace Window
    right: the Editor Window
    bottom: the Output Window

Creating the Project:

  1. Select 'File | New'

  2. Click on 'Projects' Tab

  3. Select 'Win32 Application'

  4. Name the project (e.g. example)
       The system will use the directory stated in 'Location' as the
       parent directory for the project directory that it will create. 
       You can change this parent directory as you like. Be sure to 
       use drive C. The project directory will have the name you give
       in this step, and all files created by Developer Studio will be 
       in that directory.

  5. Click 'OK'
     Note there are now three tabs in the project workspace window:
       ClassView -- to look at the classes in a C++ pgm
       FileView -- to look at the various files in the project
       InfoView -- to access on-line help

Inserting the source files into the project (quick and dirty method):

  1. Use the Developer Studio editor (or any other editor) to create
     the .c (.cpp), .h and .rc files. Save them in the directory that
     contains your other project files--i.e., the directory that was 
     created above by Developer Studio. If the source files already
     exist, you should copy them into the project's directory.

  2. From the menu select 'Project | Add to Project | Files'

  3. Make sure the 'Look In' box contains the directory with your files. 
     The files should appear in the larger box below. 

  4. Select the .c or .cpp file(s) (e.g., example.cpp) and the .rc file
     (e.g., example.rc) and click 'OK'. If you now click on the FileView 
     tab in the Workspace Window, you will see that the files have been 
     included in the project. To see them in the Editor Window, click on 
     the file name from the FileView window.

Building the Project:

  1. Select 'Build | Build project_name.exe' (e.g., Build example.exe)
       The Project will be compiled/linked.
       Messages (errors) will appear in the Output Window.


  The entire project (LOTS of files--over 3 Megabytes worth!) will be
  in the directory you chose when you created the project on C drive. 
  The most important files in this directory are the .dsp (Designer Studio
  Project) and .dsw (Designer Studio Workspace) files. You should copy 
  them (along with all your source files) to your diskette. In future 
  sessions, the project can be brought into Designer Studio by copying the 
  .dsp, .dsw, and source files to the C drive (in a temporary directory) 
  and selecting 'File | OpenWorkspace'. Open the temporary   directory, 
  select 'Files of Type:' 'Project' from the lower list box, and double 
  click on your .dsp or .dsw file in the upper box. You can then rebuild
  the project.

  After building a project, the project directory will will have a
  DEBUG subdirectory. The executable (.exe) will be in that DEBUG
  subdirectory. You should also copy it to you diskette.

  After you are sure that you have all your source files, your .dsp and
  .dws files, and your .exe file on your diskette, delete the project
  directory on drive C: to clean it up.

Exiting Developer Studio:

  Select 'File | Exit'