home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Gam…ming Gurus (2nd Edition) / Disc2.iso / msdn_vcb / samples / vc98 / sdk / winui / comctl / reitp / reitp.c < prev    next >
Encoding:
C/C++ Source or Header  |  1997-10-02  |  115.2 KB  |  4,665 lines

  1. /*
  2.  *    reitp.c
  3.  *    
  4.  *    Purpose:
  5.  *        Test program for RichEdit.  Excercises main RichEdit
  6.  *        functionality while providing a good replacement for notepad.
  7.  *    
  8.  *    Owner:
  9.  *
  10.  *  Copyright (c) 1997 Microsoft Coporation
  11.  */
  12.  
  13. #include "preinc.h"
  14.  
  15. #include <windows.h>
  16. #include <windowsx.h>
  17.  
  18. #include <commdlg.h>
  19. #include <cderr.h>
  20. #include <ctype.h>
  21. #include <stdio.h>
  22. #include <tchar.h>
  23.  
  24. // for the benefit of the outside world,
  25. // richedit.h uses cpMax instead of cpMost
  26. // I highly prefer cpMost
  27. #ifdef cpMax
  28. #error "cpMax hack won't work"
  29. #endif    // cpMax
  30. #define cpMax cpMost
  31. #include <richedit.h>
  32. #undef cpMax
  33.  
  34. #include "olestd.h"
  35. #include "reguid.h"
  36. #include "dbugit.h"
  37. #include <richole.h>
  38.  
  39. #include "reitp.h"
  40. #include "reitp.rh"
  41. #include "frmtbar.h"
  42. #include <oledlg.h>
  43.  
  44.  
  45. ASSERTDATA
  46.  
  47.  
  48. #define SUNKENRICHEDIT
  49.  
  50. // define to use LiFormatRange() directly instead of via blitting
  51. //#define NOBLIT
  52.  
  53. // used to make life simpler while testing, should not normally be defined
  54. //#define NO_SAVE_PROMPT
  55.  
  56.  
  57. struct _itpcall;
  58.  
  59. typedef struct _pp
  60. {
  61.     BOOL fDone;
  62.     HWND hwndDlg;
  63.     REDOC *predoc;
  64.     LONG cchText;
  65.     LONG dxPage;
  66.     LONG dyPage;
  67.     RECT rc;
  68.     FORMATRANGE fr;
  69. #ifndef NOBLIT
  70.     HBITMAP hbmp;
  71.     HBITMAP hbmpOld;
  72.     INT dxBmp;
  73.     INT dyBmp;
  74. #endif    // !NOBLIT
  75.     INT ipage;
  76.     INT cpage;
  77.     INT cpageMost;
  78.     LONG *rgcpPages;
  79. } PRINTPREVIEW;
  80.  
  81. // number of pages to allocate at once in PRINTPREVIEW.rgcpPages
  82. #define cpageChunk 4
  83.  
  84. #define szFmtPrintPreview TEXT("Print Preview - Page %d")
  85.  
  86. typedef struct _assensz
  87. {
  88.     WORD wNotification;
  89.     LPCSTR szDescription;
  90. } ASSENSZ;
  91.  
  92. // added to the client rect to get the RichEdit size
  93. #ifdef SUNKENRICHEDIT
  94. #define dxRESize -GetSystemMetrics(SM_CXBORDER)
  95. #define dyRESize -GetSystemMetrics(SM_CYBORDER)
  96. #else    // SUNKENRICHEDIT
  97. #define dxRESize 0
  98. #define dyRESize 0
  99. #endif    // SUNKENRICHEDIT, else
  100.  
  101. // Control ID for the format bar
  102. #define    FBR_FormatBar    217
  103.  
  104. #define HinstFromHwnd(_hwnd) ((HINSTANCE) GetWindowLong(_hwnd, GWL_HINSTANCE))
  105.  
  106. #define uiMFDisabled MF_DISABLED | MF_GRAYED
  107. #define uiMFEnabled MF_ENABLED
  108.  
  109. // Maximum text to be corrected under PenWin
  110. #define cchMaxCorrectText        4096
  111.  
  112. #define szClosedName szAppName
  113.  
  114. static TCHAR szAppName[] = TEXT("REITP");
  115. static const TCHAR szClassRE[] = TEXT(RICHEDIT_CLASS);
  116.  
  117. static const TCHAR szFmtTitle[] = TEXT("REITP - %s");
  118. static const TCHAR szUntitled[] = TEXT("[Untitled]");
  119. static const TCHAR szRTFSig[] = TEXT("{\\rtf");
  120. #define cchRTFSig 5
  121. static TCHAR szRegKey[] = TEXT("software\\microsoft\\reitp");
  122. static TCHAR szRegValue[] = TEXT("placement");
  123. static const POINT ptMinTrackSize = {300, 90};
  124. // Make sure that these strings match the order of SF_*
  125. static TCHAR szFilterLoad[] = TEXT("Text and Rich Text\0*.TXT;*.RTF\0Text Files (*.TXT)\0*.TXT\0Rich Text Format (*.RTF)\0*.RTF\0All Files\0*.*\0\0");
  126. static TCHAR szFilterSave[] = TEXT("Text Files (*.TXT)\0*.TXT\0Rich Text Format (*.RTF)\0*.RTF\0RTF w/o Objects (*.RTF)\0*.RTF\0Textized\0*.TXT\0\0");
  127.  
  128. static HMODULE hmod = 0;        // Flag for FreeLibrary()
  129. HWND hwndMain = 0;
  130. static HMENU hmenuLoaded = 0;
  131. HMENU hmenuFull = 0;
  132. static PRINTDLG pdDef = {0};
  133. static BOOL fPrint = fFalse;
  134. static BOOL fWysiwygDefault = fFalse;
  135. static BOOL fWrapDefault = fTrue;
  136. static UINT msgFindReplace = 0;
  137. static HWND hwndFR = 0;                    // find/replace dialog
  138. HINSTANCE hinst = 0;
  139.  
  140. static LONG cchTextMost = 0;
  141. static CLIPFORMAT cfTxtObj = 0;
  142. static BOOL fErrSpace = fFalse;
  143.  
  144.  
  145.  
  146.  
  147. static CHARFORMAT cfDefault =
  148. {
  149.     sizeof(CHARFORMAT),
  150.     CFM_EFFECTS | CFM_PROTECTED | CFM_SIZE | CFM_OFFSET | CFM_COLOR | CFM_CHARSET | CFM_FACE,
  151.     CFE_AUTOCOLOR,        // effects
  152.     200,                // height, 200 twips == 10 points
  153.     0,                    // offset
  154.     0,                    // color (not used since CFE_AUTOCOLOR is specified)
  155.     ANSI_CHARSET,
  156.     FF_ROMAN,            // pitch and family
  157.     "Arial"                // face name
  158. };
  159.  
  160. static ASSENSZ rgassenszErrors[] =
  161. {
  162.     {EN_ERRSPACE, "Out of memory. Exit some other applications and try again."},
  163.     {EN_MAXTEXT, "The maximum text length has been reached."},
  164.     {0, NULL}
  165. };
  166.  
  167. /*
  168.  *    ITPOLEINPLACEFRAME
  169.  *    
  170.  *    Purpose:
  171.  *        Frame window support for in place editing
  172.  */
  173. typedef struct _itpoleinplaceframe
  174. {
  175.     IOleInPlaceFrameVtbl * lpVtbl;        // Virtual table
  176.     ULONG cRef;                        // Reference count
  177.     REDOC * predoc;                    // Document
  178.     LPOLEINPLACEACTIVEOBJECT pipaobj;        // Current active object
  179. }
  180. ITPOLEINPLACEFRAME;
  181.  
  182. #define PipframeFromPunk(_p) ((ITPOLEINPLACEFRAME *) (_p))
  183.  
  184. // Functions for ITP in place frame
  185. ITPOLEINPLACEFRAME * ITPOLEINPLACEFRAME_New(REDOC * predoc);
  186. STDMETHODIMP ITPOLEINPLACEFRAME_QueryInterface(LPUNKNOWN punk, REFIID riid,
  187.                                                LPUNKNOWN * ppvObj);
  188. STDMETHODIMP_(ULONG) ITPOLEINPLACEFRAME_AddRef(LPUNKNOWN punk);
  189. STDMETHODIMP_(ULONG) ITPOLEINPLACEFRAME_Release(LPUNKNOWN punk);
  190. STDMETHODIMP ITPOLEINPLACEFRAME_GetWindow(ITPOLEINPLACEFRAME * pipframe,
  191.                                           HWND * phwnd);
  192. STDMETHODIMP ITPOLEINPLACEFRAME_ContextSensitiveHelp(ITPOLEINPLACEFRAME *pipframe,
  193.                                                      BOOL fEnterMode);
  194. STDMETHODIMP ITPOLEINPLACEFRAME_GetBorder(ITPOLEINPLACEFRAME * pipframe,
  195.                                           LPRECT prcBorder);
  196. STDMETHODIMP ITPOLEINPLACEFRAME_RequestBorderSpace(ITPOLEINPLACEFRAME * pipframe,
  197.                                                    LPCBORDERWIDTHS pbw);
  198. STDMETHODIMP ITPOLEINPLACEFRAME_SetBorderSpace(ITPOLEINPLACEFRAME * pipframe,
  199.                                                LPCBORDERWIDTHS pbw);
  200. STDMETHODIMP ITPOLEINPLACEFRAME_SetActiveObject(ITPOLEINPLACEFRAME * pipframe,
  201.                                                 LPOLEINPLACEACTIVEOBJECT pipaobj,
  202.                                                 LPCSTR szObjName); 
  203. STDMETHODIMP ITPOLEINPLACEFRAME_InsertMenus(ITPOLEINPLACEFRAME * pipframe,
  204.                                             HMENU hmenuShared, 
  205.                                             LPOLEMENUGROUPWIDTHS pmgw);
  206. STDMETHODIMP ITPOLEINPLACEFRAME_SetMenu(ITPOLEINPLACEFRAME * pipframe, 
  207.                                         HMENU hmenuShared, HOLEMENU holemenu, 
  208.                                         HWND hwndActiveObject);
  209. STDMETHODIMP ITPOLEINPLACEFRAME_RemoveMenus(ITPOLEINPLACEFRAME * pipframe, 
  210.                                             HMENU hmenuShared);
  211. STDMETHODIMP ITPOLEINPLACEFRAME_SetStatusText(ITPOLEINPLACEFRAME * pipframe, 
  212.                                               LPCSTR szStatusText);    
  213. STDMETHODIMP ITPOLEINPLACEFRAME_EnableModeless(ITPOLEINPLACEFRAME * pipframe, 
  214.                                                BOOL fEnable);
  215. STDMETHODIMP ITPOLEINPLACEFRAME_TranslateAccelerator(ITPOLEINPLACEFRAME *pipframe,
  216.                                                      LPMSG pmsg, WORD wID);
  217.  
  218. // Virtual table for ole in place frame interface
  219. IOleInPlaceFrameVtbl ITPOLEINPLACEFRAME_Vtbl =
  220. {
  221.     (LPVOID) ITPOLEINPLACEFRAME_QueryInterface,
  222.     (LPVOID) ITPOLEINPLACEFRAME_AddRef,
  223.     (LPVOID) ITPOLEINPLACEFRAME_Release,
  224.     (LPVOID) ITPOLEINPLACEFRAME_GetWindow,
  225.     (LPVOID) ITPOLEINPLACEFRAME_ContextSensitiveHelp,
  226.     (LPVOID) ITPOLEINPLACEFRAME_GetBorder,
  227.     (LPVOID) ITPOLEINPLACEFRAME_RequestBorderSpace,
  228.     (LPVOID) ITPOLEINPLACEFRAME_SetBorderSpace,
  229.     (LPVOID) ITPOLEINPLACEFRAME_SetActiveObject,
  230.     (LPVOID) ITPOLEINPLACEFRAME_InsertMenus,
  231.     (LPVOID) ITPOLEINPLACEFRAME_SetMenu,
  232.     (LPVOID) ITPOLEINPLACEFRAME_RemoveMenus,
  233.     (LPVOID) ITPOLEINPLACEFRAME_SetStatusText,
  234.     (LPVOID) ITPOLEINPLACEFRAME_EnableModeless,
  235.     (LPVOID) ITPOLEINPLACEFRAME_TranslateAccelerator
  236. };
  237.  
  238.  
  239. /*
  240.  *    ITPCALL
  241.  *    
  242.  *    Purpose:
  243.  *        Callbacks from the Rich Edit OLE support
  244.  */
  245.  
  246. typedef struct _itpcall
  247. {
  248.     IRichEditOleCallbackVtbl * lpVtbl;    // Virtual table
  249.     ULONG cRef;                            // Reference count
  250.     REDOC * predoc;                        // Document
  251.     ITPOLEINPLACEFRAME * pipframe;        // In place frame object
  252. }
  253. ITPCALL;
  254.  
  255.  
  256. #define PitpcallFromPunk(_p) ((ITPCALL *) (_p))
  257.  
  258. // Functions for ITP callbacks
  259. ITPCALL * ITPCALL_New(REDOC * predoc);
  260. STDMETHODIMP ITPCALL_QueryInterface(LPUNKNOWN punk, REFIID riid,
  261.                                     LPUNKNOWN * ppvObj);
  262. STDMETHODIMP_(ULONG) ITPCALL_AddRef(LPUNKNOWN punk);
  263. STDMETHODIMP_(ULONG) ITPCALL_Release(LPUNKNOWN punk);
  264. STDMETHODIMP ITPCALL_GetNewStorage(ITPCALL * pitpcall, LPSTORAGE FAR * ppstg);
  265. STDMETHODIMP ITPCALL_GetInPlaceContext(ITPCALL * pitpcall, 
  266.                                        LPOLEINPLACEFRAME FAR * ppipframe,
  267.                                        LPOLEINPLACEUIWINDOW FAR* ppipuiDoc,
  268.                                        LPOLEINPLACEFRAMEINFO pipfinfo);
  269. STDMETHODIMP ITPCALL_ShowContainerUI(ITPCALL * pitpcall, BOOL fShow);
  270. STDMETHODIMP ITPCALL_QueryInsertObject(ITPCALL * pitpcall, LPCLSID pclsid,
  271.                 LPSTORAGE pstg, LONG cp);
  272. STDMETHODIMP ITPCALL_DeleteObject(ITPCALL * pitpcall, LPOLEOBJECT poleobj);
  273. STDMETHODIMP ITPCALL_QueryAcceptData(ITPCALL * pitpcall, LPDATAOBJECT pdataobj,
  274.                 CLIPFORMAT *pcfFormat, DWORD reco, BOOL fReally,
  275.                 HGLOBAL hMetaPict);
  276. STDMETHODIMP ITPCALL_ContextSensitiveHelp(ITPCALL * pitpcall, BOOL fEnterMode);
  277. STDMETHODIMP ITPCALL_GetClipboardData(ITPCALL *pitpcall, CHARRANGE *pchrg,
  278.                 DWORD reco, LPDATAOBJECT *ppdataobj);
  279. STDMETHODIMP ITPCALL_GetDragDropEffect(ITPCALL *pitpcall, BOOL fDrag,
  280.                 DWORD grfKeyState, LPDWORD pdwEffect);
  281. STDMETHODIMP ITPCALL_GetContextMenu(ITPCALL *pitpcall, WORD seltype,
  282.                 LPOLEOBJECT poleobj, CHARRANGE * pchrg, HMENU * phmenu);
  283.  
  284. // Virtual table for ITP callbacks
  285. IRichEditOleCallbackVtbl ITPCALL_Vtbl =
  286. {
  287.     (LPVOID) ITPCALL_QueryInterface,
  288.     (LPVOID) ITPCALL_AddRef,
  289.     (LPVOID) ITPCALL_Release,
  290.     (LPVOID) ITPCALL_GetNewStorage,
  291.     (LPVOID) ITPCALL_GetInPlaceContext,
  292.     (LPVOID) ITPCALL_ShowContainerUI,
  293.     (LPVOID) ITPCALL_QueryInsertObject,
  294.     (LPVOID) ITPCALL_DeleteObject,
  295.     (LPVOID) ITPCALL_QueryAcceptData,
  296.     (LPVOID) ITPCALL_ContextSensitiveHelp,
  297.     (LPVOID) ITPCALL_GetClipboardData,
  298.     (LPVOID) ITPCALL_GetDragDropEffect,
  299.     (LPVOID) ITPCALL_GetContextMenu
  300. };
  301.  
  302.  
  303. LOCAL VOID ParseArguments(LPSTR *pszDoc, LPCSTR szCmdLine);
  304. LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam);
  305. LOCAL LRESULT HandleCreate(REDOC *predoc, LPCSTR szCmdLine);
  306. LOCAL VOID ResizeRedoc(REDOC *predoc, RECT rc);
  307. LOCAL VOID SetupMenu(REDOC *predoc, int iMenu, HMENU hmenu);
  308. LOCAL LRESULT HandleCommand(REDOC *predoc, HWND hwnd, WPARAM wparam,
  309.                                 LPARAM lparam);
  310. LOCAL BOOL ToggleCheck(REDOC *predoc, UINT uiMenuid);
  311. LOCAL BOOL QueryCheck(REDOC *predoc, UINT uiMenuid);
  312. LOCAL LRESULT NewREDoc(REDOC *predoc, BOOL fPrompt, BOOL fUpdateUI);
  313. LOCAL LONG CheckSave(REDOC *predoc);
  314. LOCAL INT CheckRevert(REDOC *predoc);
  315. LOCAL LRESULT CloseREDoc(REDOC *predoc, BOOL fPrompt, BOOL fUpdateUI);
  316. DWORD CALLBACK MyRead(DWORD dwCookie, LPBYTE pbBuffer, LONG cb, LONG *pcb);
  317. LOCAL LRESULT OpenREDoc(REDOC *predoc, BOOL fInsert);
  318. LOCAL LRESULT RevertREDoc(REDOC *predoc);
  319. LOCAL DWORD ReadREDoc(REDOC *predoc, LPCSTR szFile, LPCSTR szTitle,
  320.                         DWORD dwFormat, BOOL fInsert);
  321. DWORD CALLBACK MyWrite(DWORD dwCookie, LPBYTE pbBuffer, LONG cb, LONG *pcb);
  322. LOCAL LRESULT SaveREDoc(REDOC *predoc);
  323. LOCAL LRESULT SaveREDocAs(REDOC *predoc, BOOL fSelect);
  324. LOCAL LRESULT InsertObject(REDOC *predoc);
  325. LOCAL VOID SelectCharFormat(REDOC *predoc);
  326. LOCAL VOID SaveWindowPos(HWND hwnd);
  327. LOCAL BOOL FRestoreWindowPos(WINDOWPLACEMENT *pwndpl);
  328. LOCAL VOID SetAlignment(REDOC *predoc, WORD wAlignment);
  329. LOCAL VOID IndentFirst(REDOC *predoc, BOOL fIndent);
  330. LOCAL VOID ProtectSelection(REDOC *predoc);
  331. LOCAL VOID SetWordWrap(REDOC *predoc, BOOL fWysiwyg, BOOL fWrap);
  332. LOCAL VOID SetupWordWrapMenu(REDOC *predoc);
  333. LOCAL VOID SetOffset(REDOC *predoc, BOOL fSuperscript);
  334. LRESULT CALLBACK PPDlgProc(HWND hdlg, UINT msg, WPARAM wparam, LPARAM lparam);
  335. LOCAL BOOL FPPInit(PRINTPREVIEW *ppp);
  336. LOCAL VOID PPInitDialogSize(PRINTPREVIEW *ppp);
  337. LOCAL VOID PPChangePage(PRINTPREVIEW *ppp, BOOL fPrev);
  338. LOCAL VOID PPPaint(PRINTPREVIEW *ppp);
  339. VOID DoVerb(REDOC * predoc, INT ioleverb);
  340. LOCAL VOID FindReplace(REDOC *predoc, BOOL fReplace);
  341. LOCAL VOID ProcessFindReplace(REDOC *predoc, FINDREPLACE *pfr);
  342. LOCAL BOOL FEnablePaste(VOID);
  343. LOCAL VOID UpdateFormatBar(REDOC *predoc);
  344. LOCAL VOID ShowMargins(REDOC *predoc);
  345.  
  346.  
  347. int PASCAL
  348. WinMain(HINSTANCE hinstCurr, HINSTANCE hinstPrev, LPSTR szCmdLine, int nCmdShow)
  349. {
  350.     SCODE sc;
  351.     MSG msg;
  352.     WNDCLASS wndclass;
  353.     WINDOWPLACEMENT wndpl;
  354.     TCHAR *szDoc = NULL;
  355.     REDOC *predoc = NULL;
  356.     HACCEL hAccels;
  357. #ifndef NO_OLE
  358.     LPOLEINPLACEACTIVEOBJECT pipaobj;
  359. #endif    // NO_OLE
  360.  
  361.     LoadLibrary("RichEd32.Dll"); // Load the RichEdit DLL to activate the
  362.                  // RichEdit classes
  363.  
  364.     wndclass.style         = CS_HREDRAW | CS_VREDRAW;
  365.     wndclass.lpfnWndProc   = WndProc;
  366.     wndclass.cbClsExtra    = 0;
  367.     wndclass.cbWndExtra    = sizeof(REDOC *);
  368.     wndclass.hInstance     = hinstCurr;
  369.     wndclass.hCursor       = LoadCursor(NULL, IDC_ARROW);
  370.     wndclass.hbrBackground = (HBRUSH) (COLOR_BACKGROUND + 1);
  371.     wndclass.hIcon           = LoadIcon(hinstCurr, TEXT("IconApp"));
  372.     wndclass.lpszMenuName  = NULL;
  373.     wndclass.lpszClassName = szAppName;
  374.  
  375.     RegisterClass(&wndclass);
  376.     hinst = hinstCurr;
  377.  
  378. #ifdef TEST_OLE_INITIALIZE
  379.     OleInitialize(NULL);
  380.     OleUninitialize();
  381.     OleInitialize(NULL);
  382.     OleUninitialize();
  383. #endif    // TEST_OLE_INITIALIZE
  384.  
  385.     OleInitialize(NULL);
  386.     sc = OleInitialize(NULL);
  387.     if (FAILED(sc))
  388.     {
  389.         TraceError("OleInitialize failed", sc);
  390.         goto done;                // If OLE can't be initialized abort.
  391.     }
  392.     // OleStdInitialize();
  393.  
  394.     // Initialize the format bar class
  395.     if(!FInitFormatBarClass(hinst))
  396.     {                        
  397.         MessageBoxA(NULL, "Unable to register format bar", NULL,
  398.                     MB_ICONSTOP | MB_OK);
  399.         goto done;
  400.     }
  401.  
  402.     hmenuLoaded = LoadMenu(hinstCurr, TEXT("LoadedMenu"));
  403.     hmenuFull = LoadMenu(hinstCurr, TEXT("FullMenu"));
  404.  
  405.     msgFindReplace = RegisterWindowMessage(TEXT("commdlg_FindReplace"));
  406.  
  407.     cfTxtObj = RegisterClipboardFormat(TEXT(CF_RETEXTOBJ));
  408.  
  409.     ParseArguments(&szDoc, szCmdLine);
  410.  
  411.     if(fPrint && !szDoc)
  412.         goto done;
  413.  
  414.     hwndMain = CreateWindow(szAppName, szAppName,
  415.             WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN, 
  416.             0, 0, 750, 500, NULL, NULL, hinstCurr, szDoc);
  417.     if(!hwndMain)
  418.     {
  419.         MessageBoxA(NULL, "Unable to create main window", NULL, MB_ICONSTOP | MB_OK);
  420.         goto done;
  421.     }
  422.     SideAssert(predoc = (REDOC *) GetWindowLong(hwndMain, 0));
  423.  
  424.     if(!fPrint)
  425.     {
  426.         if(FRestoreWindowPos(&wndpl))
  427.             SetWindowPlacement(hwndMain, &wndpl);
  428.         ShowWindow(hwndMain, nCmdShow);
  429.     }
  430.  
  431.     hAccels = LoadAccelerators(hinstCurr, "WARPKEYS");
  432.     Assert(hAccels);
  433.     while(GetMessage(&msg, NULL, 0, 0))
  434.     {
  435. # ifndef NO_OLE
  436.         // Translate accelerators for possible in place objects
  437.         if(predoc->pitpcall && (pipaobj = predoc->pitpcall->pipframe->pipaobj))
  438.             pipaobj->lpVtbl->TranslateAccelerator(pipaobj, &msg);
  439. # endif    // NO_OLE
  440.  
  441.         if(predoc->hwndRE && TranslateAccelerator(hwndMain, hAccels, &msg))
  442.             continue;
  443.  
  444.         if(!hwndFR || !IsDialogMessage(hwndFR, &msg))
  445.         {
  446.             TranslateMessage(&msg);
  447.             DispatchMessage(&msg);
  448.         }
  449.     }
  450.  
  451.  
  452.  
  453. done:
  454.     if(szDoc)
  455.         GlobalFreePtr(szDoc);
  456.     if(hwndMain)
  457.         DestroyWindow(hwndMain);
  458.     if(hmenuLoaded)
  459.         DestroyMenu(hmenuLoaded);
  460.     if(hmenuFull)
  461.         DestroyMenu(hmenuFull);
  462.  
  463.     // OleStdUninitialize();
  464.  
  465.     return msg.wParam;
  466. }
  467.  
  468.  
  469. LOCAL VOID ParseArguments(LPSTR *pszDoc, LPCSTR szCmdLine)
  470. {
  471.     const TCHAR *pch;
  472.  
  473.     *pszDoc = NULL;
  474.     pch = szCmdLine - 1;
  475.     while(pch)
  476.     {
  477.         pch++;
  478.         if(*pch == TEXT('/') || *pch == '-')
  479.         {
  480.             pch++;
  481.             switch(*pch)
  482.             {
  483.             case TEXT('p'):
  484.             case TEXT('P'):
  485.                 fPrint = fTrue;
  486.                 break;
  487.  
  488.             case TEXT('w'):
  489.             case TEXT('W'):
  490.                 pch++;
  491.                 if(*pch == 'p' || *pch == 'P')
  492.                 {
  493.                     pch++;
  494.                     fWrapDefault = fTrue;
  495.                     fWysiwygDefault = fTrue;
  496.                 }
  497.                 else if(*pch == 'n' || *pch == 'N')
  498.                 {
  499.                     pch++;
  500.                     fWrapDefault = fFalse;
  501.                     fWysiwygDefault = fFalse;
  502.                 }
  503.                 else
  504.                 {
  505.                     fWrapDefault = fTrue;
  506.                     fWysiwygDefault = fFalse;
  507.                 }
  508.                 break;
  509.  
  510.             default:
  511.                 if(*pch >= TEXT('0') && *pch <= TEXT('9') && !cchTextMost)
  512.                 {
  513.                     while(*pch >= TEXT('0') && *pch <= TEXT('9'))
  514.                     {
  515.                         cchTextMost *= 10;
  516.                         cchTextMost += *pch++ - TEXT('0');
  517.                     }
  518.                 }
  519.                 break;
  520.             }
  521.         }
  522.         else if(!*pszDoc)
  523.         {
  524.             while(*pch == TEXT(' '))
  525.                 pch++;
  526.             if(*pch)
  527.             {
  528.                 INT cch;
  529.                 const TCHAR *pchT;
  530.  
  531.                 pchT = _tcschr(pch, TEXT(' '));
  532.                 if(pchT)
  533.                     cch = pchT - pch;
  534.                 else
  535.                     cch = lstrlen(pch);
  536.                 *pszDoc = GlobalAllocPtr(GHND, cch + 1);
  537.                 if(!*pszDoc)
  538.                     break;
  539.                 lstrcpyn(*pszDoc, (LPCSTR) pch, cch + 1);
  540.                 (*pszDoc)[cch] = '\0';
  541.             }
  542.         }
  543.         pch = _tcschr(pch, TEXT(' '));
  544.     }
  545. }
  546.  
  547.  
  548. LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
  549. {
  550.     REDOC *predoc = (REDOC *) GetWindowLong(hwnd, 0);
  551. #ifndef NO_OLE
  552.     LPOLEINPLACEACTIVEOBJECT pipaobj;
  553. #endif    // !NO_OLE
  554.  
  555.     switch(msg)
  556.     {
  557.     case WM_NCCREATE:
  558.         predoc = (REDOC *) GlobalAllocPtr(GHND, sizeof(REDOC));
  559.         if(!predoc)
  560.             return 0;
  561.         SetWindowLong(hwnd, 0, (LONG) predoc);
  562.         predoc->hwndParent = hwnd;
  563. #ifndef MAC                
  564.         predoc->pd.lStructSize = sizeof(PRINTDLG);
  565.         predoc->pd.hwndOwner = hwnd;
  566.         predoc->pd.Flags = PD_RETURNDEFAULT;
  567.  
  568.         if(!PrintDlg(&predoc->pd) && CommDlgExtendedError())
  569.             memset(&predoc->pd, 0, sizeof(PRINTDLG));
  570. #endif        
  571.         break;
  572.  
  573.     case WM_NCDESTROY:
  574.         if(predoc)
  575.         {
  576.             if(predoc->pfr)
  577.                 GlobalFreePtr(predoc->pfr);
  578.             GlobalFreePtr(predoc);
  579.             predoc = NULL;
  580.             SetWindowLong(hwnd, 0, 0);
  581.         }
  582.         break;
  583.  
  584.     case WM_CREATE:
  585.         hwndMain = hwnd;    // a bit of a cheat...
  586.  
  587.         return HandleCreate(predoc,
  588.                 (LPCSTR) ((CREATESTRUCT *) lparam)->lpCreateParams);
  589.     case WM_DESTROY:
  590.         PostQuitMessage(0);
  591.         return 0l;
  592.  
  593.     case WM_ACTIVATEAPP:
  594. #ifndef NO_OLE
  595.         // Notify in place active object of frame activation
  596.         if(predoc->pitpcall && (pipaobj = predoc->pitpcall->pipframe->pipaobj))
  597.         {
  598.             TraceTag(tagInPlace, "OnFrameWindowActivate(%d)", !!wparam);
  599.             pipaobj->lpVtbl->OnFrameWindowActivate(pipaobj, !!wparam);
  600.         }
  601. #endif    // !NO_OLE
  602.         break;
  603.  
  604.     case WM_INITMENU:
  605.         if(predoc->hwndRE)
  606.             predoc->fUpdateEditMenu = TRUE;
  607.         break;
  608.  
  609.     case WM_INITMENUPOPUP:
  610.         if(predoc->hwndRE)
  611.             SetupMenu(predoc, (int) lparam, (HMENU) wparam);
  612.         return 0;
  613.  
  614.     case WM_GETMINMAXINFO:
  615.         ((MINMAXINFO *) lparam)->ptMinTrackSize = ptMinTrackSize;
  616.         return 0;
  617.  
  618.     case WM_COMMAND:
  619.         return HandleCommand(predoc, hwnd, wparam, lparam);
  620.  
  621.     case WM_CLOSE:
  622.         if(predoc && predoc->hwndRE && CloseREDoc(predoc, fTrue, fFalse) < 0)
  623.             return 0;
  624.         if(!fPrint)
  625.             SaveWindowPos(hwnd);
  626.         DestroyWindow(hwnd);
  627.         return 0;
  628.  
  629.     case WM_ACTIVATE:
  630.         if(predoc->hwndRE && LOWORD(wparam))
  631.         {
  632.             SetFocus(predoc->hwndRE);
  633.             return 0;
  634.         }
  635.         break;
  636.  
  637.     case WM_SIZE:
  638.         if(predoc->hwndFormatBar)
  639.             SendMessage(predoc->hwndFormatBar, WM_SIZE, 0, 0);
  640.         if(predoc->hwndRE)
  641.         {
  642.             RECT rc;
  643.  
  644.             GetClientRect(hwnd, &rc);
  645.             ResizeRedoc(predoc, rc);
  646. #ifdef DEBUG
  647.             SendMessage(predoc->hwndRE, EM_REQUESTRESIZE, 0, 0);
  648. #endif    // DEBUG
  649.         }
  650.         break;
  651.  
  652.  
  653.     case WM_NOTIFY:
  654.         switch(((NMHDR *) lparam)->code)
  655.         {
  656.         case EN_SELCHANGE:
  657.             if(predoc->hwndFormatBar)
  658.                 UpdateFormatBar(predoc);
  659.             return 0;
  660.  
  661.         case EN_PROTECTED:
  662.         {
  663.             ENPROTECTED *penprotected = (ENPROTECTED *) lparam;
  664.  
  665.             // allow change of protected attribute
  666.             if(penprotected->msg == EM_SETCHARFORMAT &&
  667.                 ((CHARFORMAT *) penprotected->lParam)->dwMask & CFM_PROTECTED)
  668.             {
  669.                 return 0;
  670.             }
  671.         }
  672.             MessageBeep(0);
  673.             return 1;
  674.  
  675.         case EN_CORRECTTEXT:
  676.         {
  677.             ENCORRECTTEXT *pct = (ENCORRECTTEXT *) lparam;
  678.  
  679.             if(pct->chrg.cpMost - pct->chrg.cpMin > cchMaxCorrectText)
  680.             {
  681.                 MessageBox(hwndMain,
  682.                             "You are trying to correct too much text. "
  683.                             "Decrease the size of your selection.",
  684.                             "REITP: Correct Text", MB_OK);
  685.                 return 0;
  686.             }
  687.         }
  688.         return 1;
  689.  
  690. #ifndef NO_OLE
  691.         case EN_DROPFILES:
  692. # ifdef DEBUG
  693.             if(!QueryCheck(predoc, IDM_IGNOREDROPS))
  694.                 return fFalse;
  695.             TraceTag(tagGeneral, "Ignoring drop of %d file(s) at position %d",
  696.                 DragQueryFile(((ENDROPFILES *) lparam)->hDrop, (UINT) -1,
  697.                     NULL, 0),
  698.                 ((ENDROPFILES *) lparam)->cp);
  699.             // ignore file drops
  700.             return fTrue;
  701. # else    // DEBUG
  702.             return ((ENDROPFILES *) lparam)->fProtected;
  703. # endif    // DEBUG, else
  704. #endif    // !NO_OLE
  705.  
  706.  
  707. #ifdef DEBUG
  708.         case EN_MSGFILTER:
  709.         {
  710.             MSGFILTER *    pmsgfilter = (MSGFILTER *) lparam;
  711.  
  712.             // eat left button downs and 'e's
  713.             return (pmsgfilter->msg == WM_LBUTTONDOWN) ||
  714.                         ((pmsgfilter->msg == WM_CHAR) &&
  715.                             (pmsgfilter->wParam == 'e'));
  716.         }
  717.  
  718.         case EN_REQUESTRESIZE:
  719.             ResizeRedoc(predoc, ((REQRESIZE *) lparam)->rc);
  720.             return 0;
  721. #endif    // DEBUG
  722.         }
  723.         break;
  724.  
  725.     default:
  726.         if(msg != msgFindReplace)
  727.             break;
  728.  
  729.         if(((FINDREPLACE *) lparam)->Flags & FR_DIALOGTERM)
  730.         {
  731.             hwndFR = 0;
  732.             SendMessage(predoc->hwndRE, EM_HIDESELECTION, fTrue, fTrue);
  733.             return 0;
  734.         }
  735.         ProcessFindReplace(predoc, (FINDREPLACE *) lparam);
  736.         return 0;
  737.     }
  738.  
  739.     return DefWindowProc(hwnd, msg, wparam, lparam);
  740. }
  741.  
  742.  
  743. LOCAL LRESULT HandleCreate(REDOC *predoc, LPCSTR szFile)
  744. {
  745.     DWORD dwError;
  746.  
  747.     if(!szFile || !*szFile)
  748.         goto no_file;
  749.  
  750.     if((dwError = ReadREDoc(predoc, szFile, NULL, 0, FALSE)))
  751.     {
  752.         TCHAR szErr[300];
  753.  
  754.         wsprintf(szErr, TEXT("Error opening %s [%ld]"), szFile, dwError);
  755.         MessageBoxA(hwndMain, szErr, NULL, MB_OK);
  756.         goto no_file;
  757.     }
  758.  
  759.     if(fPrint)
  760.     {
  761.         PrintREDoc(predoc);
  762.         PostQuitMessage(0);
  763.     }
  764.     else
  765.     {
  766.         TCHAR szT[256];
  767.  
  768.         wsprintf(szT, szFmtTitle, predoc->szTitle);
  769.         SetWindowText(predoc->hwndParent, szT);
  770.  
  771.         SetMenu(hwndMain, hmenuFull);
  772.         SetupWordWrapMenu(predoc);
  773.         DrawMenuBar(hwndMain);
  774.     }
  775.  
  776. #ifdef TIME_OPEN
  777.     PostMessage(hwndMain, WM_CLOSE, 0, 0);
  778. #endif    // TIME_OPEN
  779.  
  780.     return 0;
  781.  
  782. no_file:
  783.     if(NewREDoc(predoc, fFalse, fTrue) < 0)
  784.     {
  785.         SetMenu(hwndMain, hmenuLoaded);
  786.     }
  787.     else
  788.     {
  789.         SetMenu(hwndMain, hmenuFull);
  790.         SetupWordWrapMenu(predoc);
  791.     }
  792.     DrawMenuBar(hwndMain);
  793.  
  794.     return 0;
  795. }
  796.  
  797.  
  798. LOCAL VOID ResizeRedoc(REDOC *predoc, RECT rc)
  799. {
  800.     RECT rcParent;
  801. #ifndef NO_OLE
  802.     LPOLEINPLACEACTIVEOBJECT pipaobj = NULL;
  803. #endif    // NO_OLE
  804.  
  805.     GetClientRect(predoc->hwndParent, &rcParent);
  806.     InflateRect(&rcParent, dxRESize, dyRESize);
  807.  
  808.     // If we have a format bar, take it into account
  809.     if(predoc->hwndFormatBar)
  810.     {
  811.         RECT rcFmtBar;
  812.  
  813.         GetClientRect(predoc->hwndFormatBar, &rcFmtBar);
  814.         rcParent.top += rcFmtBar.bottom;
  815.     }
  816.     rc.top = max(rcParent.top, rc.top);
  817.     rc.left = max(rcParent.left, rc.left);
  818.     rc.right = min(rcParent.right, rc.right);
  819.     rc.bottom = max(rc.bottom, rc.top + ptMinTrackSize.y);
  820.     rc.bottom = min(rcParent.bottom, rc.bottom);
  821.  
  822.     MoveWindow(predoc->hwndRE, rc.left, rc.top, rc.right - rc.left,
  823.         rc.bottom - rc.top, fTrue);
  824.  
  825.     if(GetMenuState(hmenuFull, IDM_SHOWMARGINS, MF_BYCOMMAND) & MF_CHECKED)
  826.     {
  827.         rc.bottom -= rc.top;
  828.         rc.right -= rc.left;
  829.  
  830.         rc.top = 20;
  831.         rc.bottom -= 30;
  832.         if(rc.bottom < rc.top)
  833.             rc.bottom = rc.top;
  834.         rc.left = 30;
  835.         rc.right -= 30;
  836.         if(rc.right < rc.left)
  837.             rc.right = rc.left;
  838.         SendMessage(predoc->hwndRE, EM_SETRECT, 0, (LPARAM) &rc);
  839.     }
  840.  
  841.     // Notify in place active object of resize
  842.     //
  843.     // NOTE : Do not change the following line so that it uses an &&
  844.     // operation, this causes the Mac to lock up since the compiler
  845.     // apparently checks the second half of an AND regardless of the
  846.     // initial half's value.
  847.  
  848. #ifndef NO_OLE
  849.     if(predoc->pitpcall && (pipaobj = predoc->pitpcall->pipframe->pipaobj))
  850.     {
  851.         TraceTag(tagInPlace, "ResizeBorder");
  852.         GetClientRect(hwndMain, &rc);
  853. # ifdef MAC
  854.         pipaobj->lpVtbl->ResizeBorder(pipaobj, (RectPtr) &rc,
  855.           (LPOLEINPLACEUIWINDOW) predoc->pitpcall->pipframe, TRUE);
  856.         // Throw out the mem
  857. # else    // MAC
  858.         pipaobj->lpVtbl->ResizeBorder(pipaobj, &rc, 
  859.            (LPOLEINPLACEUIWINDOW) predoc->pitpcall->pipframe, TRUE);
  860. # endif    // MAC, else
  861.     }
  862. #endif     // !NO_OLE        
  863. }
  864.  
  865.  
  866. LOCAL VOID SetupMenu(REDOC *predoc, int iMenu, HMENU hmenu)
  867. {
  868.     DWORD dw;
  869.     LPOLEOBJECT poleobj = NULL;
  870.  
  871.     switch(iMenu)
  872.     {
  873.     case 0:        // file
  874.         if(!predoc->szFile[0])
  875.             dw = 0;
  876.         else
  877.             dw = (DWORD) SendMessage(predoc->hwndRE, EM_GETMODIFY, 0, 0);
  878.         EnableMenuItem(hmenu, IDM_REVERT, dw ? uiMFEnabled : uiMFDisabled);
  879.         EnableMenuItem(hmenu, IDM_SAVE, predoc->fReadOnly
  880.                                             ? uiMFDisabled : uiMFEnabled);
  881.         break;
  882.  
  883.     case 1:        // edit
  884.     
  885.         dw = uiMFDisabled;
  886.         // see if something can be pasted
  887.         // let RichEdit figure out if it's read-only
  888.         if(SendMessage(predoc->hwndRE, EM_CANPASTE, 0, 0))
  889.             dw = uiMFEnabled;
  890.         EnableMenuItem(hmenu, IDM_PASTE, (UINT) dw);
  891.  
  892.         dw = 0;
  893.         if(!predoc->fReadOnly)
  894.             dw = (DWORD) SendMessage(predoc->hwndRE, EM_CANUNDO, 0, 0);
  895.         EnableMenuItem(hmenu, IDM_UNDO, dw ? uiMFEnabled : uiMFDisabled);
  896.  
  897. //$ REVIEW: use EN_SELCHANGE?
  898.         dw = (DWORD) SendMessage(predoc->hwndRE, EM_SELECTIONTYPE, 0, 0);
  899.         EnableMenuItem(hmenu, IDM_COPY, dw ? uiMFEnabled : uiMFDisabled);
  900. #ifdef DEBUG
  901.         if(predoc->fReadOnly && !QueryCheck(predoc, IDM_ENABLECUTREADONLY))
  902.             dw = 0;
  903.         EnableMenuItem(hmenu, IDM_CUT, dw ? uiMFEnabled : uiMFDisabled);
  904.         if(predoc->fReadOnly)
  905.             dw = 0;
  906. #else    // DEBUG
  907.         if(predoc->fReadOnly)
  908.             dw = 0;
  909.         EnableMenuItem(hmenu, IDM_CUT, dw ? uiMFEnabled : uiMFDisabled);
  910. #endif    // DEBUG, else
  911.         EnableMenuItem(hmenu, IDM_DELETE, dw ? uiMFEnabled : uiMFDisabled);
  912.  
  913.         EnableMenuItem(hmenu, IDM_INSOBJ, predoc->fReadOnly
  914.                                             ? uiMFDisabled : uiMFEnabled);
  915.         EnableMenuItem(hmenu, IDM_REPLACE, predoc->fReadOnly ?
  916.                                                 uiMFDisabled : uiMFEnabled);
  917.  
  918.  
  919.         // That's all we need to do
  920.         if(!predoc->fUpdateEditMenu)
  921.             break;
  922.  
  923. #ifndef NO_OLE
  924.         // Find out if we have a single object to deal with
  925.         if(!(dw ^ SEL_OBJECT))
  926.         {
  927.             REOBJECT reobj = { 0 };
  928.  
  929.             reobj.cbStruct = sizeof(REOBJECT);
  930.             reobj.cp = REO_CP_SELECTION;
  931.  
  932.             if(!predoc->preole->lpVtbl->GetObject(predoc->preole,
  933.                                                     REO_IOB_USE_CP, &reobj,
  934.                                                     REO_GETOBJ_POLEOBJ))
  935.             {
  936.                 poleobj = reobj.poleobj;
  937.             }
  938.         }
  939.         // Ask OLE to build the menu for us
  940.  
  941. # ifdef MAC
  942. //$ FUTURE MAC
  943.         dw = IDM_OBJECTCONVERT;
  944. #  ifdef NEVER
  945.         macMenu1 = CheckoutMenu(hmenu, 2);
  946.         if(!macMenu1)
  947.             DebugStr("\pCheckoutMenu(macMenu1) failed");
  948.         macMenu2 = CheckoutMenu(predoc->hmenuVerbs, 2);
  949.         if(!macMenu2)
  950.             DebugStr("\pCheckoutMenu(macMenu2) failed");
  951.  
  952.         if(!OleUIAddVerbMenu(poleobj,
  953.                         NULL,            // Ask OLE to look up the name for us
  954.                         macMenu1, predoc->hmenuVerbs, ipos_Object,
  955.                         TRUE, (short *) &dw))
  956.         {
  957.                 DebugStr("\pOleUIAddVerbMenu failed!");
  958.         }
  959.         CheckinMenu(hmenu, 2);
  960.         CheckinMenu(predoc->hmenuVerbs, 2);
  961. #  endif    // NEVER
  962. # else    // MAC
  963.         OleUIAddVerbMenu(poleobj,
  964.                         NULL,            // Ask OLE to look up the name for us
  965.                         hmenu, ipos_Object, IDM_OBJECTMIN, 
  966.                         0, TRUE, IDM_OBJECTCONVERT, &predoc->hmenuVerbs);
  967. # endif    // MAC, else
  968.  
  969.         if(poleobj)
  970.             poleobj->lpVtbl->Release(poleobj);
  971. #endif     // !NO_OLE
  972.     // We don't have to do all this hard work again unless the user leaves the
  973.     // menu
  974.         predoc->fUpdateEditMenu = FALSE;
  975.         break;
  976.  
  977.     case 2:        // format
  978.     {
  979.         BOOL fReadOnly = !!predoc->fReadOnly;
  980.         UINT uiSuperscript = MF_UNCHECKED;
  981.         UINT uiSubscript = MF_UNCHECKED;
  982.         UINT uiProtected = MF_UNCHECKED;
  983.         UINT uiLeft = MF_UNCHECKED;
  984.         UINT uiCenter = MF_UNCHECKED;
  985.         UINT uiRight = MF_UNCHECKED;
  986.         UINT uiFirstIndent = MF_UNCHECKED;
  987.         UINT uiFirstOutdent = MF_UNCHECKED;
  988.         CHARFORMAT cf;
  989.         PARAFORMAT pf;
  990.  
  991.         cf.cbSize = sizeof(CHARFORMAT);
  992.         pf.cbSize = sizeof(PARAFORMAT);
  993.  
  994.         SendMessage(predoc->hwndRE, EM_GETCHARFORMAT, fTrue, (LPARAM) &cf);
  995.         if(cf.yOffset > 0)
  996.             uiSuperscript = MF_CHECKED;
  997.         else if(cf.yOffset < 0)
  998.             uiSubscript = MF_CHECKED;
  999.         if(cf.dwEffects & CFE_PROTECTED)
  1000.             uiProtected = MF_CHECKED;
  1001.  
  1002.         SendMessage(predoc->hwndRE, EM_GETPARAFORMAT, 0, (LPARAM) &pf);
  1003.         if(!pf.wAlignment || pf.wAlignment == PFA_LEFT)
  1004.             uiLeft = MF_CHECKED;
  1005.         else if(pf.wAlignment == PFA_CENTER)
  1006.             uiCenter = MF_CHECKED;
  1007.         else
  1008.             uiRight = MF_CHECKED;
  1009.         if(pf.dxOffset < 0)
  1010.             uiFirstIndent = MF_CHECKED;
  1011.         else if(pf.dxOffset > 0)
  1012.             uiFirstOutdent = MF_CHECKED;
  1013.  
  1014.         CheckMenuItem(hmenu, IDM_SUPERSCRIPT, uiSuperscript);
  1015.         CheckMenuItem(hmenu, IDM_SUBSCRIPT, uiSubscript);
  1016.         CheckMenuItem(hmenu, IDM_PROTECTED, uiProtected);
  1017.         CheckMenuItem(hmenu, IDM_ALIGNLEFT, uiLeft);
  1018.         CheckMenuItem(hmenu, IDM_ALIGNCENTER, uiCenter);
  1019.         CheckMenuItem(hmenu, IDM_ALIGNRIGHT, uiRight);
  1020.         CheckMenuItem(hmenu, IDM_INDENTFIRST, uiFirstIndent);
  1021.         CheckMenuItem(hmenu, IDM_OUTDENTFIRST, uiFirstOutdent);
  1022.  
  1023.         EnableMenuItem(hmenu, IDM_CHARFORMAT, fReadOnly
  1024.                                                 ? uiMFDisabled : uiMFEnabled);
  1025.         EnableMenuItem(hmenu, IDM_SUPERSCRIPT, fReadOnly
  1026.                                                 ? uiMFDisabled : uiMFEnabled);
  1027.         EnableMenuItem(hmenu, IDM_SUBSCRIPT, fReadOnly
  1028.                                                 ? uiMFDisabled : uiMFEnabled);
  1029.         EnableMenuItem(hmenu, IDM_ALIGNLEFT, fReadOnly
  1030.                                                 ? uiMFDisabled : uiMFEnabled);
  1031.         EnableMenuItem(hmenu, IDM_ALIGNCENTER, fReadOnly
  1032.                                                 ? uiMFDisabled : uiMFEnabled);
  1033.         EnableMenuItem(hmenu, IDM_ALIGNRIGHT, fReadOnly
  1034.                                                 ? uiMFDisabled : uiMFEnabled);
  1035.         EnableMenuItem(hmenu, IDM_INDENTFIRST, fReadOnly
  1036.                                                 ? uiMFDisabled : uiMFEnabled);
  1037.         EnableMenuItem(hmenu, IDM_OUTDENTFIRST, fReadOnly
  1038.                                                 ? uiMFDisabled : uiMFEnabled);
  1039.     }
  1040.         break;
  1041.  
  1042.     case 3:        // options
  1043.     {
  1044.         const DWORD eco = SendMessage(predoc->hwndRE, EM_GETOPTIONS, 0, 0);
  1045.         UINT uiSelBar = MF_UNCHECKED;
  1046.         UINT uiAutoWordSel = MF_UNCHECKED;
  1047. #ifdef DEBUG
  1048.         UINT uiReadOnly = MF_UNCHECKED;
  1049.         UINT uiAutoHScroll = MF_UNCHECKED;
  1050.         UINT uiAutoVScroll = MF_UNCHECKED;
  1051.         UINT uiAutoHideSel = MF_UNCHECKED;
  1052. #endif    // DEBUG
  1053.  
  1054.         if(eco & ECO_SELECTIONBAR)
  1055.             uiSelBar = MF_CHECKED;
  1056.         if(eco & ECO_AUTOWORDSELECTION)
  1057.             uiAutoWordSel = MF_CHECKED;
  1058. #ifdef DEBUG
  1059.         if(eco & ECO_READONLY)
  1060.             uiReadOnly = MF_CHECKED;
  1061.         if(eco & ECO_AUTOHSCROLL)
  1062.             uiAutoHScroll = MF_CHECKED;
  1063.         if(eco & ECO_AUTOVSCROLL)
  1064.             uiAutoVScroll = MF_CHECKED;
  1065.         if(!(eco & ECO_NOHIDESEL))
  1066.             uiAutoHideSel = MF_CHECKED;
  1067. #endif    // DEBUG
  1068.  
  1069.         CheckMenuItem(hmenu, IDM_SELBAR, uiSelBar);
  1070.         CheckMenuItem(hmenu, IDM_AUTOWORDSEL, uiAutoWordSel);
  1071. #ifdef DEBUG
  1072.         CheckMenuItem(hmenu, IDM_READONLY, uiReadOnly);
  1073.         CheckMenuItem(hmenu, IDM_AUTOHSCROLL, uiAutoHScroll);
  1074.         CheckMenuItem(hmenu, IDM_AUTOVSCROLL, uiAutoVScroll);
  1075.         CheckMenuItem(hmenu, IDM_AUTOHIDESEL, uiAutoHideSel);
  1076. #endif    // DEBUG
  1077.     }
  1078.         break;
  1079.  
  1080.     }
  1081. }
  1082.  
  1083.  
  1084. LOCAL LRESULT HandleCommand(REDOC *predoc, HWND hwnd, WPARAM wparam,
  1085.                                 LPARAM lparam)
  1086. {
  1087.     LRESULT lres = 0;
  1088.     INT        nID;
  1089.  
  1090.     if(GET_WM_COMMAND_HWND(wparam, lparam) == predoc->hwndRE && predoc->hwndRE)
  1091.     {
  1092.         WORD wNotification = GET_WM_COMMAND_CMD(wparam, lparam);
  1093.         ASSENSZ *passensz;
  1094.  
  1095.         switch(wNotification)
  1096.         {
  1097.         case EN_CHANGE:
  1098.             if(predoc->hwndFormatBar)
  1099.                 UpdateFormatBar(predoc);
  1100.             break;
  1101.  
  1102.         case EN_ERRSPACE:
  1103.             if(fErrSpace)
  1104.                 break;
  1105.             fErrSpace = fTrue;
  1106.             // fall through to default
  1107.  
  1108.         default:
  1109.             for(passensz = rgassenszErrors; passensz->szDescription; passensz++)
  1110.             {
  1111.                 if(passensz->wNotification == wNotification)
  1112.                 {
  1113.                     MessageBeep(0);
  1114.                     MessageBoxA(hwndMain, passensz->szDescription, NULL,
  1115.                         MB_ICONSTOP | MB_OK);
  1116.                     return 0;
  1117.                 }
  1118.             }
  1119.             break;
  1120.         }
  1121.         return 0;
  1122.     }
  1123.  
  1124.     fErrSpace = fFalse;
  1125.  
  1126.     nID = GET_WM_COMMAND_ID(wparam, lparam);
  1127.     switch(nID)
  1128.     {
  1129. #ifdef DEBUG
  1130.     case IDM_CLSDBG:
  1131.         ClearDebugScreen();
  1132.         break;
  1133.  
  1134.     case IDM_TRACEDLG:
  1135.         DoTagsDialog();
  1136.         break;
  1137. #endif    // DEBUG
  1138.  
  1139.     case IDM_NEW:
  1140.         lres = NewREDoc(predoc, fTrue, fTrue);
  1141. #ifdef DEBUG
  1142.         if(predoc->hwndRE)
  1143.             SendMessage(predoc->hwndRE, EM_REQUESTRESIZE, 0, 0);
  1144. #endif    // DEBUG
  1145.         break;
  1146.  
  1147.     case IDM_OPEN:
  1148.         lres = OpenREDoc(predoc, FALSE);
  1149.         break;
  1150.  
  1151.     case IDM_REVERT:
  1152.         lres = RevertREDoc(predoc);
  1153.         break;
  1154.  
  1155.     case IDM_PRINT:
  1156.         PrintREDoc(predoc);
  1157.         break;
  1158.  
  1159.     case IDM_PRINTPREVIEW:
  1160.         DialogBoxParam(HinstFromHwnd(hwndMain), TEXT("PRINTPREVIEW"), hwndMain,
  1161.             (DLGPROC) PPDlgProc, (LPARAM) predoc);
  1162.         break;
  1163.  
  1164.     case IDM_PRINTSETUP:
  1165.         predoc->pd.lStructSize = sizeof(PRINTDLG);
  1166.         predoc->pd.Flags = PD_PRINTSETUP;
  1167.         if(PrintDlg(&predoc->pd) && predoc->fWysiwyg)
  1168.         {
  1169.             // illegal values to force SetWordWrap() to do something
  1170.             predoc->fWrap = fFalse;
  1171.             predoc->fWysiwyg = fTrue;
  1172.             SetWordWrap(predoc, fTrue, fTrue);
  1173.         }
  1174.         break;
  1175.  
  1176.     case IDM_EXIT:
  1177.         PostMessage(hwndMain, WM_CLOSE, 0, 0);
  1178.         return 0;
  1179.  
  1180.     case IDM_CLOSE:
  1181.         return CloseREDoc(predoc, fTrue, fTrue);
  1182.  
  1183.     case IDM_SAVE:
  1184.         lres = SaveREDoc(predoc);
  1185.         break;
  1186.  
  1187.     case IDM_SAVEAS:
  1188.         lres = SaveREDocAs(predoc, FALSE);
  1189.         break;
  1190.  
  1191.     case IDM_UNDO:
  1192.         lres = SendMessage(predoc->hwndRE, EM_UNDO, 0, 0);
  1193.         break;
  1194.  
  1195.     case IDM_CUT:
  1196.         lres = SendMessage(predoc->hwndRE, WM_CUT, 0, 0);
  1197.         break;
  1198.  
  1199.     case IDM_COPY:
  1200.         lres = SendMessage(predoc->hwndRE, WM_COPY, 0, 0);
  1201.         break;
  1202.  
  1203.     case IDM_PASTE:
  1204.         lres = SendMessage(predoc->hwndRE, WM_PASTE, 0, 0);
  1205.         break;
  1206.  
  1207.     case IDM_PASTESPECIAL:
  1208.         NYI("Paste special");
  1209.         break;
  1210.  
  1211.     case IDM_DELETE:
  1212.         lres = SendMessage(predoc->hwndRE, WM_KEYDOWN,
  1213.                 (WPARAM) VK_DELETE, 0);
  1214.         break;
  1215.  
  1216.     case IDM_SELECTALL:
  1217.         lres = SendMessage(predoc->hwndRE, EM_SETSEL, 0, (LPARAM) -1);
  1218.         break;
  1219.  
  1220.     case IDM_FIND:
  1221.         FindReplace(predoc, fFalse);
  1222.         break;
  1223.  
  1224.     case IDM_REPLACE:
  1225.         FindReplace(predoc, fTrue);
  1226.         break;
  1227.  
  1228.     case IDM_OBJECT:
  1229.         NYI("Object");
  1230.         break;
  1231.  
  1232.     case IDM_OBJECTCONVERT:
  1233.         NYI("Object Convert");
  1234.         break;
  1235.  
  1236.     case IDM_INSOBJ:
  1237.         return InsertObject(predoc);
  1238.  
  1239.     case IDM_INSFILE:
  1240.         lres = OpenREDoc(predoc, TRUE);
  1241.         break;
  1242.  
  1243.     case IDM_SAVESEL:
  1244.         lres = SaveREDocAs(predoc, TRUE);
  1245.         break;
  1246.  
  1247.     case IDM_CHARFORMAT:
  1248.         SelectCharFormat(predoc);
  1249.         break;
  1250.  
  1251.     case IDM_APPLYTOWORD:
  1252.         predoc->scf = SCF_SELECTION;
  1253.         if(ToggleCheck(predoc, IDM_APPLYTOWORD))
  1254.             predoc->scf |= SCF_WORD;
  1255.         break;
  1256.  
  1257.     case IDM_SUPERSCRIPT:
  1258.         SetOffset(predoc, fTrue);
  1259.         break;
  1260.  
  1261.     case IDM_SUBSCRIPT:
  1262.         SetOffset(predoc, fFalse);
  1263.         break;
  1264.  
  1265.     case IDM_ALIGNLEFT:
  1266.         SetAlignment(predoc, PFA_LEFT);
  1267.         break;
  1268.  
  1269.     case IDM_ALIGNCENTER:
  1270.         SetAlignment(predoc, PFA_CENTER);
  1271.         break;
  1272.  
  1273.     case IDM_ALIGNRIGHT:
  1274.         SetAlignment(predoc, PFA_RIGHT);
  1275.         break;
  1276.  
  1277.     case IDM_INDENTFIRST:
  1278.         IndentFirst(predoc, fTrue);
  1279.         break;
  1280.  
  1281.     case IDM_OUTDENTFIRST:
  1282.         IndentFirst(predoc, fFalse);
  1283.         break;
  1284.  
  1285.     case IDM_MARGINS:
  1286.         NYI("set margins");
  1287.         break;
  1288.  
  1289.     case IDM_TABS:
  1290.         NYI("set tabs");
  1291.         break;
  1292.  
  1293.     case IDM_PROTECTED:
  1294.         ProtectSelection(predoc);
  1295.         break;
  1296.  
  1297.     case IDM_NOWRAP:
  1298.         SetWordWrap(predoc, fFalse, fFalse);
  1299.         break;
  1300.  
  1301.     case IDM_WRAP:
  1302.         SetWordWrap(predoc, fFalse, fTrue);
  1303.         break;
  1304.  
  1305.     case IDM_WYSIWYG:
  1306.         SetWordWrap(predoc, fTrue, fTrue);
  1307.         break;
  1308.  
  1309.     case IDM_SELBAR:
  1310.         SendMessage(predoc->hwndRE, EM_SETOPTIONS, ECOOP_XOR, ECO_SELECTIONBAR);
  1311.         ToggleCheck(predoc, IDM_SELBAR);
  1312.         break;
  1313.  
  1314.     case IDM_AUTOWORDSEL:
  1315.         SendMessage(predoc->hwndRE, EM_SETOPTIONS, ECOOP_XOR, ECO_AUTOWORDSELECTION);
  1316.         ToggleCheck(predoc, IDM_AUTOWORDSEL);
  1317.         break;
  1318.  
  1319.     case IDM_SHOWMARGINS:
  1320.         ShowMargins(predoc);
  1321.         break;
  1322.  
  1323. #ifdef DEBUG
  1324.     case IDM_READONLY:
  1325.         SendMessage(predoc->hwndRE, EM_SETOPTIONS, ECOOP_XOR, ECO_READONLY);
  1326.         predoc->fReadOnly = !!ToggleCheck(predoc, IDM_READONLY);
  1327.         EnableWindow(predoc->hwndFormatBar, !predoc->fReadOnly);
  1328.         break;
  1329.  
  1330.     case IDM_AUTOHSCROLL:
  1331.         SendMessage(predoc->hwndRE, EM_SETOPTIONS, ECOOP_XOR, ECO_AUTOHSCROLL);
  1332.         ToggleCheck(predoc, IDM_AUTOHSCROLL);
  1333.         break;
  1334.  
  1335.     case IDM_AUTOVSCROLL:
  1336.         SendMessage(predoc->hwndRE, EM_SETOPTIONS, ECOOP_XOR, ECO_AUTOVSCROLL);
  1337.         ToggleCheck(predoc, IDM_AUTOVSCROLL);
  1338.         break;
  1339.  
  1340.     case IDM_AUTOHIDESEL:
  1341.         SendMessage(predoc->hwndRE, EM_SETOPTIONS, ECOOP_XOR, ECO_NOHIDESEL);
  1342.         ToggleCheck(predoc, IDM_AUTOHIDESEL);
  1343.         break;
  1344. #endif    // DEBUG
  1345.  
  1346.     case IDM_GOTOCURSOR:
  1347.         {
  1348.             CHARRANGE cr;
  1349.             POINT pt;
  1350.  
  1351.             GetCursorPos(&pt);
  1352.             ScreenToClient(predoc->hwndRE, &pt);
  1353.             cr.cpMin = SendMessage(predoc->hwndRE, EM_CHARFROMPOS, 0,
  1354.                                     (LPARAM) &pt);
  1355.             cr.cpMost = cr.cpMin;
  1356.             SendMessage(predoc->hwndRE, EM_EXSETSEL, 0, (LPARAM) &cr);
  1357.         }
  1358.         break;
  1359.  
  1360.     case IDM_MOVECURSOR:
  1361.         {
  1362.             CHARRANGE cr;
  1363.             POINT pt;
  1364.  
  1365.             SendMessage(predoc->hwndRE, EM_EXGETSEL, 0, (LPARAM) &cr);
  1366.             SendMessage(predoc->hwndRE, EM_POSFROMCHAR, (WPARAM) &pt, cr.cpMin);
  1367.             ClientToScreen(predoc->hwndRE, &pt);
  1368.             SetCursorPos(pt.x, pt.y);
  1369.         }
  1370.         break;
  1371.  
  1372.     case TBI_IncreaseIndent:
  1373.     case TBI_DecreaseIndent:
  1374.         if(predoc->fReadOnly)
  1375.         {
  1376.             MessageBeep(0);
  1377.         }
  1378.         else
  1379.         {
  1380.             PARAFORMAT pf;
  1381.  
  1382.             pf.cbSize = sizeof(PARAFORMAT);
  1383.  
  1384.             if(GetFocus() == predoc->hwndFormatBar)
  1385.                 SetFocus(predoc->hwndRE);
  1386.             pf.dwMask = PFM_OFFSETINDENT;
  1387.             pf.dxStartIndent = (nID == TBI_IncreaseIndent)
  1388.                                     ? cxBulletIndent
  1389.                                     : -cxBulletIndent;
  1390.             if(!SendMessage(predoc->hwndRE, EM_SETPARAFORMAT, FALSE,
  1391.                                 (LPARAM) &pf))
  1392.             {
  1393.                 MessageBeep(0);
  1394.             }
  1395.         }
  1396.         break;
  1397.  
  1398.     case TBI_Name:
  1399.     case TBI_Size:
  1400.     case TBI_Bold:
  1401.     case TBI_Italic:
  1402.     case TBI_Underline:
  1403.     case TBI_Color:
  1404.         {
  1405.             CHARFORMAT cf;
  1406.  
  1407.             cf.cbSize = sizeof(CHARFORMAT);
  1408.             if(GetFocus() == predoc->hwndFormatBar)
  1409.                 SetFocus(predoc->hwndRE);
  1410.             SendMessage(predoc->hwndFormatBar, EM_GETCHARFORMAT, 0,
  1411.                         (LPARAM) &cf);
  1412.             SendMessage(predoc->hwndRE, EM_SETCHARFORMAT, predoc->scf,
  1413.                             (LPARAM) &cf);
  1414.         }
  1415.         break;
  1416.  
  1417.     case TBI_AccelBold:
  1418.     case TBI_AccelItalic:
  1419.     case TBI_AccelUnderline:
  1420.         {
  1421.             CHARFORMAT cf;
  1422.             DWORD dwEffects;
  1423.  
  1424.             cf.cbSize = sizeof(CHARFORMAT);
  1425.             SendMessage(predoc->hwndFormatBar, EM_GETCHARFORMAT, 0,
  1426.                         (LPARAM) &cf);
  1427.             switch (nID)
  1428.             {
  1429.             case TBI_AccelBold:
  1430.                 dwEffects = CFE_BOLD;
  1431.                 break;
  1432.             case TBI_AccelItalic:
  1433.                 dwEffects = CFE_ITALIC;
  1434.                 break;
  1435.             case TBI_AccelUnderline:
  1436.                 dwEffects = CFE_UNDERLINE;
  1437.                 break;
  1438.             }
  1439.  
  1440.             cf.dwMask |= dwEffects;
  1441.             cf.dwEffects ^= dwEffects;
  1442.  
  1443.             if(GetFocus() == predoc->hwndFormatBar)
  1444.                 SetFocus(predoc->hwndRE);
  1445.             SendMessage(predoc->hwndFormatBar, EM_SETCHARFORMAT, predoc->scf,
  1446.                             (LPARAM) &cf);
  1447.             SendMessage(predoc->hwndRE, EM_SETCHARFORMAT, predoc->scf,
  1448.                             (LPARAM) &cf);
  1449.         }
  1450.         break;
  1451.  
  1452.     case TBI_Bullet:
  1453.     case TBI_Left:
  1454.     case TBI_Center:
  1455.     case TBI_Right:
  1456.         {
  1457.             PARAFORMAT pf;
  1458.  
  1459.             pf.cbSize = sizeof(PARAFORMAT);
  1460.  
  1461.             if(GetFocus() == predoc->hwndFormatBar)
  1462.                 SetFocus(predoc->hwndRE);
  1463.             SendMessage(predoc->hwndFormatBar, EM_GETPARAFORMAT, 0,
  1464.                         (LPARAM) &pf);
  1465.             SendMessage(predoc->hwndRE, EM_SETPARAFORMAT, FALSE, (LPARAM) &pf);
  1466.         }
  1467.         break;
  1468.  
  1469.  
  1470. #ifdef DEBUG
  1471.     case IDM_DBGPED:
  1472.         SendMessage(predoc->hwndRE, EM_DBGPED, 0, 0);
  1473.         break;
  1474.  
  1475.     case IDM_GETTEXT:
  1476.         return GetText(predoc);
  1477.  
  1478.     case IDM_IGNORELEFTCLICK:
  1479.         IgnoreLeftClick(predoc);
  1480.         break;
  1481.  
  1482.     case IDM_EATES:
  1483.         EatEs(predoc);
  1484.         break;
  1485.  
  1486.     case IDM_BOTTOMLESS:
  1487.         Bottomless(predoc);
  1488.         break;
  1489.  
  1490.     case IDM_IGNOREDROPS:
  1491.     case IDM_TEXTONLY:
  1492.     case IDM_REFUSEGRAPH:
  1493.     case IDM_PPMETA:
  1494.     case IDM_ENABLECUTREADONLY:
  1495.     case IDM_ENABLEPASTEREADONLY:
  1496.     case IDM_ENABLEDRAGREADONLY:
  1497.     case IDM_SWAPDRAGEFFECT:
  1498.         ToggleCheck(predoc, nID);
  1499.         break;
  1500.  
  1501.     case IDM_HIDE:
  1502.         ShowWindow(predoc->hwndRE, ToggleCheck(predoc, IDM_HIDE) ? SW_HIDE : SW_SHOW);
  1503.         break;        
  1504.  
  1505.     case IDM_PASTEPLAINTEXT:
  1506.         lres = SendMessage(predoc->hwndRE, EM_PASTESPECIAL, CF_TEXT, 0);
  1507.         break;
  1508.  
  1509.     case IDM_PASTETXTOBJ:
  1510.         lres = SendMessage(predoc->hwndRE, EM_PASTESPECIAL, cfTxtObj, 0);
  1511.         break;
  1512.  
  1513.     case IDM_PASTERTFASTEXT:
  1514.         lres = SendMessage(predoc->hwndRE, EM_PASTESPECIAL, cfRTFAsText, 0);
  1515.         break;
  1516.  
  1517.     case IDM_BIGLIMIT:
  1518.         SetLimit(predoc);
  1519.         break;
  1520.  
  1521.     case IDM_FILLERUP:
  1522.         FillerUp(predoc);
  1523.         break;
  1524. #endif    // DEBUG
  1525.  
  1526.     default:
  1527.         // Pass through OLE verbs
  1528.         if(nID >= IDM_OBJECTMIN)
  1529.         {
  1530.             DoVerb(predoc, nID - IDM_OBJECTMIN);
  1531.         }
  1532.         return DefWindowProc(hwnd, WM_COMMAND, wparam, lparam);
  1533.     }
  1534.  
  1535.     return lres;
  1536. }
  1537.  
  1538.  
  1539. VOID DoVerb(REDOC * predoc, INT ioleverb)
  1540. {
  1541.     REOBJECT reobj = { 0 };
  1542.     POINT pt;
  1543.     RECT rc = { 0 };
  1544.  
  1545.     reobj.cbStruct = sizeof(REOBJECT);
  1546.     if(predoc->preole->lpVtbl->GetObject(predoc->preole, REO_IOB_SELECTION,
  1547.                                             &reobj,
  1548.                                             REO_GETOBJ_POLESITE |
  1549.                                             REO_GETOBJ_POLEOBJ))
  1550.     {
  1551.         AssertSz(FALSE, "DoVerb without object");
  1552.     }
  1553.  
  1554.     SendMessage(predoc->hwndRE, EM_POSFROMCHAR, (WPARAM) &pt, reobj.cp);
  1555.  
  1556.     XformSizeInHimetricToPixels(NULL, &reobj.sizel, &reobj.sizel);
  1557.     rc.right = (INT) reobj.sizel.cx;
  1558.     rc.bottom = (INT) reobj.sizel.cy;
  1559.     OffsetRect(&rc, pt.x, pt.y);
  1560.  
  1561.     reobj.poleobj->lpVtbl->DoVerb(reobj.poleobj, ioleverb, NULL,
  1562.                                     reobj.polesite, 0, predoc->hwndRE, &rc);
  1563.     reobj.poleobj->lpVtbl->Release(reobj.poleobj);
  1564.     reobj.polesite->lpVtbl->Release(reobj.polesite);
  1565.  
  1566. }
  1567.  
  1568.  
  1569. #ifdef DEBUG
  1570.  
  1571. LOCAL VOID IgnoreLeftClick(REDOC *predoc)
  1572. {
  1573.     HMENU hmenu = GetMenu(hwndMain);
  1574.     UINT uiMenuFlags;
  1575.     DWORD dwMask;
  1576.  
  1577.     Assert(predoc->hwndRE);
  1578.  
  1579.     dwMask = SendMessage(predoc->hwndRE, EM_GETEVENTMASK, 0, 0);
  1580.     uiMenuFlags = GetMenuState(hmenu, IDM_IGNORELEFTCLICK, MF_BYCOMMAND);
  1581.     if(uiMenuFlags & MF_CHECKED)
  1582.         dwMask &= ~ENM_MOUSEEVENTS;
  1583.     else
  1584.         dwMask |= ENM_MOUSEEVENTS;
  1585.     uiMenuFlags ^= MF_CHECKED;
  1586.     CheckMenuItem(hmenu, IDM_IGNORELEFTCLICK, MF_BYCOMMAND |
  1587.         (uiMenuFlags & MF_CHECKED));
  1588.     SendMessage(predoc->hwndRE, EM_SETEVENTMASK, 0, dwMask);
  1589. }
  1590.  
  1591.  
  1592. LOCAL VOID EatEs(REDOC *predoc)
  1593. {
  1594.     HMENU hmenu = GetMenu(hwndMain);
  1595.     UINT uiMenuFlags;
  1596.     DWORD dwMask;
  1597.  
  1598.     Assert(predoc->hwndRE);
  1599.  
  1600.     dwMask = SendMessage(predoc->hwndRE, EM_GETEVENTMASK, 0, 0);
  1601.     uiMenuFlags = GetMenuState(hmenu, IDM_EATES, MF_BYCOMMAND);
  1602.     if(uiMenuFlags & MF_CHECKED)
  1603.         dwMask &= ~ENM_KEYEVENTS;
  1604.     else
  1605.         dwMask |= ENM_KEYEVENTS;
  1606.     uiMenuFlags ^= MF_CHECKED;
  1607.     CheckMenuItem(hmenu, IDM_EATES, MF_BYCOMMAND | (uiMenuFlags & MF_CHECKED));
  1608.     SendMessage(predoc->hwndRE, EM_SETEVENTMASK, 0, dwMask);
  1609. }
  1610.  
  1611.  
  1612. LOCAL VOID Bottomless(REDOC *predoc)
  1613. {
  1614.     HMENU hmenu = GetMenu(hwndMain);
  1615.     UINT uiMenuFlags;
  1616.     DWORD dwMask;
  1617.  
  1618.     Assert(predoc->hwndRE);
  1619.  
  1620.     dwMask = SendMessage(predoc->hwndRE, EM_GETEVENTMASK, 0, 0);
  1621.     uiMenuFlags = GetMenuState(hmenu, IDM_BOTTOMLESS, MF_BYCOMMAND);
  1622.     if(uiMenuFlags & MF_CHECKED)
  1623.         dwMask &= ~ENM_REQUESTRESIZE;
  1624.     else
  1625.         dwMask |= ENM_REQUESTRESIZE;
  1626.     uiMenuFlags ^= MF_CHECKED;
  1627.     CheckMenuItem(hmenu, IDM_BOTTOMLESS,
  1628.         MF_BYCOMMAND | (uiMenuFlags & MF_CHECKED));
  1629.     SendMessage(predoc->hwndRE, EM_SETEVENTMASK, 0, dwMask);
  1630.     if(dwMask & ENM_REQUESTRESIZE)
  1631.     {
  1632.         SendMessage(predoc->hwndRE, EM_REQUESTRESIZE, 0, 0);
  1633.     }
  1634.     else
  1635.     {
  1636.         RECT rc;
  1637.  
  1638.         GetClientRect(predoc->hwndParent, &rc);
  1639.         ResizeRedoc(predoc, rc);
  1640.     }
  1641. }
  1642.  
  1643. #endif    // DEBUG
  1644.  
  1645.  
  1646. LOCAL BOOL ToggleCheck(REDOC *predoc, UINT uiMenuid)
  1647. {
  1648.     HMENU hmenu = GetMenu(hwndMain);
  1649.     UINT uiMenuFlags;
  1650.  
  1651.     Assert(predoc->hwndRE);
  1652.  
  1653.     uiMenuFlags = GetMenuState(hmenu, uiMenuid, MF_BYCOMMAND);
  1654.     uiMenuFlags ^= MF_CHECKED;
  1655.     CheckMenuItem(hmenu, uiMenuid, MF_BYCOMMAND | (uiMenuFlags & MF_CHECKED));
  1656.  
  1657.     return !!(uiMenuFlags & MF_CHECKED);
  1658. }
  1659.  
  1660.  
  1661. LOCAL BOOL QueryCheck(REDOC *predoc, UINT uiMenuid)
  1662. {
  1663.     HMENU hmenu = GetMenu(hwndMain);
  1664.     UINT uiMenuFlags;
  1665.  
  1666.     Assert(predoc->hwndRE);
  1667.     if(!hmenu)
  1668.         return fFalse;
  1669.  
  1670.     uiMenuFlags = GetMenuState(hmenu, uiMenuid, MF_BYCOMMAND);
  1671.  
  1672.     return !!(uiMenuFlags & MF_CHECKED);
  1673. }
  1674.  
  1675.  
  1676. LOCAL LRESULT NewREDoc(REDOC *predoc, BOOL fPrompt, BOOL fUpdateUI)
  1677. {
  1678.     RECT rc;
  1679.     DWORD dwStyle;
  1680.     if(predoc->hwndRE)
  1681.     {
  1682.         PARAFORMAT pf = {0};
  1683.  
  1684.         pf.cbSize = sizeof(PARAFORMAT);
  1685.  
  1686.         if(fPrompt && CheckSave(predoc) < 0)
  1687.             return -1;
  1688.         predoc->szFile[0] = TEXT('\0');
  1689.         lstrcpy(predoc->szTitle, szUntitled);
  1690.         SetWindowText(predoc->hwndRE, TEXT(""));
  1691.         pf.wAlignment = PFA_LEFT;
  1692.         pf.cTabCount = 1;
  1693.         pf.rgxTabs[0] = lDefaultTab;
  1694.         pf.dwMask = PFM_STARTINDENT | PFM_RIGHTINDENT | PFM_OFFSET |
  1695.                         PFM_ALIGNMENT | PFM_TABSTOPS | PFM_NUMBERING;
  1696.         SendMessage(predoc->hwndRE, EM_SETPARAFORMAT, 0, (LPARAM) &pf);
  1697.         SendMessage(predoc->hwndRE, EM_SETCHARFORMAT, 0,
  1698.                         (LPARAM) (LPVOID) &cfDefault);
  1699.         goto done;
  1700.     }
  1701.     else
  1702.     {
  1703.         predoc->szFile[0] = TEXT('\0');
  1704.         lstrcpy(predoc->szTitle, szUntitled);
  1705.     }
  1706.     GetClientRect(predoc->hwndParent, &rc);
  1707.     InflateRect(&rc, dxRESize, dyRESize);
  1708.  
  1709.     // Create and display the format bar
  1710.     if(predoc->hwndFormatBar = HwndCreateFormatBar(predoc->hwndParent,
  1711.                             FBR_FormatBar, NULL))
  1712.     {
  1713.         RECT rcFormatBar;
  1714.  
  1715.         ShowWindow(predoc->hwndFormatBar, SW_SHOW);
  1716.         GetClientRect(predoc->hwndFormatBar, &rcFormatBar);
  1717.         rc.top += rcFormatBar.bottom;
  1718.     }
  1719.  
  1720. #ifdef SUNKENRICHEDIT
  1721.     dwStyle = 
  1722.                 ES_AUTOHSCROLL |
  1723.                 ES_AUTOVSCROLL |
  1724. //                ES_DISABLENOSCROLL |
  1725.                 ES_MULTILINE |
  1726. //                ES_NOHIDESEL |
  1727.                 ES_SAVESEL |
  1728.                 ES_SELECTIONBAR |
  1729.                 ES_SUNKEN |
  1730. //                WS_BORDER |
  1731.                 WS_CHILD |
  1732.                 WS_CLIPCHILDREN |
  1733.                 WS_HSCROLL |
  1734.                 WS_VISIBLE |
  1735.                 WS_VSCROLL |
  1736.                 0;        // zero gets or'd with above
  1737.     predoc->hwndRE = CreateWindow(szClassRE, TEXT(""),
  1738.                 dwStyle,
  1739.                 rc.left, rc.top,
  1740.                 rc.right - rc.left,    rc.bottom - rc.top, predoc->hwndParent,
  1741.                 NULL, HinstFromHwnd(predoc->hwndParent), NULL);
  1742.  
  1743. #else    // SUNKENRICHEDIT
  1744.                 ES_AUTOHSCROLL |
  1745.                 ES_AUTOVSCROLL |
  1746. //                ES_DISABLENOSCROLL |
  1747.                 ES_MULTILINE |
  1748. //                ES_NOHIDESEL |
  1749.                 ES_SAVESEL |
  1750.                 ES_SELECTIONBAR |
  1751. //                ES_SUNKEN |
  1752. //                WS_BORDER |
  1753.                 WS_CHILD |
  1754.                 WS_CLIPCHILDREN |
  1755.                 WS_HSCROLL |
  1756.                 WS_VISIBLE |
  1757.                 WS_VSCROLL |
  1758.                 0;        // zero gets or'd with above
  1759.     predoc->hwndRE = CreateWindow(szClassRE, TEXT(""),
  1760.                 dwStyle,
  1761.                 rc.left, rc.top,
  1762.                 rc.right - rc.left,    rc.bottom - rc.top, predoc->hwndParent,
  1763.                 NULL, HinstFromHwnd(predoc->hwndParent), NULL);
  1764. #endif    // SUNKENRICHEDIT, else
  1765.     if(!predoc->hwndRE)
  1766.     {
  1767.         MessageBoxA(hwndMain, "Unable to create a new document", NULL, MB_ICONSTOP | MB_OK);
  1768.         return -1;
  1769.     }
  1770.     if(cchTextMost)
  1771.         SendMessage(predoc->hwndRE, EM_EXLIMITTEXT, 0, cchTextMost);
  1772. #ifndef NO_OLE
  1773.     DragAcceptFiles(predoc->hwndRE, TRUE);
  1774. #endif    // !NO_OLE
  1775.  
  1776.  
  1777.     // request EN_SELCHANGE, EN_CHANGE, EN_PROTECTED, and EN_DROPFILES
  1778.     SendMessage(predoc->hwndRE, EM_SETEVENTMASK, 0,
  1779.         ENM_SELCHANGE | ENM_CHANGE | ENM_PROTECTED | EN_DROPFILES |
  1780.         ENM_CORRECTTEXT);
  1781.  
  1782.     SetFocus(predoc->hwndRE);
  1783.  
  1784.     predoc->scf = SCF_SELECTION;
  1785.     if(GetMenu(hwndMain) && QueryCheck(predoc, IDM_APPLYTOWORD))
  1786.         predoc->scf |= SCF_WORD;
  1787.  
  1788. #ifndef NO_OLE
  1789.     if(!SendMessage(predoc->hwndRE, EM_GETOLEINTERFACE, 0, (LPARAM) &predoc->preole))
  1790.     {
  1791.         MessageBoxA(hwndMain, "No OLE interface!", NULL, MB_OK);
  1792.         DestroyWindow(predoc->hwndRE);
  1793.         predoc->hwndRE = 0;
  1794.         return -1;
  1795.     }
  1796.  
  1797.     if(!(predoc->pstg = OleStdCreateRootStorage(NULL, STGM_SHARE_EXCLUSIVE)))
  1798.     {
  1799.         MessageBoxA(hwndMain, "No Storage!", NULL, MB_OK);
  1800.         DestroyWindow(predoc->hwndRE);
  1801.         predoc->hwndRE = 0;
  1802.         return -1;
  1803.     }
  1804.  
  1805.     if(!(predoc->pitpcall = ITPCALL_New(predoc)))
  1806.     {
  1807.         MessageBoxA(hwndMain, "No callback object!", NULL, MB_OK);
  1808.         DestroyWindow(predoc->hwndRE);
  1809.         predoc->hwndRE = 0;
  1810.         return -1;
  1811.     }
  1812.     SendMessage(predoc->hwndRE, EM_SETOLECALLBACK, 0, (LPARAM) predoc->pitpcall);
  1813. #endif    // !NO_OLE
  1814.  
  1815. done:
  1816.     if(fUpdateUI)
  1817.     {
  1818.         TCHAR szT[64];
  1819.  
  1820.         wsprintf(szT, szFmtTitle, predoc->szTitle);
  1821.         SetWindowText(predoc->hwndParent, szT);
  1822.         SetMenu(hwndMain, hmenuFull);
  1823.         DrawMenuBar(hwndMain);
  1824.     }
  1825.  
  1826.     predoc->fReadOnly = fFalse;
  1827.     EnableWindow(predoc->hwndFormatBar, TRUE);
  1828.  
  1829.     // illegal values to force SetWordWrap() to do something
  1830.     predoc->fWrap = fFalse;
  1831.     predoc->fWysiwyg = fTrue;
  1832.     SetWordWrap(predoc, fWysiwygDefault, fWrapDefault);
  1833.     // if we don't have a default font, use the windows variable width font
  1834.     // otherwise, use the default font
  1835.     if(cfDefault.dwMask == 0)
  1836.     {
  1837.         SendMessage(predoc->hwndRE, WM_SETFONT,
  1838.                         (WPARAM) GetStockObject(ANSI_VAR_FONT), 0);
  1839.         SendMessage(predoc->hwndRE, EM_GETCHARFORMAT, FALSE,
  1840.                         (LPARAM) (LPVOID) &cfDefault);
  1841.     }
  1842.     else
  1843.     {
  1844.         SendMessage(predoc->hwndRE, EM_SETCHARFORMAT, 0,
  1845.                         (LPARAM) (LPVOID) &cfDefault);
  1846.     }
  1847.     SendMessage(predoc->hwndRE, EM_SETMODIFY, (WPARAM) fFalse, 0);
  1848.     SendMessage(predoc->hwndRE, EM_SETREADONLY, (WPARAM) fFalse, 0);
  1849.     UpdateFormatBar(predoc);
  1850.  
  1851.     return 0;
  1852. }
  1853.  
  1854.  
  1855. LOCAL LONG CheckSave(REDOC *predoc)
  1856. {
  1857.     int iMbid;
  1858.     TCHAR szT[128];
  1859.  
  1860. #ifdef NO_SAVE_PROMPT
  1861.     return 0;
  1862. #endif    // NO_SAVE_PROMPT
  1863.  
  1864.     if(!SendMessage(predoc->hwndRE, EM_GETMODIFY, 0, 0))
  1865.         return 0;
  1866.  
  1867.     wsprintf(szT, TEXT("Save changes to %s?"), predoc->szTitle);
  1868.     iMbid = MessageBox(hwndMain, szT, szAppName, MB_APPLMODAL |
  1869.             MB_ICONQUESTION | MB_YESNOCANCEL);
  1870.     switch(iMbid)
  1871.     {
  1872.     case IDYES:
  1873.         if(SaveREDoc(predoc) < 0)
  1874.             return -1;
  1875.         break;
  1876.  
  1877.     case IDCANCEL:
  1878.         return -1;
  1879.     }
  1880.     return 0;
  1881. }
  1882.  
  1883.  
  1884. // returns 0 if no changes have been made
  1885. // returns > 0 if revert should continue
  1886. // returns < 0 if revert should be aborted
  1887. LOCAL INT CheckRevert(REDOC *predoc)
  1888. {
  1889.     int iMbid;
  1890.     TCHAR szT[128];
  1891.  
  1892.     if(!SendMessage(predoc->hwndRE, EM_GETMODIFY, 0, 0))
  1893.         return 0;
  1894.  
  1895. #ifdef NO_SAVE_PROMPT
  1896.     return 1;
  1897. #endif    // NO_SAVE_PROMPT
  1898.  
  1899.     wsprintf(szT, TEXT("Revert %s to last saved changes?"), predoc->szTitle);
  1900.     iMbid = MessageBox(hwndMain, szT, szAppName, MB_APPLMODAL |
  1901.             MB_ICONQUESTION | MB_YESNO);
  1902.  
  1903.     return iMbid == IDYES ? 1 : -1;
  1904. }
  1905.  
  1906.  
  1907. LOCAL LRESULT CloseREDoc(REDOC *predoc, BOOL fPrompt, BOOL fUpdateUI)
  1908. {
  1909.     if(fPrompt && CheckSave(predoc) < 0)
  1910.         return -1;
  1911.  
  1912.     if(predoc->hdcTarget)
  1913.     {
  1914.         DeleteDC(predoc->hdcTarget);
  1915.         predoc->hdcTarget = 0;
  1916.     }
  1917. #ifndef NO_OLE
  1918.     // Deactivate any existing in place object
  1919.     //$ FUTURE: This might be some generic I'm gonna close you call
  1920.     predoc->preole->lpVtbl->InPlaceDeactivate(predoc->preole);
  1921.     ITPCALL_Release((LPUNKNOWN) predoc->pitpcall);
  1922.     predoc->pitpcall = NULL;
  1923.     predoc->pstg->lpVtbl->Release(predoc->pstg);
  1924.     predoc->pstg = NULL;
  1925.     predoc->preole->lpVtbl->Release(predoc->preole);
  1926.     predoc->preole = NULL;
  1927.     predoc->cItem = 0;
  1928. #endif    // !NO_OLE
  1929.     DestroyWindow(predoc->hwndRE);
  1930.     DestroyWindow(predoc->hwndFormatBar);
  1931.  
  1932.     predoc->hwndRE = 0;
  1933.     predoc->szFile[0] = TEXT('\0');
  1934.     lstrcpy(predoc->szTitle, szUntitled);
  1935.     predoc->dwFormat = SF_TEXT;
  1936.     predoc->fReadOnly = fFalse;
  1937.     EnableWindow(predoc->hwndFormatBar, TRUE);
  1938. #ifdef DEBUG
  1939.     CheckMenuItem(hmenuFull, IDM_IGNORELEFTCLICK, MF_BYCOMMAND | MF_UNCHECKED);
  1940.     CheckMenuItem(hmenuFull, IDM_EATES, MF_BYCOMMAND | MF_UNCHECKED);
  1941.     CheckMenuItem(hmenuFull, IDM_IGNOREDROPS, MF_BYCOMMAND | MF_UNCHECKED);
  1942.     CheckMenuItem(hmenuFull, IDM_BOTTOMLESS, MF_BYCOMMAND | MF_UNCHECKED);
  1943.     CheckMenuItem(hmenuFull, IDM_TEXTONLY, MF_BYCOMMAND | MF_UNCHECKED);
  1944.  
  1945.     if(hwndGT)
  1946.     {
  1947.         DestroyWindow(hwndGT);
  1948.         hwndGT = 0;
  1949.     }
  1950. #endif    // DEBUG
  1951.  
  1952.     if(fUpdateUI)
  1953.     {
  1954.         SetWindowText(predoc->hwndParent, szClosedName);
  1955.         SetMenu(hwndMain, hmenuLoaded);
  1956.         DrawMenuBar(hwndMain);
  1957.     }
  1958.  
  1959.     return 1;
  1960. }
  1961.  
  1962.  
  1963. DWORD CALLBACK MyRead(DWORD dwCookie, LPBYTE pbBuffer, LONG cb, LONG *pcb)
  1964. {
  1965.     HFILE    hf = (HFILE) dwCookie;
  1966.  
  1967.     if(hf == HFILE_ERROR)
  1968.         return (DWORD) E_FAIL;
  1969.     *pcb = _lread(hf, pbBuffer, cb);
  1970.     return (DWORD) (*pcb >= 0 ? NOERROR : (*pcb = 0, E_FAIL));
  1971. }
  1972.  
  1973.  
  1974. // This function gives the Mac version the ability to open and print
  1975. // files via Apple Events.
  1976. LRESULT DoOpen(predoc, szT, szTitle, fInsert)
  1977. REDOC *predoc;
  1978. LPSTR szT, szTitle;
  1979. BOOL fInsert;
  1980. {
  1981.     DWORD dwError;
  1982.  
  1983.     if((dwError = ReadREDoc(predoc, szT, szTitle, 0, fInsert)))
  1984.         goto err;
  1985.     wsprintf(szT, szFmtTitle, szTitle);
  1986.     SetWindowText(predoc->hwndParent, szT);
  1987.  
  1988.     EnableWindow(predoc->hwndFormatBar, !predoc->fReadOnly);
  1989.     SendMessage(predoc->hwndRE, EM_SETREADONLY, (WPARAM) predoc->fReadOnly, 0);
  1990.     SetMenu(hwndMain, hmenuFull);
  1991.  
  1992.     SetupWordWrapMenu(predoc);
  1993.     DrawMenuBar(hwndMain);
  1994.     return 0;
  1995.  
  1996. err:
  1997.     wsprintf(szT, TEXT("Error opening document. [%ld]"), dwError);
  1998.     MessageBox(hwndMain, szT, NULL, MB_OK);
  1999.     return -1;
  2000. }
  2001.  
  2002.  
  2003. LOCAL LRESULT OpenREDoc(REDOC *predoc, BOOL fInsert)
  2004. {
  2005.     DWORD dwError;
  2006.     OPENFILENAME ofn;
  2007.     TCHAR szTitle[64];
  2008.     TCHAR szT[256];
  2009.  
  2010.     if(predoc->hwndRE && !fInsert && CheckSave(predoc) < 0)
  2011.         return -1;
  2012.  
  2013.     if(fInsert && predoc->fReadOnly)
  2014.         return -1;
  2015.  
  2016.     ofn.lStructSize            = sizeof(ofn);
  2017.     ofn.hInstance            = 0;
  2018.     ofn.lpstrFilter            = szFilterLoad;
  2019.     ofn.lpstrCustomFilter    = NULL;
  2020.     ofn.nMaxCustFilter        = 0;
  2021.     ofn.nFilterIndex        = 0;
  2022.     ofn.lpstrFileTitle        = szTitle;
  2023.     ofn.nMaxFileTitle        = sizeof(szTitle);
  2024.     ofn.lpstrInitialDir        = NULL;
  2025.     ofn.lpstrTitle            = fInsert ? "Insert from File" : NULL;
  2026.     ofn.nFileOffset            = 0;
  2027.     ofn.nFileExtension        = 0;
  2028.     ofn.lpstrDefExt            = NULL;
  2029.     ofn.lCustData            = 0L;
  2030.     ofn.lpfnHook            = NULL;
  2031.     ofn.lpTemplateName        = NULL;
  2032.     ofn.hwndOwner            = hwndMain;
  2033.     ofn.lpstrFile            = szT;
  2034.     ofn.nMaxFile            = sizeof(szT);
  2035.     ofn.Flags                = OFN_FILEMUSTEXIST;
  2036.  
  2037.     szTitle[0] = TEXT('\0');
  2038.     szT[0] = TEXT('\0');
  2039.  
  2040.     // Query user for filename for input
  2041.     if(!GetOpenFileName(&ofn))
  2042.     {
  2043.         if((dwError = CommDlgExtendedError()) != 0)
  2044.         {
  2045.             wsprintf(szT, TEXT("Error opening document. [%ld]"), dwError);
  2046.             MessageBox(hwndMain, szT, NULL, MB_OK);
  2047.             return -1;
  2048.         }
  2049.         return 0;
  2050.     }
  2051.     predoc->fReadOnly = (ofn.Flags & OFN_READONLY) ? fTrue : fFalse;
  2052.     EnableWindow(predoc->hwndFormatBar, !predoc->fReadOnly);
  2053.     return(DoOpen(predoc, szT, szTitle, fInsert));    
  2054. }
  2055.  
  2056.  
  2057. LOCAL LRESULT RevertREDoc(REDOC *predoc)
  2058. {
  2059.     DWORD dwError;
  2060.     TCHAR szT[256];
  2061.  
  2062.     if(CheckRevert(predoc) <= 0)
  2063.         return 0;
  2064.  
  2065.     lstrcpy(szT, predoc->szFile);
  2066.     dwError = ReadREDoc(predoc, szT, NULL, predoc->dwFormat, FALSE);
  2067.     if(!dwError)
  2068.         return 0;
  2069.  
  2070.     wsprintf(szT, TEXT("Error reading document. [%ld]"), dwError);
  2071.     MessageBox(hwndMain, szT, NULL, MB_OK);
  2072.  
  2073.     return -1;
  2074. }
  2075.  
  2076.  
  2077. LOCAL DWORD ReadREDoc(REDOC *predoc, LPCSTR szFile, LPCSTR szTitle,
  2078.                 DWORD dwFormat, BOOL fInsert)
  2079. {
  2080.     LONG cch;
  2081.     HCURSOR hcur;
  2082.     EDITSTREAM es;
  2083.     TCHAR szType[cchRTFSig + 1];
  2084.  
  2085.      hcur = SetCursor(LoadCursor(NULL, IDC_WAIT));
  2086.  
  2087.     es.dwCookie = (DWORD) _lopen(szFile, OF_READ);
  2088.     if(es.dwCookie == (DWORD) HFILE_ERROR)
  2089.     {
  2090.         return GetLastError();
  2091.     }
  2092.  
  2093.     if(!fInsert)
  2094.     {
  2095.         // save read-only flag across NewREDoc()
  2096.         const BOOL fReadOnlySave = predoc->fReadOnly;
  2097.  
  2098.         if(NewREDoc(predoc, fFalse, fFalse) < 0)
  2099.         {
  2100.             _lclose((HFILE) es.dwCookie);
  2101.             return (DWORD) -1;
  2102.         }
  2103.         predoc->fReadOnly = fReadOnlySave;
  2104.     }
  2105.     if(dwFormat == 0)    // unknown format, figure out what it is
  2106.     {
  2107.         UINT cb = cchRTFSig * sizeof(TCHAR);
  2108.  
  2109.         cb = _lread((HFILE) es.dwCookie, szType, cb);
  2110.         szType[cb / sizeof(TCHAR)] = TEXT('\0');
  2111.         if(cb == cchRTFSig * sizeof(TCHAR))
  2112.             dwFormat = lstrcmpi(szRTFSig, szType) ? SF_TEXT : SF_RTF;
  2113.         else
  2114.             dwFormat = SF_TEXT;        // not big enough to be RTF, assume text
  2115.  
  2116.         // move back to the beginning of the file
  2117.         _llseek((HFILE) es.dwCookie, 0, 0);
  2118.     }
  2119.  
  2120.     SendMessage(predoc->hwndRE, WM_SETREDRAW, (WPARAM) fFalse, 0);
  2121.  
  2122.     es.dwError = 0;
  2123.     es.pfnCallback = MyRead;
  2124.  
  2125.     cch = SendMessage(predoc->hwndRE, EM_STREAMIN,
  2126.             (WPARAM) (fInsert ? dwFormat | SFF_SELECTION : dwFormat),
  2127.             (LPARAM) &es);
  2128.     _lclose((HFILE) es.dwCookie);
  2129. #ifdef DEBUG
  2130.     if(predoc->hwndRE)
  2131.         SendMessage(predoc->hwndRE, EM_REQUESTRESIZE, 0, 0);
  2132. #endif    // DEBUG
  2133.  
  2134.     SendMessage(predoc->hwndRE, EM_SETMODIFY, (WPARAM) fFalse, 0);
  2135.  
  2136.     predoc->dwFormat = dwFormat;
  2137.     lstrcpy(predoc->szFile, szFile);
  2138.     if(szTitle)
  2139.         lstrcpy(predoc->szTitle, szTitle);
  2140.     else
  2141.         GetFileTitle(szFile, predoc->szTitle, sizeof(predoc->szTitle));
  2142.  
  2143.     SendMessage(predoc->hwndRE, WM_SETREDRAW, (WPARAM) fTrue, 0);
  2144.     InvalidateRect(predoc->hwndRE, NULL, fTrue);
  2145.     UpdateWindow(predoc->hwndRE);
  2146.  
  2147.     SetCursor(hcur);
  2148.  
  2149.     UpdateFormatBar(predoc);
  2150.     return 0;
  2151. }
  2152.  
  2153.  
  2154. DWORD CALLBACK MyWrite(DWORD dwCookie, LPBYTE pbBuffer, LONG cb, LONG *pcb)
  2155. {
  2156.     HFILE    hf = (HFILE) dwCookie;
  2157.  
  2158.     if(hf == HFILE_ERROR)
  2159.         return (DWORD) E_FAIL;
  2160.  
  2161.     *pcb = _lwrite(hf, pbBuffer, cb);
  2162.     return (DWORD) (*pcb == cb ? NOERROR : E_FAIL);
  2163. }
  2164.  
  2165.  
  2166. LOCAL LRESULT SaveREDoc(REDOC *predoc)
  2167. {
  2168.     HCURSOR hcur;
  2169.     LONG cch;
  2170.     DWORD dwError;
  2171.     EDITSTREAM es;
  2172.  
  2173.     if(!predoc->szFile[0])
  2174.         return SaveREDocAs(predoc, FALSE);
  2175.  
  2176.     hcur = SetCursor(LoadCursor(NULL, IDC_WAIT));
  2177.  
  2178.     es.dwCookie = _lcreat(predoc->szFile, 0);
  2179.     if(es.dwCookie == (DWORD) HFILE_ERROR)
  2180.     {
  2181.         dwError = GetLastError();
  2182.         goto err;
  2183.     }
  2184.     es.dwError = 0;
  2185.     es.pfnCallback = MyWrite;
  2186.     cch = SendMessage(predoc->hwndRE, EM_STREAMOUT,    (WPARAM) predoc->dwFormat,
  2187.             (LPARAM) &es);
  2188.     _lclose((HFILE) es.dwCookie);
  2189.  
  2190.     SendMessage(predoc->hwndRE, EM_SETMODIFY, (WPARAM) fFalse, 0);
  2191.     SendMessage(predoc->hwndRE, EM_SETREADONLY, (WPARAM) fFalse, 0);
  2192.     predoc->fReadOnly = fFalse;
  2193.     EnableWindow(predoc->hwndFormatBar, TRUE);
  2194.  
  2195.     SetCursor(hcur);
  2196.  
  2197.     return 0;
  2198.  
  2199. err:
  2200.     {
  2201.         TCHAR szT[64];
  2202.  
  2203.         wsprintf(szT, TEXT("Error saving document. [%ld]"), dwError);
  2204.         MessageBox(hwndMain, szT, NULL, MB_OK);
  2205.     }
  2206.  
  2207.     return -1;
  2208. }
  2209.  
  2210.  
  2211. LOCAL LRESULT SaveREDocAs(REDOC *predoc, BOOL fSelect)
  2212. {
  2213.     HCURSOR hcur;
  2214.     LONG cch;
  2215.     DWORD dwError;
  2216.     EDITSTREAM es;
  2217.     OPENFILENAME ofn;
  2218.     TCHAR szTitle[64];
  2219.     TCHAR szT[256];
  2220.  
  2221.     ofn.lStructSize            = sizeof(ofn);
  2222.     ofn.hInstance            = 0;
  2223.     ofn.lpstrFilter            = szFilterSave;
  2224.     ofn.lpstrCustomFilter    = NULL;
  2225.     ofn.nMaxCustFilter        = 0;
  2226.     ofn.nFilterIndex        = 0;
  2227.     ofn.lpstrFileTitle        = szTitle;
  2228.     ofn.nMaxFileTitle        = sizeof(szTitle);
  2229.     ofn.lpstrInitialDir        = NULL;
  2230.     ofn.lpstrTitle            = fSelect ? "Save Selection As": NULL;
  2231.     ofn.nFileOffset            = 0;
  2232.     ofn.nFileExtension        = 0;
  2233.      ofn.lpstrDefExt            = NULL;
  2234.     ofn.lCustData            = 0L;
  2235.     ofn.lpfnHook            = NULL;
  2236.     ofn.lpTemplateName        = NULL;
  2237.     ofn.hwndOwner            = hwndMain;
  2238.     ofn.lpstrFile            = szT;
  2239.     ofn.nMaxFile            = sizeof(szT);
  2240.     ofn.Flags                = OFN_CREATEPROMPT | OFN_HIDEREADONLY |
  2241.                                 OFN_OVERWRITEPROMPT;
  2242.  
  2243.     szT[0] = TEXT('\0');
  2244.     szTitle[0] = TEXT('\0');
  2245.     // Query user for filename for input
  2246.     if(!GetSaveFileName(&ofn))
  2247.     {
  2248.         if((dwError = CommDlgExtendedError()) != 0)
  2249.             goto err;
  2250.         return -1;
  2251.     }
  2252.  
  2253.     hcur = SetCursor(LoadCursor(NULL, IDC_WAIT));
  2254.  
  2255.     es.dwCookie = _lcreat(szT, 0);
  2256.     if(es.dwCookie == (DWORD) HFILE_ERROR)
  2257.     {
  2258.         dwError = GetLastError();
  2259.         goto err;
  2260.     }
  2261.     es.dwError = 0;
  2262.     es.pfnCallback = MyWrite;
  2263.     cch = SendMessage(predoc->hwndRE, EM_STREAMOUT,
  2264.         (WPARAM) (fSelect ? ofn.nFilterIndex | SFF_SELECTION
  2265.                           : ofn.nFilterIndex),
  2266.         (LPARAM) &es);
  2267.     _lclose((HFILE) es.dwCookie);
  2268.  
  2269.     // Don't mark the doc as clean, nor remember format if only selection
  2270.     if(fSelect)
  2271.         goto Quit;
  2272.  
  2273.     SendMessage(predoc->hwndRE, EM_SETMODIFY, (WPARAM) fFalse, 0);
  2274.  
  2275.     predoc->dwFormat = (DWORD) ofn.nFilterIndex;
  2276.     predoc->fReadOnly = fFalse;
  2277.     EnableWindow(predoc->hwndFormatBar, TRUE);
  2278.  
  2279.     lstrcpy(predoc->szFile, szT);
  2280.     lstrcpy(predoc->szTitle, szTitle);
  2281.  
  2282.     wsprintf(szT, szFmtTitle, szTitle);
  2283.     SetWindowText(predoc->hwndParent, szT);
  2284.  
  2285.     SendMessage(predoc->hwndRE, EM_SETMODIFY, (WPARAM) fFalse, 0);
  2286.     SendMessage(predoc->hwndRE, EM_SETREADONLY, (WPARAM) fFalse, 0);
  2287.  
  2288. Quit:
  2289.     SetCursor(hcur);
  2290.  
  2291.     return 0;
  2292.  
  2293. err:
  2294.     wsprintf(szT, TEXT("Error saving document. [%ld]"), dwError);
  2295.     MessageBox(hwndMain, szT, NULL, MB_OK);
  2296.  
  2297.     return -1;
  2298. }
  2299.  
  2300.  
  2301. LOCAL LRESULT InsertObject(REDOC *predoc)
  2302. {
  2303. #ifdef NO_OLE
  2304.     MessageBox(NULL, "Not yet implemented", NULL, MB_OK);
  2305.     return 0;
  2306. #else    // NO_OLE
  2307.     const LPRICHEDITOLE preole = predoc->preole;
  2308.     LPOLECLIENTSITE polesite = NULL;
  2309.     LPSTORAGE pstgItem = NULL;
  2310.     OLEUIINSERTOBJECT ouio = { 0 };
  2311.     REOBJECT reobj = { 0 };
  2312.     LPOLEOBJECT poleobj = NULL;
  2313.     CHAR szFileA[OLEUI_CCHPATHMAX];
  2314.     WCHAR szItemW[OLEUI_CCHPATHMAX];
  2315.     DWORD dwRet;
  2316.     RECT rect;
  2317.  
  2318.     if(!preole)
  2319.         return 0;
  2320.  
  2321.     if(preole->lpVtbl->SetHostNames(preole, "REITP", predoc->szTitle))
  2322.     {
  2323.         MessageBoxA(hwndMain, "Can't set host name", NULL, MB_OK);
  2324.         goto error;
  2325.     }
  2326.  
  2327.     if(preole->lpVtbl->GetClientSite(preole, (LPOLECLIENTSITE FAR *) &polesite))
  2328.     {
  2329.         MessageBoxA(hwndMain, "No client site!", NULL, MB_OK);
  2330.         goto error;
  2331.     }
  2332.  
  2333.     wsprintfW(szItemW, L"REOBJ%ld", ++predoc->cItem);
  2334.     if(!(pstgItem = OleStdCreateChildStorage(predoc->pstg, szItemW)))
  2335.     {
  2336.         MessageBoxW(hwndMain, szItemW, L"No item storage!", MB_OK);
  2337.         goto error;
  2338.     }
  2339.  
  2340.     szFileA[0] = '\0';
  2341.     ouio.cbStruct = sizeof(ouio);
  2342.     ouio.dwFlags = IOF_SHOWHELP | IOF_CREATENEWOBJECT | IOF_CREATEFILEOBJECT |
  2343.                    IOF_CREATELINKOBJECT | IOF_SELECTCREATENEW;
  2344. //                   IOF_VERIFYSERVERSEXIST;
  2345. # ifdef MAC    // Mac version doesn't have the same members
  2346.     ouio.pszFile = szFileA;
  2347. # else    // MAC
  2348.     ouio.hWndOwner = hwndMain;
  2349.     ouio.lpszFile = szFileA;
  2350. # endif    // MAC, else
  2351.     ouio.lpszCaption = "Insert Object (REITP)";
  2352.     ouio.cchFile = OLEUI_CCHPATHMAX;
  2353.     ouio.iid = IID_IOleObject;
  2354.     ouio.oleRender = OLERENDER_DRAW;
  2355.     ouio.lpIOleClientSite = polesite;
  2356.     ouio.lpIStorage = pstgItem;
  2357.     ouio.ppvObj = (LPVOID FAR *) &poleobj;
  2358.     ouio.clsid = CLSID_NULL;
  2359.  
  2360.     if((dwRet = OleUIInsertObject(&ouio)) != OLEUI_SUCCESS)
  2361.     {
  2362.         if(dwRet == OLEUI_CANCEL)
  2363.             goto error;
  2364.         if(dwRet == OLEUI_IOERR_SCODEHASERROR)
  2365.             wsprintfA(szFileA, "OleUIInsertObject scode is %lx", ouio.sc);
  2366.         else
  2367.             wsprintfA(szFileA, "OleUIInsertObject returned %ld", dwRet);
  2368.         MessageBoxA(hwndMain, szFileA, NULL, MB_OK);
  2369.         goto error;
  2370.     }
  2371.  
  2372.     AssertSz(ouio.sc == S_OK, "Object wasn't created properly");
  2373.  
  2374.     reobj.cbStruct = sizeof(REOBJECT);
  2375.     reobj.clsid = ouio.clsid;
  2376.     reobj.cp = REO_CP_SELECTION;
  2377.     reobj.poleobj = poleobj;
  2378.     reobj.pstg = pstgItem;
  2379.     reobj.polesite = polesite;
  2380.     reobj.dvaspect = DVASPECT_CONTENT;
  2381.     reobj.dwFlags = REO_RESIZABLE;
  2382.     reobj.dwUser = 0;
  2383.  
  2384.     if(ouio.dwFlags & IOF_SELECTCREATENEW)
  2385.         reobj.dwFlags |= REO_BLANK;
  2386.  
  2387.     //$ Raid 101: RichEdit doesn't setup advises if reobj.clsid == CLSID_NULL
  2388.     // Try our darnest to get a CLSID
  2389.  
  2390.     if(IsEqualCLSID(&reobj.clsid, &CLSID_NULL) &&
  2391.         HrGetClassFileA(szFileA, &reobj.clsid))
  2392.     {
  2393.         MessageBoxA(hwndMain, "No CLSID, but forging on", "Insert Object",
  2394.                     MB_OK);
  2395.     }
  2396.  
  2397.  
  2398.     // Do we want an iconized version ?
  2399.     if(ouio.dwFlags & IOF_CHECKDISPLAYASICON)
  2400.     {
  2401.     BOOL        fUpdate;                // Can't pass in NULL instead of &this
  2402.  
  2403.         // OLE call will update dvaspect on success
  2404. # ifdef MAC
  2405.         // NOTE : There presently is no Mac equivalent of the <.hMetaPict>
  2406.         // member of the tagOleUIInsertObject structure. This is certainly
  2407.         // a problem. For now just pass in NULL since the Mac routines will
  2408.         // not try to use this member.
  2409.         DebugStr("\pBefore OleStdSwitchDisplayAspect() call");
  2410.         if(OleStdSwitchDisplayAspect(poleobj, &reobj.dvaspect, 
  2411.                                       DVASPECT_ICON, (Handle) NULL, 
  2412.                                       TRUE, FALSE, NULL, &fUpdate))
  2413. # else    // MAC
  2414.         if(OleStdSwitchDisplayAspect(poleobj, &reobj.dvaspect, 
  2415.                                       DVASPECT_ICON, ouio.hMetaPict, 
  2416.                                       TRUE, FALSE, NULL, &fUpdate))
  2417. # endif    // MAC, else
  2418.         {
  2419.             // How much do we care about reporting errors?  Alot!! {Mac will have more}
  2420.             MessageBoxA(hwndMain, "Object couldn't be displayed as an icon.",
  2421.                         "Insert Object", MB_OK);
  2422.         }
  2423.         AssertSz(!fUpdate, "We gave it an hMetaPict, should not need updating");
  2424.     }
  2425.  
  2426.     // Put the thing in the edit control
  2427.     if(preole->lpVtbl->InsertObject(preole, &reobj))
  2428.     {
  2429.         MessageBoxA(hwndMain, "Object couldn't be inserted",
  2430.                     "Insert object", MB_OK);
  2431.         goto error;
  2432.     }
  2433.  
  2434.     // Do show verb only on new objects
  2435.     if(ouio.dwFlags & IOF_SELECTCREATENEW)
  2436.     {
  2437.         rect.top = rect.left = 0;
  2438.         rect.bottom = rect.right = 50;
  2439.         dwRet = (ULONG) poleobj->lpVtbl->DoVerb(poleobj, OLEIVERB_SHOW, NULL,
  2440.                                             polesite, 0, hwndMain, 
  2441.                                             (LPCRECT) &rect);
  2442.     }
  2443.  
  2444. error:
  2445. # ifndef MAC
  2446.     if(ouio.hMetaPict)
  2447.         OleUIMetafilePictIconFree(ouio.hMetaPict);
  2448. # endif    // !MAC
  2449.     if(polesite)
  2450.         polesite->lpVtbl->Release(polesite);
  2451.     if(pstgItem)
  2452.         pstgItem->lpVtbl->Release(pstgItem);
  2453.     if(poleobj)
  2454.         poleobj->lpVtbl->Release(poleobj);
  2455.  
  2456.     return 0;
  2457. #endif    // NO_OLE, else
  2458. }
  2459.  
  2460.  
  2461. #ifdef DEBUG
  2462.  
  2463. LOCAL LRESULT GetText(REDOC *predoc)
  2464. {
  2465.     HWND hwndEdit;
  2466.     LONG cch;
  2467.     TCHAR *pch;
  2468.  
  2469.     if(!hwndGT)
  2470.     {
  2471.         hwndGT = CreateDialog(HinstFromHwnd(hwndMain), TEXT("GETTEXT"),
  2472.                     hwndMain, (DLGPROC) GTDlgProc);
  2473.         if(!hwndGT)
  2474.         {
  2475.             MessageBoxA(hwndMain, "Unable to create dialog", NULL, MB_ICONSTOP | MB_OK);
  2476.             return 0;
  2477.         }
  2478.     }
  2479.     hwndEdit = GetDlgItem(hwndGT, GTCTRL);
  2480.     cch = SendMessage(predoc->hwndRE, WM_GETTEXTLENGTH, 0, 0);
  2481. # ifdef WIN16
  2482.     if(cch > 65000)
  2483.     {
  2484.         MessageBoxA(hwndMain, "Text too big, truncating", NULL,
  2485.             MB_ICONSTOP | MB_OK);
  2486.         cch = 65000;
  2487.     }
  2488. # endif    // WIN16
  2489.     pch = GlobalAllocPtr(GHND, cch + 1);
  2490.     if(!pch)
  2491.     {
  2492.         MessageBoxA(hwndMain, "Not enough memory to hold text", NULL,
  2493.             MB_ICONSTOP | MB_OK);
  2494.         return 0;
  2495.     }
  2496.     GetWindowText(predoc->hwndRE, pch, (int) cch + 1);
  2497.     *pch = toupper(*pch);
  2498.     SetWindowText(hwndEdit, pch);
  2499.     GlobalFreePtr(pch);
  2500.  
  2501.     return 0;
  2502. }
  2503.  
  2504.  
  2505. LRESULT CALLBACK GTDlgProc(HWND hdlg, UINT msg, WPARAM wparam, LPARAM lparam)
  2506. {
  2507.     switch(msg)
  2508.     {
  2509.     case WM_INITDIALOG:
  2510.         return 1;
  2511.  
  2512.     case WM_SIZE:
  2513.         MoveWindow(GetDlgItem(hdlg, GTCTRL), 5, 5, LOWORD(lparam)-10,
  2514.                    HIWORD(lparam)-10, TRUE);
  2515.         return 0;
  2516.  
  2517.     case WM_CLOSE:
  2518.         EndDialog(hdlg, 0);
  2519.         hwndGT = NULL;
  2520.         return 1;
  2521.     }
  2522.  
  2523.     return 0;
  2524. }
  2525.  
  2526.  
  2527. LOCAL VOID ClearDebugScreen(void)
  2528. {
  2529.     HFILE hf;
  2530.  
  2531.     hf = _lopen("COM1", OF_WRITE);
  2532.     if(hf)
  2533.     {
  2534.         _lwrite(hf, "\x1B[H\x1B[J", 6);
  2535.         _lclose(hf);
  2536.     }
  2537. }
  2538.  
  2539. #endif    // DEBUG
  2540.  
  2541.  
  2542. LOCAL VOID SelectCharFormat(REDOC *predoc)
  2543. {
  2544.     LOGFONT lf;
  2545.     CHOOSEFONT csf = {0};
  2546.     CHARFORMAT cf;
  2547.     LONG yPerInch;
  2548.     HDC hdc;
  2549.  
  2550.     cf.cbSize = sizeof(CHARFORMAT);
  2551.  
  2552.     hdc = GetDC(hwndMain);
  2553.     yPerInch = GetDeviceCaps(hdc, LOGPIXELSY);
  2554.     ReleaseDC(hwndMain, hdc);
  2555.  
  2556.     (void) SendMessage(predoc->hwndRE, EM_GETCHARFORMAT, (WPARAM) fTrue,
  2557.             (LPARAM) &cf);
  2558.  
  2559.     csf.lStructSize = sizeof(csf);
  2560.     csf.hwndOwner = hwndMain;
  2561.     csf.hDC = 0;
  2562.     csf.lpLogFont = &lf;
  2563.     csf.Flags = CF_EFFECTS | CF_SCREENFONTS | CF_INITTOLOGFONTSTRUCT |
  2564.                 CF_LIMITSIZE;
  2565.     csf.nSizeMin = 1;
  2566.     csf.nSizeMax = yHeightCharPtsMost;
  2567.     csf.rgbColors = cf.crTextColor;
  2568.     csf.lpszStyle = NULL;
  2569.     csf.nFontType = REGULAR_FONTTYPE | SCREEN_FONTTYPE;
  2570.     lf.lfHeight = -(INT) ((cf.yHeight * yPerInch) / 1440);
  2571.     lf.lfWidth = 0;
  2572.     lf.lfEscapement = 0;
  2573.     lf.lfOrientation = 0;
  2574.     lf.lfWeight = (cf.dwEffects & CFE_BOLD) ? FW_BOLD : FW_NORMAL;
  2575.     lf.lfItalic = (cf.dwEffects & CFE_ITALIC) ? fTrue : fFalse;
  2576.     lf.lfUnderline = (cf.dwEffects & CFE_UNDERLINE) ? fTrue : fFalse;
  2577.     lf.lfStrikeOut = (cf.dwEffects & CFE_STRIKEOUT) ? fTrue : fFalse;
  2578.     lf.lfOutPrecision = OUT_DEFAULT_PRECIS;
  2579.     lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
  2580.     lf.lfQuality = DRAFT_QUALITY;
  2581.     lf.lfCharSet = cf.bCharSet;
  2582.     lf.lfPitchAndFamily = cf.bPitchAndFamily;
  2583.     _tcscpy(lf.lfFaceName, cf.szFaceName);
  2584.  
  2585.     if(!ChooseFont(&csf))
  2586.         return;
  2587.  
  2588.     cf.cbSize = sizeof(CHARFORMAT);
  2589.  
  2590.     // don't change read-only bit
  2591.     cf.dwMask = CFM_SIZE | CFM_EFFECTS | CFM_COLOR | CFM_FACE | CFM_CHARSET;
  2592.     cf.yHeight = (LONG) csf.iPointSize * 2;
  2593.     cf.dwEffects = CFM_EFFECTS;
  2594.     if(lf.lfWeight < FW_BOLD)
  2595.         cf.dwEffects &= ~CFE_BOLD;
  2596.     if(!lf.lfItalic)
  2597.         cf.dwEffects &= ~CFE_ITALIC;
  2598.     if(!lf.lfUnderline)
  2599.         cf.dwEffects &= ~CFE_UNDERLINE;
  2600.     if(!lf.lfStrikeOut)
  2601.         cf.dwEffects &= ~CFE_STRIKEOUT;
  2602.     cf.crTextColor = csf.rgbColors;
  2603.     cf.bCharSet = lf.lfCharSet;
  2604.     cf.bPitchAndFamily = lf.lfPitchAndFamily;
  2605.     _tcscpy(cf.szFaceName, lf.lfFaceName);
  2606.  
  2607.     if(!SendMessage(predoc->hwndRE, EM_SETCHARFORMAT, predoc->scf,
  2608.         (LPARAM) &cf))
  2609.     {
  2610.         MessageBoxA(hwndMain, "Error setting character format", NULL,
  2611.             MB_ICONSTOP | MB_OK);
  2612.     }
  2613. }
  2614.  
  2615.  
  2616. LOCAL VOID SaveWindowPos(HWND hwnd)
  2617. {
  2618.     WINDOWPLACEMENT    wndpl;
  2619.     HKEY hkey;
  2620.  
  2621.     wndpl.length = sizeof(wndpl);
  2622.     GetWindowPlacement(hwnd, &wndpl);
  2623.     if(RegCreateKeyEx(HKEY_CURRENT_USER, szRegKey, 0, szAppName, 0,
  2624.         KEY_ALL_ACCESS, NULL, &hkey, NULL) == ERROR_SUCCESS)
  2625.     {
  2626.         RegSetValueEx(hkey, szRegValue, 0, REG_BINARY, (LPBYTE) &wndpl,
  2627.             sizeof(wndpl));
  2628.         RegCloseKey(hkey);
  2629.     }
  2630. }
  2631.  
  2632.  
  2633. LOCAL BOOL FRestoreWindowPos(WINDOWPLACEMENT *pwndpl)
  2634. {
  2635.     BOOL fReturn = fFalse;
  2636.     DWORD cb;
  2637.     HKEY hkey = 0;
  2638.  
  2639.     if(RegOpenKeyEx(HKEY_CURRENT_USER, szRegKey, 0, KEY_READ, &hkey)
  2640.         == ERROR_SUCCESS)
  2641.     {
  2642.         cb = sizeof(*pwndpl);
  2643.         if(RegQueryValueEx(hkey, szRegValue, 0, 0, (LPBYTE) pwndpl,
  2644.             &cb) == ERROR_SUCCESS)
  2645.         {
  2646.             fReturn = (cb == sizeof(*pwndpl));
  2647.         }
  2648.         RegCloseKey(hkey);
  2649.     }
  2650.  
  2651.     return fReturn;
  2652. }
  2653.  
  2654.  
  2655. LOCAL VOID SetAlignment(REDOC *predoc, WORD wAlignment)
  2656. {
  2657.     PARAFORMAT pf;
  2658.  
  2659.     pf.cbSize = sizeof(PARAFORMAT);
  2660.  
  2661.     SendMessage(predoc->hwndRE, EM_GETPARAFORMAT, 0, (LPARAM) &pf);
  2662.  
  2663.     if(!(pf.dwMask & PFM_ALIGNMENT) || pf.wAlignment != wAlignment)
  2664.     {
  2665.         pf.dwMask = PFM_ALIGNMENT;        // only change the alignment
  2666.         pf.wAlignment = wAlignment;
  2667.         SendMessage(predoc->hwndRE, EM_SETPARAFORMAT, 0, (LPARAM) &pf);
  2668.     }
  2669. }
  2670.  
  2671.  
  2672. LOCAL VOID IndentFirst(REDOC *predoc, BOOL fIndent)
  2673. {
  2674.     PARAFORMAT pf;
  2675.  
  2676.     pf.cbSize = sizeof(PARAFORMAT);
  2677.  
  2678.     SendMessage(predoc->hwndRE, EM_GETPARAFORMAT, 0, (LPARAM) &pf);
  2679.  
  2680.     pf.dwMask = PFM_OFFSET | PFM_OFFSETINDENT;
  2681.     if(fIndent)
  2682.     {
  2683.         if(pf.dxOffset < 0)
  2684.         {
  2685.             pf.dxStartIndent = pf.dxOffset;
  2686.             pf.dxOffset = 0;
  2687.         }
  2688.         else
  2689.         {
  2690.             pf.dxOffset = pf.dxOffset ? -pf.dxOffset : -lDefaultTab;
  2691.             pf.dxStartIndent = -pf.dxOffset;
  2692.         }
  2693.     }
  2694.     else
  2695.     {
  2696.         if(pf.dxOffset < 0)
  2697.         {
  2698.             pf.dxStartIndent = pf.dxOffset;
  2699.             pf.dxOffset = -pf.dxOffset;
  2700.         }
  2701.         else
  2702.         {
  2703.             pf.dxStartIndent = 0;
  2704.             pf.dxOffset = pf.dxOffset ? 0 : lDefaultTab;
  2705.         }
  2706.     }
  2707.  
  2708.     SendMessage(predoc->hwndRE, EM_SETPARAFORMAT, 0, (LPARAM) &pf);
  2709. }
  2710.  
  2711.  
  2712. LOCAL VOID ProtectSelection(REDOC *predoc)
  2713. {
  2714.     CHARFORMAT cf;
  2715.  
  2716.     cf.cbSize = sizeof(CHARFORMAT);
  2717.  
  2718.     (void) SendMessage(predoc->hwndRE, EM_GETCHARFORMAT, fTrue, (LPARAM) &cf);
  2719.     cf.dwMask = CFM_PROTECTED;
  2720.     cf.dwEffects = cf.dwEffects ^ CFE_PROTECTED;
  2721.     (void) SendMessage(predoc->hwndRE, EM_SETCHARFORMAT, predoc->scf,
  2722.                         (LPARAM) &cf);
  2723. }
  2724.  
  2725.  
  2726. LOCAL VOID SetWordWrap(REDOC *predoc, BOOL fWysiwyg, BOOL fWrap)
  2727. {
  2728.     HCURSOR hcur;
  2729.     HDC hdcDel = predoc->hdcTarget;
  2730.     LONG xWidth;
  2731.  
  2732.     if(!fWysiwyg == !predoc->fWysiwyg && !fWrap == !predoc->fWrap)
  2733.         return;
  2734.  
  2735.     hcur = SetCursor(LoadCursor(NULL, IDC_WAIT));
  2736.  
  2737.     if(fWysiwyg)
  2738.     {
  2739.         POINT pt;
  2740.         LPDEVMODE pDevMode;
  2741.         LPDEVNAMES pDevNames;
  2742.  
  2743.         if(predoc->pd.lStructSize != sizeof(PRINTDLG))
  2744.             goto done;    // error occured getting default printer
  2745.  
  2746.         pDevMode = (LPDEVMODE) GlobalLock(predoc->pd.hDevMode);
  2747.         pDevNames = (LPDEVNAMES) GlobalLock(predoc->pd.hDevNames);
  2748.         predoc->hdcTarget = CreateIC((LPTSTR) pDevNames +
  2749.                                         pDevNames->wDriverOffset,
  2750.                                 (LPTSTR) pDevNames + pDevNames->wDeviceOffset,
  2751.                                 (LPTSTR) pDevNames + pDevNames->wOutputOffset,
  2752.                                 pDevMode);
  2753.         GlobalUnlock(predoc->pd.hDevNames);
  2754.         GlobalUnlock(predoc->pd.hDevMode);
  2755.         if(!predoc->hdcTarget)
  2756.             goto done;
  2757.         SetMapMode(predoc->hdcTarget, MM_TEXT);
  2758.         if(Escape(predoc->hdcTarget, GETPHYSPAGESIZE, 0, NULL, &pt) > 0)
  2759.         {
  2760.             const LONG xPerInch = GetDeviceCaps(predoc->hdcTarget, LOGPIXELSX);
  2761.  
  2762.             xWidth = (pt.x * 1440l) / xPerInch;
  2763.             // leave 1.25" (1800 twips) margins if that will leave >= 1"
  2764.             if(xWidth >= 1800 + 1440 + 1800)
  2765.                 xWidth -= 1800 + 1800;
  2766.         }
  2767.         else
  2768.         {
  2769.             const LONG xPerInch = GetDeviceCaps(predoc->hdcTarget, LOGPIXELSX);
  2770.  
  2771.             xWidth = (GetDeviceCaps(predoc->hdcTarget, HORZRES) * 1440l) /
  2772.                         xPerInch;
  2773.         }
  2774.     }
  2775.     else
  2776.     {
  2777.         predoc->hdcTarget = 0;
  2778.         xWidth = (LONG) !fWrap;
  2779.     }
  2780.     predoc->fWysiwyg = fWysiwyg;
  2781.     predoc->fWrap = fWrap;
  2782.  
  2783.     SetupWordWrapMenu(predoc);
  2784.  
  2785.     SendMessage(predoc->hwndRE, EM_SETTARGETDEVICE,
  2786.             (WPARAM) predoc->hdcTarget, (LPARAM) xWidth);
  2787.     if(hdcDel)
  2788.         DeleteDC(hdcDel);
  2789.  
  2790. done:
  2791.     SetCursor(hcur);
  2792. }
  2793.  
  2794.  
  2795. LOCAL VOID SetupWordWrapMenu(REDOC *predoc)
  2796. {
  2797.     HMENU hmenu = GetMenu(hwndMain);
  2798.  
  2799.     CheckMenuItem(hmenu, IDM_NOWRAP,
  2800.         (!predoc->fWysiwyg && !predoc->fWrap) ? MF_CHECKED : MF_UNCHECKED);
  2801.     CheckMenuItem(hmenu, IDM_WRAP,
  2802.         (!predoc->fWysiwyg && predoc->fWrap) ? MF_CHECKED : MF_UNCHECKED);
  2803.     CheckMenuItem(hmenu, IDM_WYSIWYG,
  2804.         predoc->fWysiwyg ? MF_CHECKED :    MF_UNCHECKED);
  2805. }
  2806.  
  2807.  
  2808. LOCAL VOID SetOffset(REDOC *predoc, BOOL fSuperscript)
  2809. {
  2810.     CHARFORMAT cf;
  2811.  
  2812.     cf.cbSize = sizeof(CHARFORMAT);
  2813.  
  2814.     SendMessage(predoc->hwndRE, EM_GETCHARFORMAT, fTrue, (LPARAM) &cf);
  2815.  
  2816.     cf.dwMask = CFM_OFFSET;            // only change the yOffset
  2817.     if(fSuperscript)
  2818.     {
  2819.         if(cf.yOffset > 0)
  2820.             cf.yOffset = 0;
  2821.         else
  2822.             cf.yOffset = 50;
  2823.     }
  2824.     else
  2825.     {
  2826.         if(cf.yOffset < 0)
  2827.             cf.yOffset = 0;
  2828.         else
  2829.             cf.yOffset = -50;
  2830.     }
  2831.  
  2832.     SendMessage(predoc->hwndRE, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM) &cf);
  2833. }
  2834.  
  2835.  
  2836. VOID PrintREDoc(REDOC *predoc)
  2837. {
  2838.     LONG cchText;
  2839.     HCURSOR hcur;
  2840.     POINT pt;
  2841.     DOCINFO di;
  2842.     FORMATRANGE fr;
  2843.     RECT rc;
  2844.  
  2845.     cchText = SendMessage(predoc->hwndRE, WM_GETTEXTLENGTH, 0, 0);
  2846.  
  2847.     predoc->pd.nFromPage = 0;
  2848.     predoc->pd.nToPage = 0;
  2849.     predoc->pd.nMinPage = 0;
  2850.     predoc->pd.nMaxPage = 0;
  2851.     predoc->pd.nCopies = 1;
  2852.     predoc->pd.Flags = 
  2853.             PD_NOPAGENUMS | PD_NOSELECTION |
  2854.             PD_USEDEVMODECOPIES | PD_COLLATE | PD_RETURNDC;
  2855.  
  2856.     if(!PrintDlg(&predoc->pd))
  2857.         return;
  2858.  
  2859.     hcur = SetCursor(LoadCursor(NULL, IDC_WAIT));
  2860.  
  2861.     di.cbSize = sizeof(DOCINFO);
  2862.     di.lpszDocName = predoc->szTitle;
  2863.     di.lpszOutput = NULL;
  2864.  
  2865.     fr.hdc = predoc->pd.hDC;
  2866.     fr.hdcTarget = 0;
  2867.  
  2868.     if(Escape(fr.hdc, GETPHYSPAGESIZE, 0, NULL, &pt) > 0)
  2869.     {
  2870.         const LONG xPerInch = GetDeviceCaps(fr.hdc, LOGPIXELSX);
  2871.         const LONG yPerInch = GetDeviceCaps(fr.hdc, LOGPIXELSY);
  2872.  
  2873.         rc.left = rc.top = 0;
  2874.         fr.rcPage.left = fr.rcPage.top = 0;
  2875.         rc.right = (INT) ((pt.x * 1440l) / xPerInch);
  2876.         fr.rcPage.right = rc.right;
  2877.         // leave 1.25" (1800 twips) margins if that will leave >= 1"
  2878.         if(rc.right >= 1800 + 1440 + 1800)
  2879.             rc.right -= (rc.left = 1800);
  2880.         rc.bottom = (INT) ((pt.y * 1440l) / yPerInch);
  2881.         fr.rcPage.bottom = rc.bottom;
  2882.         // leave 1" (1440 twips) margins if that will leave >= 1"
  2883.         if(rc.bottom >= 1440 + 1440 + 1440)
  2884.             rc.bottom -= (rc.top = 1440);
  2885.     }
  2886.     else
  2887.     {
  2888.         const LONG xPerInch = GetDeviceCaps(fr.hdc, LOGPIXELSX);
  2889.         const LONG yPerInch = GetDeviceCaps(fr.hdc, LOGPIXELSY);
  2890.  
  2891.         rc.left = rc.top = 0;
  2892.         rc.right = (INT) ((GetDeviceCaps(fr.hdc, HORZRES) * 1440l) /
  2893.                                 xPerInch);
  2894.         rc.bottom = (INT) ((GetDeviceCaps(fr.hdc, VERTRES) * 1440l) /
  2895.                                 yPerInch);
  2896.         fr.rcPage = rc;
  2897.     }
  2898.  
  2899.     if(StartDoc(fr.hdc, &di) <= 0)
  2900.         goto err;
  2901.  
  2902.     // tell RichEdit not to erase before rendering text
  2903.     SetBkMode(fr.hdc, TRANSPARENT);
  2904.  
  2905.     fr.chrg.cpMin = 0;
  2906.     fr.chrg.cpMost = cchText;
  2907.     do
  2908.     {
  2909.         if(StartPage(fr.hdc) <= 0)
  2910.             goto abort;
  2911.         fr.rc = rc;
  2912.         fr.chrg.cpMin = SendMessage(predoc->hwndRE, EM_FORMATRANGE,
  2913.                             (WPARAM) fTrue, (LPARAM) &fr);
  2914.         if(EndPage(fr.hdc) <= 0)
  2915.             goto abort;
  2916.     } while(fr.chrg.cpMin > 0 && fr.chrg.cpMin < fr.chrg.cpMost);
  2917.  
  2918.     if(fr.chrg.cpMin >= 0 && EndDoc(fr.hdc) > 0)
  2919.     {
  2920.         fr.chrg.cpMin = fr.chrg.cpMost = cchText;
  2921.         // free up RichEdit's format range info
  2922.         SendMessage(predoc->hwndRE, EM_FORMATRANGE, 0, 0);
  2923.         (void) SetCursor(hcur);
  2924.         return;
  2925.     }
  2926.  
  2927. abort:
  2928.     (void) AbortDoc(fr.hdc);
  2929.  
  2930. err:
  2931.     fr.chrg.cpMin = fr.chrg.cpMost = cchText;
  2932.     // free up RichEdit's format range info
  2933.     SendMessage(predoc->hwndRE, EM_FORMATRANGE, 0, 0);
  2934.     (void) SetCursor(hcur);
  2935.     MessageBoxA(hwndMain, "An error occurred while printing", NULL,
  2936.         MB_ICONSTOP | MB_OK);
  2937. }
  2938.  
  2939.  
  2940. LRESULT CALLBACK PPDlgProc(HWND hdlg, UINT msg, WPARAM wparam, LPARAM lparam)
  2941. {
  2942.     PRINTPREVIEW * ppp = (PRINTPREVIEW *) GetWindowLong(hdlg, DWL_USER);
  2943.  
  2944.     switch(msg)
  2945.     {
  2946.     case WM_INITDIALOG:
  2947.         // hide the button we use to tell us where the top left is
  2948.         ShowWindow(GetDlgItem(hdlg, PSB_TopLeft), SW_HIDE);
  2949.  
  2950.         ppp = (PRINTPREVIEW *) GlobalAllocPtr(GHND, sizeof(PRINTPREVIEW));
  2951.         SetWindowLong(hdlg, DWL_USER, (LONG) ppp);
  2952.         if(!ppp)
  2953.         {
  2954.             MessageBoxA(hwndMain,
  2955.                 "Not enough memory for Print Preview window.",
  2956.                 NULL, MB_ICONSTOP | MB_OK);
  2957.             EndDialog(hdlg, 0);
  2958.             return 0;
  2959.         }
  2960.         ppp->hwndDlg = hdlg;
  2961.         ppp->predoc = (REDOC *) lparam;
  2962.         AssertSz(ppp->predoc, "print preview: no redoc");
  2963.         ppp->cchText = -1;
  2964.         ppp->ipage = -1;
  2965.         PPChangePage(ppp, fFalse);
  2966.         if(ppp->ipage < 0)
  2967.         {
  2968.             ppp->fDone = fTrue;        // prevent any movement
  2969.             // bail
  2970.             PostMessage(hdlg, WM_CLOSE, 0, 0);
  2971.             return 0;
  2972.         }
  2973.         return 1;
  2974.  
  2975.     case WM_PAINT:
  2976.         PPPaint(ppp);
  2977.         break;
  2978.  
  2979.     case WM_SIZE:
  2980.         // cause complete redraw
  2981.         InvalidateRect(hdlg, NULL, fTrue);
  2982.         break;
  2983.  
  2984. #if defined(DEBUG) && defined(CLIPMETA)
  2985.     case WM_LBUTTONDBLCLK:
  2986.         if(ppp->hmf)
  2987.         {
  2988.             HMETAFILE hmf = 0;
  2989.             HANDLE hMfp = 0;
  2990.             METAFILEPICT *pmfp;
  2991.  
  2992.             if(!OpenClipboard(hwndMain))
  2993.                 break;
  2994.             EmptyClipboard();
  2995.             hmf = CopyMetaFile(ppp->hmf, NULL);
  2996.             if(!hmf)
  2997.             {
  2998.                 MessageBeep(0);
  2999.                 break;
  3000.             }
  3001.             hMfp = GlobalAlloc(GHND | GMEM_DDESHARE, sizeof(METAFILEPICT));
  3002.             if(!hMfp)
  3003.                 goto err;
  3004.             pmfp = (METAFILEPICT *) GlobalLock(hMfp);
  3005.             pmfp->mm = MM_ANISOTROPIC;
  3006.             pmfp->xExt = (INT) ppp->dxPage;
  3007.             pmfp->yExt = (INT) ppp->dyPage;
  3008.             pmfp->hMF = hmf;
  3009.             GlobalUnlock(hMfp);
  3010.             SetClipboardData(CF_METAFILEPICT, hMfp);
  3011.             CloseClipboard();
  3012.             TraceTag(tagNull, "clipped");
  3013.             break;
  3014. err:
  3015.             if(hmf)
  3016.                 DeleteMetaFile(hmf);
  3017.             if(hMfp)
  3018.                 GlobalFree(hMfp);
  3019.             CloseClipboard();
  3020.         }
  3021.         break;
  3022. #endif    // DEBUG && CLIPMETA
  3023.  
  3024.     case WM_COMMAND:
  3025.         switch(GET_WM_COMMAND_ID(wparam, lparam))
  3026.         {
  3027.         case PSB_NextPage:
  3028.             PPChangePage(ppp, fFalse);
  3029.             break;
  3030.         case PSB_PrevPage:
  3031.             PPChangePage(ppp, fTrue);
  3032.             break;
  3033.         case PSB_Close:
  3034.             PostMessage(hdlg, WM_CLOSE, 0, 0);
  3035.             break;
  3036.         }
  3037.         break;
  3038.  
  3039.     case WM_CLOSE:
  3040.         if(ppp)
  3041.         {
  3042.             // free up RichEdit's format range info
  3043.             SendMessage(ppp->predoc->hwndRE, EM_FORMATRANGE, 0, 0);
  3044. #ifdef DEBUG
  3045.             if(ppp->hmf)
  3046.                 DeleteMetaFile(ppp->hmf);
  3047. #endif    // DEBUG
  3048.             if(ppp->fr.hdc)
  3049.             {
  3050. #ifndef NOBLIT
  3051.                 SelectObject(ppp->fr.hdc, ppp->hbmpOld);
  3052. #endif    // !NOBLIT
  3053.                 DeleteDC(ppp->fr.hdc);
  3054.             }
  3055. #ifndef NOBLIT
  3056.             if(ppp->hbmp)
  3057.                 DeleteObject(ppp->hbmp);
  3058. #endif    // !NOBLIT
  3059.             if(ppp->fr.hdcTarget)
  3060.                 DeleteDC(ppp->fr.hdcTarget);
  3061.             GlobalFreePtr(ppp);
  3062.         }
  3063.         SetWindowLong(hdlg, DWL_USER, 0);
  3064.         EndDialog(hdlg, 0);
  3065.         return 1;
  3066.     }
  3067.  
  3068.     return 0;
  3069. }
  3070.  
  3071.  
  3072. LOCAL BOOL FPPInit(PRINTPREVIEW *ppp)
  3073. {
  3074.     LPDEVMODE pDevMode;
  3075.     LPDEVNAMES pDevNames;
  3076.     POINT pt;
  3077.  
  3078. #ifndef NOBLIT
  3079.     ppp->hbmp = ppp->hbmpOld = 0;
  3080. #endif    // !NOBLIT
  3081.     ppp->fr.hdc = 0;
  3082.     ppp->cchText = SendMessage(ppp->predoc->hwndRE, WM_GETTEXTLENGTH, 0, 0);
  3083.  
  3084.     if(ppp->predoc->pd.lStructSize != sizeof(PRINTDLG))
  3085.     {
  3086.         MessageBoxA(hwndMain, "No printer selected.", NULL,
  3087.             MB_ICONSTOP | MB_OK);
  3088.         return fFalse;
  3089.     }
  3090.  
  3091.     ppp->cpage = 0;
  3092.     ppp->ipage = -1;    // first increment will display page 0
  3093.     ppp->cpageMost = cpageChunk;
  3094.     ppp->rgcpPages = (LONG *) GlobalAllocPtr(GHND, cpageChunk * sizeof(LONG));
  3095.     if(!ppp->rgcpPages)
  3096.         ppp->cpageMost = 0;
  3097.  
  3098.     pDevMode = (LPDEVMODE) GlobalLock(ppp->predoc->pd.hDevMode);
  3099.     pDevNames = (LPDEVNAMES) GlobalLock(ppp->predoc->pd.hDevNames);
  3100.     ppp->fr.hdcTarget = CreateIC((LPTSTR) pDevNames + pDevNames->wDriverOffset,
  3101.                                 (LPTSTR) pDevNames + pDevNames->wDeviceOffset,
  3102.                                 (LPTSTR) pDevNames + pDevNames->wOutputOffset,
  3103.                                 pDevMode);
  3104.     GlobalUnlock(ppp->predoc->pd.hDevNames);
  3105.     GlobalUnlock(ppp->predoc->pd.hDevMode);
  3106.     if(!ppp->fr.hdcTarget)
  3107.         goto err;
  3108.  
  3109.     // does this matter?
  3110.     SetMapMode(ppp->fr.hdcTarget, MM_TEXT);
  3111.  
  3112.     if(Escape(ppp->fr.hdcTarget, GETPHYSPAGESIZE, 0, NULL, &pt) > 0)
  3113.     {
  3114.         const LONG xPerInch = GetDeviceCaps(ppp->fr.hdcTarget, LOGPIXELSX);
  3115.         const LONG yPerInch = GetDeviceCaps(ppp->fr.hdcTarget, LOGPIXELSY);
  3116.  
  3117.         ppp->rc.left = ppp->rc.top = 0;
  3118.         ppp->dxPage = (pt.x * 1440l) / xPerInch;
  3119.         ppp->rc.right = (INT) ppp->dxPage;
  3120.         ppp->fr.rcPage.left = 0;
  3121.         ppp->fr.rcPage.right = ppp->rc.right;
  3122.         // leave 1.25" (1800 twips) margins if that will leave >= 1"
  3123.         if(ppp->rc.right >= 1800 + 1440 + 1800)
  3124.             ppp->rc.right -= (ppp->rc.left = 1800);
  3125.         ppp->dyPage = (pt.y * 1440l) / yPerInch;
  3126.         ppp->rc.bottom = (INT) ppp->dyPage;
  3127.         ppp->fr.rcPage.top = 0;
  3128.         ppp->fr.rcPage.bottom = ppp->rc.bottom;
  3129.         // leave 1" (1440 twips) margins if that will leave >= 1"
  3130.         if(ppp->rc.bottom >= 1440 + 1440 + 1440)
  3131.             ppp->rc.bottom -= (ppp->rc.top = 1440);
  3132.     }
  3133.     else
  3134.     {
  3135.         const LONG xPerInch = GetDeviceCaps(ppp->fr.hdcTarget, LOGPIXELSX);
  3136.         const LONG yPerInch = GetDeviceCaps(ppp->fr.hdcTarget, LOGPIXELSY);
  3137.         const LONG dxRes = GetDeviceCaps(ppp->fr.hdcTarget, HORZRES);
  3138.         const LONG dyRes = GetDeviceCaps(ppp->fr.hdcTarget, VERTRES);
  3139.  
  3140.         ppp->rc.left = ppp->rc.top = 0;
  3141.         ppp->dxPage = (dxRes * 1440l) / xPerInch;
  3142.         ppp->rc.right = (INT) ppp->dxPage;
  3143.         ppp->dyPage = (dyRes * 1440l) / yPerInch;
  3144.         ppp->rc.bottom = (INT) ppp->dyPage;
  3145.         ppp->fr.rcPage = ppp->rc;
  3146.     }
  3147.  
  3148.     PPInitDialogSize(ppp);
  3149.  
  3150. #ifdef DEBUG
  3151.     if(!QueryCheck(ppp->predoc, IDM_PPMETA))
  3152. #endif    // DEBUG
  3153.     {
  3154.         HDC hdcT;
  3155. #ifdef NOBLIT
  3156.  
  3157.         hdcT = GetDC(ppp->hwndDlg);
  3158.         ppp->fr.hdc = CreateCompatibleDC(hdcT);
  3159.         ReleaseDC(ppp->hwndDlg, hdcT);
  3160.         if(!ppp->fr.hdc)
  3161.             goto err;
  3162. #else    // NOBLIT
  3163.         LONG xPerInch;
  3164.         LONG yPerInch;
  3165.  
  3166.         hdcT = GetDC(ppp->hwndDlg);
  3167.         SaveDC(hdcT);
  3168.         SetMapMode(hdcT, MM_TEXT);
  3169.         xPerInch = GetDeviceCaps(hdcT, LOGPIXELSX);
  3170.         yPerInch = GetDeviceCaps(hdcT, LOGPIXELSY);
  3171.         ppp->dxBmp = (INT) ((ppp->dxPage * xPerInch) / 1440l);
  3172.         ppp->dyBmp = (INT) ((ppp->dyPage * yPerInch) / 1440l);
  3173.         ppp->fr.hdc = CreateCompatibleDC(hdcT);
  3174.         ppp->hbmp = CreateCompatibleBitmap(hdcT, ppp->dxBmp, ppp->dyBmp);
  3175.         RestoreDC(hdcT, -1);
  3176.         ReleaseDC(ppp->hwndDlg, hdcT);
  3177.         if(!ppp->fr.hdc)
  3178.         {
  3179.             if(ppp->hbmp)
  3180.                 DeleteObject(ppp->hbmp);
  3181.             ppp->hbmp = 0;
  3182.             goto err;
  3183.         }
  3184.         if(!ppp->hbmp)
  3185.             goto err;
  3186.         ppp->hbmpOld = SelectObject(ppp->fr.hdc, ppp->hbmp);
  3187. #endif    // NOBLIT, else
  3188.         SetMapMode(ppp->fr.hdc, MM_TEXT);
  3189.     }
  3190.  
  3191.     ppp->fr.chrg.cpMin = 0;
  3192.     ppp->fr.chrg.cpMost = ppp->cchText;
  3193.  
  3194.     return fTrue;
  3195.  
  3196. err:
  3197.     if(ppp->fr.hdcTarget)
  3198.     {
  3199.         DeleteDC(ppp->fr.hdcTarget);
  3200.         ppp->fr.hdcTarget = 0;
  3201.     }
  3202.     if(ppp->fr.hdc)
  3203.     {
  3204.         DeleteDC(ppp->fr.hdc);
  3205.         ppp->fr.hdc = 0;
  3206.     }
  3207. #ifndef NOBLIT
  3208.     Assert(!ppp->hbmp);
  3209.     Assert(!ppp->hbmpOld);
  3210. #endif    // !NOBLIT
  3211.  
  3212.     MessageBoxA(hwndMain,
  3213.         "An error occurred while processing the print preview",
  3214.         NULL, MB_ICONSTOP | MB_OK);
  3215.  
  3216.     return fFalse;
  3217. }
  3218.  
  3219.  
  3220. LOCAL VOID PPInitDialogSize(PRINTPREVIEW *ppp)
  3221. {
  3222.     LONG dx;
  3223.     LONG dy;
  3224.     LONG numer;
  3225.     LONG denom;
  3226.     RECT rc;
  3227.  
  3228.     dx = GetSystemMetrics(SM_CXFULLSCREEN) - 2 * GetSystemMetrics(SM_CXBORDER);
  3229.     dy = GetSystemMetrics(SM_CYFULLSCREEN) - 2 * GetSystemMetrics(SM_CYBORDER);
  3230.  
  3231.     // select initial scale
  3232.     if(dy * ppp->dxPage > dx * ppp->dyPage)
  3233.     {
  3234.         numer = dx;
  3235.         denom = ppp->dxPage;
  3236.     }
  3237.     else
  3238.     {
  3239.         numer = dy;
  3240.         denom = ppp->dyPage;
  3241.     }
  3242.     rc.top = 0;
  3243.     rc.left = 0;
  3244.     rc.bottom = (INT) ((numer * ppp->dyPage) / denom);
  3245.     rc.right = (INT) ((numer * ppp->dxPage) / denom);
  3246.  
  3247.     rc.right += 2 * GetSystemMetrics(SM_CXFRAME);
  3248.     rc.bottom += GetSystemMetrics(SM_CYCAPTION) + GetSystemMetrics(SM_CYFRAME);
  3249.  
  3250.     MoveWindow(ppp->hwndDlg, rc.left, rc.top, rc.right, rc.bottom, fTrue);
  3251.     ShowWindow(ppp->hwndDlg, SW_SHOW);
  3252. }
  3253.  
  3254.  
  3255. LOCAL VOID PPChangePage(PRINTPREVIEW *ppp, BOOL fPrev)
  3256. {
  3257.     HCURSOR hcur;
  3258.     TCHAR szCaption[40];
  3259.  
  3260.     if(ppp->cchText < 0 && !FPPInit(ppp))
  3261.         return;
  3262.  
  3263.     if(fPrev)
  3264.     {
  3265.         // no page before page zero or no page array so we can't go back
  3266.         if(ppp->ipage <= 0 || !ppp->rgcpPages)
  3267.         {
  3268.             MessageBeep(0);
  3269.             return;
  3270.         }
  3271.         Assert(ppp->ipage - 1 < ppp->cpage);
  3272.         // backup a page
  3273.         ppp->fr.chrg.cpMin = ppp->rgcpPages[ppp->ipage - 1];
  3274.     }
  3275.     else if(ppp->ipage + 1 >= ppp->cpage)
  3276.     {
  3277.         if(ppp->fDone)
  3278.         {
  3279.             MessageBeep(0);
  3280.             return;
  3281.         }
  3282.         if(!ppp->rgcpPages)
  3283.             goto doit;
  3284.         if(ppp->ipage + 1 >= ppp->cpageMost)
  3285.         {
  3286.             LONG *pcp;
  3287.  
  3288.             pcp = (LONG *) GlobalReAllocPtr(ppp->rgcpPages,
  3289.                     (ppp->cpageMost + cpageChunk) * sizeof(LONG), GHND);
  3290.             if(!pcp)
  3291.             {
  3292.                 GlobalFreePtr(ppp->rgcpPages);
  3293.                 ppp->rgcpPages = NULL;
  3294.                 ppp->cpage = ppp->cpageMost = 0;
  3295.                 goto doit;
  3296.             }
  3297.             ppp->rgcpPages = pcp;
  3298.             ppp->cpageMost += cpageChunk;
  3299.         }
  3300.         ppp->cpage++;
  3301.         ppp->rgcpPages[ppp->ipage + 1] = ppp->fr.chrg.cpMin;
  3302.     }
  3303.  
  3304. doit:
  3305.     hcur = SetCursor(LoadCursor(NULL, IDC_WAIT));
  3306.  
  3307. #ifndef NOBLIT
  3308.     if(ppp->fr.hdc)
  3309.     {
  3310.         RECT rc;
  3311.  
  3312.         rc.top = rc.left = 0;
  3313.         rc.bottom = ppp->dyBmp;
  3314.         rc.right = ppp->dxBmp;
  3315.         // erase the background
  3316.         SetBkColor(ppp->fr.hdc, GetSysColor(COLOR_WINDOW));
  3317.         ExtTextOut(ppp->fr.hdc, 0, 0, ETO_OPAQUE, &rc, "", 0, NULL);
  3318.         // tell RichEdit not to bother erasing the background
  3319.         SetBkMode(ppp->fr.hdc, TRANSPARENT);
  3320.     }
  3321. #endif    // !NOBLIT
  3322.  
  3323. #ifdef DEBUG
  3324.     if(ppp->hmf)
  3325.     {
  3326.         // delete any metafile left around from the last page
  3327.         DeleteMetaFile(ppp->hmf);
  3328.         ppp->hmf = NULL;
  3329.     }
  3330.     if(QueryCheck(ppp->predoc, IDM_PPMETA))
  3331.     {
  3332.         AssertSz(!ppp->fr.hdc, "How'd that get there?");
  3333.         ppp->fr.hdc = CreateMetaFile(NULL);
  3334.         if(!ppp->fr.hdc)
  3335.             goto err;
  3336.         TraceTag(tagEnumMF, "Window Ext = %d, %d", ppp->dxPage, ppp->dyPage);
  3337.     }
  3338. #endif    // DEBUG
  3339.  
  3340.     ppp->fr.rc = ppp->rc;
  3341.     ppp->fr.chrg.cpMin = SendMessage(ppp->predoc->hwndRE, EM_FORMATRANGE,
  3342.                             (WPARAM) fTrue, (LPARAM) &ppp->fr);
  3343.  
  3344.     if(!fPrev && ppp->fr.chrg.cpMin >= ppp->fr.chrg.cpMost)
  3345.     {
  3346.         // free up RichEdit's format range info
  3347.         ppp->fr.chrg.cpMin = ppp->fr.chrg.cpMost = ppp->cchText;
  3348.         SendMessage(ppp->predoc->hwndRE, EM_FORMATRANGE, 0, 0);
  3349.         // setup for a prev
  3350.         ppp->fr.chrg.cpMost = ppp->cchText;
  3351.         // done with all pages, ppp->cpage is the max # of pages
  3352.         ppp->fDone = fTrue;
  3353.     }
  3354.  
  3355. #ifdef DEBUG
  3356.     if(QueryCheck(ppp->predoc, IDM_PPMETA))
  3357.     {
  3358.         //$ REVIEW: what happens to ppp->fr.hdc if this fails?
  3359.         ppp->hmf = CloseMetaFile(ppp->fr.hdc);
  3360.         ppp->fr.hdc = 0;
  3361.         if(!ppp->hmf)
  3362.             goto err;
  3363.     }
  3364. #endif    // DEBUG
  3365.  
  3366.     // update the current page number
  3367.     ppp->ipage += fPrev ? -1 : 1;
  3368.  
  3369.     EnableWindow(GetDlgItem(ppp->hwndDlg, PSB_PrevPage), ppp->ipage > 0);
  3370.     EnableWindow(GetDlgItem(ppp->hwndDlg, PSB_NextPage),
  3371.         !ppp->fDone || ppp->ipage + 1 < ppp->cpage);
  3372.  
  3373.     wsprintf(szCaption, szFmtPrintPreview, ppp->ipage + 1);
  3374.     SetWindowText(ppp->hwndDlg, szCaption);
  3375.  
  3376.     // cause redraw
  3377.     InvalidateRect(ppp->hwndDlg, NULL, fTrue);
  3378.  
  3379.     (void) SetCursor(hcur);
  3380.  
  3381.     return;
  3382.  
  3383. #ifdef DEBUG
  3384. err:
  3385.     ppp->fDone = fTrue;
  3386.  
  3387.     // free up RichEdit's format range info
  3388.     ppp->fr.chrg.cpMin = ppp->fr.chrg.cpMost = ppp->cchText;
  3389.     SendMessage(ppp->predoc->hwndRE, EM_FORMATRANGE, 0, 0);
  3390.     // setup for a prev
  3391.     ppp->fr.chrg.cpMost = ppp->cchText;
  3392.     (void) SetCursor(hcur);
  3393.     MessageBoxA(hwndMain,
  3394.         "An error occurred while processing the print preview",
  3395.         NULL, MB_ICONSTOP | MB_OK);
  3396. #endif    // DEBUG
  3397. }
  3398.  
  3399.  
  3400. LOCAL VOID PPPaint(PRINTPREVIEW *ppp)
  3401. {
  3402.     HDC hdc;
  3403.     RECT rc;
  3404.     RECT rcClient;
  3405.     PAINTSTRUCT ps;
  3406.  
  3407.     // if we're iconic, don't bother
  3408.     if(IsIconic(ppp->hwndDlg))
  3409.         return;
  3410.  
  3411.     hdc = BeginPaint(ppp->hwndDlg, &ps);
  3412.     SaveDC(hdc);
  3413.     GetClientRect(ppp->hwndDlg, &rcClient);
  3414.     GetWindowRect(GetDlgItem(ppp->hwndDlg, PSB_TopLeft), &rc);
  3415.     MapWindowPoints(GetDesktopWindow(), ppp->hwndDlg, (LPPOINT) &rc, 2);
  3416.     rc.bottom = rc.top + GetSystemMetrics(SM_CYBORDER);
  3417.     rc.right = rcClient.right;
  3418.     SetBkColor(hdc, GetSysColor(COLOR_WINDOWFRAME));
  3419.     ExtTextOut(hdc, rc.left, rc.top, ETO_OPAQUE, &rc, "", 0, NULL);
  3420.     rc.top = rc.bottom;
  3421.     rc.bottom = rcClient.bottom;
  3422. #ifdef DEBUG
  3423.     if(ppp->hmf)
  3424.     {
  3425.         // erase the background
  3426.         SetBkColor(hdc, GetSysColor(COLOR_WINDOW));
  3427.         ExtTextOut(hdc, rc.left, rc.top, ETO_OPAQUE, &rc, "", 0, NULL);
  3428.         // make the window the same logical size as the page
  3429.         SetMapMode(hdc, MM_ANISOTROPIC);
  3430.         SetViewportOrgEx(hdc, rc.left, rc.top, NULL);
  3431.         TraceTag(tagEnumMF, "Viewport Org = %d, %d", rc.left, rc.top);
  3432.         SetViewportExtEx(hdc, rc.right - rc.left, rc.bottom - rc.top, NULL);
  3433.         TraceTag(tagEnumMF, "Viewport Ext = %d, %d", rc.right - rc.left, rc.bottom - rc.top);
  3434.         if(FFromTag(tagEnumMF))
  3435.             EnumMetaFile(hdc, ppp->hmf, MFEnumCallback, 0);
  3436.         PlayMetaFile(hdc, ppp->hmf);
  3437.     }
  3438.     else
  3439. #endif    // DEBUG
  3440.     if(ppp->ipage >= 0)
  3441.     {
  3442. #ifdef NOBLIT
  3443.         HDC hdcSave = ppp->fr.hdc;
  3444.         LONG xPerInch = GetDeviceCaps(hdc, LOGPIXELSX);
  3445.         LONG yPerInch = GetDeviceCaps(hdc, LOGPIXELSY);
  3446.  
  3447.         // make the window the same logical size as the page
  3448.         SetMapMode(hdc, MM_ANISOTROPIC);
  3449.         SetWindowExtEx(hdc, (ppp->dxPage * xPerInch) / 1440,
  3450.             (ppp->dyPage * yPerInch) / 1440, NULL);
  3451.         SetViewportExtEx(hdc, rc.right - rc.left, rc.bottom - rc.top, NULL);
  3452.  
  3453.         // erase the background
  3454.         SetBkColor(hdc, GetSysColor(COLOR_WINDOW));
  3455.         ExtTextOut(hdc, rc.left, rc.top, ETO_OPAQUE, &rc, "", 0, NULL);
  3456.  
  3457.         // tell RichEdit not to bother erasing the background
  3458.         SetBkMode(hdc, TRANSPARENT);
  3459.  
  3460.         ppp->fr.hdc = hdc;
  3461.         ppp->fr.rc = ppp->rc;
  3462.         ppp->fr.chrg.cpMin = ppp->rgcpPages[ppp->ipage];
  3463.         ppp->fr.chrg.cpMin = SendMessage(ppp->predoc->hwndRE, EM_FORMATRANGE,
  3464.                                 (WPARAM) fTrue, (LPARAM) &ppp->fr);
  3465.         ppp->fr.hdc = hdcSave;
  3466. #else    // NOBLIT
  3467.         // convert RECT to x,y,dx,dy
  3468.         rc.right -= rc.left;
  3469.         rc.bottom -= rc.top;
  3470.  
  3471.         StretchBlt(hdc, rc.left, rc.top, rc.right, rc.bottom,
  3472.             ppp->fr.hdc, 0, 0, ppp->dxBmp, ppp->dyBmp, SRCCOPY);
  3473. #endif    // NOBLIT, else
  3474.     }
  3475.     RestoreDC(hdc, -1);
  3476.     EndPaint(ppp->hwndDlg, &ps);
  3477. }
  3478.  
  3479. #ifdef DEBUG
  3480.  
  3481. int CALLBACK MFEnumCallback(HDC hdc, HANDLETABLE *lpHTable, METARECORD *pmfr,
  3482.                 int nObj, LPARAM lparam)
  3483. {
  3484.     switch(pmfr->rdFunction)
  3485.     {
  3486.     case META_SETWINDOWORG:
  3487.         TraceTag(tagEnumMF, "SetWindowOrg(): %d, %d", (INT) (SHORT) pmfr->rdParm[1], (INT) (SHORT) pmfr->rdParm[0]);
  3488.         break;
  3489.  
  3490.     case META_SETVIEWPORTORG:
  3491.         TraceTag(tagEnumMF, "SetViewportOrg(): %d, %d", (INT) (SHORT) pmfr->rdParm[1], (INT) (SHORT) pmfr->rdParm[0]);
  3492.         break;
  3493.  
  3494.     case META_OFFSETWINDOWORG:
  3495.         TraceTag(tagEnumMF, "OffsetWindowOrg(): %d, %d", (INT) (SHORT) pmfr->rdParm[1], (INT) (SHORT) pmfr->rdParm[0]);
  3496.         break;
  3497.  
  3498.     case META_OFFSETVIEWPORTORG:
  3499.         TraceTag(tagEnumMF, "OffsetViewportOrg(): %d, %d", (INT) (SHORT) pmfr->rdParm[1], (INT) (SHORT) pmfr->rdParm[0]);
  3500.         break;
  3501.  
  3502.     case META_SETWINDOWEXT:
  3503.         TraceTag(tagEnumMF, "SetWindowExt(): %d, %d", (INT) (SHORT) pmfr->rdParm[1], (INT) (SHORT) pmfr->rdParm[0]);
  3504.         break;
  3505.  
  3506.     case META_SETVIEWPORTEXT:
  3507.         TraceTag(tagEnumMF, "SetViewportExt(): %d, %d", (INT) (SHORT) pmfr->rdParm[1], (INT) (SHORT) pmfr->rdParm[0]);
  3508.         break;
  3509.  
  3510.     case META_SCALEWINDOWEXT:
  3511.         TraceTag(tagEnumMF, "ScaleWindowExt(): %d, %d, %d, %d", (INT) (SHORT) pmfr->rdParm[3], (INT) (SHORT) pmfr->rdParm[2], (INT) (SHORT) pmfr->rdParm[1], (INT) (SHORT) pmfr->rdParm[0]);
  3512.         break;
  3513.  
  3514.     case META_SCALEVIEWPORTEXT:
  3515.         TraceTag(tagEnumMF, "ScaleViewportExt(): %d, %d, %d, %d", (INT) (SHORT) pmfr->rdParm[3], (INT) (SHORT) pmfr->rdParm[2], (INT) (SHORT) pmfr->rdParm[1], (INT) (SHORT) pmfr->rdParm[0]);
  3516.         break;
  3517.  
  3518.     case META_SAVEDC:
  3519.         TraceTag(tagEnumMF, "SaveDC()");
  3520.         break;
  3521.  
  3522.     case META_RESTOREDC:
  3523.         TraceTag(tagEnumMF, "RestoreDC()");
  3524.         break;
  3525.  
  3526.     case META_SELECTPALETTE:
  3527.         TraceTag(tagEnumMF, "Select Palette");
  3528.         break;
  3529.  
  3530.     case META_SETMAPMODE:
  3531.         TraceTag(tagEnumMF, "SetMapMode(): %d", (INT) (SHORT) pmfr->rdParm[0]);
  3532.         break;
  3533.  
  3534.     case META_EXTTEXTOUT:
  3535.         TraceTag(tagEnumMF, "ExtTextOut(): %d, %d", (INT) (SHORT) pmfr->rdParm[1], (INT) (SHORT) pmfr->rdParm[0]);
  3536.         break;
  3537.  
  3538.     case META_TEXTOUT:
  3539.         TraceTag(tagEnumMF, "TextOut(): %d, %d", (INT) (SHORT) pmfr->rdParm[3], (INT) (SHORT) pmfr->rdParm[2]);
  3540.         break;
  3541.  
  3542.     case META_LINETO:
  3543.         TraceTag(tagEnumMF, "LineTo(): %d, %d", (INT) (SHORT) pmfr->rdParm[1], (INT) (SHORT) pmfr->rdParm[0]);
  3544.         break;
  3545.  
  3546.     case META_RECTANGLE:
  3547.         TraceTag(tagEnumMF, "Rectangle(): %d, %d, %d, %d", (INT) (SHORT) pmfr->rdParm[3], (INT) (SHORT) pmfr->rdParm[2], (INT) (SHORT) pmfr->rdParm[1], (INT) (SHORT) pmfr->rdParm[0]);
  3548.         break;
  3549.     }
  3550.  
  3551.     return fTrue;
  3552. }
  3553.  
  3554. #endif    // DEBUG
  3555.  
  3556.  
  3557. /*
  3558.  *    I T P C A L L   I m p l e m e n t a t i o n
  3559.  */
  3560.  
  3561.  
  3562. /* 
  3563.  *    ITPCALL_New
  3564.  *
  3565.  *    Purpose:
  3566.  *        Creates a new ITPCALL.
  3567.  *
  3568.  *    Arguments:
  3569.  *        REDOC *        Pointer to the document information.
  3570.  *
  3571.  *    Returns:
  3572.  *        ITPCALL *    The newly created ITPCALL.
  3573.  */
  3574. ITPCALL * ITPCALL_New(REDOC * predoc)
  3575. {
  3576. #ifndef NO_OLE
  3577.     ITPCALL * pitpcall;
  3578.  
  3579.     if(!(pitpcall = (ITPCALL *) GlobalAllocPtr(GHND, sizeof(ITPCALL))))
  3580.         goto Error;
  3581.     pitpcall->lpVtbl = &ITPCALL_Vtbl;
  3582.     pitpcall->cRef = 1;                    // Start with one reference
  3583.     pitpcall->predoc = predoc;
  3584.     if(!(pitpcall->pipframe = ITPOLEINPLACEFRAME_New(predoc)))
  3585.         GlobalFreePtr(pitpcall);
  3586.     else
  3587.         return pitpcall;
  3588. Error:
  3589. #endif    // !NO_OLE
  3590.  
  3591.     return NULL;
  3592. }
  3593.  
  3594.  
  3595. /*
  3596.  *    ITPCALL_QueryInterface
  3597.  *
  3598.  *    Purpose:
  3599.  *        Returns a pointer to the specified site.
  3600.  *
  3601.  *    Arguments:
  3602.  *        LPUNKNOWN *        Object from which we want an interface.
  3603.  *        REFIID            Interface we want.
  3604.  *        LPUNKNOWN *        Interface we return.
  3605.  *
  3606.  *    Returns:
  3607.  *        HRESULT         Error status.
  3608.  */
  3609. STDMETHODIMP ITPCALL_QueryInterface(LPUNKNOWN punk, REFIID riid, 
  3610.                                    LPUNKNOWN * ppvObj)
  3611. {
  3612.     SCODE sc = S_OK;
  3613.  
  3614.     if(IsEqualIID(riid, &IID_IUnknown))
  3615.         ITPCALL_AddRef(*ppvObj = punk);
  3616.     else if(IsEqualIID(riid, &IID_IRichEditOleCallback))
  3617.         ITPCALL_AddRef(*ppvObj = punk);
  3618.     else
  3619.         sc = E_NOINTERFACE, *ppvObj = NULL;
  3620.  
  3621.     return sc;
  3622. }
  3623.  
  3624.  
  3625. /*
  3626.  *    ITPCALL_AddRef
  3627.  *
  3628.  *    Purpose:
  3629.  *        Increments reference count on the specified site.
  3630.  *
  3631.  *    Arguments:
  3632.  *        LPUNKNOWN *        Object whose count we want to increment.
  3633.  *
  3634.  *    Returns:
  3635.  *        ULONG            New value of reference count.
  3636.  */
  3637. STDMETHODIMP_(ULONG) ITPCALL_AddRef(LPUNKNOWN punk)
  3638. {
  3639.     return ++PitpcallFromPunk(punk)->cRef;
  3640. }
  3641.  
  3642.  
  3643. /*
  3644.  *    ITPCALL_Release
  3645.  *
  3646.  *    Purpose:
  3647.  *        Decrements reference count on the specified site.  If count is
  3648.  *        decremented to zero, the object is freed.
  3649.  *
  3650.  *    Arguments:
  3651.  *        LPUNKNOWN *        Object whose count we want to decrement.
  3652.  *
  3653.  *    Returns:
  3654.  *        ULONG            New value of reference count.
  3655.  */
  3656. STDMETHODIMP_(ULONG) ITPCALL_Release(LPUNKNOWN punk)
  3657. {
  3658. #ifndef NO_OLE
  3659.     ITPCALL * pitpcall = PitpcallFromPunk(punk);
  3660.     ULONG cRef = --pitpcall->cRef;
  3661.  
  3662.     if(!cRef)
  3663.     {
  3664.         // Free stuff we own
  3665.         if(pitpcall->pipframe)
  3666.         {
  3667.             pitpcall->pipframe->lpVtbl->Release((LPOLEINPLACEFRAME) 
  3668.                                                  pitpcall->pipframe);
  3669.         }
  3670.  
  3671.         // Free memory allocated for us
  3672.         GlobalFreePtr(pitpcall);
  3673.         TraceTag(tagITPCALL, "ITPCALL_Release: freeing the itpcall");
  3674.     }
  3675.  
  3676.     AssertSz(cRef >= 0, "ITPCALL_Release: negative cRef");
  3677.     return cRef;
  3678. #endif    // !NO_OLE
  3679.  
  3680.     return (ULONG) NULL;
  3681. }
  3682.  
  3683.  
  3684. /*
  3685.  *    ITPCALL_GetNewStorage
  3686.  *
  3687.  *    Purpose:
  3688.  *        Gets storage for a new object.
  3689.  *
  3690.  *    Arguments:
  3691.  *        ITPCALL *            Callback object.
  3692.  *        LPSTORAGE FAR *        Where to return storage.
  3693.  *
  3694.  *    Returns:
  3695.  *        HRESULT                Error status.
  3696.  */
  3697. STDMETHODIMP ITPCALL_GetNewStorage(ITPCALL * pitpcall, LPSTORAGE FAR * ppstg)
  3698. {
  3699.     SCODE sc = S_OK;
  3700.     WCHAR szItemW[OLEUI_CCHPATHMAX];
  3701.  
  3702.     wsprintfW(szItemW, L"REOBJ%ld", ++pitpcall->predoc->cItem);
  3703.     if(!(*ppstg = OleStdCreateChildStorage(pitpcall->predoc->pstg, szItemW)))
  3704.     {
  3705.         MessageBoxW(hwndMain, szItemW, L"No item storage!", MB_OK);
  3706.         sc = E_FAIL;
  3707.     }
  3708.  
  3709.     return sc;
  3710. }
  3711.  
  3712.  
  3713. /*
  3714.  *    ITPCALL_GetInPlaceContext
  3715.  *
  3716.  *    Purpose:
  3717.  *        Gets context information for an in place object.
  3718.  *
  3719.  *    Arguments:
  3720.  *        ITPCALL *                Callback object.
  3721.  *        LPOLEINPLACEFRAME *        Frame window object.
  3722.  *        LPOLEINPLACEUIWINDOW *    Document window object.
  3723.  *        LPOLEINPLACEFRAMEINFO    Frame window information.
  3724.  *
  3725.  *    Returns:
  3726.  *        HRESULT                    Error status.
  3727.  */
  3728. STDMETHODIMP ITPCALL_GetInPlaceContext(ITPCALL * pitpcall, 
  3729.                                        LPOLEINPLACEFRAME FAR * ppipframe,
  3730.                                        LPOLEINPLACEUIWINDOW FAR* ppipuiDoc,
  3731.                                        LPOLEINPLACEFRAMEINFO pipfinfo)
  3732. {
  3733. #ifndef NO_OLE
  3734.     // Return window pointers
  3735.     *ppipframe = (LPOLEINPLACEFRAME) pitpcall->pipframe;
  3736.     (VOID) (*ppipframe)->lpVtbl->AddRef(*ppipframe);
  3737.     *ppipuiDoc = NULL;
  3738.  
  3739.     // Fill in frame window information
  3740.     pipfinfo->cb = sizeof(OLEINPLACEFRAMEINFO);
  3741.     pipfinfo->fMDIApp = FALSE;
  3742.     pipfinfo->hwndFrame = pitpcall->predoc->hwndParent;
  3743.     pipfinfo->haccel = (long) NULL;
  3744.     pipfinfo->cAccelEntries = 0;
  3745. #endif    // !NO_OLE
  3746.  
  3747.     return S_OK;
  3748. }
  3749.  
  3750.  
  3751. /*
  3752.  *    ITPCALL_ShowContainerUI
  3753.  *
  3754.  *    Purpose:
  3755.  *        Displays or hides REITP's container UI.
  3756.  *
  3757.  *    Arguments:
  3758.  *        ITPCALL *        Callback object.
  3759.  *        BOOL            
  3760.  *
  3761.  *    Returns:
  3762.  *        HRESULT            Error status.
  3763.  */
  3764. STDMETHODIMP ITPCALL_ShowContainerUI(ITPCALL * pitpcall, BOOL fShow)
  3765. {
  3766.     TraceTag(tagITPCALL, "ITPCALL_ShowContainerUI(%d)", fShow);
  3767.  
  3768.     // If we're displaying our UI, show our menus
  3769.     if(fShow)
  3770.         ITPOLEINPLACEFRAME_SetMenu(pitpcall->pipframe, NULL, NULL, NULL);
  3771.  
  3772.     return S_OK;
  3773. }
  3774.  
  3775.  
  3776. STDMETHODIMP ITPCALL_QueryInsertObject(ITPCALL * pitpcall, LPCLSID pclsid,
  3777.                 LPSTORAGE pstg, LONG cp)
  3778. {
  3779. #if !defined(NO_OLE) && defined(DEBUG)
  3780.     LPTSTR szProgID;
  3781.  
  3782.     if(HrProgIDFromCLSIDA(pclsid, &szProgID))
  3783.     {
  3784.         TraceTag(tagITPCALL, "QueryInsertObject(): unknown class id");
  3785.     }
  3786.     else
  3787.     {
  3788.         SCODE sc = S_OK;
  3789.  
  3790.         TraceTag(tagITPCALL, "QueryInsertObject(): %s object", szProgID);
  3791.         if(QueryCheck(pitpcall->predoc, IDM_REFUSEGRAPH) &&
  3792.             !lstrcmpi(szProgID, "MSGraph"))
  3793.         {
  3794.             TraceTag(tagITPCALL, "Refusing object");
  3795.             sc = S_FALSE;
  3796.         }
  3797.         OleStdFreeString((LPSTR) szProgID, NULL);
  3798.         return sc;
  3799.     }
  3800. #endif    // !NO_OLE && DEBUG
  3801.  
  3802.     return NOERROR;
  3803. }
  3804.  
  3805.  
  3806. STDMETHODIMP ITPCALL_DeleteObject(ITPCALL * pitpcall, LPOLEOBJECT poleobj)
  3807. {
  3808.     TraceTag(tagITPCALL, "DeleteObject()");
  3809.     return NOERROR;
  3810. }
  3811.  
  3812.  
  3813. STDMETHODIMP ITPCALL_QueryAcceptData(ITPCALL * pitpcall, LPDATAOBJECT pdataobj,
  3814.                 CLIPFORMAT *pcfFormat, DWORD reco, BOOL fReally,
  3815.                 HGLOBAL hMetaPict)
  3816. {
  3817. #if !defined(NO_OLE) && defined(DEBUG)
  3818.     TraceTag(tagITPCALL, "QueryAcceptData(%s) for %s", fReally ? "really" : "test", (reco == RECO_DROP ? "drop" : (reco == RECO_PASTE ? "paste" : "unknown op")));
  3819.     if(pitpcall->predoc->fReadOnly)
  3820.     {
  3821.         BOOL fDoIt = fFalse;
  3822.         HRESULT hr;
  3823.  
  3824.         switch(reco)
  3825.         {
  3826.         case RECO_DROP:
  3827.             fDoIt = QueryCheck(pitpcall->predoc, IDM_ENABLEDRAGREADONLY);
  3828.             break;
  3829.  
  3830.         case RECO_PASTE:
  3831.             fDoIt = QueryCheck(pitpcall->predoc, IDM_ENABLEPASTEREADONLY);
  3832.             break;
  3833.  
  3834.         default:
  3835.             TraceTag(tagNull, "QAD: invalid RECO %lx", reco);
  3836.             AssertSz(fFalse, "QAD: invalid RECO");
  3837.             break;
  3838.         }
  3839.         if(fDoIt)
  3840.         {
  3841.             if(fReally)
  3842.             {
  3843.                 LPRICHEDITOLE const preole = pitpcall->predoc->preole;
  3844.  
  3845.                 // import that sucker
  3846.  
  3847.                 hr = preole->lpVtbl->ImportDataObject(preole, pdataobj,
  3848.                                                         *pcfFormat, hMetaPict);
  3849.                 TraceError("IRichEditOle::ImportDataObject", hr);
  3850.                 if(SUCCEEDED(hr))
  3851.                     hr = S_FALSE;    // we did it ourselves
  3852.             }
  3853.             else
  3854.             {
  3855.                 // return that we'll import it ourselves
  3856.                 hr = S_FALSE;
  3857.             }
  3858.         }
  3859.         else
  3860.         {
  3861.             hr = E_FAIL;
  3862.         }
  3863.         TraceError("IPCALL_QueryAcceptData", hr);
  3864.         return hr;
  3865.     }
  3866.     if(QueryCheck(pitpcall->predoc, IDM_TEXTONLY))
  3867.     {
  3868.         TraceTag(tagITPCALL, "QueryAcceptData(): asking for text only");
  3869.         *pcfFormat = CF_TEXT;        // accept only text
  3870.     }
  3871.     else
  3872.     {
  3873.         TraceTag(tagITPCALL, "QueryAcceptData(): delegating back to RichEdit");
  3874.     }
  3875. #endif    // !NO_OLE && DEBUG
  3876.  
  3877.     return NOERROR;
  3878. }
  3879.  
  3880.  
  3881. STDMETHODIMP ITPCALL_ContextSensitiveHelp(ITPCALL * pitpcall, BOOL fEnterMode)
  3882. {
  3883.     return NOERROR;
  3884. }
  3885.  
  3886.  
  3887. STDMETHODIMP ITPCALL_GetClipboardData(ITPCALL *pitpcall, CHARRANGE *pchrg,
  3888.                     DWORD reco, LPDATAOBJECT *ppdataobj)
  3889. {
  3890. #if !defined(NO_OLE) && defined(DEBUG)
  3891.     TraceTag(tagITPCALL, "GetClipboardData(%d-%d) for %s", pchrg->cpMin, pchrg->cpMost, reco == RECO_COPY ? "copy" : (reco == RECO_CUT ? "cut" : (reco == RECO_DRAG ? "drag" : "unknown op")));
  3892.  
  3893.     if(pitpcall->predoc->fReadOnly)
  3894.     {
  3895.         BOOL fDoIt = fFalse;
  3896.  
  3897.         switch(reco)
  3898.         {
  3899.         case RECO_COPY:
  3900.             // prevent assert in default case
  3901.             break;
  3902.  
  3903.         case RECO_CUT:
  3904.             fDoIt = QueryCheck(pitpcall->predoc, IDM_ENABLECUTREADONLY);
  3905.             break;
  3906.  
  3907.         case RECO_DRAG:
  3908.             fDoIt = QueryCheck(pitpcall->predoc, IDM_ENABLEDRAGREADONLY);
  3909.             break;
  3910.  
  3911.         default:
  3912.             TraceTag(tagNull, "GCD: invalid RECO %lx", reco);
  3913.             AssertSz(fFalse, "GCD: invalid RECO");
  3914.             break;
  3915.         }
  3916.         if(fDoIt)
  3917.         {
  3918.             LPRICHEDITOLE const preole = pitpcall->predoc->preole;
  3919.             HRESULT hr;
  3920.  
  3921.             // delegate to IRichEditOle::GetClipboardData()
  3922.  
  3923.             *ppdataobj = NULL;
  3924.             hr = preole->lpVtbl->GetClipboardData(preole, pchrg, reco,
  3925.                                                     ppdataobj);
  3926.             TraceError("IRichEditOle::GetClipboardData", hr);
  3927.             if(SUCCEEDED(hr) && *ppdataobj)
  3928.                 hr = S_FALSE;    // we did it ourselves
  3929.             TraceError("IPCALL_GetClipboardData", hr);
  3930.             return hr;
  3931.         }
  3932.         // go return E_NOTIMPL & let RichEdit deal with it itself
  3933.     }
  3934. #endif    // !NO_OLE && DEBUG
  3935.  
  3936.     // *ppdataobj isn't used if E_NOTIMPL is returned
  3937.     // so we don't need to set it
  3938.  
  3939.     // tell RichEdit to do it itself
  3940.     TraceTag(tagITPCALL, "GetClipboardData(): delegating back to RichEdit");
  3941.     return E_NOTIMPL;
  3942. }
  3943.  
  3944.  
  3945. STDMETHODIMP ITPCALL_GetDragDropEffect(ITPCALL *pitpcall, BOOL fDrag,
  3946.                 DWORD grfKeyState, LPDWORD pdwEffect)
  3947. {
  3948.     TraceTag(tagITPCALL, "GetDragDropEffect(%s)", fDrag ? "drag" : "drop");
  3949.  
  3950. #ifdef DEBUG
  3951.     if(QueryCheck(pitpcall->predoc, IDM_SWAPDRAGEFFECT))
  3952.     {
  3953.         DWORD dwT;
  3954.  
  3955.         // strip off move, copy, and link
  3956.         dwT = *pdwEffect &
  3957.                 ~(DWORD) (DROPEFFECT_MOVE | DROPEFFECT_COPY | DROPEFFECT_LINK);
  3958.  
  3959.         if(!pitpcall->predoc->fReadOnly ||
  3960.             QueryCheck(pitpcall->predoc, IDM_ENABLEDRAGREADONLY))
  3961.         {
  3962.             if(fDrag)
  3963.                 dwT = DROPEFFECT_MOVE | DROPEFFECT_COPY;
  3964.             else if(grfKeyState & MK_CONTROL)
  3965.                 dwT = DROPEFFECT_MOVE;
  3966.             else
  3967.                 dwT = DROPEFFECT_COPY;
  3968.         }
  3969.  
  3970.         *pdwEffect = dwT;
  3971.  
  3972.         return NOERROR;
  3973.     }
  3974. #endif    // DEBUG
  3975.  
  3976.     // delegate back to RichEdit
  3977.     return E_NOTIMPL;
  3978. }
  3979.  
  3980.  
  3981. STDMETHODIMP ITPCALL_GetContextMenu(ITPCALL *pitpcall, WORD seltype,
  3982.                 LPOLEOBJECT poleobj, CHARRANGE * pchrg, HMENU * phmenu)
  3983. {
  3984.     HMENU hmenu;
  3985.     HMENU hmenuParent = NULL;
  3986.     HMENU hmenuVerbs = NULL;
  3987.     UINT uiT;
  3988.  
  3989.     TraceTag(tagITPCALL, "GetContextMenu");
  3990.  
  3991.     hmenuParent = CreatePopupMenu();
  3992.     if(!hmenuParent)
  3993.         goto Cleanup;
  3994.  
  3995.     // Put the verbs on the menu
  3996.     if(poleobj)
  3997.     {
  3998.         OleUIAddVerbMenu(poleobj, NULL, hmenuParent, 0, IDM_OBJECTMIN, 
  3999.                         0, TRUE, IDM_OBJECTCONVERT, &hmenuVerbs);
  4000.     }
  4001.  
  4002.     // Determine which menu to pass back to RichEdit
  4003.     *phmenu = hmenu = hmenuVerbs ? hmenuVerbs : hmenuParent;
  4004.  
  4005.     if(poleobj)
  4006.         AppendMenu(hmenu, MF_SEPARATOR, 0, NULL);
  4007.  
  4008.     // Add the cut, copy, paste verbs
  4009.     
  4010.     uiT = MF_STRING | MF_BYCOMMAND;
  4011.     uiT |= pchrg->cpMin == pchrg->cpMost ? uiMFDisabled : uiMFEnabled;
  4012.     AppendMenu(hmenu, uiT, IDM_CUT, "Cut");
  4013.     AppendMenu(hmenu, uiT, IDM_COPY, "Copy");
  4014.  
  4015.  
  4016.     uiT = MF_STRING | MF_BYCOMMAND;
  4017.     uiT |= SendMessage(pitpcall->predoc->hwndRE, EM_CANPASTE, 0, 0)
  4018.                 ? uiMFEnabled : uiMFDisabled;
  4019.     AppendMenu(hmenu, uiT, IDM_PASTE, "Paste");
  4020.  
  4021. Cleanup:
  4022.     if(hmenu == hmenuVerbs && hmenuParent)
  4023.         DestroyMenu(hmenuParent);
  4024.     else if(hmenu == hmenuParent && hmenuVerbs)
  4025.         DestroyMenu(hmenuVerbs);
  4026.     
  4027.     return S_OK;
  4028. }
  4029.  
  4030.  
  4031. /*
  4032.  *    I T P O L E I N P L A C E F R A M E  I m p l e m e n t a t i o n
  4033.  */
  4034.  
  4035.  
  4036. /* 
  4037.  *    ITPOLEINPLACEFRAME_New
  4038.  *
  4039.  *    Purpose:
  4040.  *        Creates a new ITPOLEINPLACEFRAME.
  4041.  *
  4042.  *    Arguments:
  4043.  *        REDOC *                    Pointer to the document information.
  4044.  *
  4045.  *    Returns:
  4046.  *        ITPOLEINPLACEFRAME *    The newly created ITPOLEINPLACEFRAME.
  4047.  */
  4048. ITPOLEINPLACEFRAME * ITPOLEINPLACEFRAME_New(REDOC * predoc)
  4049. {
  4050. #ifndef NO_OLE
  4051.     ITPOLEINPLACEFRAME * pipframe;
  4052.  
  4053.     if(!(pipframe = (ITPOLEINPLACEFRAME *) GlobalAllocPtr(GHND, sizeof(ITPOLEINPLACEFRAME))))
  4054.         return NULL;
  4055.     pipframe->lpVtbl = &ITPOLEINPLACEFRAME_Vtbl;
  4056.     pipframe->cRef = 1;                    // Start with one reference
  4057.     pipframe->predoc = predoc;
  4058.     return pipframe;
  4059. #endif    // !NO_OLE
  4060.  
  4061.     return NULL;
  4062. }
  4063.  
  4064.  
  4065. /*
  4066.  *    ITPOLEINPLACEFRAME_QueryInterface
  4067.  *
  4068.  *    Purpose:
  4069.  *        Returns a pointer to the specified site.
  4070.  *
  4071.  *    Arguments:
  4072.  *        LPUNKNOWN *        Object from which we want an interface.
  4073.  *        REFIID            Interface we want.
  4074.  *        LPUNKNOWN *        Interface we return.
  4075.  *
  4076.  *    Returns:
  4077.  *        HRESULT            Error status.
  4078.  */
  4079. STDMETHODIMP ITPOLEINPLACEFRAME_QueryInterface(LPUNKNOWN punk, REFIID riid, 
  4080.                                    LPUNKNOWN * ppvObj)
  4081. {
  4082.     SCODE sc = S_OK;
  4083.  
  4084.     if(IsEqualIID(riid, &IID_IUnknown) ||
  4085.         IsEqualIID(riid, &IID_IOleWindow) ||
  4086.         IsEqualIID(riid, &IID_IOleInPlaceUIWindow) ||
  4087.         IsEqualIID(riid, &IID_IOleInPlaceFrame))
  4088.     {
  4089.         ITPOLEINPLACEFRAME_AddRef(*ppvObj = punk);
  4090.     }
  4091.     else
  4092.     {
  4093.         sc = E_NOINTERFACE, *ppvObj = NULL;
  4094.     }
  4095.  
  4096.     return sc;
  4097. }
  4098.  
  4099.  
  4100. /*
  4101.  *    ITPOLEINPLACEFRAME_AddRef
  4102.  *
  4103.  *    Purpose:
  4104.  *        Increments reference count on the specified site.
  4105.  *
  4106.  *    Arguments:
  4107.  *        LPUNKNOWN *        Object whose count we want to increment.
  4108.  *
  4109.  *    Returns:
  4110.  *        ULONG            New value of reference count.
  4111.  */
  4112. STDMETHODIMP_(ULONG) ITPOLEINPLACEFRAME_AddRef(LPUNKNOWN punk)
  4113. {
  4114.     return ++PipframeFromPunk(punk)->cRef;
  4115. }
  4116.  
  4117.  
  4118. /*
  4119.  *    ITPOLEINPLACEFRAME_Release
  4120.  *
  4121.  *    Purpose:
  4122.  *        Decrements reference count on the specified site.  If count is
  4123.  *        decremented to zero, the object is freed.
  4124.  *
  4125.  *    Arguments:
  4126.  *        LPUNKNOWN *        Object whose count we want to decrement.
  4127.  *
  4128.  *    Returns:
  4129.  *        ULONG            New value of reference count.
  4130.  */
  4131. STDMETHODIMP_(ULONG) ITPOLEINPLACEFRAME_Release(LPUNKNOWN punk)
  4132. {
  4133.     ITPOLEINPLACEFRAME * pipframe = PipframeFromPunk(punk);
  4134.     ULONG cRef = --pipframe->cRef;
  4135.  
  4136.     if(!cRef)
  4137.     {
  4138.         // Free memory allocated for us
  4139.         GlobalFreePtr(pipframe);
  4140.         TraceTag(tagInPlace, "ITPOLEINPLACEFRAME_Release: freeing the ipframe");
  4141.     }
  4142.  
  4143.     AssertSz(cRef >= 0, "ITPOLEINPLACEFRAME_Release: negative cRef");
  4144.  
  4145.     return cRef;
  4146. }
  4147.  
  4148.  
  4149. /*
  4150.  *    ITPOLEINPLACEFRAME_GetWindow
  4151.  *
  4152.  *    Purpose:
  4153.  *        Return the window handle of the app-level window for in place use.
  4154.  *
  4155.  *    Arguments:
  4156.  *        ITPOLEINPLACESITE *    Client site.
  4157.  *
  4158.  *    Returns:
  4159.  *        HRESULT                Error status.
  4160.  */
  4161. STDMETHODIMP ITPOLEINPLACEFRAME_GetWindow(ITPOLEINPLACEFRAME * pipframe,
  4162.                                           HWND * phwnd)
  4163. {
  4164.     TraceTag(tagInPlace, "ITPOLEINPLACEFRAME_GetWindow: NYI");
  4165.  
  4166.     return E_NOTIMPL;
  4167. }
  4168.  
  4169.  
  4170. /*
  4171.  *    ITPOLEINPLACEFRAME_ContextSensitiveHelp
  4172.  *
  4173.  *    Purpose:
  4174.  *        Notifies the frame that the object has entered Context Help mode.
  4175.  *
  4176.  *    Arguments:
  4177.  *        ITPOLEINPLACESITE *    Client site.
  4178.  *
  4179.  *    Returns:
  4180.  *        HRESULT                Error status.
  4181.  */
  4182. STDMETHODIMP ITPOLEINPLACEFRAME_ContextSensitiveHelp(ITPOLEINPLACEFRAME *pipframe,
  4183.                                                      BOOL fEnterMode)
  4184. {
  4185.     TraceTag(tagInPlace, "ITPOLEINPLACEFRAME_ContextSensitiveHelp: NYI");
  4186.     TraceError("ITPOLEINPLACEFRAME_ContextSensitiveHelp()", E_NOTIMPL);
  4187.  
  4188.     return E_NOTIMPL;
  4189. }
  4190.  
  4191.  
  4192. /*
  4193.  *    ITPOLEINPLACEFRAME_GetBorder
  4194.  *
  4195.  *    Purpose:
  4196.  *        Returns a RECT structure in which the object can put toolbars and 
  4197.  *        similar controls while an object is active in place.
  4198.  *
  4199.  *    Arguments:
  4200.  *        ITPOLEINPLACESITE *    Client site.
  4201.  *
  4202.  *    Returns:
  4203.  *        HRESULT                Error status.
  4204.  */
  4205. STDMETHODIMP ITPOLEINPLACEFRAME_GetBorder(ITPOLEINPLACEFRAME * pipframe,
  4206.                                           LPRECT prcBorder)
  4207. {
  4208.     TraceTag(tagInPlace, "ITPOLEINPLACEFRAME_GetBorder: NYI");
  4209.     TraceError("ITPOLEINPLACEFRAME_GetBorder()", E_NOTIMPL);
  4210.  
  4211.     return E_NOTIMPL;
  4212. }
  4213.  
  4214.  
  4215. /*
  4216.  *    ITPOLEINPLACEFRAME_RequestBorderSpace
  4217.  *
  4218.  *    Purpose:
  4219.  *        Determines whether tools can be installed around the objects 
  4220.  *        window frame while the object is active in place.
  4221.  *
  4222.  *    Arguments:
  4223.  *        ITPOLEINPLACESITE *    Client site.
  4224.  *
  4225.  *    Returns:
  4226.  *        HRESULT                Error status.
  4227.  */
  4228. STDMETHODIMP ITPOLEINPLACEFRAME_RequestBorderSpace(ITPOLEINPLACEFRAME * pipframe,
  4229.                                                    LPCBORDERWIDTHS pbw)
  4230. {
  4231.     TraceTag(tagInPlace, "ITPOLEINPLACEFRAME_RequestBorderSpace: NYI");
  4232.     TraceError("ITPOLEINPLACEFRAME_RequestBorderSpace()", E_NOTIMPL);
  4233.  
  4234.     return E_NOTIMPL;
  4235. }
  4236.  
  4237.  
  4238. /*
  4239.  *    ITPOLEINPLACEFRAME_SetBorderSpace
  4240.  *
  4241.  *    Purpose:
  4242.  *        Allocates space for the border requested in the call to the 
  4243.  *        RequestBorderSpace member function.
  4244.  *
  4245.  *    Arguments:
  4246.  *        ITPOLEINPLACESITE *    Client site.
  4247.  *
  4248.  *    Returns:
  4249.  *        HRESULT                Error status.
  4250.  */
  4251. STDMETHODIMP ITPOLEINPLACEFRAME_SetBorderSpace(ITPOLEINPLACEFRAME * pipframe,
  4252.                                                LPCBORDERWIDTHS pbw)
  4253. {
  4254.     //$ FUTURE: If NULL, then put our tools back
  4255.     TraceTag(tagInPlace, "ITPOLEINPLACEFRAME_SetBorderSpace: NYI");
  4256.     TraceError("ITPOLEINPLACEFRAME_SetBorderSpace()", E_NOTIMPL);
  4257.  
  4258.     return E_NOTIMPL;
  4259. }
  4260.  
  4261.  
  4262. /*
  4263.  *    ITPOLEINPLACEFRAME_SetActiveObject
  4264.  *
  4265.  *    Purpose:
  4266.  *        Called by the object to provide the frame window a direct channel 
  4267.  *        of communication with the active in-place object.
  4268.  *
  4269.  *    Arguments:
  4270.  *        ITPOLEINPLACESITE *    Client site.
  4271.  *
  4272.  *    Returns:
  4273.  *        HRESULT                Error status.
  4274.  */
  4275. STDMETHODIMP ITPOLEINPLACEFRAME_SetActiveObject(ITPOLEINPLACEFRAME * pipframe,
  4276.                                                 LPOLEINPLACEACTIVEOBJECT pipaobj,
  4277.                                                 LPCSTR szObjName)
  4278. {
  4279. #ifndef NO_OLE
  4280.     // Free any existing active object
  4281.     if(pipframe->pipaobj)
  4282.         pipframe->pipaobj->lpVtbl->Release(pipframe->pipaobj);
  4283.  
  4284.     // If we're given an object, AddRef it; update our remembered ipaobj
  4285.     if(pipaobj)
  4286.         pipaobj->lpVtbl->AddRef(pipaobj);
  4287.     pipframe->pipaobj = pipaobj;
  4288.  
  4289.     TraceTag(tagInPlace, "ITPOLEINPLACEFRAME_SetActiveObject: %s", szObjName ? szObjName : "NULL");
  4290. #endif    // !NO_OLE
  4291.  
  4292.     return S_OK;
  4293. }
  4294.  
  4295.  
  4296. /*
  4297.  *    ITPOLEINPLACEFRAME_InsertMenus
  4298.  *
  4299.  *    Purpose:
  4300.  *        Called by the object server to allow the container to insert 
  4301.  *        its menu groups in the composite menu that will be used during
  4302.  *        the in-place session.
  4303.  *
  4304.  *    Arguments:
  4305.  *        ITPOLEINPLACESITE *    Client site.
  4306.  *
  4307.  *    Returns:
  4308.  *        HRESULT                Error status.
  4309.  */
  4310. STDMETHODIMP ITPOLEINPLACEFRAME_InsertMenus(ITPOLEINPLACEFRAME * pipframe,
  4311.                                             HMENU hmenuShared, 
  4312.                                             LPOLEMENUGROUPWIDTHS pmgw)
  4313. {
  4314.     //$ FUTURE: Do something interesting here
  4315.     // Don't actually put any menus on right now
  4316.     pmgw->width[0] = pmgw->width[2] = pmgw->width[4] = 0;
  4317.     TraceTag(tagInPlace, "ITPOLEINPLACEFRAME_InsertMenus: S_OK");
  4318.  
  4319.     return S_OK;
  4320. }
  4321.  
  4322.  
  4323. /*
  4324.  *    ITPOLEINPLACEFRAME_SetMenu
  4325.  *
  4326.  *    Purpose:
  4327.  *        Installs the composite menu into the window frame containing
  4328.  *        the object that is being activated in place.
  4329.  *
  4330.  *    Arguments:
  4331.  *        ITPOLEINPLACESITE *    Client site.
  4332.  *
  4333.  *    Returns:
  4334.  *        HRESULT                Error status.
  4335.  */
  4336. STDMETHODIMP ITPOLEINPLACEFRAME_SetMenu(ITPOLEINPLACEFRAME * pipframe, 
  4337.                                         HMENU hmenuShared, HOLEMENU holemenu, 
  4338.                                         HWND hwndActiveObject)
  4339. {
  4340. #ifndef NO_OLE
  4341.     HWND hwnd = pipframe->predoc->hwndParent;
  4342.  
  4343.     TraceTag(tagInPlace, "ITPOLEINPLACEFRAME_SetMenu: hMenuShared=%08lx holemenu=%08lx", (DWORD) (LPVOID) hmenuShared, (DWORD) (LPVOID) holemenu);
  4344.  
  4345.     // Did OLE give us a menu, or leave us to ourselves?
  4346.     if(hmenuShared && holemenu)
  4347.     {
  4348.         // Put the merged menu OLE gave us on our menu bar
  4349.         SetMenu(hwnd, hmenuShared);
  4350.     }
  4351.     else
  4352.     {
  4353.         // Put our regular menu on the menu bar
  4354.         SetMenu(hwnd, hmenuFull);
  4355.         SetupWordWrapMenu(pipframe->predoc);
  4356.     }
  4357.     DrawMenuBar(hwnd);
  4358. # ifdef MAC
  4359.     DebugStr("\pTry calling OleSetMenuDescriptor()");
  4360. # else    // MAC
  4361.     // Pass the menu descriptor to OLE
  4362.     return OleSetMenuDescriptor(holemenu, pipframe->predoc->hwndParent, 
  4363.                                 hwndActiveObject, (LPOLEINPLACEFRAME) pipframe,
  4364.                                 pipframe->pipaobj);
  4365. # endif    // MAC, else
  4366. #endif    // !NO_OLE
  4367.  
  4368.     return S_OK;
  4369. }
  4370.  
  4371.  
  4372. /*
  4373.  *    ITPOLEINPLACEFRAME_RemoveMenus
  4374.  *
  4375.  *    Purpose:
  4376.  *        Called by the object server to give the container a chance to 
  4377.  *        remove its menu elements from the in-place composite menu.
  4378.  *
  4379.  *    Arguments:
  4380.  *        ITPOLEINPLACESITE *    Client site.
  4381.  *
  4382.  *    Returns:
  4383.  *        HRESULT                Error status.
  4384.  */
  4385. STDMETHODIMP ITPOLEINPLACEFRAME_RemoveMenus(ITPOLEINPLACEFRAME * pipframe, 
  4386.                                             HMENU hmenuShared)
  4387. {
  4388.     // We didn't put any menus on!
  4389.     TraceTag(tagInPlace, "ITPOLEINPLACEFRAME_RemoveMenus: S_OK");
  4390.  
  4391.     return S_OK;
  4392. }
  4393.  
  4394.  
  4395. /*
  4396.  *    ITPOLEINPLACEFRAME_SetStatusText
  4397.  *
  4398.  *    Purpose:
  4399.  *        Sets and displays status text about the in-place object in the
  4400.  *        containers frame window status line.
  4401.  *
  4402.  *    Arguments:
  4403.  *        ITPOLEINPLACESITE *    Client site.
  4404.  *
  4405.  *    Returns:
  4406.  *        HRESULT                Error status.
  4407.  */
  4408. STDMETHODIMP ITPOLEINPLACEFRAME_SetStatusText(ITPOLEINPLACEFRAME * pipframe, 
  4409.                                               LPCSTR szStatusText)
  4410. {
  4411.     TraceTag(tagInPlace, "ITPOLEINPLACEFRAME_SetStatusText: NYI");
  4412.     TraceError("ITPOLEINPLACEFRAME_SetStatusText()", E_NOTIMPL);
  4413.  
  4414.     return E_NOTIMPL;
  4415. }
  4416.  
  4417.  
  4418. /*
  4419.  *    ITPOLEINPLACEFRAME_EnableModeless
  4420.  *
  4421.  *    Purpose:
  4422.  *        Enables or disables modeless dialogs of the frame.
  4423.  *
  4424.  *    Arguments:
  4425.  *        ITPOLEINPLACESITE *    Client site.
  4426.  *
  4427.  *    Returns:
  4428.  *        HRESULT                Error status.
  4429.  */
  4430. STDMETHODIMP ITPOLEINPLACEFRAME_EnableModeless(ITPOLEINPLACEFRAME * pipframe, 
  4431.                                                BOOL fEnable)
  4432. {
  4433.     TraceTag(tagInPlace, "ITPOLEINPLACEFRAME_EnableModeless: NYI");
  4434.     TraceError("ITPOLEINPLACEFRAME_EnableModeless()", E_NOTIMPL);
  4435.  
  4436.     return E_NOTIMPL;
  4437. }
  4438.  
  4439.  
  4440. /*
  4441.  *    ITPOLEINPLACEFRAME_TranslateAccelerator
  4442.  *
  4443.  *    Purpose:
  4444.  *        Translates keystrokes intended for the container frame while
  4445.  *        an object is active in place.
  4446.  *
  4447.  *    Arguments:
  4448.  *        ITPOLEINPLACESITE *    Client site.
  4449.  *
  4450.  *    Returns:
  4451.  *        HRESULT                Error status.
  4452.  */
  4453. STDMETHODIMP ITPOLEINPLACEFRAME_TranslateAccelerator(ITPOLEINPLACEFRAME *pipframe,
  4454.                                                      LPMSG pmsg, WORD wID)
  4455. {
  4456.     // REITP doesn't have any accelerators!
  4457.     return S_FALSE;
  4458. }
  4459.  
  4460.  
  4461. LOCAL VOID FindReplace(REDOC *predoc, BOOL fReplace)
  4462. {
  4463.     FINDREPLACE *pfr;
  4464.  
  4465.     if(hwndFR)
  4466.         return;
  4467.  
  4468.     if(!(pfr = predoc->pfr))
  4469.     {
  4470.         pfr = predoc->pfr = (FINDREPLACE * ) GlobalAllocPtr(GHND,
  4471.                                 sizeof(FINDREPLACE) + 2 * 80 * sizeof(TCHAR));
  4472.         if(!predoc->pfr)
  4473.             return;
  4474.     }
  4475.     else
  4476.     {
  4477.         memset(pfr, 0, sizeof(FINDREPLACE));
  4478.     }
  4479.  
  4480.     SendMessage(predoc->hwndRE, EM_HIDESELECTION, fFalse, fTrue);
  4481.  
  4482.     pfr->lStructSize = sizeof(FINDREPLACE);
  4483.     pfr->hwndOwner = predoc->hwndParent;
  4484.     pfr->Flags = FR_HIDEUPDOWN;
  4485.     pfr->lpstrFindWhat = (LPSTR) (((BYTE *) pfr) + sizeof(FINDREPLACE));
  4486.     pfr->lpstrReplaceWith = pfr->lpstrFindWhat + 80;
  4487.     pfr->wFindWhatLen = 80 * sizeof(TCHAR);
  4488.     pfr->wReplaceWithLen = 80 * sizeof(TCHAR);
  4489.  
  4490.     hwndFR = fReplace ? ReplaceText(pfr) : FindText(pfr);
  4491. }
  4492.  
  4493.  
  4494. LOCAL VOID ProcessFindReplace(REDOC *predoc, FINDREPLACE *pfr)
  4495. {
  4496.     HCURSOR hcur;
  4497.     LONG cszReplaced = 0;
  4498.     LONG cpMatch;
  4499.     CHARRANGE chrgSave;
  4500.     FINDTEXTEX ft;
  4501.  
  4502.     SendMessage(predoc->hwndRE, EM_EXGETSEL, 0, (LPARAM) &chrgSave);
  4503.     ft.chrg.cpMost = -1;    // search through end of the text
  4504.     ft.chrg.cpMin = chrgSave.cpMin;
  4505.     if(!(pfr->Flags & (FR_REPLACE | FR_REPLACEALL)))
  4506.         ft.chrg.cpMin = chrgSave.cpMost;
  4507.     ft.lpstrText = pfr->lpstrFindWhat;
  4508.  
  4509.     if(pfr->Flags & FR_REPLACEALL)
  4510.     {
  4511.         hcur = SetCursor(LoadCursor(NULL, IDC_WAIT));
  4512.         SendMessage(predoc->hwndRE, EM_HIDESELECTION, fTrue, fFalse);
  4513.     }
  4514.  
  4515. next:
  4516.     cpMatch = SendMessage(predoc->hwndRE, EM_FINDTEXTEX,
  4517.         (WPARAM) (pfr->Flags),
  4518.         (LPARAM) &ft);
  4519.     if(cpMatch < 0)
  4520.     {
  4521.         if(cszReplaced == 0)
  4522.         {
  4523.             MessageBoxA(hwndFR,
  4524.                 "The search text is not found.", szAppName, MB_OK);
  4525.         }
  4526.         else
  4527.         {
  4528.             char rgch[80];
  4529.  
  4530.             wsprintfA(rgch, "Replaced %ld occurances.", cszReplaced);
  4531.             MessageBoxA(hwndFR, rgch, szAppName, MB_OK);
  4532.         }
  4533.         SetFocus(hwndFR);
  4534.         goto done;
  4535.     }
  4536. //    ft.chrg.cpMin = cpMatch;
  4537. //    ft.chrg.cpMost = cpMatch + lstrlen(ft.lpstrText);
  4538.     ft.chrg.cpMin = ft.chrgText.cpMin;
  4539.     ft.chrg.cpMost = ft.chrgText.cpMost;
  4540.     SendMessage(predoc->hwndRE, EM_EXSETSEL, 0, (LPARAM) &ft.chrg);
  4541.     if(((pfr->Flags & FR_REPLACE) && cszReplaced == 0) ||
  4542.         (pfr->Flags & FR_REPLACEALL))
  4543.     {
  4544.         SendMessage(predoc->hwndRE, EM_REPLACESEL, 0,
  4545.             (LPARAM) pfr->lpstrReplaceWith);
  4546.         ft.chrg.cpMin = cpMatch + lstrlen(pfr->lpstrReplaceWith);
  4547.         ft.chrg.cpMost = -1;    // search through end of the text
  4548.         cszReplaced++;
  4549.         goto next;
  4550.     }
  4551.  
  4552. done:
  4553.     if(pfr->Flags & FR_REPLACEALL)
  4554.     {
  4555.         SetCursor(hcur);
  4556.  
  4557.         SendMessage(predoc->hwndRE, EM_HIDESELECTION, fFalse, fFalse);
  4558.     }
  4559. }
  4560.  
  4561.  
  4562. VOID UpdateFormatBar(REDOC * predoc)
  4563. {
  4564.     CHARFORMAT cf;
  4565.     PARAFORMAT pf;
  4566.  
  4567.     cf.cbSize = sizeof(CHARFORMAT);
  4568.     pf.cbSize = sizeof(PARAFORMAT);
  4569.  
  4570.     SendMessage(predoc->hwndRE, EM_GETCHARFORMAT, TRUE, (LPARAM) &cf);
  4571.     SendMessage(predoc->hwndFormatBar, EM_SETCHARFORMAT, 0, (LPARAM) &cf);
  4572.     SendMessage(predoc->hwndRE, EM_GETPARAFORMAT, FALSE, (LPARAM) &pf);
  4573.     SendMessage(predoc->hwndFormatBar, EM_SETPARAFORMAT, 0, (LPARAM) &pf);
  4574. }
  4575.  
  4576.  
  4577.  
  4578. LOCAL VOID ShowMargins(REDOC *predoc)
  4579. {
  4580.     if(ToggleCheck(predoc, IDM_SHOWMARGINS))
  4581.     {
  4582.         RECT rc;
  4583.  
  4584.         GetClientRect(predoc->hwndParent, &rc);
  4585.         ResizeRedoc(predoc, rc);
  4586.     }
  4587.     else
  4588.     {
  4589.         SendMessage(predoc->hwndRE, EM_SETRECT, 0, 0);
  4590.     }
  4591. }
  4592.  
  4593.  
  4594. # ifdef DEBUG
  4595.  
  4596. LOCAL VOID SetLimit(REDOC *predoc)
  4597. {
  4598.     LONG cchLimit = 32767;
  4599.  
  4600.     if(ToggleCheck(predoc, IDM_BIGLIMIT))
  4601.         cchLimit = 1024 * (LONG) 1024 - 1;
  4602.  
  4603.     SendMessage(predoc->hwndRE, EM_EXLIMITTEXT, 0, cchLimit);
  4604. }
  4605.  
  4606.  
  4607. static TCHAR szText[] = "Once upon a time there was an edit control.  "
  4608.     "This was a happy edit control until some mean evil tester "
  4609.     "(who shall remain nameless) came along and started beating on "
  4610.     "the poor little helpless edit control.  The edit control bravely "
  4611.     "faced it's unprovoked attacker, but an edit control can only take "
  4612.     "so much.  One day when it was being ferociously tortured it thought "
  4613.     "to itself \"What have I ever done to this poor homely creature to "
  4614.     "deserve this type of punishment?\".  It stirred up it's self esteem "
  4615.     "and stood up and said to the nasty creature \"I am an edit control, "
  4616.     "hear me roar!  I deserve to be treated with dignity and respect!\".  "
  4617.     "The evil little tester was taken aback by the edit control's sudden "
  4618.     "show of courage, but being the spawn of hell, he dismissed the edit "
  4619.     "control's declaration and continued his ghastly attacks.  The edit "
  4620.     "control decided that nothing would ever reform this hideous beast "
  4621.     "imparting terror upon it so he decided to do something about it.  "
  4622.     "The next day when the heathen was preparing to nuke the edit control "
  4623.     "the edit control jumped out at the beast and ripped it's heart out.  "
  4624.     "The tester stood shocked for a millisecond and then dropped over dead.  "
  4625.     "The end.\r\n\r\n";
  4626.  
  4627. LOCAL VOID FillerUp(REDOC *predoc)
  4628. {
  4629.     const LONG cch = lstrlen(szText);
  4630.     LONG cchAdded;
  4631.     LONG cchText;
  4632.     DWORD dwTicks;
  4633.  
  4634.     SetWindowText(predoc->hwndRE, TEXT(""));
  4635.     cchText = 0;
  4636.  
  4637.     (void) GetAsyncKeyState(VK_ESCAPE);    // reset key state
  4638.     dwTicks = GetTickCount();
  4639.     do
  4640.     {
  4641.         LONG cchT;
  4642.  
  4643.         SendMessage(predoc->hwndRE, EM_REPLACESEL, 0, (LPARAM) (LPSTR) szText);
  4644.         cchT = SendMessage(predoc->hwndRE, WM_GETTEXTLENGTH, 0, 0);
  4645.         cchAdded = cchT - cchText;
  4646.         if(cchText % 8192 > cchT % 8192)
  4647.         {
  4648.             const DWORD dwT = GetTickCount();
  4649.  
  4650.             TraceTag(tagGeneral, "%ld characters, %ld ticks", cchT, dwT - dwTicks);
  4651.             dwTicks = dwT;
  4652.         }
  4653.         cchText = cchT;
  4654.         if(GetAsyncKeyState(VK_ESCAPE) & 0x8001)
  4655.         {
  4656.             TraceTag(tagGeneral, "stopping for escape");
  4657.             break;
  4658.         }
  4659.     } while(cchAdded > 0 && !fErrSpace);
  4660.  
  4661.     TraceTag(tagGeneral, "Stopped at %ld character", cchText);
  4662. }
  4663.  
  4664. #endif    // DEBUG
  4665.