home *** CD-ROM | disk | FTP | other *** search
/ PC World Komputer 1998 May / Pcwk5b98.iso / Borland / Cplus45 / BC45 / TUTORIAL.PAK / CPPOCF3.CPP < prev    next >
C/C++ Source or Header  |  1995-08-29  |  30KB  |  1,295 lines

  1. // ---------------------------------------------------------------------------
  2. // Copyright (C) 1994 Borland International
  3. // Simple OLE Container using OCF
  4. // ---------------------------------------------------------------------------
  5. #include <ocf/ocfpch.h>
  6. #include <ocf/ocapp.h>
  7. #include <ocf/ocdoc.h>
  8. #include <ocf/ocview.h>
  9. #include <ocf/ocpart.h>
  10. #include <ocf/ocstorag.h>
  11. #include <classlib/arrays.h>
  12. #include <cstring.h>
  13. #include <windowsx.h>
  14. #include "cppocf3.h"
  15. #include "ocfhlpr.h"
  16.  
  17. //
  18. // MDI Window Style constants
  19. //
  20. const DWORD MDIClientStyle = MDIS_ALLCHILDSTYLES | WS_GROUP | WS_TABSTOP |
  21.                              WS_CLIPCHILDREN|WS_CLIPSIBLINGS | WS_VSCROLL|
  22.                              WS_HSCROLL | WS_VISIBLE| WS_CHILD;
  23. const DWORD MDIChildStyle  = WS_VISIBLE | WS_CHILD | WS_CLIPSIBLINGS |
  24.                              WS_CLIPCHILDREN |WS_SYSMENU | WS_CAPTION |
  25.                              WS_THICKFRAME |WS_MINIMIZEBOX | WS_MAXIMIZEBOX;
  26.  
  27. //
  28. // Macros/constants
  29. //
  30. #define DEFEXT  "sc3"
  31. #define DEFDESC "Sample Container 3"
  32.  
  33.  
  34. //
  35. // Global variables
  36. //
  37. const  char childClassName[]  = "__fenΩtreOLE";
  38. const  char frameClassName[]  = "__fenΩtrePrincipale";
  39. const  char appTitle[]        = DEFDESC;
  40. const  char untitled[]        = "Untitled";
  41. const  char AboutMsg[]        = "C++ OLE Container using OCF";
  42. const  char AboutTitle[]      = "About "DEFDESC;
  43.  
  44. static char FileName[MAXPATH] = {0};
  45. const  char Filter[]          = DEFDESC"\0*."DEFEXT"\0";
  46.  
  47.  
  48. //
  49. // App/Frame related variables
  50. //
  51. HWND      Frame     = 0;
  52. HWND      Client    = 0;
  53. HWND      StatusBar = 0;
  54. HMENU     FrameMenu = 0;
  55. uint      ChildID   = 0x1000;
  56. HINSTANCE HInstance = 0;
  57.  
  58.  
  59. //
  60. // OCF variables
  61. //
  62. static TRegLink* RegLinkHead = 0;
  63. static TRect     Decorations(0, 0, 0, 0);
  64.  
  65. //
  66. // registration information
  67. //
  68. REGISTRATION_FORMAT_BUFFER(100)
  69.  
  70. BEGIN_REGISTRATION(AppReg)
  71.   REGDATA(clsid,    "{8646DB82-94E5-101B-B01F-00608CC04F66}")
  72.   REGDATA(appname,  "SampContainer")
  73. END_REGISTRATION
  74.  
  75. //
  76. // Register clipboard formats
  77. //
  78. BEGIN_REGISTRATION(DocReg)
  79.   REGDATA(progid,      "Sample.Container.3")
  80.   REGDATA(description, DEFDESC)
  81.   REGDATA(extension,   DEFEXT)
  82.   REGDATA(docfilter,   "*." DEFEXT)
  83.   REGFORMAT(0, ocrEmbedSource,  ocrContent,  ocrIStorage, ocrGet)
  84.   REGFORMAT(1, ocrMetafilePict, ocrContent,  ocrMfPict|ocrStaticMed, ocrGet)
  85.   REGFORMAT(2, ocrBitmap, ocrContent,  ocrGDI|ocrStaticMed, ocrGet)
  86.   REGFORMAT(3, ocrDib, ocrContent,  ocrHGlobal|ocrStaticMed, ocrGet)
  87.   REGFORMAT(4, ocrLinkSource, ocrContent,  ocrIStream, ocrGet)
  88. END_REGISTRATION
  89. static TRegLink  DocLink(DocReg, RegLinkHead);
  90.  
  91.  
  92. //
  93. // Application's Entry Point
  94. //
  95. int PASCAL
  96. WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
  97.       char far* lpCmdLine, int nCmdShow)
  98. {
  99.   HInstance = hInstance;
  100.   try {
  101.     // Initialize OLE
  102.     //
  103.     TOleInit oleInit(::AppReg, /*Factory Callback*/0, string(lpCmdLine),
  104.                      ::RegLinkHead, hInstance);
  105.  
  106.     // Initialize application related items (eg. Window Classes)
  107.     //
  108.     if (!hPrevInstance  && (!InitFrame(hInstance) || !InitChild(hInstance)))
  109.       return 0;
  110.  
  111.     // Initialize per-instanace related items (eg. create main window)
  112.     //
  113.     if (!InitInstance(hInstance, nCmdShow))
  114.       return 0;
  115.  
  116.     // Standard Windows message loop
  117.     //
  118.     MSG msg;
  119.     while (GetMessage(&msg, 0, 0, 0)) {
  120.       if (!TranslateMDISysAccel(Client, &msg)) {
  121.         TranslateMessage(&msg);
  122.         DispatchMessage(&msg);
  123.       }
  124.     }
  125.   }
  126.  
  127.   catch (TXBase& xbase) {
  128.     MessageBox(GetFocus(), xbase.why().c_str(), "Exception caught", MB_OK);
  129.   }
  130.   return 0;
  131. }
  132.  
  133.  
  134. //
  135. // Initialize main frame
  136. //
  137. bool
  138. InitFrame(HINSTANCE hInstance)
  139. {
  140.   WNDCLASS wc;
  141.   wc.style          = CS_HREDRAW | CS_VREDRAW;
  142.   wc.lpfnWndProc    = (WNDPROC)MainWndProc;
  143.   wc.cbClsExtra     = 0;
  144.   wc.cbWndExtra     = sizeof(TOleFrameWin*);
  145.   wc.hInstance      = hInstance;
  146.   wc.hIcon          = LoadIcon(0, IDI_APPLICATION);
  147.   wc.hCursor        = LoadCursor(0, IDC_ARROW);
  148.   wc.hbrBackground  = (HBRUSH)(COLOR_WINDOW+1);
  149.   wc.lpszMenuName   = 0;
  150.   wc.lpszClassName  = frameClassName;
  151.  
  152.   return (RegisterClass(&wc) != 0);
  153. }
  154.  
  155.  
  156. //
  157. // Initialize instance and display the main window
  158. //
  159. bool
  160. InitInstance(HINSTANCE hInstance, int nCmdShow)
  161. {
  162.   Frame = CreateWindow(frameClassName, appTitle,
  163.                        WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN |
  164.                        WS_CLIPSIBLINGS,
  165.                        CW_USEDEFAULT, CW_USEDEFAULT,
  166.                        CW_USEDEFAULT, CW_USEDEFAULT,
  167.                        0,
  168.                        0,
  169.                        hInstance,
  170.                        0);
  171.   if (!Frame)
  172.     return false;
  173.  
  174.   ShowWindow(Frame, nCmdShow);
  175.   UpdateWindow(Frame);
  176.  
  177.   return true;
  178. }
  179.  
  180.  
  181. //
  182. // Accessor to retrieve OLE helper object associated with an HWND
  183. //
  184. TOleFrameWin*
  185. GetOleFrameWinObj(HWND hwnd)
  186. {
  187.   return (TOleFrameWin*)(LONG)GetWindowLong(hwnd, 0);
  188. }
  189.  
  190.  
  191. //
  192. // Function to associate an OLE Helper object with a window
  193. //
  194. void
  195. SetOleFrameWinObj(HWND hwnd, TOleFrameWin* oleFrameWinObj)
  196. {
  197.   SetWindowLong(hwnd, 0, (LONG)oleFrameWinObj);
  198. }
  199.  
  200.  
  201. LRESULT
  202. MainWnd_DefProc(HWND hwnd, uint msg, WPARAM wParam, LPARAM lParam)
  203. {
  204.   return DefFrameProc(hwnd, Client, msg, wParam, lParam);
  205. }
  206.  
  207.  
  208. //
  209. // Returns frame's active child window handle
  210. //
  211. HWND
  212. MainWnd_GetActiveChild(HWND /*hwnd*/)
  213. {
  214.   return IsWindow(Client) ? FORWARD_WM_MDIGETACTIVE(Client, SendMessage) : 0;
  215. }
  216.  
  217.  
  218. //
  219. // Returns frame window
  220. //
  221. HWND
  222. GetFrame()
  223. {
  224.    return Frame;
  225. }
  226.  
  227.  
  228. //
  229. // Sets the Frame's menu
  230. //
  231. void
  232. MainWnd_SetMenu(HWND hwnd, HMENU hMenu, int winIndex = 0)
  233. {
  234.   if (!hMenu && FrameMenu)
  235.     hMenu = FrameMenu;
  236.  
  237.   if (IsWindow(Client)) {
  238.     FORWARD_WM_MDISETMENU(Client, FALSE, hMenu, GetSubMenu(hMenu, winIndex),
  239.                           SendMessage);
  240.     DrawMenuBar(hwnd);
  241.   }
  242. }
  243.  
  244.  
  245. //
  246. // Closes all MDI Child Windows
  247. //
  248. void
  249. MainWnd_CloseAll(HWND hwnd)
  250. {
  251.   if (!IsWindow(Client))
  252.     return;
  253.  
  254.   //
  255.   // Iterate through children to close them...
  256.   //
  257.   HWND child = MainWnd_GetActiveChild(hwnd);
  258.   while (IsWindow(child)) {
  259.     HWND next = GetWindow(child, GW_HWNDNEXT);
  260.     FORWARD_WM_MDIDESTROY(Client, child, SendMessage);
  261.     child = next;
  262.   }
  263. }
  264.  
  265.  
  266. bool
  267. MainWnd_OnCreate(HWND hwnd, CREATESTRUCT FAR* /*lpCreateStruct*/)
  268. {
  269.   TOleFrameWin* oleFrameWinObj = new TOleFrameWin(hwnd);
  270.   SetOleFrameWinObj(hwnd, oleFrameWinObj);
  271.  
  272.   // Allow OLE Helper to perform initialization
  273.   //
  274.   oleFrameWinObj->OnCreate();
  275.  
  276.   // Set Frame window's menu
  277.   //
  278.   HINSTANCE hInstance = GetWindowInstance(hwnd);
  279.   FrameMenu           = LoadMenu(hInstance, MAKEINTRESOURCE(ID_MAINMENU));
  280.  
  281.   if (FrameMenu)
  282.     SetMenu(hwnd, FrameMenu);
  283.  
  284.   // Create MDI Client window
  285.   //
  286.   CLIENTCREATESTRUCT cs;
  287.   memset(&cs, 0,  sizeof(cs));
  288.   cs.hWindowMenu  = FrameMenu ? GetSubMenu(FrameMenu, 0) : 0;
  289.   cs.idFirstChild = ChildID;
  290.   Client = CreateWindow("MDICLIENT", "",
  291.                         MDIClientStyle,
  292.                         0, 0, 0, 0,
  293.                         hwnd,
  294.                         0,
  295.                         hInstance,
  296.                         (LPSTR)(LPCLIENTCREATESTRUCT)&cs);
  297.   return (Client != 0);
  298. }
  299.  
  300.  
  301. //
  302. //
  303. //
  304. void
  305. MainWnd_OnDestroy(HWND hwnd)
  306. {
  307.   //
  308.   // Allow OLE Helper object to perform cleanup
  309.   //
  310.   TOleFrameWin* oleFrameWinObj = GetOleFrameWinObj(hwnd);
  311.   oleFrameWinObj->OnDestroy();
  312.  
  313.   // Delete OLE Helper object
  314.   //
  315.   delete oleFrameWinObj;
  316.  
  317.   // Usual posting of WM_QUIT
  318.   //
  319.   PostQuitMessage(0);
  320. }
  321.  
  322.  
  323. //
  324. // Handles WM_CLOSE
  325. //
  326. void
  327. MainWnd_OnClose(HWND hwnd)
  328. {
  329.   //
  330.   // First restore the frame's original menu to allow proper cleanup
  331.   //
  332.   if (FrameMenu && GetMenu(hwnd) != FrameMenu) {
  333.     MainWnd_SetMenu(hwnd, FrameMenu);
  334.   }
  335.  
  336.   //
  337.   // Close all children
  338.   //
  339.   MainWnd_CloseAll(hwnd);
  340.  
  341.   //
  342.   // Pass on to default proc
  343.   //
  344.   FORWARD_WM_CLOSE(hwnd, MainWnd_DefProc);
  345. }
  346.  
  347.  
  348. //
  349. // Create MDI child
  350. //
  351. HWND
  352. MainWnd_CreateMDIChild(const char* className,
  353.                        const char* title,
  354.                        DWORD style,
  355.                        int x, int y, int w, int h, HWND parent,
  356.                        HINSTANCE hInstance, LPARAM lParam)
  357. {
  358.   MDICREATESTRUCT mcs;
  359.   mcs.szClass = className;
  360.   mcs.szTitle = title;
  361.   mcs.hOwner  = hInstance;
  362.   mcs.x       = x;
  363.   mcs.y       = y;
  364.   mcs.cx      = w;
  365.   mcs.cy      = h;
  366.   mcs.style   = style;
  367.   mcs.lParam  = lParam;
  368.  
  369.   return FORWARD_WM_MDICREATE(parent, &mcs, SendMessage);
  370. }
  371.  
  372.  
  373. //
  374. // Handle request to create a new MDI Child
  375. //
  376. HWND
  377. MainWnd_NewChild(HWND hwnd)
  378. {
  379.   return IsWindow(Client) ?
  380.          MainWnd_CreateMDIChild(childClassName, untitled, MDIChildStyle,
  381.                                 CW_USEDEFAULT, CW_USEDEFAULT,
  382.                                 CW_USEDEFAULT, CW_USEDEFAULT,
  383.                                 Client, GetWindowInstance(hwnd), 0) : 0;
  384. }
  385.  
  386.  
  387. //
  388. // Handles WM_COMMAND sent to frame window
  389. //
  390. void
  391. MainWnd_OnCommand(HWND hwnd, int id, HWND hwndCtl, uint codeNotify)
  392. {
  393.   switch (id) {
  394.     // Handle Exit Request
  395.     //
  396.     case CM_FILEEXIT:
  397.       PostMessage(hwnd, WM_CLOSE, 0, 0);
  398.       break;
  399.  
  400.     case CM_FILENEW:
  401.       MainWnd_NewChild(hwnd);
  402.       break;
  403.  
  404.     case CM_FILEOPEN:
  405.       // Prompt user - Create new window - have child load data
  406.       //
  407.       if (GetOpenFileName(hwnd, Filter, FileName, sizeof(FileName)))
  408.         FORWARD_WM_COMMAND(MainWnd_NewChild(hwnd), id, hwndCtl,
  409.                            codeNotify, SendMessage);
  410.       break;
  411.  
  412.     case CM_FILESAVE:
  413.     case CM_FILESAVEAS: {
  414.       // Tell active child to save parts
  415.       //
  416.       HWND child = MainWnd_GetActiveChild(hwnd);
  417.       FORWARD_WM_COMMAND(child, id, hwndCtl, codeNotify, SendMessage);
  418.       break;
  419.     }
  420.  
  421.     case CM_WINDOWCASCADECHILDREN:
  422.       FORWARD_WM_MDICASCADE(Client, 0, SendMessage);
  423.       break;
  424.  
  425.     case CM_WINDOWTILECHILDREN:
  426.       FORWARD_WM_MDITILE(Client, 0, SendMessage);
  427.       break;
  428.  
  429.     case CM_WINDOWARRANGEICONS:
  430.       FORWARD_WM_MDIICONARRANGE(Client, SendMessage);
  431.       break;
  432.  
  433.     case CM_WINDOWCLOSEALL:
  434.       MainWnd_CloseAll(hwnd);
  435.       break;
  436.  
  437.     case CM_HELPABOUT:
  438.       MessageBox(hwnd, AboutMsg, AboutTitle, MB_OK|MB_ICONINFORMATION);
  439.       break;
  440.  
  441.     // If we do not process the command, pass it on
  442.     //
  443.     default: {
  444.       // forward messages to MDI frame
  445.       FORWARD_WM_COMMAND(hwnd, id, hwndCtl, codeNotify, MainWnd_DefProc);
  446.  
  447.       // forward to active child too
  448.       HWND child = MainWnd_GetActiveChild(hwnd);
  449.       if (child)
  450.         FORWARD_WM_COMMAND(child, id, hwndCtl, codeNotify, SendMessage);
  451.     }
  452.   }
  453. }
  454.  
  455.  
  456. //
  457. // Resizes Client window
  458. //
  459. void
  460. MainWnd_ResizeClient(HWND hwnd)
  461. {
  462.   if (IsWindow(Client)) {
  463.     TRect rect;
  464.     GetClientRect(hwnd, &rect);
  465.     MoveWindow(Client,
  466.                rect.left    + Decorations.left,
  467.                rect.top     + Decorations.top,
  468.                rect.right   - Decorations.right,
  469.                rect.bottom  - Decorations.bottom,
  470.                true);
  471.   }
  472. }
  473.  
  474.  
  475. //
  476. // Handles WM_SIZE be resizing client window
  477. //
  478. void
  479. MainWnd_OnSize(HWND hwnd, uint /*state*/, int /*cx*/, int /*cy*/)
  480. {
  481.   MainWnd_ResizeClient(hwnd);
  482. }
  483.  
  484.  
  485. //
  486. // Handles WM_INITMENU message
  487. //
  488. void
  489. MainWnd_OnInitMenu(HWND hwnd, HMENU hMenu)
  490. {
  491.   //
  492.   // Pass on to child to handle menu enabling/disabling
  493.   //
  494.   HWND child = MainWnd_GetActiveChild(hwnd);
  495.   if (child)
  496.     FORWARD_WM_INITMENU(child, hMenu, SendMessage);
  497. }
  498.  
  499.  
  500. //
  501. // Handles OCAPPFRAMERECT
  502. //
  503. bool
  504. MainWnd_OnOcAppFrameRect(HWND hwnd, TRect far* rect)
  505. {
  506.   GetClientRect(hwnd, rect);
  507.   return true;
  508. }
  509.  
  510.  
  511. //
  512. // Pass on OCAPPINSMENU to active child so it may merge in its menu
  513. //
  514. bool
  515. MainWnd_OnOcAppInsMenus(HWND hwnd, TOcMenuDescr far* sharedMenu)
  516. {
  517.   HWND child = MainWnd_GetActiveChild(hwnd);
  518.   return child ? GetOleWinObj(child)->OnOcAppInsMenus(sharedMenu) : false;
  519. }
  520.  
  521.  
  522. //
  523. // Set menu handle specified by active child
  524. //
  525. bool
  526. MainWnd_OnOcAppMenus(HWND hwnd, TOcMenuDescr far* menuDescr)
  527. {
  528.   HWND child = MainWnd_GetActiveChild(hwnd);
  529.   if (child) {
  530.     HMENU menu = GetOleWinObj(child)->OnOcAppMenus(menuDescr);
  531.     if (menu) {
  532.       MainWnd_SetMenu(hwnd, menu);
  533.       return true;
  534.     }
  535.   }
  536.   return false;
  537. }
  538.  
  539.  
  540. bool
  541. MainWnd_OnOcAppProcessMsg(HWND, MSG far*)
  542. {
  543.   return false;
  544. }
  545.  
  546.  
  547. bool
  548. MainWnd_OnOcAppBorderSpaceReq(HWND, TRect far*)
  549. {
  550.   return true;  // We'll negotiate anything!
  551. }
  552.  
  553.  
  554. bool
  555. MainWnd_OnOcAppBorderSpaceSet(HWND hwnd, TRect far* rect)
  556. {
  557.   if (rect) {
  558.     // Store space requested
  559.     //
  560.     Decorations = *rect;
  561.  
  562.     // Resize our client window
  563.     //
  564.     MainWnd_ResizeClient(hwnd);
  565.   }
  566.   return true;
  567. }
  568.  
  569.  
  570. //
  571. //
  572. //
  573. void
  574. MainWnd_OnOcAppStatusText(HWND, const char far* /*text*/)
  575. {
  576. }
  577.  
  578.  
  579. //
  580. //
  581. //
  582. void
  583. MainWnd_OnOcAppRestoreUI(HWND hwnd)
  584. {
  585.   HWND child = MainWnd_GetActiveChild(hwnd);
  586.   if (child) {
  587.     HMENU menu = GetOleWinObj(child)->OnOcAppRestoreUI();
  588.     MainWnd_SetMenu(hwnd, menu ? menu : FrameMenu);
  589.   }
  590.  
  591.   // Reset space allocated for decorations
  592.   //
  593.   Decorations.SetNull();
  594.   MainWnd_ResizeClient(hwnd);
  595. }
  596.  
  597.  
  598. //
  599. // Subdispatch OC_... messages
  600. //
  601. LRESULT
  602. MainWnd_OnOcEvent(HWND hwnd, WPARAM wParam, LPARAM lParam)
  603. {
  604.   switch (wParam) {
  605.     HANDLE_OCF(hwnd, OC_APPFRAMERECT,       MainWnd_OnOcAppFrameRect);
  606.     HANDLE_OCF(hwnd, OC_APPBORDERSPACESET,  MainWnd_OnOcAppBorderSpaceSet);
  607.     HANDLE_OCF(hwnd, OC_APPBORDERSPACEREQ,  MainWnd_OnOcAppBorderSpaceReq);
  608.     HANDLE_OCF(hwnd, OC_APPINSMENUS,        MainWnd_OnOcAppInsMenus);
  609.     HANDLE_OCF(hwnd, OC_APPMENUS,           MainWnd_OnOcAppMenus);
  610.     HANDLE_OCF(hwnd, OC_APPRESTOREUI,       MainWnd_OnOcAppRestoreUI);
  611.  
  612.     default:
  613.       return 0;
  614.   }
  615. }
  616.  
  617.  
  618. //
  619. // Standard message-handler routine for main window
  620. //
  621. LRESULT CALLBACK _export
  622. MainWndProc(HWND hwnd, uint message, WPARAM wParam, LPARAM lParam)
  623. {
  624.   switch (message) {
  625.     HANDLE_MSG(hwnd, WM_CREATE,         MainWnd_OnCreate);
  626.     HANDLE_MSG(hwnd, WM_CLOSE,          MainWnd_OnClose);
  627.     HANDLE_MSG(hwnd, WM_DESTROY,        MainWnd_OnDestroy);
  628.     HANDLE_MSG(hwnd, WM_COMMAND,        MainWnd_OnCommand);
  629.     HANDLE_MSG(hwnd, WM_SIZE,           MainWnd_OnSize);
  630.     HANDLE_MSG(hwnd, WM_INITMENU,       MainWnd_OnInitMenu);
  631.  
  632.     // handle the OCF events sent to the frame window
  633.     //
  634.     HANDLE_MSG(hwnd, WM_OCEVENT,  MainWnd_OnOcEvent);
  635.   }
  636.   return MainWnd_DefProc(hwnd, message, wParam, lParam);
  637. }
  638.  
  639.  
  640. // ----------------------------------------------------------------------------
  641. //  MDI Child - related functions/handlers
  642. // ----------------------------------------------------------------------------
  643.  
  644.  
  645. //
  646. // View related global variables
  647. //
  648. static HDC DC                 = 0;
  649. static HPEN OldPen            = 0;
  650. static HPEN CurPen            = 0;
  651. static TLine* ScratchLine     = 0;
  652. static int CurrentPenSize     = 1;
  653. static bool MouseCaptured     = false;
  654. static COLORREF CurrentColor  = RGB(0, 0, 0);
  655.  
  656.  
  657. //
  658. // Initialize child window
  659. //
  660. bool
  661. InitChild(HINSTANCE hInstance)
  662. {
  663.   WNDCLASS wcView;
  664.   wcView.style          = CS_DBLCLKS|CS_HREDRAW|CS_VREDRAW;
  665.   wcView.lpfnWndProc    = (WNDPROC) ViewWndProc;
  666.   wcView.cbClsExtra     = 0;
  667.   wcView.cbWndExtra     = sizeof(TOleWin*);
  668.   wcView.hInstance      = hInstance;
  669.   wcView.hIcon          = LoadIcon(0, IDI_APPLICATION);
  670.   wcView.hCursor        = LoadCursor(0, IDC_ARROW);
  671.   wcView.hbrBackground  = (HBRUSH)(COLOR_WINDOW+1);
  672.   wcView.lpszMenuName   = 0;
  673.   wcView.lpszClassName  = childClassName;
  674.  
  675.   return RegisterClass(&wcView) != 0;
  676. }
  677.  
  678.  
  679. //
  680. // Accessor to retrieve OLE helper object associated with an HWND
  681. //
  682. TOleWin*
  683. GetOleWinObj(HWND hwnd)
  684. {
  685.   return (TOleWin*)(LONG)GetWindowLong(hwnd, 0);
  686. }
  687.  
  688.  
  689. //
  690. // Function to associate an OLE Helper object with a window
  691. //
  692. void
  693. SetOleWinObj(HWND hwnd, TOleWin* oleWinObj)
  694. {
  695.   SetWindowLong(hwnd, 0, (LONG)oleWinObj);
  696. }
  697.  
  698.  
  699. ViewWndData*
  700. GetViewWndData(HWND hwnd)
  701. {
  702.   TOleWin* oleWinObj = GetOleWinObj(hwnd);
  703.   return (ViewWndData*)(oleWinObj ? oleWinObj->GetUserInfo() : 0);
  704. }
  705.  
  706.  
  707. ViewWndData*
  708. SetViewWndData(HWND hwnd, ViewWndData* data)
  709. {
  710.   TOleWin* oleWinObj = GetOleWinObj(hwnd);
  711.   return (ViewWndData*)(oleWinObj ? oleWinObj->SetUserInfo(data) : 0);
  712. }
  713.  
  714.  
  715. LRESULT
  716. ViewWnd_DefProc(HWND hwnd, uint message, WPARAM wParam, LPARAM lParam)
  717. {
  718.   return DefMDIChildProc(hwnd, message, wParam, lParam);
  719. }
  720.  
  721.  
  722. //
  723. // view window
  724. //
  725. BOOL
  726. ViewWnd_OnCreate(HWND hwnd, CREATESTRUCT FAR* /*lpCreateStruct*/)
  727. {
  728.   // Create an OLE helper object
  729.   //
  730.   TOleWin* oleWinObj = new TOleWin(hwnd);
  731.   SetOleWinObj(hwnd, oleWinObj);
  732.  
  733.   // Create per window data
  734.   //
  735.   ViewWndData* data = new ViewWndData;
  736.   SetViewWndData(hwnd, data);
  737.  
  738.   // Call the OnCreate method to allow initialization
  739.   //
  740.   oleWinObj->OnCreate();
  741.  
  742.   //
  743.   // Pass the OCF object our menu description
  744.   //
  745.   MenuDescr menuDescr(LoadMenu(GetWindowInstance(hwnd),
  746.                                MAKEINTRESOURCE(ID_CHILDMENU)),
  747.                       1,    // File group      (File)
  748.                       2,    // Edit group      (Edit + Tools)
  749.                       0,    // Container group
  750.                       0,    // Object group
  751.                       1,    // Window group    (Window)
  752.                       1);   // Help group      (Help)
  753.   oleWinObj->SetWinMenu(menuDescr);
  754.  
  755.   return true;
  756. }
  757.  
  758.  
  759. //
  760. // Handles WM_DESTROY message
  761. //
  762. void
  763. ViewWnd_OnDestroy(HWND hwnd)
  764. {
  765.   // cleanup per window data
  766.   //
  767.   ViewWndData* data = SetViewWndData(hwnd, 0);
  768.   delete data;
  769.  
  770.   TOleWin* oleWinObj = GetOleWinObj(hwnd);
  771.  
  772.   //
  773.   // Retrieve and cleanup our menu
  774.   //
  775.   HMENU hMenu = oleWinObj->GetWinMenu();
  776.   if (hMenu)
  777.     DestroyMenu(hMenu);
  778.  
  779.   // Allow OLE Helper to perform cleanup
  780.   //
  781.   oleWinObj->OnDestroy();
  782.  
  783.   // Cleanup C++ object
  784.   //
  785.   delete oleWinObj;
  786.   FORWARD_WM_DESTROY(hwnd, ViewWnd_DefProc);
  787. }
  788.  
  789.  
  790. //
  791. //
  792. //
  793. void
  794. ViewWnd_OnMDIActivate(HWND hwnd, BOOL fActive, HWND /*hwndActivate*/,
  795.                       HWND /*hwndDeactivate*/)
  796. {
  797.   //
  798.   // Reset menu when we're deactivated
  799.   //
  800.   if (!fActive) {
  801.     MainWnd_SetMenu(GetFrame(), 0);
  802.   } else {
  803.     //
  804.     // Set the child's menu when it's activated
  805.     //
  806.     TOleWin* oleWinObj = GetOleWinObj(hwnd);
  807.     HMENU currentMenu  = oleWinObj->GetMergedMenu();
  808.     if (!currentMenu)
  809.       currentMenu = oleWinObj->GetWinMenu();
  810.  
  811.     MainWnd_SetMenu(GetFrame(), currentMenu);
  812.   }
  813. }
  814.  
  815.  
  816. //
  817. //
  818. //
  819. void
  820. ViewWnd_OnSetFocus(HWND hwnd, HWND hwndOldFocus)
  821. {
  822.   GetOleWinObj(hwnd)->OnSetFocus(hwndOldFocus);
  823. }
  824.  
  825.  
  826. //
  827. // Handles WM_PAINT message
  828. //
  829. void
  830. ViewWnd_OnPaint(HWND hwnd)
  831. {
  832.   PAINTSTRUCT ps;
  833.   HDC dc = BeginPaint(hwnd, &ps);
  834.  
  835.   HPEN oldPen;
  836.   ViewWndData* data = GetViewWndData(hwnd);
  837.   if (data) {
  838.     // go through array of lines
  839.     //
  840.     TLinesIterator linesIter(*data->Lines);
  841.     while (linesIter) {
  842.       // about to draw a line
  843.       //
  844.       TLine line = linesIter.Current();
  845.       HPEN pen = CreatePen(PS_INSIDEFRAME, line.PenSize, line.Color);
  846.       oldPen = SelectPen(dc, pen);
  847.  
  848.       // go through the points in a line
  849.       //
  850.       TPointsIterator pointsIter(line);
  851.       bool firstPoint = true;
  852.  
  853.       while (pointsIter) {
  854.         TPoint point = pointsIter.Current();
  855.         if (firstPoint) {
  856.           MoveToEx(dc, point.x, point.y, 0);
  857.           firstPoint = false;
  858.         } else {
  859.           LineTo(dc, point.x, point.y);
  860.         }
  861.         pointsIter++;
  862.       }
  863.  
  864.       SelectPen(dc, oldPen);
  865.       DeletePen(pen);
  866.  
  867.       linesIter++;
  868.     }
  869.   }
  870.  
  871.   // OLE Helper will draw embedded parts
  872.   //
  873.   GetOleWinObj(hwnd)->OnPaint(dc, ps);
  874.  
  875.   EndPaint(hwnd, &ps);
  876. }
  877.  
  878.  
  879. //
  880. // Handles WM_SIZE message
  881. //
  882. void
  883. ViewWnd_OnSize(HWND hwnd, uint /*state*/, int /*cx*/, int /*cy*/)
  884. {
  885.   // Inform OLE Helper object that we've been resized
  886.   //
  887.   GetOleWinObj(hwnd)->OnSize();
  888. }
  889.  
  890.  
  891. //
  892. // Handles CM_FILESAVEAS command
  893. //
  894. void
  895. ViewWnd_OnFileSaveAs(HWND hwnd)
  896. {
  897.   ViewWndData* data = GetViewWndData(hwnd);
  898.   if (data) {
  899.     // Prompt user for file name
  900.     //
  901.     if (GetSaveFileName(hwnd, Filter, FileName, sizeof(FileName))) {
  902.       // Create the file
  903.       //
  904.       TOcDocument* doc = GetOleWinObj(hwnd)->GetOcDoc();
  905.       if (doc) {
  906.         try {
  907.           doc->SaveToFile(FileName);
  908.  
  909.           // Save the embedded objects
  910.           //
  911.           doc->SaveParts(0, true);
  912.  
  913.           // write out user data
  914.           //
  915.           TOcStorage* storage = doc->GetStorage();
  916.           if (storage) {
  917.             // create a storage within the file and save our data into it
  918.             //
  919.             TOcStream stream(*storage, DEFDESC, true, STGM_WRITE);
  920.  
  921.             int numLines = data->Lines->GetItemsInContainer();
  922.             stream.Write(&numLines, sizeof numLines);
  923.  
  924.             // go through array of lines
  925.             //
  926.             TLinesIterator linesIter(*data->Lines);
  927.             while (linesIter) {
  928.               // get a line
  929.               //
  930.               TLine line = linesIter.Current();
  931.               int numPoints = line.GetItemsInContainer();
  932.  
  933.               // save info about the line
  934.               //
  935.               stream.Write(&numPoints, sizeof numPoints);
  936.               stream.Write(&line.Color, sizeof line.Color);
  937.               stream.Write(&line.PenSize, sizeof line.PenSize);
  938.  
  939.               // save the points in the line
  940.               //
  941.               TPointsIterator pointsIter(line);
  942.               while (pointsIter) {
  943.                 TPoint point = pointsIter.Current();
  944.                 stream.Write(&point, sizeof point);
  945.                 pointsIter++;
  946.               }
  947.               linesIter++;
  948.             }
  949.  
  950.             stream.Commit(STGC_DEFAULT);
  951.           }
  952.           doc->GetStorage()->Commit(STGC_DEFAULT);
  953.  
  954.           // Update our caption with new file name
  955.           //
  956.           SetWindowText(hwnd, FileName);
  957.         }
  958.  
  959.         catch(TXOle& xole) {
  960.           MessageBox(hwnd, xole.why().c_str(), "EXCEPTION", MB_OK);
  961.         }
  962.       }
  963.     }
  964.   }
  965. }
  966.  
  967.  
  968. //
  969. // Handles CM_FILEOPEN command by loading saved parts and line data
  970. // (Variable 'FileName' contains the filename at this point)
  971. //
  972. void
  973. ViewWnd_OnFileOpen(HWND hwnd)
  974. {
  975.   ViewWndData* data = GetViewWndData(hwnd);
  976.   if (data) {
  977.     TOcDocument* doc = GetOleWinObj(hwnd)->GetOcDoc();
  978.     if (doc) {
  979.       try {
  980.         doc->SetStorage(FileName);
  981.         // load embedded objects
  982.         //
  983.         doc->LoadParts();
  984.  
  985.         TOcStorage* storage = doc->GetStorage();
  986.           if (storage) {
  987.             // open the stream that contains the lines
  988.             //
  989.             TOcStream stream(*storage, DEFDESC, false, STGM_READ);
  990.  
  991.             // how many lines?
  992.             //
  993.             int numLines;
  994.             stream.Read(&numLines, sizeof numLines);
  995.             for (int i=0; i<numLines; i++) {
  996.               // read the info about the line
  997.               //
  998.               int numPoints;
  999.               stream.Read(&numPoints, sizeof(numPoints));
  1000.               stream.Read(&CurrentColor, sizeof(CurrentColor));
  1001.               stream.Read(&CurrentPenSize, sizeof(CurrentPenSize));
  1002.               ScratchLine = new TLine(CurrentPenSize, CurrentColor);
  1003.  
  1004.               // read the points
  1005.               //
  1006.               for (int j=0; j<numPoints; j++) {
  1007.                 TPoint p;
  1008.                 stream.Read(&p, sizeof p);
  1009.                 ScratchLine->Add(p);
  1010.               }
  1011.               data->Lines->Add(*ScratchLine);
  1012.               delete ScratchLine;
  1013.               ScratchLine = 0;
  1014.             }
  1015.           InvalidateRect(hwnd, NULL, true);
  1016.         }
  1017.         SetWindowText(hwnd, FileName);
  1018.       }
  1019.       catch(TXOle& xole) {
  1020.          MessageBox(hwnd, xole.why().c_str(), "EXCEPTION", MB_OK);
  1021.       }
  1022.     }
  1023.   }
  1024. }
  1025.  
  1026.  
  1027. //
  1028. // Display Color Dialog to allow user to select pen color
  1029. //
  1030. void
  1031. ViewWnd_OnChoosePenColor(HWND hwnd)
  1032. {
  1033.   COLORREF userPal[16];
  1034.   memset(&userPal, 255, 16*sizeof(COLORREF));
  1035.   CHOOSECOLOR cc;
  1036.   memset(&cc, 0, sizeof cc);
  1037.   cc.lStructSize = sizeof cc;
  1038.   cc.hwndOwner = hwnd;
  1039.   cc.rgbResult = RGB(0, 0, 0);
  1040.   cc.lpCustColors = userPal;
  1041.   if (ChooseColor(&cc)) {
  1042.     CurrentColor = cc.rgbResult;
  1043.   }
  1044. }
  1045.  
  1046.  
  1047. //
  1048. // Handles WM_INITDIALOG for PenSize dialog
  1049. //
  1050. bool
  1051. PenDlg_OnInitDialog(HWND hwnd, HWND /*hwndFocus*/, LPARAM /*lParam*/)
  1052. {
  1053.   SetDlgItemInt(hwnd, IDC_PENSIZE, CurrentPenSize, false);
  1054.   return true;
  1055. }
  1056.  
  1057.  
  1058. //
  1059. // Handles WM_CLOSE message for PenSize dialog
  1060. //
  1061. void
  1062. PenDlg_OnClose(HWND hwnd)
  1063. {
  1064.   EndDialog(hwnd, IDCANCEL);
  1065. }
  1066.  
  1067.  
  1068. //
  1069. // Handles WM_COMMAND message from PenSize dialog
  1070. //
  1071. void
  1072. PenDlg_OnCommand(HWND hwnd, int id, HWND /*hwndCtl*/, uint /*codeNotify*/)
  1073. {
  1074.   switch (id) {
  1075.     case IDOK: {
  1076.       int penSize;
  1077.       bool translated;
  1078.       penSize = GetDlgItemInt(hwnd, IDC_PENSIZE, &translated, false);
  1079.  
  1080. #if !defined(NDEBUG)
  1081.       wsprintf(FileName, "ps = %d\n\r", penSize);
  1082.       OutputDebugString(FileName);
  1083. #endif
  1084.  
  1085.       if (penSize < 1 || 25 < penSize) {
  1086.         MessageBox(hwnd, "Pensize out of range.", "Error", MB_OK);
  1087.       } else {
  1088.         CurrentPenSize = penSize;
  1089.         EndDialog(hwnd, IDOK);
  1090.       }
  1091.       break;
  1092.     }
  1093.     case IDCANCEL: {
  1094.       EndDialog(hwnd, IDCANCEL);
  1095.       break;
  1096.     }
  1097.   }
  1098. }
  1099.  
  1100.  
  1101. //
  1102. // Callback of dialog which allows user to change pen size
  1103. //
  1104. bool CALLBACK _export
  1105. PenSizeDlgProc(HWND hwnd, uint message, WPARAM wParam, LPARAM lParam)
  1106. {
  1107.   switch (message) {
  1108.    case WM_INITDIALOG:
  1109.         HANDLE_WM_INITDIALOG(hwnd, wParam, lParam, PenDlg_OnInitDialog);
  1110.         return true;
  1111.  
  1112.    case WM_CLOSE:
  1113.         HANDLE_WM_CLOSE(hwnd, wParam, lParam, PenDlg_OnClose);
  1114.         return true;
  1115.  
  1116.    case WM_COMMAND:
  1117.         HANDLE_WM_COMMAND(hwnd, wParam, lParam, PenDlg_OnCommand);
  1118.         return true;
  1119.   }
  1120.   return false;
  1121. }
  1122.  
  1123.  
  1124. //
  1125. // Displays dialog which allows user to change pen size
  1126. //
  1127. void
  1128. ViewWnd_OnChoosePenSize(HWND hwnd)
  1129. {
  1130.   FARPROC proc = MakeProcInstance((FARPROC)PenSizeDlgProc, HInstance);
  1131.   DialogBox(HInstance, MAKEINTRESOURCE(ID_CHOOSEPENSIZE),
  1132.             hwnd, (DLGPROC)proc);
  1133.   FreeProcInstance(proc);
  1134. }
  1135.  
  1136.  
  1137. //
  1138. // Handles WM_COMMAND messages
  1139. //
  1140. void
  1141. ViewWnd_OnCommand(HWND hwnd, int id, HWND /*hwndCtl*/, uint /*codeNotify*/)
  1142. {
  1143.   switch(id) {
  1144.     case CM_FILEOPEN:
  1145.       ViewWnd_OnFileOpen(hwnd);
  1146.       break;
  1147.  
  1148.     case CM_FILESAVE:
  1149.     case CM_FILESAVEAS:
  1150.       ViewWnd_OnFileSaveAs(hwnd);
  1151.       break;
  1152.  
  1153.     case CM_PENCOLOR:
  1154.       ViewWnd_OnChoosePenColor(hwnd);
  1155.       break;
  1156.  
  1157.     case CM_PENSIZE:
  1158.       ViewWnd_OnChoosePenSize(hwnd);
  1159.       break;
  1160.  
  1161.     default:
  1162.       // Pass any command IDs that we're not handling to the OLE Helper
  1163.       // object. It will handle issues such as activating OLE UI dialogs.
  1164.       //
  1165.       GetOleWinObj(hwnd)->OnCommand(id);
  1166.       break;
  1167.   }
  1168. }
  1169.  
  1170.  
  1171. //
  1172. // Handles WM_LBUTTONDOWN message
  1173. //
  1174. void
  1175. ViewWnd_OnLButtonDown(HWND hwnd, bool fDoubleClick, int x, int y, uint keyFlags)
  1176. {
  1177.   // Pass LButtonDown/LButtonDblClk to the OLE Helper object.
  1178.   // It will deactiate/activate any OLE part if necessary
  1179.   //
  1180.   if (fDoubleClick)
  1181.     GetOleWinObj(hwnd)->OnLButtonDblClk(x, y, keyFlags);
  1182.   else {
  1183.     if (!GetOleWinObj(hwnd)->OnLButtonDown(x, y, keyFlags)) {
  1184.       if (!GetOleWinObj(hwnd)->SelectEmbedded()) {
  1185.         SetCapture(hwnd);
  1186.         MouseCaptured = true;
  1187.         ScratchLine = new TLine(CurrentPenSize, CurrentColor);
  1188.         TPoint p(x, y);
  1189.         ScratchLine->Add(p);
  1190.  
  1191.         CurPen = CreatePen(PS_INSIDEFRAME, CurrentPenSize, CurrentColor);
  1192.         DC = GetDC(hwnd);
  1193.         OldPen = SelectPen(DC, CurPen);
  1194.         MoveToEx(DC, x, y, 0);
  1195.       }
  1196.     }
  1197.   }
  1198. }
  1199.  
  1200.  
  1201. //
  1202. // Handles WM_MOUSEMOVE message
  1203. //
  1204. void
  1205. ViewWnd_OnMouseMove(HWND /*hwnd*/, int x, int y, uint /*keyFlags*/)
  1206. {
  1207.   if (MouseCaptured) {
  1208.     TPoint p(x, y);
  1209.  
  1210.     ScratchLine->Add(p);
  1211.     LineTo(DC, x, y);
  1212.   }
  1213. }
  1214.  
  1215.  
  1216. //
  1217. // Handles WM_LBUTTONUP message
  1218. //
  1219. void
  1220. ViewWnd_OnLButtonUp(HWND hwnd, int x, int y, uint /*keyFlags*/)
  1221. {
  1222.   if (MouseCaptured) {
  1223.     TPoint p(x, y);
  1224.     ScratchLine->Add(p);
  1225.  
  1226.     LineTo(DC, x, y);
  1227.     SelectPen(DC, OldPen);
  1228.     ReleaseDC(hwnd, DC);
  1229.  
  1230.     DeletePen(CurPen);
  1231.  
  1232.     ViewWndData* data = GetViewWndData(hwnd);
  1233.     data->Lines->Add(*ScratchLine);
  1234.  
  1235.     delete ScratchLine;
  1236.     ScratchLine = 0;
  1237.  
  1238.     ReleaseCapture();
  1239.     MouseCaptured = false;
  1240.   }
  1241. }
  1242.  
  1243.  
  1244. //
  1245. // Handles WM_INITMENU message
  1246. //
  1247. void
  1248. ViewWnd_OnInitMenu(HWND hwnd, HMENU hMenu)
  1249. {
  1250.   //
  1251.   // Allow OLE Helper object to enable/disable OLE related menuitems
  1252.   //
  1253.   GetOleWinObj(hwnd)->OnInitMenu(hMenu);
  1254. }
  1255.  
  1256.  
  1257. //
  1258. // Subdispatch OC_... messages
  1259. //
  1260. LRESULT
  1261. ViewWnd_OnOcEvent(HWND hwnd, WPARAM wParam, LPARAM lParam)
  1262. {
  1263.   // Pass the WM_OCEVENT from OCF to the OLE Helper Object
  1264.   //
  1265.   return GetOleWinObj(hwnd)->OnOcEvent(wParam, lParam);
  1266. }
  1267.  
  1268.  
  1269. //
  1270. // Standard message-handler routine for view window
  1271. //
  1272. LRESULT CALLBACK _export
  1273. ViewWndProc(HWND hwnd, uint message, WPARAM wParam, LPARAM lParam)
  1274. {
  1275.   switch (message) {
  1276.     HANDLE_MSG(hwnd, WM_CREATE,         ViewWnd_OnCreate);
  1277.     HANDLE_MSG(hwnd, WM_DESTROY,        ViewWnd_OnDestroy);
  1278.     HANDLE_MSG(hwnd, WM_PAINT,          ViewWnd_OnPaint);
  1279.     HANDLE_MSG(hwnd, WM_COMMAND,        ViewWnd_OnCommand);
  1280.     HANDLE_MSG(hwnd, WM_LBUTTONDOWN,    ViewWnd_OnLButtonDown);
  1281.     HANDLE_MSG(hwnd, WM_LBUTTONDBLCLK,  ViewWnd_OnLButtonDown);
  1282.     HANDLE_MSG(hwnd, WM_MOUSEMOVE,      ViewWnd_OnMouseMove);
  1283.     HANDLE_MSG(hwnd, WM_LBUTTONUP,      ViewWnd_OnLButtonUp);
  1284.     HANDLE_MSG(hwnd, WM_INITMENU,       ViewWnd_OnInitMenu);
  1285.     HANDLE_MSG(hwnd, WM_MDIACTIVATE,    ViewWnd_OnMDIActivate);
  1286.     HANDLE_MSG(hwnd, WM_SETFOCUS,       ViewWnd_OnSetFocus);
  1287.  
  1288.     case WM_OCEVENT:
  1289.       return ViewWnd_OnOcEvent(hwnd, wParam, lParam);
  1290.   }
  1291.  
  1292.   return ViewWnd_DefProc(hwnd, message, wParam, lParam);
  1293. }
  1294.  
  1295.