home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Gam…ming Gurus (2nd Edition) / Disc2.iso / msdn_vcb / samples / vc98 / sdk / com / inole2 / chap18 / cosmo1.0 / polyline.c < prev    next >
C/C++ Source or Header  |  1995-05-03  |  18KB  |  635 lines

  1. /*
  2.  * POLYLINE.C
  3.  *
  4.  * Window procedure for the polyline drawing window and support functions.
  5.  * This window is not complicated.  On creation it allocates a block of
  6.  * memory for a POLYLINE structure that contains 20 POINTs.  We do not
  7.  * attempt to reallocate this array at all just to maintain simplicity.
  8.  * This sample is to demonstrate OLE, not LocalReAlloc.
  9.  *
  10.  * Copyright(c) Microsoft Corp. 1992-1994 All Rights Reserved
  11.  * Win32 version, January 1994
  12.  */
  13.  
  14.  
  15. #include <windows.h>
  16. #include "cosmo.h"
  17.  
  18. /*
  19.  * HACK:  To fix some Invalid hDC rips, we need to supress certain
  20.  * operations on metafile DC's: GetMapMode, DPtoLP, LPtoDP.
  21.  * We use this flag to indicate supression.
  22.  */
  23. BOOL fMetaDC=FALSE;
  24.  
  25.  
  26.  
  27. /*
  28.  * HPolylineWindowCreate
  29.  *
  30.  * Purpose:
  31.  *  Creates a Polyline window within the client area of hWndParent.
  32.  *
  33.  * Parameters:
  34.  *  hWndParent      HWND of the parent window.
  35.  *  hInstance       HINSTANCE of the application instance.
  36.  *
  37.  * Return Value:
  38.  *  HWND            Result of the CreateWindowEx call.
  39.  *
  40.  */
  41.  
  42. HWND WINAPI HPolylineWindowCreate(HWND hWndParent, HINSTANCE hInstance)
  43.     {
  44.     RECT        rc;
  45.     HWND        hWndT;
  46.  
  47.     /*
  48.      * Create the secondary window for this application in a
  49.      * shrunk client area.
  50.      */
  51.     GetClientRect(hWndParent, &rc);
  52.     InflateRect(&rc, -8, -8);
  53.  
  54.     //Create the editor window.
  55.     hWndT=CreateWindowEx(WS_EX_NOPARENTNOTIFY, rgpsz[IDS_CLASSPOLYLINE]
  56.         , rgpsz[IDS_CLASSPOLYLINE], WS_CHILD | WS_VISIBLE, rc.left
  57.         , rc.top, rc.right-rc.left, rc.bottom-rc.top
  58.         , hWndParent, (HMENU)ID_POLYLINE, hInstance, NULL);
  59.  
  60.     return hWndT;
  61.     }
  62.  
  63.  
  64.  
  65.  
  66.  
  67. /*
  68.  * PolylineWndProc
  69.  *
  70.  * Purpose:
  71.  *  Window procedure for the polyline drawing window.
  72.  *
  73.  * Parameters:
  74.  *  The standard.
  75.  *
  76.  * Return Value:
  77.  *  Standard.
  78.  */
  79.  
  80. LRESULT WINAPI PolylineWndProc(HWND hWnd, UINT iMsg
  81.     , WPARAM wParam, LPARAM lParam)
  82.     {
  83.     PAINTSTRUCT     ps;
  84.     HDC             hDC;
  85.     HWND            hWndParent;
  86.     HLOCAL          hMem;
  87.     LPPOLYLINE      ppl;
  88.     RECT            rc;
  89.     DWORD           dwRet=0L;
  90.  
  91.    #ifdef WIN32
  92.     ppl=(LPPOLYLINE)(PSTR)GetWindowLong(hWnd, 0);
  93.    #else
  94.     ppl=(LPPOLYLINE)(PSTR)GetWindowWord(hWnd, 0);
  95.    #endif
  96.  
  97.     if (WM_USER <= iMsg)
  98.         return LPolylineUserMessage(hWnd, iMsg, wParam, lParam, ppl);
  99.  
  100.  
  101.     switch (iMsg)
  102.         {
  103.  
  104.         case WM_NCCREATE:
  105.             hMem=LocalAlloc(LPTR, CBPOLYLINE);
  106.  
  107.             if (NULL==hMem)
  108.                 return 0L;
  109.  
  110.            #ifdef WIN32
  111.             SetWindowLong(hWnd, 0, (LONG)hMem);
  112.            #else
  113.             SetWindowWord(hWnd, 0, (WORD)hMem);
  114.            #endif
  115.             return DefWindowProc(hWnd, iMsg, wParam, lParam);
  116.  
  117.  
  118.         case WM_NCDESTROY:
  119.            #ifdef WIN32
  120.             hMem=(HLOCAL)GetWindowLong(hWnd, 0);
  121.            #else
  122.             hMem=(HLOCAL)GetWindowWord(hWnd, 0);
  123.            #endif
  124.             LocalFree(hMem);
  125.             return DefWindowProc(hWnd, iMsg, wParam, lParam);
  126.  
  127.  
  128.         case WM_CREATE:
  129.             //Stash away the current window rectangle.
  130.             GetClientRect(hWnd, &rc);
  131.             RECTTORECTS(rc, ppl->rc);
  132.  
  133.             ppl->wVerMaj=VERSIONMAJOR;
  134.             ppl->wVerMin=VERSIONMINOR;
  135.             ppl->cPoints=0;
  136.             break;
  137.  
  138.  
  139.         case WM_PAINT:
  140.             hDC=BeginPaint(hWnd, &ps);
  141.  
  142.             if (0!=ppl->cPoints)
  143.                 {
  144.                 ppl->fDrawEntire=TRUE;
  145.                 PolylineDraw(hWnd, hDC, ppl);
  146.                 }
  147.  
  148.             EndPaint(hWnd, &ps);
  149.             break;
  150.  
  151.         case WM_LBUTTONDOWN:
  152.             //Stop if we are already at the limit.
  153.             if (CPOLYLINEPOINTS==ppl->cPoints)
  154.                 {
  155.                 MessageBeep(0);
  156.                 break;
  157.                 }
  158.  
  159.             //Stuff the new point in the array.
  160.             ppl->rgpt[ppl->cPoints].x=LOWORD(lParam);
  161.             ppl->rgpt[ppl->cPoints].y=HIWORD(lParam);
  162.  
  163.             ppl->cPoints++;
  164.  
  165.             //Draw the lines to this new point only.
  166.             hDC=GetDC(hWnd);
  167.  
  168.             ppl->fDrawEntire=FALSE;
  169.             PolylineDraw(hWnd, hDC, ppl);
  170.  
  171.             ReleaseDC(hWnd, hDC);
  172.  
  173.             hWndParent=GetParent(hWnd);
  174.  
  175.            #ifdef WIN32
  176.             SendMessage(hWndParent, WM_COMMAND
  177.                 , MAKELONG(ID_POLYLINE, PLN_POINTCHANGE), (LPARAM)hWnd);
  178.            #else
  179.             SendMessage(hWndParent, WM_COMMAND
  180.                 , ID_POLYLINE, MAKELONG(hWnd, PLN_POINTCHANGE));
  181.            #endif
  182.             break;
  183.  
  184.  
  185.         default:
  186.             dwRet=DefWindowProc(hWnd, iMsg, wParam, lParam);
  187.             break;
  188.         }
  189.  
  190.     return dwRet;
  191.     }
  192.  
  193.  
  194.  
  195.  
  196.  
  197.  
  198.  
  199. /*
  200.  * LPolylineUserMessage
  201.  *
  202.  * Purpose:
  203.  *  Handles all window-specific messages WM_USER and greater,
  204.  *  for the Polyline window:
  205.  *
  206.  *  PLM_RECTSET:        Changes the size of the window and scales the
  207.  *                      data points.
  208.  *
  209.  *  PLM_POLYLINESET:    Sets the current data points and the rectangle
  210.  *                      used to generate the figure.
  211.  *
  212.  *  PLM_POLYLINEGET:    Retrieves the current data points and rectangle
  213.  *                      used to generate the figure.
  214.  *
  215.  *  PLM_POLYLINENEW:    Resets the data points to defaults, meaning
  216.  *                      a blank figure.
  217.  *
  218.  *  PLM_BACKUPUNDO:     Backs the figure up one point.
  219.  *
  220.  *  PLM_BITMAPGET:      Retrieves a bitmap (DDB) of the current image.
  221.  *
  222.  *  PLM_METAFILEGET:    Retrieves a metafile for the current image.
  223.  *
  224.  *  PLM_METAFILEPICTGET:Retrieves a METAFILEPICT structure of the image for
  225.  *                      use in clipboard I/O.
  226.  *
  227.  * Parameters:
  228.  *  hWnd            HWND of the Polyline window.
  229.  *  iMsg            UINT message to process.
  230.  *  wParam          WPARAM parameter of the message.
  231.  *  lParam          LPARAM pameter of the message.
  232.  *  ppl             LPPOLYLINE to the window's extra data structure.
  233.  *
  234.  * Return Value:
  235.  *  DWORD           Value to return from the window procedure
  236.  *                  that recieved the message.
  237.  */
  238.  
  239. DWORD PASCAL LPolylineUserMessage(HWND hWnd, UINT iMsg, WPARAM wParam
  240.     , LPARAM lParam, LPPOLYLINE ppl)
  241.     {
  242.     DWORD           dwRet=0L;
  243.     HWND            hWndParent;
  244.     HBITMAP         hBmp, hBmpT;
  245.     HDC             hDC, hMemDC;
  246.     LPPOLYLINE      pplT;
  247.     LPMETAFILEPICT  pMF;
  248.     HGLOBAL         hMem;
  249.     HMETAFILE       hMF;
  250.     RECT            rc;
  251.     LPRECT          pRect;
  252.     UINT            i;
  253.     LONG            l, cx, cy, cxT, cyT;
  254.  
  255.     hWndParent=GetParent(hWnd);
  256.  
  257.     switch (iMsg)
  258.         {
  259.         case PLM_RECTSET:
  260.             /*
  261.              * Resize the window to the given size, letting WM_SIZE handlers
  262.              * take care of the rest.
  263.              */
  264.             pRect=(LPRECT)lParam;
  265.  
  266.             /*
  267.              * Scale all the current points to new dimensions.  ppl->rc
  268.              * has the old dimensions, pRect points to the new.  We
  269.              * force each of cx and cy to 1 if they are zero to prevent
  270.              * exceptions.
  271.              */
  272.  
  273.             RECTSTORECT(ppl->rc, rc);
  274.             cxT=rc.right  - rc.left;
  275.             cyT=rc.bottom - rc.top;
  276.  
  277.             RECTTORECTS(ppl->rc, *pRect);
  278.             cx=pRect->right  - pRect->left;
  279.             cy=pRect->bottom - pRect->top;
  280.  
  281.             //Prevent crashes
  282.             if (0L==cxT)
  283.                 cxT=1;
  284.  
  285.             if (0L==cyT)
  286.                 cyT=1;
  287.  
  288.             //Loop through each point, scaling if necessary.
  289.             for (i=0; i< ppl->cPoints; i++)
  290.                 {
  291.                 //Must use DWORD to insure proper scaling.
  292.                 if (cx!=cxT)
  293.                     {
  294.                     l=((LONG)ppl->rgpt[i].x*cx);
  295.                     ppl->rgpt[i].x=(short)(l/cxT);
  296.                     }
  297.  
  298.                 if (cy!=cyT)
  299.                     {
  300.                     l=((LONG)ppl->rgpt[i].y*cy);
  301.                     ppl->rgpt[i].y=(short)(l/cyT);
  302.                     }
  303.                 }
  304.  
  305.  
  306.             SetWindowPos(hWnd, NULL, pRect->left, pRect->top, (int)cx
  307.                 , (int)cy, SWP_NOMOVE | SWP_NOZORDER);
  308.  
  309.  
  310.             //Check if we need to notify the parent.
  311.             if (0!=wParam)
  312.                 {
  313.                #ifdef WIN32
  314.                 SendMessage(hWndParent, WM_COMMAND
  315.                     , MAKELONG(ID_POLYLINE, PLN_SIZECHANGE), (LPARAM)hWnd);
  316.                #else
  317.                 SendMessage(hWndParent, WM_COMMAND
  318.                     , ID_POLYLINE, MAKELONG(hWnd, PLN_SIZECHANGE));
  319.                #endif
  320.                 }
  321.  
  322.             //Insure repaint
  323.             InvalidateRect(hWnd, NULL, TRUE);
  324.             UpdateWindow(hWnd);
  325.             break;
  326.  
  327.  
  328.         case PLM_POLYLINESET:
  329.             /*
  330.              * Copy the structure in lParam to ppl and repaint to
  331.              * reflect the new point set.  Note that unlike the
  332.              * PLM_RECTSET message, we do no scaling, assuming that
  333.              * the rectangle in the POLYLINE structure is appropriate
  334.              * for the data.
  335.              */
  336.             pplT=(LPPOLYLINE)lParam;
  337.             *ppl=*pplT;
  338.  
  339.             //Resize this window to fit the data and notify the parent.
  340.             SetWindowPos(hWnd, NULL, ppl->rc.left, ppl->rc.top
  341.                 , ppl->rc.right-ppl->rc.left, ppl->rc.bottom-ppl->rc.top
  342.                 , SWP_NOMOVE | SWP_NOZORDER);
  343.  
  344.             if (0!=wParam)
  345.                 {
  346.                #ifdef WIN32
  347.                 SendMessage(hWndParent, WM_COMMAND
  348.                     , MAKELONG(ID_POLYLINE, PLN_SIZECHANGE), (LPARAM)hWnd);
  349.                #else
  350.                 SendMessage(hWndParent, WM_COMMAND
  351.                     , ID_POLYLINE, MAKELONG(hWnd, PLN_SIZECHANGE));
  352.                #endif
  353.                 }
  354.  
  355.             //Insure a repaint.
  356.             InvalidateRect(hWnd, NULL, TRUE);
  357.             UpdateWindow(hWnd);
  358.             break;
  359.  
  360.  
  361.         case PLM_POLYLINEGET:
  362.             //Copy the structure in ppl to lParam.  No repaint needed.
  363.             pplT=(LPPOLYLINE)lParam;
  364.             *pplT=*ppl;
  365.             break;
  366.  
  367.  
  368.         case PLM_POLYLINENEW:
  369.             //Clean out the POLYLINE structure and repaint the window.
  370.             for (i=0; i< CPOLYLINEPOINTS; i++)
  371.                 {
  372.                 ppl->rgpt[i].x=0;
  373.                 ppl->rgpt[i].y=0;
  374.                 }
  375.  
  376.             ppl->cPoints=0;
  377.  
  378.             InvalidateRect(hWnd, NULL, TRUE);
  379.             UpdateWindow(hWnd);
  380.             break;
  381.  
  382.  
  383.         case PLM_BACKUPUNDO:
  384.             //Decrement the number of active points and repaint.
  385.             if (ppl->cPoints > 0)
  386.                 {
  387.                 ppl->cPoints--;
  388.                 InvalidateRect(hWnd, NULL, TRUE);
  389.                 UpdateWindow(hWnd);
  390.                 }
  391.  
  392.             //Notify parent window of the change.
  393.            #ifdef WIN32
  394.             SendMessage(hWndParent, WM_COMMAND
  395.                 , MAKELONG(ID_POLYLINE, PLN_POINTCHANGE), (LPARAM)hWnd);
  396.            #else
  397.             SendMessage(hWndParent, WM_COMMAND
  398.                 , ID_POLYLINE, MAKELONG(hWnd, PLN_POINTCHANGE));
  399.            #endif
  400.             break;
  401.  
  402.  
  403.         case PLM_BITMAPGET:
  404.             /*
  405.              * Create and return a bitmap of the window contents.
  406.              * The bitmap is the size of the POLYLINE edit window.
  407.              */
  408.  
  409.             hDC=GetDC(hWnd);
  410.             hMemDC=CreateCompatibleDC(hDC);
  411.  
  412.             GetClientRect(hWnd, &rc);
  413.             hBmp=CreateCompatibleBitmap(hDC, rc.right, rc.bottom);
  414.  
  415.             if (NULL!=hBmp)
  416.                 {
  417.                 //Draw the POLYLINE into the bitmap.
  418.                 hBmpT=SelectObject(hMemDC, hBmp);
  419.  
  420.                 ppl->fDrawEntire=TRUE;
  421.                 PolylineDraw(hWnd, hMemDC, ppl);
  422.                 ppl->fDrawEntire=FALSE;
  423.  
  424.                 SelectObject(hMemDC, hBmpT);
  425.                 }
  426.  
  427.             DeleteDC(hMemDC);
  428.             ReleaseDC(hWnd, hDC);
  429.  
  430.             //Return the created bitmap handle.
  431.             dwRet=(DWORD)(UINT)hBmp;
  432.             break;
  433.  
  434.  
  435.         case PLM_METAFILEGET:
  436.             //Create a memory metafile and return its handle.
  437.             hDC=(HDC)CreateMetaFile(NULL);
  438.             hMF=NULL;
  439.  
  440.             if (NULL!=hDC)
  441.                 {
  442.                 /*
  443.                  * This is absolutely essential to the metafile so it
  444.                  * can be scaled in the clipboard and any destination
  445.                  * application.
  446.                  */
  447.                 fMetaDC=TRUE;
  448.                 SetMapMode(hDC, MM_ANISOTROPIC);
  449.                 GetClientRect(hWnd, &rc);
  450.                 SetWindowOrgEx(hDC, 0, 0, NULL);
  451.                 SetWindowExtEx(hDC, rc.right, rc.bottom, NULL);
  452.  
  453.                 ppl->fDrawEntire=TRUE;
  454.                 PolylineDraw(hWnd, hDC, ppl);
  455.                 ppl->fDrawEntire=FALSE;
  456.  
  457.                 hMF=CloseMetaFile(hDC);
  458.                 fMetaDC=FALSE;
  459.                 }
  460.  
  461.             dwRet=(DWORD)(UINT)hMF;
  462.             break;
  463.  
  464.  
  465.         case PLM_METAFILEPICTGET:
  466.             /*
  467.              * Create a METAFILEPICT structure for the clipboard.
  468.              * First attempt to get a metafile.
  469.              */
  470.             lParam=SendMessage(hWnd, PLM_METAFILEGET, 0, 0L);
  471.             hMF=(HMETAFILE)(UINT)lParam;
  472.  
  473.             if (NULL==hMF)
  474.                 break;
  475.  
  476.             //Allocate the METAFILEPICT structure.
  477.             hMem=GlobalAlloc(GMEM_DDESHARE | GMEM_MOVEABLE
  478.                 , sizeof(METAFILEPICT));
  479.  
  480.             if (NULL==hMem)
  481.                 {
  482.                 DeleteMetaFile(hMF);
  483.                 break;
  484.                 }
  485.  
  486.             /*
  487.              * Global lock only fails in PMODE if the selector is invalid
  488.              * (like it was discarded) or references a 0 length segment,
  489.              * neither of which can happen here.
  490.              */
  491.             pMF=(LPMETAFILEPICT)GlobalLock(hMem);
  492.  
  493.             pMF->hMF=hMF;
  494.             pMF->mm=MM_ANISOTROPIC;             //Required by OLE libraries.
  495.  
  496.             //Insert the extents in MM_HIMETRIC units.
  497.             GetClientRect(hWnd, &rc);
  498.  
  499.             RectConvertToHiMetric(hWnd, &rc);     //Found in CLIP.C
  500.             pMF->xExt=rc.right;
  501.             pMF->yExt=rc.bottom;
  502.  
  503.             GlobalUnlock(hMem);
  504.  
  505.             dwRet=(DWORD)(UINT)hMem;
  506.             break;
  507.  
  508.  
  509.         default:
  510.             break;
  511.         }
  512.  
  513.     return dwRet;
  514.     }
  515.  
  516.  
  517.  
  518.  
  519.  
  520.  
  521. /*
  522.  * PolylineDraw
  523.  *
  524.  * Purpose:
  525.  *  Paints the current line in the polyline window.
  526.  *
  527.  * Parameters:
  528.  *  hWnd            HWND of the polyline window.
  529.  *  hDC             HDC to draw on, could be a metafile or printer DC.
  530.  *  ppl            LPPOLYLINE to the polyline structure.
  531.  *
  532.  * Return Value:
  533.  *  none
  534.  */
  535.  
  536. void PASCAL PolylineDraw(HWND hWnd, HDC hDC, LPPOLYLINE ppl)
  537.     {
  538.  
  539.     HBRUSH          hBrush, hBrushT;
  540.     HPEN            hPen, hPenT;
  541.     UINT            i, j;
  542.     UINT            nMM;
  543.     POINTS          pt;
  544.     POINT           rgpt[CPOLYLINEPOINTS];
  545.     RECT            rc;
  546.     COLORREF        cr;
  547.  
  548.  
  549.     GetClientRect(hWnd, &rc);
  550.  
  551.     //Get the line color.
  552.     cr=GetSysColor(COLOR_WINDOWTEXT);
  553.  
  554.     //Make a 32-bit working copy of the point array for DPtoLP.
  555.     for (i=0; i < ppl->cPoints; i++)
  556.         {
  557.         rgpt[i].x=ppl->rgpt[i].x;
  558.         rgpt[i].y=ppl->rgpt[i].y;
  559.         }
  560.  
  561.     /*
  562.      * If the mapping mode is not MM_TEXT, convert the points to
  563.      * whatever mapping mode in in effect before drawing.
  564.      * This specifically supports metafiles in MM_ANISOTROPIC.
  565.      */
  566.     nMM=fMetaDC ? MM_TEXT : GetMapMode(hDC);
  567.  
  568.     if (MM_TEXT!=nMM)
  569.         DPtoLP(hDC, rgpt, ppl->cPoints);
  570.  
  571.     hPen=CreatePen(PS_SOLID, 1, cr);
  572.     hPenT=SelectObject(hDC, hPen);
  573.  
  574.     hBrush=CreateSolidBrush(GetSysColor(COLOR_WINDOW));
  575.     hBrushT=SelectObject(hDC, hBrush);
  576.  
  577.     /*
  578.      * Either draw the entire figure or just a single point.  The
  579.      * entire figure also includes erasing the background completely,
  580.      * since hDC may be a metafile DC.  Drawing a single point just
  581.      * updates the figure for that new point.
  582.      */
  583.     if (ppl->fDrawEntire)
  584.         {
  585.         //Erase the background for bitmaps and metafiles.
  586.         SelectObject(hDC, GetStockObject(NULL_PEN));
  587.         Rectangle(hDC, rc.left, rc.top, rc.right+1, rc.bottom+1);
  588.         SelectObject(hDC, hPen);
  589.  
  590.  
  591.         /*
  592.          * If we are drawing the entire figure, then loop through each
  593.          * point drawing a line to each successive point.
  594.          */
  595.  
  596.         for (i=0; i < ppl->cPoints; i++)
  597.             {
  598.             for (j=i; j < ppl->cPoints; j++)
  599.                 {
  600.                 MoveToEx(hDC, rgpt[i].x, rgpt[i].y, NULL);
  601.                 LineTo(hDC, rgpt[j].x, rgpt[j].y);
  602.                 }
  603.             }
  604.         }
  605.     else
  606.         {
  607.         /*
  608.          * If we are only drawing the last point, just cycle once
  609.          * through previous points.
  610.          */
  611.  
  612.         //Get the last point entered in the array.
  613.         j=ppl->cPoints-1;
  614.         pt.x=(short)rgpt[j].x;
  615.         pt.y=(short)rgpt[j].y;
  616.  
  617.         for (i=0; i < j; i++)
  618.             {
  619.             MoveToEx(hDC, pt.x, pt.y, NULL);
  620.             LineTo(hDC, rgpt[i].x, rgpt[i].y);
  621.             }
  622.         }
  623.  
  624.     //If we only had one point, draw a dot to indicate it's position.
  625.     if (1==ppl->cPoints)
  626.         SetPixel(hDC, rgpt[0].x, rgpt[0].y, cr);
  627.  
  628.  
  629.     SelectObject(hDC, hPenT);
  630.     SelectObject(hDC, hBrushT);
  631.     DeleteObject(hBrush);
  632.     DeleteObject(hPen);
  633.     return;
  634.     }
  635.