/*
*reitp.c
*
*Purpose:
*Test program for RichEdit. Excercises main RichEdit
*functionality while providing a good replacement for notepad.
*
*Owner:
*
* Copyright 1997 - 1998 Microsoft Coporation
*/
#include "preinc.h"
#include <windows.h>
#include <windowsx.h>
#include <commdlg.h>
#include <cderr.h>
#include <ctype.h>
#include <stdio.h>
#include <tchar.h>
// for the benefit of the outside world,
// richedit.h uses cpMax instead of cpMost
// I highly prefer cpMost
#ifdef cpMax
#error "cpMax hack won't work"
#endif// cpMax
#define cpMax cpMost
#include <richedit.h>
#undef cpMax
#include "olestd.h"
#include "reguid.h"
#include "dbugit.h"
#include <richole.h>
#include "reitp.h"
#include "reitp.rh"
#include "frmtbar.h"
#include <oledlg.h>
ASSERTDATA
#define SUNKENRICHEDIT
// define to use LiFormatRange() directly instead of via blitting
//#define NOBLIT
// used to make life simpler while testing, should not normally be defined
//#define NO_SAVE_PROMPT
struct _itpcall;
typedef struct _pp
{
BOOL fDone;
HWND hwndDlg;
REDOC *predoc;
LONG cchText;
LONG dxPage;
LONG dyPage;
RECT rc;
FORMATRANGE fr;
#ifndef NOBLIT
HBITMAP hbmp;
HBITMAP hbmpOld;
INT dxBmp;
INT dyBmp;
#endif// !NOBLIT
INT ipage;
INT cpage;
INT cpageMost;
LONG *rgcpPages;
} PRINTPREVIEW;
// number of pages to allocate at once in PRINTPREVIEW.rgcpPages
#define cpageChunk 4
#define szFmtPrintPreview TEXT("Print Preview - Page %d")
typedef struct _assensz
{
WORD wNotification;
LPCSTR szDescription;
} ASSENSZ;
// added to the client rect to get the RichEdit size
#ifdef SUNKENRICHEDIT
#define dxRESize -GetSystemMetrics(SM_CXBORDER)
#define dyRESize -GetSystemMetrics(SM_CYBORDER)
#else// SUNKENRICHEDIT
#define dxRESize 0
#define dyRESize 0
#endif// SUNKENRICHEDIT, else
// Control ID for the format bar
#defineFBR_FormatBar217
#define HinstFromHwnd(_hwnd) ((HINSTANCE) GetWindowLong(_hwnd, GWL_HINSTANCE))
#define uiMFDisabled MF_DISABLED | MF_GRAYED
#define uiMFEnabled MF_ENABLED
// Maximum text to be corrected under PenWin
#define cchMaxCorrectText4096
#define szClosedName szAppName
static TCHAR szAppName[] = TEXT("REITP");
static const TCHAR szClassRE[] = TEXT(RICHEDIT_CLASS);
static const TCHAR szFmtTitle[] = TEXT("REITP - %s");
static const TCHAR szUntitled[] = TEXT("[Untitled]");
static const TCHAR szRTFSig[] = TEXT("{\\rtf");
#define cchRTFSig 5
static TCHAR szRegKey[] = TEXT("software\\microsoft\\reitp");
static TCHAR szRegValue[] = TEXT("placement");
static const POINT ptMinTrackSize = {300, 90};
// Make sure that these strings match the order of SF_*
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");
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");
static HMODULE hmod = 0;// Flag for FreeLibrary()
HWND hwndMain = 0;
static HMENU hmenuLoaded = 0;
HMENU hmenuFull = 0;
static PRINTDLG pdDef = {0};
static BOOL fPrint = fFalse;
static BOOL fWysiwygDefault = fFalse;
static BOOL fWrapDefault = fTrue;
static UINT msgFindReplace = 0;
static HWND hwndFR = 0;// find/replace dialog
HINSTANCE hinst = 0;
static LONG cchTextMost = 0;
static CLIPFORMAT cfTxtObj = 0;
static BOOL fErrSpace = fFalse;
static CHARFORMAT cfDefault =
{
sizeof(CHARFORMAT),
CFM_EFFECTS | CFM_PROTECTED | CFM_SIZE | CFM_OFFSET | CFM_COLOR | CFM_CHARSET | CFM_FACE,
CFE_AUTOCOLOR,// effects
200,// height, 200 twips == 10 points
0,// offset
0,// color (not used since CFE_AUTOCOLOR is specified)
ANSI_CHARSET,
FF_ROMAN,// pitch and family
"Arial"// face name
};
static ASSENSZ rgassenszErrors[] =
{
{EN_ERRSPACE, "Out of memory. Exit some other applications and try again."},
{EN_MAXTEXT, "The maximum text length has been reached."},
{0, NULL}
};
/*
*ITPOLEINPLACEFRAME
*
*Purpose:
*Frame window support for in place editing
*/
typedef struct _itpoleinplaceframe
{
IOleInPlaceFrameVtbl * lpVtbl;// Virtual table
ULONG cRef;// Reference count
REDOC * predoc;// Document
LPOLEINPLACEACTIVEOBJECT pipaobj;// Current active object
}
ITPOLEINPLACEFRAME;
#define PipframeFromPunk(_p) ((ITPOLEINPLACEFRAME *) (_p))
// Functions for ITP in place frame
ITPOLEINPLACEFRAME * ITPOLEINPLACEFRAME_New(REDOC * predoc);
STDMETHODIMP ITPOLEINPLACEFRAME_QueryInterface(LPUNKNOWN punk, REFIID riid,
LPUNKNOWN * ppvObj);
STDMETHODIMP_(ULONG) ITPOLEINPLACEFRAME_AddRef(LPUNKNOWN punk);
STDMETHODIMP_(ULONG) ITPOLEINPLACEFRAME_Release(LPUNKNOWN punk);
STDMETHODIMP ITPOLEINPLACEFRAME_GetWindow(ITPOLEINPLACEFRAME * pipframe,
HWND * phwnd);
STDMETHODIMP ITPOLEINPLACEFRAME_ContextSensitiveHelp(ITPOLEINPLACEFRAME *pipframe,
BOOL fEnterMode);
STDMETHODIMP ITPOLEINPLACEFRAME_GetBorder(ITPOLEINPLACEFRAME * pipframe,
LPRECT prcBorder);
STDMETHODIMP ITPOLEINPLACEFRAME_RequestBorderSpace(ITPOLEINPLACEFRAME * pipframe,
LPCBORDERWIDTHS pbw);
STDMETHODIMP ITPOLEINPLACEFRAME_SetBorderSpace(ITPOLEINPLACEFRAME * pipframe,
LPCBORDERWIDTHS pbw);
STDMETHODIMP ITPOLEINPLACEFRAME_SetActiveObject(ITPOLEINPLACEFRAME * pipframe,
LPOLEINPLACEACTIVEOBJECT pipaobj,
LPCSTR szObjName);
STDMETHODIMP ITPOLEINPLACEFRAME_InsertMenus(ITPOLEINPLACEFRAME * pipframe,
HMENU hmenuShared,
LPOLEMENUGROUPWIDTHS pmgw);
STDMETHODIMP ITPOLEINPLACEFRAME_SetMenu(ITPOLEINPLACEFRAME * pipframe,
HMENU hmenuShared, HOLEMENU holemenu,
HWND hwndActiveObject);
STDMETHODIMP ITPOLEINPLACEFRAME_RemoveMenus(ITPOLEINPLACEFRAME * pipframe,
HMENU hmenuShared);
STDMETHODIMP ITPOLEINPLACEFRAME_SetStatusText(ITPOLEINPLACEFRAME * pipframe,
LPCSTR szStatusText);
STDMETHODIMP ITPOLEINPLACEFRAME_EnableModeless(ITPOLEINPLACEFRAME * pipframe,
BOOL fEnable);
STDMETHODIMP ITPOLEINPLACEFRAME_TranslateAccelerator(ITPOLEINPLACEFRAME *pipframe,
LPMSG pmsg, WORD wID);
// Virtual table for ole in place frame interface
IOleInPlaceFrameVtbl ITPOLEINPLACEFRAME_Vtbl =
{
(LPVOID) ITPOLEINPLACEFRAME_QueryInterface,
(LPVOID) ITPOLEINPLACEFRAME_AddRef,
(LPVOID) ITPOLEINPLACEFRAME_Release,
(LPVOID) ITPOLEINPLACEFRAME_GetWindow,
(LPVOID) ITPOLEINPLACEFRAME_ContextSensitiveHelp,
(LPVOID) ITPOLEINPLACEFRAME_GetBorder,
(LPVOID) ITPOLEINPLACEFRAME_RequestBorderSpace,
(LPVOID) ITPOLEINPLACEFRAME_SetBorderSpace,
(LPVOID) ITPOLEINPLACEFRAME_SetActiveObject,
(LPVOID) ITPOLEINPLACEFRAME_InsertMenus,
(LPVOID) ITPOLEINPLACEFRAME_SetMenu,
(LPVOID) ITPOLEINPLACEFRAME_RemoveMenus,
(LPVOID) ITPOLEINPLACEFRAME_SetStatusText,
(LPVOID) ITPOLEINPLACEFRAME_EnableModeless,
(LPVOID) ITPOLEINPLACEFRAME_TranslateAccelerator
};
/*
*ITPCALL
*
*Purpose:
*Callbacks from the Rich Edit OLE support
*/
typedef struct _itpcall
{
IRichEditOleCallbackVtbl * lpVtbl;// Virtual table
ULONG cRef; // Reference count
REDOC * predoc;// Document
ITPOLEINPLACEFRAME * pipframe;// In place frame object
}
ITPCALL;
#define PitpcallFromPunk(_p) ((ITPCALL *) (_p))
// Functions for ITP callbacks
ITPCALL * ITPCALL_New(REDOC * predoc);
STDMETHODIMP ITPCALL_QueryInterface(LPUNKNOWN punk, REFIID riid,
LPUNKNOWN * ppvObj);
STDMETHODIMP_(ULONG) ITPCALL_AddRef(LPUNKNOWN punk);
STDMETHODIMP_(ULONG) ITPCALL_Release(LPUNKNOWN punk);
STDMETHODIMP ITPCALL_GetNewStorage(ITPCALL * pitpcall, LPSTORAGE FAR * ppstg);
STDMETHODIMP ITPCALL_GetInPlaceContext(ITPCALL * pitpcall,
LPOLEINPLACEFRAME FAR * ppipframe,
LPOLEINPLACEUIWINDOW FAR* ppipuiDoc,
LPOLEINPLACEFRAMEINFO pipfinfo);
STDMETHODIMP ITPCALL_ShowContainerUI(ITPCALL * pitpcall, BOOL fShow);
STDMETHODIMP ITPCALL_QueryInsertObject(ITPCALL * pitpcall, LPCLSID pclsid,
LPSTORAGE pstg, LONG cp);
STDMETHODIMP ITPCALL_DeleteObject(ITPCALL * pitpcall, LPOLEOBJECT poleobj);
STDMETHODIMP ITPCALL_QueryAcceptData(ITPCALL * pitpcall, LPDATAOBJECT pdataobj,
CLIPFORMAT *pcfFormat, DWORD reco, BOOL fReally,
HGLOBAL hMetaPict);
STDMETHODIMP ITPCALL_ContextSensitiveHelp(ITPCALL * pitpcall, BOOL fEnterMode);
STDMETHODIMP ITPCALL_GetClipboardData(ITPCALL *pitpcall, CHARRANGE *pchrg,
DWORD reco, LPDATAOBJECT *ppdataobj);
STDMETHODIMP ITPCALL_GetDragDropEffect(ITPCALL *pitpcall, BOOL fDrag,
DWORD grfKeyState, LPDWORD pdwEffect);
STDMETHODIMP ITPCALL_GetContextMenu(ITPCALL *pitpcall, WORD seltype,
LPOLEOBJECT poleobj, CHARRANGE * pchrg, HMENU * phmenu);
// Virtual table for ITP callbacks
IRichEditOleCallbackVtbl ITPCALL_Vtbl =
{
(LPVOID) ITPCALL_QueryInterface,
(LPVOID) ITPCALL_AddRef,
(LPVOID) ITPCALL_Release,
(LPVOID) ITPCALL_GetNewStorage,
(LPVOID) ITPCALL_GetInPlaceContext,
(LPVOID) ITPCALL_ShowContainerUI,
(LPVOID) ITPCALL_QueryInsertObject,
(LPVOID) ITPCALL_DeleteObject,
(LPVOID) ITPCALL_QueryAcceptData,
(LPVOID) ITPCALL_ContextSensitiveHelp,
(LPVOID) ITPCALL_GetClipboardData,
(LPVOID) ITPCALL_GetDragDropEffect,
(LPVOID) ITPCALL_GetContextMenu
};
LOCAL VOID ParseArguments(LPSTR *pszDoc, LPCSTR szCmdLine);
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam);
LOCAL LRESULT HandleCreate(REDOC *predoc, LPCSTR szCmdLine);
LOCAL VOID ResizeRedoc(REDOC *predoc, RECT rc);
LOCAL VOID SetupMenu(REDOC *predoc, int iMenu, HMENU hmenu);
LOCAL LRESULT HandleCommand(REDOC *predoc, HWND hwnd, WPARAM wparam,
LPARAM lparam);
LOCAL BOOL ToggleCheck(REDOC *predoc, UINT uiMenuid);
LOCAL BOOL QueryCheck(REDOC *predoc, UINT uiMenuid);
LOCAL LRESULT NewREDoc(REDOC *predoc, BOOL fPrompt, BOOL fUpdateUI);
LOCAL LONG CheckSave(REDOC *predoc);
LOCAL INT CheckRevert(REDOC *predoc);
LOCAL LRESULT CloseREDoc(REDOC *predoc, BOOL fPrompt, BOOL fUpdateUI);
DWORD CALLBACK MyRead(DWORD dwCookie, LPBYTE pbBuffer, LONG cb, LONG *pcb);
LOCAL LRESULT OpenREDoc(REDOC *predoc, BOOL fInsert);
LOCAL LRESULT RevertREDoc(REDOC *predoc);
LOCAL DWORD ReadREDoc(REDOC *predoc, LPCSTR szFile, LPCSTR szTitle,
DWORD dwFormat, BOOL fInsert);
DWORD CALLBACK MyWrite(DWORD dwCookie, LPBYTE pbBuffer, LONG cb, LONG *pcb);
LOCAL LRESULT SaveREDoc(REDOC *predoc);
LOCAL LRESULT SaveREDocAs(REDOC *predoc, BOOL fSelect);
LOCAL LRESULT InsertObject(REDOC *predoc);
LOCAL VOID SelectCharFormat(REDOC *predoc);
LOCAL VOID SaveWindowPos(HWND hwnd);
LOCAL BOOL FRestoreWindowPos(WINDOWPLACEMENT *pwndpl);
LOCAL VOID SetAlignment(REDOC *predoc, WORD wAlignment);
LOCAL VOID IndentFirst(REDOC *predoc, BOOL fIndent);
LOCAL VOID ProtectSelection(REDOC *predoc);
LOCAL VOID SetWordWrap(REDOC *predoc, BOOL fWysiwyg, BOOL fWrap);
LOCAL VOID SetupWordWrapMenu(REDOC *predoc);
LOCAL VOID SetOffset(REDOC *predoc, BOOL fSuperscript);
LRESULT CALLBACK PPDlgProc(HWND hdlg, UINT msg, WPARAM wparam, LPARAM lparam);
LOCAL BOOL FPPInit(PRINTPREVIEW *ppp);
LOCAL VOID PPInitDialogSize(PRINTPREVIEW *ppp);
LOCAL VOID PPChangePage(PRINTPREVIEW *ppp, BOOL fPrev);
LOCAL VOID PPPaint(PRINTPREVIEW *ppp);
VOID DoVerb(REDOC * predoc, INT ioleverb);
LOCAL VOID FindReplace(REDOC *predoc, BOOL fReplace);
LOCAL VOID ProcessFindReplace(REDOC *predoc, FINDREPLACE *pfr);
LOCAL BOOL FEnablePaste(VOID);
LOCAL VOID UpdateFormatBar(REDOC *predoc);
LOCAL VOID ShowMargins(REDOC *predoc);
int PASCAL
WinMain(HINSTANCE hinstCurr, HINSTANCE hinstPrev, LPSTR szCmdLine, int nCmdShow)
{
SCODE sc;
MSG msg;
WNDCLASS wndclass;
WINDOWPLACEMENT wndpl;
TCHAR *szDoc = NULL;
REDOC *predoc = NULL;
HACCEL hAccels;
#ifndef NO_OLE
LPOLEINPLACEACTIVEOBJECT pipaobj;
#endif// NO_OLE
LoadLibrary("RichEd32.Dll"); // Load the RichEdit DLL to activate the
// RichEdit classes
wndclass.style = CS_HREDRAW | CS_VREDRAW;
wndclass.lpfnWndProc = WndProc;
wndclass.cbClsExtra = 0;
wndclass.cbWndExtra = sizeof(REDOC *);
wndclass.hInstance = hinstCurr;
wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
wndclass.hbrBackground = (HBRUSH) (COLOR_BACKGROUND + 1);
wndclass.hIcon = LoadIcon(hinstCurr, TEXT("IconApp"));
wndclass.lpszMenuName = NULL;
wndclass.lpszClassName = szAppName;
RegisterClass(&wndclass);
hinst = hinstCurr;
#ifdef TEST_OLE_INITIALIZE
OleInitialize(NULL);
OleUninitialize();
OleInitialize(NULL);
OleUninitialize();
#endif// TEST_OLE_INITIALIZE
OleInitialize(NULL);
sc = OleInitialize(NULL);
if (FAILED(sc))
{
TraceError("OleInitialize failed", sc);
goto done;// If OLE can't be initialized abort.
}
// OleStdInitialize();
// Initialize the format bar class
if(!FInitFormatBarClass(hinst))
{
MessageBoxA(NULL, "Unable to register format bar", NULL,
MB_ICONSTOP | MB_OK);
goto done;
}
hmenuLoaded = LoadMenu(hinstCurr, TEXT("LoadedMenu"));
hmenuFull = LoadMenu(hinstCurr, TEXT("FullMenu"));
msgFindReplace = RegisterWindowMessage(TEXT("commdlg_FindReplace"));
cfTxtObj = RegisterClipboardFormat(TEXT(CF_RETEXTOBJ));
ParseArguments(&szDoc, szCmdLine);
if(fPrint && !szDoc)
goto done;
hwndMain = CreateWindow(szAppName, szAppName,
WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN,
0, 0, 750, 500, NULL, NULL, hinstCurr, szDoc);
if(!hwndMain)
{
MessageBoxA(NULL, "Unable to create main window", NULL, MB_ICONSTOP | MB_OK);
goto done;
}
SideAssert(predoc = (REDOC *) GetWindowLong(hwndMain, 0));
if(!fPrint)
{
if(FRestoreWindowPos(&wndpl))
SetWindowPlacement(hwndMain, &wndpl);
ShowWindow(hwndMain, nCmdShow);
}
hAccels = LoadAccelerators(hinstCurr, "WARPKEYS");
Assert(hAccels);
while(GetMessage(&msg, NULL, 0, 0))
{
# ifndef NO_OLE
// Translate accelerators for possible in place objects
if(predoc->pitpcall && (pipaobj = predoc->pitpcall->pipframe->pipaobj))
pipaobj->lpVtbl->TranslateAccelerator(pipaobj, &msg);
# endif// NO_OLE
if(predoc->hwndRE && TranslateAccelerator(hwndMain, hAccels, &msg))
continue;
if(!hwndFR || !IsDialogMessage(hwndFR, &msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
done:
if(szDoc)
GlobalFreePtr(szDoc);
if(hwndMain)
DestroyWindow(hwndMain);
if(hmenuLoaded)
DestroyMenu(hmenuLoaded);
if(hmenuFull)
DestroyMenu(hmenuFull);
// OleStdUninitialize();
return msg.wParam;
}
LOCAL VOID ParseArguments(LPSTR *pszDoc, LPCSTR szCmdLine)
{
const TCHAR *pch;
*pszDoc = NULL;
pch = szCmdLine - 1;
while(pch)
{
pch++;
if(*pch == TEXT('/') || *pch == '-')
{
pch++;
switch(*pch)
{
case TEXT('p'):
case TEXT('P'):
fPrint = fTrue;
break;
case TEXT('w'):
case TEXT('W'):
pch++;
if(*pch == 'p' || *pch == 'P')
{
pch++;
fWrapDefault = fTrue;
fWysiwygDefault = fTrue;
}
else if(*pch == 'n' || *pch == 'N')
{
pch++;
fWrapDefault = fFalse;
fWysiwygDefault = fFalse;
}
else
{
fWrapDefault = fTrue;
fWysiwygDefault = fFalse;
}
break;
default:
if(*pch >= TEXT('0') && *pch <= TEXT('9') && !cchTextMost)
{
while(*pch >= TEXT('0') && *pch <= TEXT('9'))
{
cchTextMost *= 10;
cchTextMost += *pch++ - TEXT('0');
}
}
break;
}
}
else if(!*pszDoc)
{
while(*pch == TEXT(' '))
pch++;
if(*pch)
{
INT cch;
const TCHAR *pchT;
pchT = _tcschr(pch, TEXT(' '));
if(pchT)
cch = pchT - pch;
else
cch = lstrlen(pch);
*pszDoc = GlobalAllocPtr(GHND, cch + 1);
if(!*pszDoc)
break;
lstrcpyn(*pszDoc, (LPCSTR) pch, cch + 1);
(*pszDoc)[cch] = '\0';
}
}
pch = _tcschr(pch, TEXT(' '));
}
}
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
{
REDOC *predoc = (REDOC *) GetWindowLong(hwnd, 0);
#ifndef NO_OLE
LPOLEINPLACEACTIVEOBJECT pipaobj;
#endif// !NO_OLE
switch(msg)
{
case WM_NCCREATE:
predoc = (REDOC *) GlobalAllocPtr(GHND, sizeof(REDOC));
if(!predoc)
return 0;
SetWindowLong(hwnd, 0, (LONG) predoc);
predoc->hwndParent = hwnd;
#ifndef MAC
predoc->pd.lStructSize = sizeof(PRINTDLG);
predoc->pd.hwndOwner = hwnd;
predoc->pd.Flags = PD_RETURNDEFAULT;
if(!PrintDlg(&predoc->pd) && CommDlgExtendedError())
memset(&predoc->pd, 0, sizeof(PRINTDLG));
#endif
break;
case WM_NCDESTROY:
if(predoc)
{
if(predoc->pfr)
GlobalFreePtr(predoc->pfr);
GlobalFreePtr(predoc);
predoc = NULL;
SetWindowLong(hwnd, 0, 0);
}
break;
case WM_CREATE:
hwndMain = hwnd;// a bit of a cheat...
return HandleCreate(predoc,
(LPCSTR) ((CREATESTRUCT *) lparam)->lpCreateParams);
case WM_DESTROY:
PostQuitMessage(0);
return 0l;
case WM_ACTIVATEAPP:
#ifndef NO_OLE
// Notify in place active object of frame activation
if(predoc->pitpcall && (pipaobj = predoc->pitpcall->pipframe->pipaobj))
{
TraceTag(tagInPlace, "OnFrameWindowActivate(%d)", !!wparam);
pipaobj->lpVtbl->OnFrameWindowActivate(pipaobj, !!wparam);
}
#endif// !NO_OLE
break;
case WM_INITMENU:
if(predoc->hwndRE)
predoc->fUpdateEditMenu = TRUE;
break;
case WM_INITMENUPOPUP:
if(predoc->hwndRE)
SetupMenu(predoc, (int) lparam, (HMENU) wparam);
return 0;
case WM_GETMINMAXINFO:
((MINMAXINFO *) lparam)->ptMinTrackSize = ptMinTrackSize;
return 0;
case WM_COMMAND:
return HandleCommand(predoc, hwnd, wparam, lparam);
case WM_CLOSE:
if(predoc && predoc->hwndRE && CloseREDoc(predoc, fTrue, fFalse) < 0)
return 0;
if(!fPrint)
SaveWindowPos(hwnd);
DestroyWindow(hwnd);
return 0;
case WM_ACTIVATE:
if(predoc->hwndRE && LOWORD(wparam))
{
SetFocus(predoc->hwndRE);
return 0;
}
break;
case WM_SIZE:
if(predoc->hwndFormatBar)
SendMessage(predoc->hwndFormatBar, WM_SIZE, 0, 0);
if(predoc->hwndRE)
{
RECT rc;
GetClientRect(hwnd, &rc);
ResizeRedoc(predoc, rc);
#ifdef DEBUG
SendMessage(predoc->hwndRE, EM_REQUESTRESIZE, 0, 0);
#endif// DEBUG
}
break;
case WM_NOTIFY:
switch(((NMHDR *) lparam)->code)
{
case EN_SELCHANGE:
if(predoc->hwndFormatBar)
UpdateFormatBar(predoc);
return 0;
case EN_PROTECTED:
{
ENPROTECTED *penprotected = (ENPROTECTED *) lparam;
// allow change of protected attribute
if(penprotected->msg == EM_SETCHARFORMAT &&
((CHARFORMAT *) penprotected->lParam)->dwMask & CFM_PROTECTED)
{
return 0;
}
}
MessageBeep(0);
return 1;
case EN_CORRECTTEXT:
{
ENCORRECTTEXT *pct = (ENCORRECTTEXT *) lparam;
if(pct->chrg.cpMost - pct->chrg.cpMin > cchMaxCorrectText)
{
MessageBox(hwndMain,
"You are trying to correct too much text. "
"Decrease the size of your selection.",
"REITP: Correct Text", MB_OK);
return 0;
}
}
return 1;
#ifndef NO_OLE
case EN_DROPFILES:
# ifdef DEBUG
if(!QueryCheck(predoc, IDM_IGNOREDROPS))
return fFalse;
TraceTag(tagGeneral, "Ignoring drop of %d file(s) at position %d",
DragQueryFile(((ENDROPFILES *) lparam)->hDrop, (UINT) -1,
NULL, 0),
((ENDROPFILES *) lparam)->cp);
// ignore file drops
return fTrue;
# else// DEBUG
return ((ENDROPFILES *) lparam)->fProtected;
# endif// DEBUG, else
#endif// !NO_OLE
#ifdef DEBUG
case EN_MSGFILTER:
{
MSGFILTER *pmsgfilter = (MSGFILTER *) lparam;
// eat left button downs and 'e's
return (pmsgfilter->msg == WM_LBUTTONDOWN) ||
((pmsgfilter->msg == WM_CHAR) &&
(pmsgfilter->wParam == 'e'));
}
case EN_REQUESTRESIZE:
ResizeRedoc(predoc, ((REQRESIZE *) lparam)->rc);
return 0;
#endif// DEBUG
}
break;
default:
if(msg != msgFindReplace)
break;
if(((FINDREPLACE *) lparam)->Flags & FR_DIALOGTERM)
{
hwndFR = 0;
SendMessage(predoc->hwndRE, EM_HIDESELECTION, fTrue, fTrue);
return 0;
}
ProcessFindReplace(predoc, (FINDREPLACE *) lparam);
return 0;
}
return DefWindowProc(hwnd, msg, wparam, lparam);
}
LOCAL LRESULT HandleCreate(REDOC *predoc, LPCSTR szFile)
{
DWORD dwError;
if(!szFile || !*szFile)
goto no_file;
if((dwError = ReadREDoc(predoc, szFile, NULL, 0, FALSE)))
{
TCHAR szErr[300];
wsprintf(szErr, TEXT("Error opening %s [%ld]"), szFile, dwError);
MessageBoxA(hwndMain, szErr, NULL, MB_OK);
goto no_file;
}
if(fPrint)
{
PrintREDoc(predoc);
PostQuitMessage(0);
}
else
{
TCHAR szT[256];
wsprintf(szT, szFmtTitle, predoc->szTitle);
SetWindowText(predoc->hwndParent, szT);
SetMenu(hwndMain, hmenuFull);
SetupWordWrapMenu(predoc);
DrawMenuBar(hwndMain);
}
#ifdef TIME_OPEN
PostMessage(hwndMain, WM_CLOSE, 0, 0);
#endif// TIME_OPEN
return 0;
no_file:
if(NewREDoc(predoc, fFalse, fTrue) < 0)
{
SetMenu(hwndMain, hmenuLoaded);
}
else
{
SetMenu(hwndMain, hmenuFull);
SetupWordWrapMenu(predoc);
}
DrawMenuBar(hwndMain);
return 0;
}
LOCAL VOID ResizeRedoc(REDOC *predoc, RECT rc)
{
RECT rcParent;
#ifndef NO_OLE
LPOLEINPLACEACTIVEOBJECT pipaobj = NULL;
#endif// NO_OLE
GetClientRect(predoc->hwndParent, &rcParent);
InflateRect(&rcParent, dxRESize, dyRESize);
// If we have a format bar, take it into account
if(predoc->hwndFormatBar)
{
RECT rcFmtBar;
GetClientRect(predoc->hwndFormatBar, &rcFmtBar);
rcParent.top += rcFmtBar.bottom;
}
rc.top = max(rcParent.top, rc.top);
rc.left = max(rcParent.left, rc.left);
rc.right = min(rcParent.right, rc.right);
rc.bottom = max(rc.bottom, rc.top + ptMinTrackSize.y);
rc.bottom = min(rcParent.bottom, rc.bottom);
MoveWindow(predoc->hwndRE, rc.left, rc.top, rc.right - rc.left,
rc.bottom - rc.top, fTrue);
if(GetMenuState(hmenuFull, IDM_SHOWMARGINS, MF_BYCOMMAND) & MF_CHECKED)
{
rc.bottom -= rc.top;
rc.right -= rc.left;
rc.top = 20;
rc.bottom -= 30;
if(rc.bottom < rc.top)
rc.bottom = rc.top;
rc.left = 30;
rc.right -= 30;
if(rc.right < rc.left)
rc.right = rc.left;
SendMessage(predoc->hwndRE, EM_SETRECT, 0, (LPARAM) &rc);
}
// Notify in place active object of resize
//
// NOTE : Do not change the following line so that it uses an &&
// operation, this causes the Mac to lock up since the compiler
// apparently checks the second half of an AND regardless of the
// initial half's value.
#ifndef NO_OLE
if(predoc->pitpcall && (pipaobj = predoc->pitpcall->pipframe->pipaobj))
{
TraceTag(tagInPlace, "ResizeBorder");
GetClientRect(hwndMain, &rc);
# ifdef MAC
pipaobj->lpVtbl->ResizeBorder(pipaobj, (RectPtr) &rc,
(LPOLEINPLACEUIWINDOW) predoc->pitpcall->pipframe, TRUE);
// Throw out the mem
# else// MAC
pipaobj->lpVtbl->ResizeBorder(pipaobj, &rc,
(LPOLEINPLACEUIWINDOW) predoc->pitpcall->pipframe, TRUE);
# endif// MAC, else
}
#endif // !NO_OLE
}
LOCAL VOID SetupMenu(REDOC *predoc, int iMenu, HMENU hmenu)
{
DWORD dw;
LPOLEOBJECT poleobj = NULL;
switch(iMenu)
{
case 0:// file
if(!predoc->szFile[0])
dw = 0;
else
dw = (DWORD) SendMessage(predoc->hwndRE, EM_GETMODIFY, 0, 0);
EnableMenuItem(hmenu, IDM_REVERT, dw ? uiMFEnabled : uiMFDisabled);
EnableMenuItem(hmenu, IDM_SAVE, predoc->fReadOnly
? uiMFDisabled : uiMFEnabled);
break;
case 1:// edit
dw = uiMFDisabled;
// see if something can be pasted
// let RichEdit figure out if it's read-only
if(SendMessage(predoc->hwndRE, EM_CANPASTE, 0, 0))
dw = uiMFEnabled;
EnableMenuItem(hmenu, IDM_PASTE, (UINT) dw);
dw = 0;
if(!predoc->fReadOnly)
dw = (DWORD) SendMessage(predoc->hwndRE, EM_CANUNDO, 0, 0);
EnableMenuItem(hmenu, IDM_UNDO, dw ? uiMFEnabled : uiMFDisabled);
//$ REVIEW: use EN_SELCHANGE?
dw = (DWORD) SendMessage(predoc->hwndRE, EM_SELECTIONTYPE, 0, 0);
EnableMenuItem(hmenu, IDM_COPY, dw ? uiMFEnabled : uiMFDisabled);
#ifdef DEBUG
if(predoc->fReadOnly && !QueryCheck(predoc, IDM_ENABLECUTREADONLY))
dw = 0;
EnableMenuItem(hmenu, IDM_CUT, dw ? uiMFEnabled : uiMFDisabled);
if(predoc->fReadOnly)
dw = 0;
#else// DEBUG
if(predoc->fReadOnly)
dw = 0;
EnableMenuItem(hmenu, IDM_CUT, dw ? uiMFEnabled : uiMFDisabled);
#endif// DEBUG, else
EnableMenuItem(hmenu, IDM_DELETE, dw ? uiMFEnabled : uiMFDisabled);
EnableMenuItem(hmenu, IDM_INSOBJ, predoc->fReadOnly
? uiMFDisabled : uiMFEnabled);
EnableMenuItem(hmenu, IDM_REPLACE, predoc->fReadOnly ?
uiMFDisabled : uiMFEnabled);
// That's all we need to do
if(!predoc->fUpdateEditMenu)
break;
#ifndef NO_OLE
// Find out if we have a single object to deal with
if(!(dw ^ SEL_OBJECT))
{
REOBJECT reobj = { 0 };
reobj.cbStruct = sizeof(REOBJECT);
reobj.cp = REO_CP_SELECTION;
if(!predoc->preole->lpVtbl->GetObject(predoc->preole,
REO_IOB_USE_CP, &reobj,
REO_GETOBJ_POLEOBJ))
{
poleobj = reobj.poleobj;
}
}
// Ask OLE to build the menu for us
# ifdef MAC
//$ FUTURE MAC
dw = IDM_OBJECTCONVERT;
# ifdef NEVER
macMenu1 = CheckoutMenu(hmenu, 2);
if(!macMenu1)
DebugStr("\pCheckoutMenu(macMenu1) failed");
macMenu2 = CheckoutMenu(predoc->hmenuVerbs, 2);
if(!macMenu2)
DebugStr("\pCheckoutMenu(macMenu2) failed");
if(!OleUIAddVerbMenu(poleobj,
NULL,// Ask OLE to look up the name for us
macMenu1, predoc->hmenuVerbs, ipos_Object,
TRUE, (short *) &dw))
{
DebugStr("\pOleUIAddVerbMenu failed!");
}
CheckinMenu(hmenu, 2);
CheckinMenu(predoc->hmenuVerbs, 2);
# endif// NEVER
# else// MAC
OleUIAddVerbMenu(poleobj,
NULL,// Ask OLE to look up the name for us
hmenu, ipos_Object, IDM_OBJECTMIN,
0, TRUE, IDM_OBJECTCONVERT, &predoc->hmenuVerbs);
# endif// MAC, else
if(poleobj)
poleobj->lpVtbl->Release(poleobj);
#endif // !NO_OLE
// We don't have to do all this hard work again unless the user leaves the
// menu
predoc->fUpdateEditMenu = FALSE;
break;
case 2:// format
{
BOOL fReadOnly = !!predoc->fReadOnly;
UINT uiSuperscript = MF_UNCHECKED;
UINT uiSubscript = MF_UNCHECKED;
UINT uiProtected = MF_UNCHECKED;
UINT uiLeft = MF_UNCHECKED;
UINT uiCenter = MF_UNCHECKED;
UINT uiRight = MF_UNCHECKED;
UINT uiFirstIndent = MF_UNCHECKED;
UINT uiFirstOutdent = MF_UNCHECKED;
CHARFORMAT cf;
PARAFORMAT pf;
cf.cbSize = sizeof(CHARFORMAT);
pf.cbSize = sizeof(PARAFORMAT);
SendMessage(predoc->hwndRE, EM_GETCHARFORMAT, fTrue, (LPARAM) &cf);
if(cf.yOffset > 0)
uiSuperscript = MF_CHECKED;
else if(cf.yOffset < 0)
uiSubscript = MF_CHECKED;
if(cf.dwEffects & CFE_PROTECTED)
uiProtected = MF_CHECKED;
SendMessage(predoc->hwndRE, EM_GETPARAFORMAT, 0, (LPARAM) &pf);
if(!pf.wAlignment || pf.wAlignment == PFA_LEFT)
uiLeft = MF_CHECKED;
else if(pf.wAlignment == PFA_CENTER)
uiCenter = MF_CHECKED;
else
uiRight = MF_CHECKED;
if(pf.dxOffset < 0)
uiFirstIndent = MF_CHECKED;
else if(pf.dxOffset > 0)
uiFirstOutdent = MF_CHECKED;
CheckMenuItem(hmenu, IDM_SUPERSCRIPT, uiSuperscript);
CheckMenuItem(hmenu, IDM_SUBSCRIPT, uiSubscript);
CheckMenuItem(hmenu, IDM_PROTECTED, uiProtected);
CheckMenuItem(hmenu, IDM_ALIGNLEFT, uiLeft);
CheckMenuItem(hmenu, IDM_ALIGNCENTER, uiCenter);
CheckMenuItem(hmenu, IDM_ALIGNRIGHT, uiRight);
CheckMenuItem(hmenu, IDM_INDENTFIRST, uiFirstIndent);
CheckMenuItem(hmenu, IDM_OUTDENTFIRST, uiFirstOutdent);
EnableMenuItem(hmenu, IDM_CHARFORMAT, fReadOnly
? uiMFDisabled : uiMFEnabled);
EnableMenuItem(hmenu, IDM_SUPERSCRIPT, fReadOnly
? uiMFDisabled : uiMFEnabled);
EnableMenuItem(hmenu, IDM_SUBSCRIPT, fReadOnly
? uiMFDisabled : uiMFEnabled);
EnableMenuItem(hmenu, IDM_ALIGNLEFT, fReadOnly
? uiMFDisabled : uiMFEnabled);
EnableMenuItem(hmenu, IDM_ALIGNCENTER, fReadOnly
? uiMFDisabled : uiMFEnabled);
EnableMenuItem(hmenu, IDM_ALIGNRIGHT, fReadOnly
? uiMFDisabled : uiMFEnabled);
EnableMenuItem(hmenu, IDM_INDENTFIRST, fReadOnly
? uiMFDisabled : uiMFEnabled);
EnableMenuItem(hmenu, IDM_OUTDENTFIRST, fReadOnly
? uiMFDisabled : uiMFEnabled);
}
break;
case 3:// options
{
const DWORD eco = SendMessage(predoc->hwndRE, EM_GETOPTIONS, 0, 0);
UINT uiSelBar = MF_UNCHECKED;
UINT uiAutoWordSel = MF_UNCHECKED;
#ifdef DEBUG
UINT uiReadOnly = MF_UNCHECKED;
UINT uiAutoHScroll = MF_UNCHECKED;
UINT uiAutoVScroll = MF_UNCHECKED;
UINT uiAutoHideSel = MF_UNCHECKED;
#endif// DEBUG
if(eco & ECO_SELECTIONBAR)
uiSelBar = MF_CHECKED;
if(eco & ECO_AUTOWORDSELECTION)
uiAutoWordSel = MF_CHECKED;
#ifdef DEBUG
if(eco & ECO_READONLY)
uiReadOnly = MF_CHECKED;
if(eco & ECO_AUTOHSCROLL)
uiAutoHScroll = MF_CHECKED;
if(eco & ECO_AUTOVSCROLL)
uiAutoVScroll = MF_CHECKED;
if(!(eco & ECO_NOHIDESEL))
uiAutoHideSel = MF_CHECKED;
#endif// DEBUG
CheckMenuItem(hmenu, IDM_SELBAR, uiSelBar);
CheckMenuItem(hmenu, IDM_AUTOWORDSEL, uiAutoWordSel);
#ifdef DEBUG
CheckMenuItem(hmenu, IDM_READONLY, uiReadOnly);
CheckMenuItem(hmenu, IDM_AUTOHSCROLL, uiAutoHScroll);
CheckMenuItem(hmenu, IDM_AUTOVSCROLL, uiAutoVScroll);
CheckMenuItem(hmenu, IDM_AUTOHIDESEL, uiAutoHideSel);
#endif// DEBUG
}
break;
}
}
LOCAL LRESULT HandleCommand(REDOC *predoc, HWND hwnd, WPARAM wparam,
LPARAM lparam)
{
LRESULT lres = 0;
INTnID;
if(GET_WM_COMMAND_HWND(wparam, lparam) == predoc->hwndRE && predoc->hwndRE)
{
WORD wNotification = GET_WM_COMMAND_CMD(wparam, lparam);
ASSENSZ *passensz;
switch(wNotification)
{
case EN_CHANGE:
if(predoc->hwndFormatBar)
UpdateFormatBar(predoc);
break;
case EN_ERRSPACE:
if(fErrSpace)
break;
fErrSpace = fTrue;
// fall through to default
default:
for(passensz = rgassenszErrors; passensz->szDescription; passensz++)
{
if(passensz->wNotification == wNotification)
{
MessageBeep(0);
MessageBoxA(hwndMain, passensz->szDescription, NULL,
MB_ICONSTOP | MB_OK);
return 0;
}
}
break;
}
return 0;
}
fErrSpace = fFalse;
nID = GET_WM_COMMAND_ID(wparam, lparam);
switch(nID)
{
#ifdef DEBUG
case IDM_CLSDBG:
ClearDebugScreen();
break;
case IDM_TRACEDLG:
DoTagsDialog();
break;
#endif// DEBUG
case IDM_NEW:
lres = NewREDoc(predoc, fTrue, fTrue);
#ifdef DEBUG
if(predoc->hwndRE)
SendMessage(predoc->hwndRE, EM_REQUESTRESIZE, 0, 0);
#endif// DEBUG
break;
case IDM_OPEN:
lres = OpenREDoc(predoc, FALSE);
break;
case IDM_REVERT:
lres = RevertREDoc(predoc);
break;
case IDM_PRINT:
PrintREDoc(predoc);
break;
case IDM_PRINTPREVIEW:
DialogBoxParam(HinstFromHwnd(hwndMain), TEXT("PRINTPREVIEW"), hwndMain,
(DLGPROC) PPDlgProc, (LPARAM) predoc);
break;
case IDM_PRINTSETUP:
predoc->pd.lStructSize = sizeof(PRINTDLG);
predoc->pd.Flags = PD_PRINTSETUP;
if(PrintDlg(&predoc->pd) && predoc->fWysiwyg)
{
// illegal values to force SetWordWrap() to do something
predoc->fWrap = fFalse;
predoc->fWysiwyg = fTrue;
SetWordWrap(predoc, fTrue, fTrue);
}
break;
case IDM_EXIT:
PostMessage(hwndMain, WM_CLOSE, 0, 0);
return 0;
case IDM_CLOSE:
return CloseREDoc(predoc, fTrue, fTrue);
case IDM_SAVE:
lres = SaveREDoc(predoc);
break;
case IDM_SAVEAS:
lres = SaveREDocAs(predoc, FALSE);
break;
case IDM_UNDO:
lres = SendMessage(predoc->hwndRE, EM_UNDO, 0, 0);
break;
case IDM_CUT:
lres = SendMessage(predoc->hwndRE, WM_CUT, 0, 0);
break;
case IDM_COPY:
lres = SendMessage(predoc->hwndRE, WM_COPY, 0, 0);
break;
case IDM_PASTE:
lres = SendMessage(predoc->hwndRE, WM_PASTE, 0, 0);
break;
case IDM_PASTESPECIAL:
NYI("Paste special");
break;
case IDM_DELETE:
lres = SendMessage(predoc->hwndRE, WM_KEYDOWN,
(WPARAM) VK_DELETE, 0);
break;
case IDM_SELECTALL:
lres = SendMessage(predoc->hwndRE, EM_SETSEL, 0, (LPARAM) -1);
break;
case IDM_FIND:
FindReplace(predoc, fFalse);
break;
case IDM_REPLACE:
FindReplace(predoc, fTrue);
break;
case IDM_OBJECT:
NYI("Object");
break;
case IDM_OBJECTCONVERT:
NYI("Object Convert");
break;
case IDM_INSOBJ:
return InsertObject(predoc);
case IDM_INSFILE:
lres = OpenREDoc(predoc, TRUE);
break;
case IDM_SAVESEL:
lres = SaveREDocAs(predoc, TRUE);
break;
case IDM_CHARFORMAT:
SelectCharFormat(predoc);
break;
case IDM_APPLYTOWORD:
predoc->scf = SCF_SELECTION;
if(ToggleCheck(predoc, IDM_APPLYTOWORD))
predoc->scf |= SCF_WORD;
break;
case IDM_SUPERSCRIPT:
SetOffset(predoc, fTrue);
break;
case IDM_SUBSCRIPT:
SetOffset(predoc, fFalse);
break;
case IDM_ALIGNLEFT:
SetAlignment(predoc, PFA_LEFT);
break;
case IDM_ALIGNCENTER:
SetAlignment(predoc, PFA_CENTER);
break;
case IDM_ALIGNRIGHT:
SetAlignment(predoc, PFA_RIGHT);
break;
case IDM_INDENTFIRST:
IndentFirst(predoc, fTrue);
break;
case IDM_OUTDENTFIRST:
IndentFirst(predoc, fFalse);
break;
case IDM_MARGINS:
NYI("set margins");
break;
case IDM_TABS:
NYI("set tabs");
break;
case IDM_PROTECTED:
ProtectSelection(predoc);
break;
case IDM_NOWRAP:
SetWordWrap(predoc, fFalse, fFalse);
break;
case IDM_WRAP:
SetWordWrap(predoc, fFalse, fTrue);
break;
case IDM_WYSIWYG:
SetWordWrap(predoc, fTrue, fTrue);
break;
case IDM_SELBAR:
SendMessage(predoc->hwndRE, EM_SETOPTIONS, ECOOP_XOR, ECO_SELECTIONBAR);
ToggleCheck(predoc, IDM_SELBAR);
break;
case IDM_AUTOWORDSEL:
SendMessage(predoc->hwndRE, EM_SETOPTIONS, ECOOP_XOR, ECO_AUTOWORDSELECTION);
ToggleCheck(predoc, IDM_AUTOWORDSEL);
break;
case IDM_SHOWMARGINS:
ShowMargins(predoc);
break;
#ifdef DEBUG
case IDM_READONLY:
SendMessage(predoc->hwndRE, EM_SETOPTIONS, ECOOP_XOR, ECO_READONLY);
predoc->fReadOnly = !!ToggleCheck(predoc, IDM_READONLY);
EnableWindow(predoc->hwndFormatBar, !predoc->fReadOnly);
break;
case IDM_AUTOHSCROLL:
SendMessage(predoc->hwndRE, EM_SETOPTIONS, ECOOP_XOR, ECO_AUTOHSCROLL);
ToggleCheck(predoc, IDM_AUTOHSCROLL);
break;
case IDM_AUTOVSCROLL:
SendMessage(predoc->hwndRE, EM_SETOPTIONS, ECOOP_XOR, ECO_AUTOVSCROLL);
ToggleCheck(predoc, IDM_AUTOVSCROLL);
break;
case IDM_AUTOHIDESEL:
SendMessage(predoc->hwndRE, EM_SETOPTIONS, ECOOP_XOR, ECO_NOHIDESEL);
ToggleCheck(predoc, IDM_AUTOHIDESEL);
break;
#endif// DEBUG
case IDM_GOTOCURSOR:
{
CHARRANGE cr;
POINT pt;
GetCursorPos(&pt);
ScreenToClient(predoc->hwndRE, &pt);
cr.cpMin = SendMessage(predoc->hwndRE, EM_CHARFROMPOS, 0,
(LPARAM) &pt);
cr.cpMost = cr.cpMin;
SendMessage(predoc->hwndRE, EM_EXSETSEL, 0, (LPARAM) &cr);
}
break;
case IDM_MOVECURSOR:
{
CHARRANGE cr;
POINT pt;
SendMessage(predoc->hwndRE, EM_EXGETSEL, 0, (LPARAM) &cr);
SendMessage(predoc->hwndRE, EM_POSFROMCHAR, (WPARAM) &pt, cr.cpMin);
ClientToScreen(predoc->hwndRE, &pt);
SetCursorPos(pt.x, pt.y);
}
break;
case TBI_IncreaseIndent:
case TBI_DecreaseIndent:
if(predoc->fReadOnly)
{
MessageBeep(0);
}
else
{
PARAFORMAT pf;
pf.cbSize = sizeof(PARAFORMAT);
if(GetFocus() == predoc->hwndFormatBar)
SetFocus(predoc->hwndRE);
pf.dwMask = PFM_OFFSETINDENT;
pf.dxStartIndent = (nID == TBI_IncreaseIndent)
? cxBulletIndent
: -cxBulletIndent;
if(!SendMessage(predoc->hwndRE, EM_SETPARAFORMAT, FALSE,
(LPARAM) &pf))
{
MessageBeep(0);
}
}
break;
case TBI_Name:
case TBI_Size:
case TBI_Bold:
case TBI_Italic:
case TBI_Underline:
case TBI_Color:
{
CHARFORMAT cf;
cf.cbSize = sizeof(CHARFORMAT);
if(GetFocus() == predoc->hwndFormatBar)
SetFocus(predoc->hwndRE);
SendMessage(predoc->hwndFormatBar, EM_GETCHARFORMAT, 0,
(LPARAM) &cf);
SendMessage(predoc->hwndRE, EM_SETCHARFORMAT, predoc->scf,
(LPARAM) &cf);
}
break;
case TBI_AccelBold:
case TBI_AccelItalic:
case TBI_AccelUnderline:
{
CHARFORMAT cf;
DWORD dwEffects;
cf.cbSize = sizeof(CHARFORMAT);
SendMessage(predoc->hwndFormatBar, EM_GETCHARFORMAT, 0,
(LPARAM) &cf);
switch (nID)
{
case TBI_AccelBold:
dwEffects = CFE_BOLD;
break;
case TBI_AccelItalic:
dwEffects = CFE_ITALIC;
break;
case TBI_AccelUnderline:
dwEffects = CFE_UNDERLINE;
break;
}
cf.dwMask |= dwEffects;
cf.dwEffects ^= dwEffects;
if(GetFocus() == predoc->hwndFormatBar)
SetFocus(predoc->hwndRE);
SendMessage(predoc->hwndFormatBar, EM_SETCHARFORMAT, predoc->scf,
(LPARAM) &cf);
SendMessage(predoc->hwndRE, EM_SETCHARFORMAT, predoc->scf,
(LPARAM) &cf);
}
break;
case TBI_Bullet:
case TBI_Left:
case TBI_Center:
case TBI_Right:
{
PARAFORMAT pf;
pf.cbSize = sizeof(PARAFORMAT);
if(GetFocus() == predoc->hwndFormatBar)
SetFocus(predoc->hwndRE);
SendMessage(predoc->hwndFormatBar, EM_GETPARAFORMAT, 0,
(LPARAM) &pf);
SendMessage(predoc->hwndRE, EM_SETPARAFORMAT, FALSE, (LPARAM) &pf);
}
break;
#ifdef DEBUG
case IDM_DBGPED:
SendMessage(predoc->hwndRE, EM_DBGPED, 0, 0);
break;
case IDM_GETTEXT:
return GetText(predoc);
case IDM_IGNORELEFTCLICK:
IgnoreLeftClick(predoc);
break;
case IDM_EATES:
EatEs(predoc);
break;
case IDM_BOTTOMLESS:
Bottomless(predoc);
break;
case IDM_IGNOREDROPS:
case IDM_TEXTONLY:
case IDM_REFUSEGRAPH:
case IDM_PPMETA:
case IDM_ENABLECUTREADONLY:
case IDM_ENABLEPASTEREADONLY:
case IDM_ENABLEDRAGREADONLY:
case IDM_SWAPDRAGEFFECT:
ToggleCheck(predoc, nID);
break;
case IDM_HIDE:
ShowWindow(predoc->hwndRE, ToggleCheck(predoc, IDM_HIDE) ? SW_HIDE : SW_SHOW);
break;
case IDM_PASTEPLAINTEXT:
lres = SendMessage(predoc->hwndRE, EM_PASTESPECIAL, CF_TEXT, 0);
break;
case IDM_PASTETXTOBJ:
lres = SendMessage(predoc->hwndRE, EM_PASTESPECIAL, cfTxtObj, 0);
break;
case IDM_PASTERTFASTEXT:
lres = SendMessage(predoc->hwndRE, EM_PASTESPECIAL, cfRTFAsText, 0);
break;
case IDM_BIGLIMIT:
SetLimit(predoc);
break;
case IDM_FILLERUP:
FillerUp(predoc);
break;
#endif// DEBUG
default:
// Pass through OLE verbs
if(nID >= IDM_OBJECTMIN)
{
DoVerb(predoc, nID - IDM_OBJECTMIN);
}
return DefWindowProc(hwnd, WM_COMMAND, wparam, lparam);
}
return lres;
}
VOID DoVerb(REDOC * predoc, INT ioleverb)
{
REOBJECT reobj = { 0 };
POINT pt;
RECT rc = { 0 };
reobj.cbStruct = sizeof(REOBJECT);
if(predoc->preole->lpVtbl->GetObject(predoc->preole, REO_IOB_SELECTION,
&reobj,
REO_GETOBJ_POLESITE |
REO_GETOBJ_POLEOBJ))
{
AssertSz(FALSE, "DoVerb without object");
}
SendMessage(predoc->hwndRE, EM_POSFROMCHAR, (WPARAM) &pt, reobj.cp);
XformSizeInHimetricToPixels(NULL, &reobj.sizel, &reobj.sizel);
rc.right = (INT) reobj.sizel.cx;
rc.bottom = (INT) reobj.sizel.cy;
OffsetRect(&rc, pt.x, pt.y);
reobj.poleobj->lpVtbl->DoVerb(reobj.poleobj, ioleverb, NULL,
reobj.polesite, 0, predoc->hwndRE, &rc);
reobj.poleobj->lpVtbl->Release(reobj.poleobj);
reobj.polesite->lpVtbl->Release(reobj.polesite);
}
#ifdef DEBUG
LOCAL VOID IgnoreLeftClick(REDOC *predoc)
{
HMENU hmenu = GetMenu(hwndMain);
UINT uiMenuFlags;
DWORD dwMask;
Assert(predoc->hwndRE);
dwMask = SendMessage(predoc->hwndRE, EM_GETEVENTMASK, 0, 0);
uiMenuFlags = GetMenuState(hmenu, IDM_IGNORELEFTCLICK, MF_BYCOMMAND);
if(uiMenuFlags & MF_CHECKED)
dwMask &= ~ENM_MOUSEEVENTS;
else
dwMask |= ENM_MOUSEEVENTS;
uiMenuFlags ^= MF_CHECKED;
CheckMenuItem(hmenu, IDM_IGNORELEFTCLICK, MF_BYCOMMAND |
(uiMenuFlags & MF_CHECKED));
SendMessage(predoc->hwndRE, EM_SETEVENTMASK, 0, dwMask);
}
LOCAL VOID EatEs(REDOC *predoc)
{
HMENU hmenu = GetMenu(hwndMain);
UINT uiMenuFlags;
DWORD dwMask;
Assert(predoc->hwndRE);
dwMask = SendMessage(predoc->hwndRE, EM_GETEVENTMASK, 0, 0);
uiMenuFlags = GetMenuState(hmenu, IDM_EATES, MF_BYCOMMAND);
if(uiMenuFlags & MF_CHECKED)
dwMask &= ~ENM_KEYEVENTS;
else
dwMask |= ENM_KEYEVENTS;
uiMenuFlags ^= MF_CHECKED;
CheckMenuItem(hmenu, IDM_EATES, MF_BYCOMMAND | (uiMenuFlags & MF_CHECKED));
SendMessage(predoc->hwndRE, EM_SETEVENTMASK, 0, dwMask);
}
LOCAL VOID Bottomless(REDOC *predoc)
{
HMENU hmenu = GetMenu(hwndMain);
UINT uiMenuFlags;
DWORD dwMask;
Assert(predoc->hwndRE);
dwMask = SendMessage(predoc->hwndRE, EM_GETEVENTMASK, 0, 0);
uiMenuFlags = GetMenuState(hmenu, IDM_BOTTOMLESS, MF_BYCOMMAND);
if(uiMenuFlags & MF_CHECKED)
dwMask &= ~ENM_REQUESTRESIZE;
else
dwMask |= ENM_REQUESTRESIZE;
uiMenuFlags ^= MF_CHECKED;
CheckMenuItem(hmenu, IDM_BOTTOMLESS,
MF_BYCOMMAND | (uiMenuFlags & MF_CHECKED));
SendMessage(predoc->hwndRE, EM_SETEVENTMASK, 0, dwMask);
if(dwMask & ENM_REQUESTRESIZE)
{
SendMessage(predoc->hwndRE, EM_REQUESTRESIZE, 0, 0);
}
else
{
RECT rc;
GetClientRect(predoc->hwndParent, &rc);
ResizeRedoc(predoc, rc);
}
}
#endif// DEBUG
LOCAL BOOL ToggleCheck(REDOC *predoc, UINT uiMenuid)
{
HMENU hmenu = GetMenu(hwndMain);
UINT uiMenuFlags;
Assert(predoc->hwndRE);
uiMenuFlags = GetMenuState(hmenu, uiMenuid, MF_BYCOMMAND);
uiMenuFlags ^= MF_CHECKED;
CheckMenuItem(hmenu, uiMenuid, MF_BYCOMMAND | (uiMenuFlags & MF_CHECKED));
return !!(uiMenuFlags & MF_CHECKED);
}
LOCAL BOOL QueryCheck(REDOC *predoc, UINT uiMenuid)
{
HMENU hmenu = GetMenu(hwndMain);
UINT uiMenuFlags;
Assert(predoc->hwndRE);
if(!hmenu)
return fFalse;
uiMenuFlags = GetMenuState(hmenu, uiMenuid, MF_BYCOMMAND);
return !!(uiMenuFlags & MF_CHECKED);
}
LOCAL LRESULT NewREDoc(REDOC *predoc, BOOL fPrompt, BOOL fUpdateUI)
{
RECT rc;
DWORD dwStyle;
if(predoc->hwndRE)
{
PARAFORMAT pf = {0};
pf.cbSize = sizeof(PARAFORMAT);
if(fPrompt && CheckSave(predoc) < 0)
return -1;
predoc->szFile[0] = TEXT('\0');
lstrcpy(predoc->szTitle, szUntitled);
SetWindowText(predoc->hwndRE, TEXT(""));
pf.wAlignment = PFA_LEFT;
pf.cTabCount = 1;
pf.rgxTabs[0] = lDefaultTab;
pf.dwMask = PFM_STARTINDENT | PFM_RIGHTINDENT | PFM_OFFSET |
PFM_ALIGNMENT | PFM_TABSTOPS | PFM_NUMBERING;
SendMessage(predoc->hwndRE, EM_SETPARAFORMAT, 0, (LPARAM) &pf);
SendMessage(predoc->hwndRE, EM_SETCHARFORMAT, 0,
(LPARAM) (LPVOID) &cfDefault);
goto done;
}
else
{
predoc->szFile[0] = TEXT('\0');
lstrcpy(predoc->szTitle, szUntitled);
}
GetClientRect(predoc->hwndParent, &rc);
InflateRect(&rc, dxRESize, dyRESize);
// Create and display the format bar
if(predoc->hwndFormatBar = HwndCreateFormatBar(predoc->hwndParent,
FBR_FormatBar, NULL))
{
RECT rcFormatBar;
ShowWindow(predoc->hwndFormatBar, SW_SHOW);
GetClientRect(predoc->hwndFormatBar, &rcFormatBar);
rc.top += rcFormatBar.bottom;
}
#ifdef SUNKENRICHEDIT
dwStyle =
ES_AUTOHSCROLL |
ES_AUTOVSCROLL |
//ES_DISABLENOSCROLL |
ES_MULTILINE |
//ES_NOHIDESEL |
ES_SAVESEL |
ES_SELECTIONBAR |
ES_SUNKEN |
//WS_BORDER |
WS_CHILD |
WS_CLIPCHILDREN |
WS_HSCROLL |
WS_VISIBLE |
WS_VSCROLL |
0;// zero gets or'd with above
predoc->hwndRE = CreateWindow(szClassRE, TEXT(""),
dwStyle,
rc.left, rc.top,
rc.right - rc.left,rc.bottom - rc.top, predoc->hwndParent,
NULL, HinstFromHwnd(predoc->hwndParent), NULL);
#else// SUNKENRICHEDIT
ES_AUTOHSCROLL |
ES_AUTOVSCROLL |
//ES_DISABLENOSCROLL |
ES_MULTILINE |
//ES_NOHIDESEL |
ES_SAVESEL |
ES_SELECTIONBAR |
//ES_SUNKEN |
//WS_BORDER |
WS_CHILD |
WS_CLIPCHILDREN |
WS_HSCROLL |
WS_VISIBLE |
WS_VSCROLL |
0;// zero gets or'd with above
predoc->hwndRE = CreateWindow(szClassRE, TEXT(""),
dwStyle,
rc.left, rc.top,
rc.right - rc.left,rc.bottom - rc.top, predoc->hwndParent,
NULL, HinstFromHwnd(predoc->hwndParent), NULL);
#endif// SUNKENRICHEDIT, else
if(!predoc->hwndRE)
{
MessageBoxA(hwndMain, "Unable to create a new document", NULL, MB_ICONSTOP | MB_OK);
return -1;
}
if(cchTextMost)
SendMessage(predoc->hwndRE, EM_EXLIMITTEXT, 0, cchTextMost);
#ifndef NO_OLE
DragAcceptFiles(predoc->hwndRE, TRUE);
#endif// !NO_OLE
// request EN_SELCHANGE, EN_CHANGE, EN_PROTECTED, and EN_DROPFILES
SendMessage(predoc->hwndRE, EM_SETEVENTMASK, 0,
ENM_SELCHANGE | ENM_CHANGE | ENM_PROTECTED | EN_DROPFILES |
ENM_CORRECTTEXT);
SetFocus(predoc->hwndRE);
predoc->scf = SCF_SELECTION;
if(GetMenu(hwndMain) && QueryCheck(predoc, IDM_APPLYTOWORD))
predoc->scf |= SCF_WORD;
#ifndef NO_OLE
if(!SendMessage(predoc->hwndRE, EM_GETOLEINTERFACE, 0, (LPARAM) &predoc->preole))
{
MessageBoxA(hwndMain, "No OLE interface!", NULL, MB_OK);
DestroyWindow(predoc->hwndRE);
predoc->hwndRE = 0;
return -1;
}
if(!(predoc->pstg = OleStdCreateRootStorage(NULL, STGM_SHARE_EXCLUSIVE)))
{
MessageBoxA(hwndMain, "No Storage!", NULL, MB_OK);
DestroyWindow(predoc->hwndRE);
predoc->hwndRE = 0;
return -1;
}
if(!(predoc->pitpcall = ITPCALL_New(predoc)))
{
MessageBoxA(hwndMain, "No callback object!", NULL, MB_OK);
DestroyWindow(predoc->hwndRE);
predoc->hwndRE = 0;
return -1;
}
SendMessage(predoc->hwndRE, EM_SETOLECALLBACK, 0, (LPARAM) predoc->pitpcall);
#endif// !NO_OLE
done:
if(fUpdateUI)
{
TCHAR szT[64];
wsprintf(szT, szFmtTitle, predoc->szTitle);
SetWindowText(predoc->hwndParent, szT);
SetMenu(hwndMain, hmenuFull);
DrawMenuBar(hwndMain);
}
predoc->fReadOnly = fFalse;
EnableWindow(predoc->hwndFormatBar, TRUE);
// illegal values to force SetWordWrap() to do something
predoc->fWrap = fFalse;
predoc->fWysiwyg = fTrue;
SetWordWrap(predoc, fWysiwygDefault, fWrapDefault);
// if we don't have a default font, use the windows variable width font
// otherwise, use the default font
if(cfDefault.dwMask == 0)
{
SendMessage(predoc->hwndRE, WM_SETFONT,
(WPARAM) GetStockObject(ANSI_VAR_FONT), 0);
SendMessage(predoc->hwndRE, EM_GETCHARFORMAT, FALSE,
(LPARAM) (LPVOID) &cfDefault);
}
else
{
SendMessage(predoc->hwndRE, EM_SETCHARFORMAT, 0,
(LPARAM) (LPVOID) &cfDefault);
}
SendMessage(predoc->hwndRE, EM_SETMODIFY, (WPARAM) fFalse, 0);
SendMessage(predoc->hwndRE, EM_SETREADONLY, (WPARAM) fFalse, 0);
UpdateFormatBar(predoc);
return 0;
}
LOCAL LONG CheckSave(REDOC *predoc)
{
int iMbid;
TCHAR szT[128];
#ifdef NO_SAVE_PROMPT
return 0;
#endif// NO_SAVE_PROMPT
if(!SendMessage(predoc->hwndRE, EM_GETMODIFY, 0, 0))
return 0;
wsprintf(szT, TEXT("Save changes to %s?"), predoc->szTitle);
iMbid = MessageBox(hwndMain, szT, szAppName, MB_APPLMODAL |
MB_ICONQUESTION | MB_YESNOCANCEL);
switch(iMbid)
{
case IDYES:
if(SaveREDoc(predoc) < 0)
return -1;
break;
case IDCANCEL:
return -1;
}
return 0;
}
// returns 0 if no changes have been made
// returns > 0 if revert should continue
// returns < 0 if revert should be aborted
LOCAL INT CheckRevert(REDOC *predoc)
{
int iMbid;
TCHAR szT[128];
if(!SendMessage(predoc->hwndRE, EM_GETMODIFY, 0, 0))
return 0;
#ifdef NO_SAVE_PROMPT
return 1;
#endif// NO_SAVE_PROMPT
wsprintf(szT, TEXT("Revert %s to last saved changes?"), predoc->szTitle);
iMbid = MessageBox(hwndMain, szT, szAppName, MB_APPLMODAL |
MB_ICONQUESTION | MB_YESNO);
return iMbid == IDYES ? 1 : -1;
}
LOCAL LRESULT CloseREDoc(REDOC *predoc, BOOL fPrompt, BOOL fUpdateUI)
{
if(fPrompt && CheckSave(predoc) < 0)
return -1;
if(predoc->hdcTarget)
{
DeleteDC(predoc->hdcTarget);
predoc->hdcTarget = 0;
}
#ifndef NO_OLE
// Deactivate any existing in place object
//$ FUTURE: This might be some generic I'm gonna close you call
predoc->preole->lpVtbl->InPlaceDeactivate(predoc->preole);
ITPCALL_Release((LPUNKNOWN) predoc->pitpcall);
predoc->pitpcall = NULL;
predoc->pstg->lpVtbl->Release(predoc->pstg);
predoc->pstg = NULL;
predoc->preole->lpVtbl->Release(predoc->preole);
predoc->preole = NULL;
predoc->cItem = 0;
#endif// !NO_OLE
DestroyWindow(predoc->hwndRE);
DestroyWindow(predoc->hwndFormatBar);
predoc->hwndRE = 0;
predoc->szFile[0] = TEXT('\0');
lstrcpy(predoc->szTitle, szUntitled);
predoc->dwFormat = SF_TEXT;
predoc->fReadOnly = fFalse;
EnableWindow(predoc->hwndFormatBar, TRUE);
#ifdef DEBUG
CheckMenuItem(hmenuFull, IDM_IGNORELEFTCLICK, MF_BYCOMMAND | MF_UNCHECKED);
CheckMenuItem(hmenuFull, IDM_EATES, MF_BYCOMMAND | MF_UNCHECKED);
CheckMenuItem(hmenuFull, IDM_IGNOREDROPS, MF_BYCOMMAND | MF_UNCHECKED);
CheckMenuItem(hmenuFull, IDM_BOTTOMLESS, MF_BYCOMMAND | MF_UNCHECKED);
CheckMenuItem(hmenuFull, IDM_TEXTONLY, MF_BYCOMMAND | MF_UNCHECKED);
if(hwndGT)
{
DestroyWindow(hwndGT);
hwndGT = 0;
}
#endif// DEBUG
if(fUpdateUI)
{
SetWindowText(predoc->hwndParent, szClosedName);
SetMenu(hwndMain, hmenuLoaded);
DrawMenuBar(hwndMain);
}
return 1;
}
DWORD CALLBACK MyRead(DWORD dwCookie, LPBYTE pbBuffer, LONG cb, LONG *pcb)
{
HFILEhf = (HFILE) dwCookie;
if(hf == HFILE_ERROR)
return (DWORD) E_FAIL;
*pcb = _lread(hf, pbBuffer, cb);
return (DWORD) (*pcb >= 0 ? NOERROR : (*pcb = 0, E_FAIL));
}
// This function gives the Mac version the ability to open and print
// files via Apple Events.
LRESULT DoOpen(predoc, szT, szTitle, fInsert)
REDOC *predoc;
LPSTR szT, szTitle;
BOOL fInsert;
{
DWORD dwError;
if((dwError = ReadREDoc(predoc, szT, szTitle, 0, fInsert)))
goto err;
wsprintf(szT, szFmtTitle, szTitle);
SetWindowText(predoc->hwndParent, szT);
EnableWindow(predoc->hwndFormatBar, !predoc->fReadOnly);
SendMessage(predoc->hwndRE, EM_SETREADONLY, (WPARAM) predoc->fReadOnly, 0);
SetMenu(hwndMain, hmenuFull);
SetupWordWrapMenu(predoc);
DrawMenuBar(hwndMain);
return 0;
err:
wsprintf(szT, TEXT("Error opening document. [%ld]"), dwError);
MessageBox(hwndMain, szT, NULL, MB_OK);
return -1;
}
LOCAL LRESULT OpenREDoc(REDOC *predoc, BOOL fInsert)
{
DWORD dwError;
OPENFILENAME ofn;
TCHAR szTitle[64];
TCHAR szT[256];
if(predoc->hwndRE && !fInsert && CheckSave(predoc) < 0)
return -1;
if(fInsert && predoc->fReadOnly)
return -1;
ofn.lStructSize= sizeof(ofn);
ofn.hInstance= 0;
ofn.lpstrFilter= szFilterLoad;
ofn.lpstrCustomFilter= NULL;
ofn.nMaxCustFilter= 0;
ofn.nFilterIndex= 0;
ofn.lpstrFileTitle= szTitle;
ofn.nMaxFileTitle= sizeof(szTitle);
ofn.lpstrInitialDir= NULL;
ofn.lpstrTitle= fInsert ? "Insert from File" : NULL;
ofn.nFileOffset= 0;
ofn.nFileExtension= 0;
ofn.lpstrDefExt= NULL;
ofn.lCustData= 0L;
ofn.lpfnHook= NULL;
ofn.lpTemplateName= NULL;
ofn.hwndOwner= hwndMain;
ofn.lpstrFile= szT;
ofn.nMaxFile= sizeof(szT);
ofn.Flags= OFN_FILEMUSTEXIST;
szTitle[0] = TEXT('\0');
szT[0] = TEXT('\0');
// Query user for filename for input
if(!GetOpenFileName(&ofn))
{
if((dwError = CommDlgExtendedError()) != 0)
{
wsprintf(szT, TEXT("Error opening document. [%ld]"), dwError);
MessageBox(hwndMain, szT, NULL, MB_OK);
return -1;
}
return 0;
}
predoc->fReadOnly = (ofn.Flags & OFN_READONLY) ? fTrue : fFalse;
EnableWindow(predoc->hwndFormatBar, !predoc->fReadOnly);
return(DoOpen(predoc, szT, szTitle, fInsert));
}
LOCAL LRESULT RevertREDoc(REDOC *predoc)
{
DWORD dwError;
TCHAR szT[256];
if(CheckRevert(predoc) <= 0)
return 0;
lstrcpy(szT, predoc->szFile);
dwError = ReadREDoc(predoc, szT, NULL, predoc->dwFormat, FALSE);
if(!dwError)
return 0;
wsprintf(szT, TEXT("Error reading document. [%ld]"), dwError);
MessageBox(hwndMain, szT, NULL, MB_OK);
return -1;
}
LOCAL DWORD ReadREDoc(REDOC *predoc, LPCSTR szFile, LPCSTR szTitle,
DWORD dwFormat, BOOL fInsert)
{
LONG cch;
HCURSOR hcur;
EDITSTREAM es;
TCHAR szType[cchRTFSig + 1];
hcur = SetCursor(LoadCursor(NULL, IDC_WAIT));
es.dwCookie = (DWORD) _lopen(szFile, OF_READ);
if(es.dwCookie == (DWORD) HFILE_ERROR)
{
return GetLastError();
}
if(!fInsert)
{
// save read-only flag across NewREDoc()
const BOOL fReadOnlySave = predoc->fReadOnly;
if(NewREDoc(predoc, fFalse, fFalse) < 0)
{
_lclose((HFILE) es.dwCookie);
return (DWORD) -1;
}
predoc->fReadOnly = fReadOnlySave;
}
if(dwFormat == 0)// unknown format, figure out what it is
{
UINT cb = cchRTFSig * sizeof(TCHAR);
cb = _lread((HFILE) es.dwCookie, szType, cb);
szType[cb / sizeof(TCHAR)] = TEXT('\0');
if(cb == cchRTFSig * sizeof(TCHAR))
dwFormat = lstrcmpi(szRTFSig, szType) ? SF_TEXT : SF_RTF;
else
dwFormat = SF_TEXT;// not big enough to be RTF, assume text
// move back to the beginning of the file
_llseek((HFILE) es.dwCookie, 0, 0);
}
SendMessage(predoc->hwndRE, WM_SETREDRAW, (WPARAM) fFalse, 0);
es.dwError = 0;
es.pfnCallback = MyRead;
cch = SendMessage(predoc->hwndRE, EM_STREAMIN,
(WPARAM) (fInsert ? dwFormat | SFF_SELECTION : dwFormat),
(LPARAM) &es);
_lclose((HFILE) es.dwCookie);
#ifdef DEBUG
if(predoc->hwndRE)
SendMessage(predoc->hwndRE, EM_REQUESTRESIZE, 0, 0);
#endif// DEBUG
SendMessage(predoc->hwndRE, EM_SETMODIFY, (WPARAM) fFalse, 0);
predoc->dwFormat = dwFormat;
lstrcpy(predoc->szFile, szFile);
if(szTitle)
lstrcpy(predoc->szTitle, szTitle);
else
GetFileTitle(szFile, predoc->szTitle, sizeof(predoc->szTitle));
SendMessage(predoc->hwndRE, WM_SETREDRAW, (WPARAM) fTrue, 0);
InvalidateRect(predoc->hwndRE, NULL, fTrue);
UpdateWindow(predoc->hwndRE);
SetCursor(hcur);
UpdateFormatBar(predoc);
return 0;
}
DWORD CALLBACK MyWrite(DWORD dwCookie, LPBYTE pbBuffer, LONG cb, LONG *pcb)
{
HFILEhf = (HFILE) dwCookie;
if(hf == HFILE_ERROR)
return (DWORD) E_FAIL;
*pcb = _lwrite(hf, pbBuffer, cb);
return (DWORD) (*pcb == cb ? NOERROR : E_FAIL);
}
LOCAL LRESULT SaveREDoc(REDOC *predoc)
{
HCURSOR hcur;
LONG cch;
DWORD dwError;
EDITSTREAM es;
if(!predoc->szFile[0])
return SaveREDocAs(predoc, FALSE);
hcur = SetCursor(LoadCursor(NULL, IDC_WAIT));
es.dwCookie = _lcreat(predoc->szFile, 0);
if(es.dwCookie == (DWORD) HFILE_ERROR)
{
dwError = GetLastError();
goto err;
}
es.dwError = 0;
es.pfnCallback = MyWrite;
cch = SendMessage(predoc->hwndRE, EM_STREAMOUT,(WPARAM) predoc->dwFormat,
(LPARAM) &es);
_lclose((HFILE) es.dwCookie);
SendMessage(predoc->hwndRE, EM_SETMODIFY, (WPARAM) fFalse, 0);
SendMessage(predoc->hwndRE, EM_SETREADONLY, (WPARAM) fFalse, 0);
predoc->fReadOnly = fFalse;
EnableWindow(predoc->hwndFormatBar, TRUE);
SetCursor(hcur);
return 0;
err:
{
TCHAR szT[64];
wsprintf(szT, TEXT("Error saving document. [%ld]"), dwError);
MessageBox(hwndMain, szT, NULL, MB_OK);
}
return -1;
}
LOCAL LRESULT SaveREDocAs(REDOC *predoc, BOOL fSelect)
{
HCURSOR hcur;
LONG cch;
DWORD dwError;
EDITSTREAM es;
OPENFILENAME ofn;
TCHAR szTitle[64];
TCHAR szT[256];
ofn.lStructSize= sizeof(ofn);
ofn.hInstance= 0;
ofn.lpstrFilter= szFilterSave;
ofn.lpstrCustomFilter= NULL;
ofn.nMaxCustFilter= 0;
ofn.nFilterIndex= 0;
ofn.lpstrFileTitle= szTitle;
ofn.nMaxFileTitle= sizeof(szTitle);
ofn.lpstrInitialDir= NULL;
ofn.lpstrTitle= fSelect ? "Save Selection As": NULL;
ofn.nFileOffset= 0;
ofn.nFileExtension= 0;
ofn.lpstrDefExt= NULL;
ofn.lCustData= 0L;
ofn.lpfnHook= NULL;
ofn.lpTemplateName= NULL;
ofn.hwndOwner= hwndMain;
ofn.lpstrFile= szT;
ofn.nMaxFile= sizeof(szT);
ofn.Flags= OFN_CREATEPROMPT | OFN_HIDEREADONLY |
OFN_OVERWRITEPROMPT;
szT[0] = TEXT('\0');
szTitle[0] = TEXT('\0');
// Query user for filename for input
if(!GetSaveFileName(&ofn))
{
if((dwError = CommDlgExtendedError()) != 0)
goto err;
return -1;
}
hcur = SetCursor(LoadCursor(NULL, IDC_WAIT));
es.dwCookie = _lcreat(szT, 0);
if(es.dwCookie == (DWORD) HFILE_ERROR)
{
dwError = GetLastError();
goto err;
}
es.dwError = 0;
es.pfnCallback = MyWrite;
cch = SendMessage(predoc->hwndRE, EM_STREAMOUT,
(WPARAM) (fSelect ? ofn.nFilterIndex | SFF_SELECTION
: ofn.nFilterIndex),
(LPARAM) &es);
_lclose((HFILE) es.dwCookie);
// Don't mark the doc as clean, nor remember format if only selection
if(fSelect)
goto Quit;
SendMessage(predoc->hwndRE, EM_SETMODIFY, (WPARAM) fFalse, 0);
predoc->dwFormat = (DWORD) ofn.nFilterIndex;
predoc->fReadOnly = fFalse;
EnableWindow(predoc->hwndFormatBar, TRUE);
lstrcpy(predoc->szFile, szT);
lstrcpy(predoc->szTitle, szTitle);
wsprintf(szT, szFmtTitle, szTitle);
SetWindowText(predoc->hwndParent, szT);
SendMessage(predoc->hwndRE, EM_SETMODIFY, (WPARAM) fFalse, 0);
SendMessage(predoc->hwndRE, EM_SETREADONLY, (WPARAM) fFalse, 0);
Quit:
SetCursor(hcur);
return 0;
err:
wsprintf(szT, TEXT("Error saving document. [%ld]"), dwError);
MessageBox(hwndMain, szT, NULL, MB_OK);
return -1;
}
LOCAL LRESULT InsertObject(REDOC *predoc)
{
#ifdef NO_OLE
MessageBox(NULL, "Not yet implemented", NULL, MB_OK);
return 0;
#else// NO_OLE
const LPRICHEDITOLE preole = predoc->preole;
LPOLECLIENTSITE polesite = NULL;
LPSTORAGE pstgItem = NULL;
OLEUIINSERTOBJECT ouio = { 0 };
REOBJECT reobj = { 0 };
LPOLEOBJECT poleobj = NULL;
CHAR szFileA[OLEUI_CCHPATHMAX];
WCHAR szItemW[OLEUI_CCHPATHMAX];
DWORD dwRet;
RECT rect;
if(!preole)
return 0;
if(preole->lpVtbl->SetHostNames(preole, "REITP", predoc->szTitle))
{
MessageBoxA(hwndMain, "Can't set host name", NULL, MB_OK);
goto error;
}
if(preole->lpVtbl->GetClientSite(preole, (LPOLECLIENTSITE FAR *) &polesite))
{
MessageBoxA(hwndMain, "No client site!", NULL, MB_OK);
goto error;
}
wsprintfW(szItemW, L"REOBJ%ld", ++predoc->cItem);
if(!(pstgItem = OleStdCreateChildStorage(predoc->pstg, szItemW)))
{
MessageBoxW(hwndMain, szItemW, L"No item storage!", MB_OK);
goto error;
}
szFileA[0] = '\0';
ouio.cbStruct = sizeof(ouio);
ouio.dwFlags = IOF_SHOWHELP | IOF_CREATENEWOBJECT | IOF_CREATEFILEOBJECT |
IOF_CREATELINKOBJECT | IOF_SELECTCREATENEW;
// IOF_VERIFYSERVERSEXIST;
# ifdef MAC// Mac version doesn't have the same members
ouio.pszFile = szFileA;
# else// MAC
ouio.hWndOwner = hwndMain;
ouio.lpszFile = szFileA;
# endif// MAC, else
ouio.lpszCaption = "Insert Object (REITP)";
ouio.cchFile = OLEUI_CCHPATHMAX;
ouio.iid = IID_IOleObject;
ouio.oleRender = OLERENDER_DRAW;
ouio.lpIOleClientSite = polesite;
ouio.lpIStorage = pstgItem;
ouio.ppvObj = (LPVOID FAR *) &poleobj;
ouio.clsid = CLSID_NULL;
if((dwRet = OleUIInsertObject(&ouio)) != OLEUI_SUCCESS)
{
if(dwRet == OLEUI_CANCEL)
goto error;
if(dwRet == OLEUI_IOERR_SCODEHASERROR)
wsprintfA(szFileA, "OleUIInsertObject scode is %lx", ouio.sc);
else
wsprintfA(szFileA, "OleUIInsertObject returned %ld", dwRet);
MessageBoxA(hwndMain, szFileA, NULL, MB_OK);
goto error;
}
AssertSz(ouio.sc == S_OK, "Object wasn't created properly");
reobj.cbStruct = sizeof(REOBJECT);
reobj.clsid = ouio.clsid;
reobj.cp = REO_CP_SELECTION;
reobj.poleobj = poleobj;
reobj.pstg = pstgItem;
reobj.polesite = polesite;
reobj.dvaspect = DVASPECT_CONTENT;
reobj.dwFlags = REO_RESIZABLE;
reobj.dwUser = 0;
if(ouio.dwFlags & IOF_SELECTCREATENEW)
reobj.dwFlags |= REO_BLANK;
//$ Raid 101: RichEdit doesn't setup advises if reobj.clsid == CLSID_NULL
// Try our darnest to get a CLSID
if(IsEqualCLSID(&reobj.clsid, &CLSID_NULL) &&
HrGetClassFileA(szFileA, &reobj.clsid))
{
MessageBoxA(hwndMain, "No CLSID, but forging on", "Insert Object",
MB_OK);
}
// Do we want an iconized version ?
if(ouio.dwFlags & IOF_CHECKDISPLAYASICON)
{
BOOLfUpdate;// Can't pass in NULL instead of &this
// OLE call will update dvaspect on success
# ifdef MAC
// NOTE : There presently is no Mac equivalent of the <.hMetaPict>
// member of the tagOleUIInsertObject structure. This is certainly
// a problem. For now just pass in NULL since the Mac routines will
// not try to use this member.
DebugStr("\pBefore OleStdSwitchDisplayAspect() call");
if(OleStdSwitchDisplayAspect(poleobj, &reobj.dvaspect,
DVASPECT_ICON, (Handle) NULL,
TRUE, FALSE, NULL, &fUpdate))
# else// MAC
if(OleStdSwitchDisplayAspect(poleobj, &reobj.dvaspect,
DVASPECT_ICON, ouio.hMetaPict,
TRUE, FALSE, NULL, &fUpdate))
# endif// MAC, else
{
// How much do we care about reporting errors? Alot!! {Mac will have more}
MessageBoxA(hwndMain, "Object couldn't be displayed as an icon.",
"Insert Object", MB_OK);
}
AssertSz(!fUpdate, "We gave it an hMetaPict, should not need updating");
}
// Put the thing in the edit control
if(preole->lpVtbl->InsertObject(preole, &reobj))
{
MessageBoxA(hwndMain, "Object couldn't be inserted",
"Insert object", MB_OK);
goto error;
}
// Do show verb only on new objects
if(ouio.dwFlags & IOF_SELECTCREATENEW)
{
rect.top = rect.left = 0;
rect.bottom = rect.right = 50;
dwRet = (ULONG) poleobj->lpVtbl->DoVerb(poleobj, OLEIVERB_SHOW, NULL,
polesite, 0, hwndMain,
(LPCRECT) &rect);
}
error:
# ifndef MAC
if(ouio.hMetaPict)
OleUIMetafilePictIconFree(ouio.hMetaPict);
# endif// !MAC
if(polesite)
polesite->lpVtbl->Release(polesite);
if(pstgItem)
pstgItem->lpVtbl->Release(pstgItem);
if(poleobj)
poleobj->lpVtbl->Release(poleobj);
return 0;
#endif// NO_OLE, else
}
#ifdef DEBUG
LOCAL LRESULT GetText(REDOC *predoc)
{
HWND hwndEdit;
LONG cch;
TCHAR *pch;
if(!hwndGT)
{
hwndGT = CreateDialog(HinstFromHwnd(hwndMain), TEXT("GETTEXT"),
hwndMain, (DLGPROC) GTDlgProc);
if(!hwndGT)
{
MessageBoxA(hwndMain, "Unable to create dialog", NULL, MB_ICONSTOP | MB_OK);
return 0;
}
}
hwndEdit = GetDlgItem(hwndGT, GTCTRL);
cch = SendMessage(predoc->hwndRE, WM_GETTEXTLENGTH, 0, 0);
# ifdef WIN16
if(cch > 65000)
{
MessageBoxA(hwndMain, "Text too big, truncating", NULL,
MB_ICONSTOP | MB_OK);
cch = 65000;
}
# endif// WIN16
pch = GlobalAllocPtr(GHND, cch + 1);
if(!pch)
{
MessageBoxA(hwndMain, "Not enough memory to hold text", NULL,
MB_ICONSTOP | MB_OK);
return 0;
}
GetWindowText(predoc->hwndRE, pch, (int) cch + 1);
*pch = toupper(*pch);
SetWindowText(hwndEdit, pch);
GlobalFreePtr(pch);
return 0;
}
LRESULT CALLBACK GTDlgProc(HWND hdlg, UINT msg, WPARAM wparam, LPARAM lparam)
{
switch(msg)
{
case WM_INITDIALOG:
return 1;
case WM_SIZE:
MoveWindow(GetDlgItem(hdlg, GTCTRL), 5, 5, LOWORD(lparam)-10,
HIWORD(lparam)-10, TRUE);
return 0;
case WM_CLOSE:
EndDialog(hdlg, 0);
hwndGT = NULL;
return 1;
}
return 0;
}
LOCAL VOID ClearDebugScreen(void)
{
HFILE hf;
hf = _lopen("COM1", OF_WRITE);
if(hf)
{
_lwrite(hf, "\x1B[H\x1B[J", 6);
_lclose(hf);
}
}
#endif// DEBUG
LOCAL VOID SelectCharFormat(REDOC *predoc)
{
LOGFONT lf;
CHOOSEFONT csf = {0};
CHARFORMAT cf;
LONG yPerInch;
HDC hdc;
cf.cbSize = sizeof(CHARFORMAT);
hdc = GetDC(hwndMain);
yPerInch = GetDeviceCaps(hdc, LOGPIXELSY);
ReleaseDC(hwndMain, hdc);
(void) SendMessage(predoc->hwndRE, EM_GETCHARFORMAT, (WPARAM) fTrue,
(LPARAM) &cf);
csf.lStructSize = sizeof(csf);
csf.hwndOwner = hwndMain;
csf.hDC = 0;
csf.lpLogFont = &lf;
csf.Flags = CF_EFFECTS | CF_SCREENFONTS | CF_INITTOLOGFONTSTRUCT |
CF_LIMITSIZE;
csf.nSizeMin = 1;
csf.nSizeMax = yHeightCharPtsMost;
csf.rgbColors = cf.crTextColor;
csf.lpszStyle = NULL;
csf.nFontType = REGULAR_FONTTYPE | SCREEN_FONTTYPE;
lf.lfHeight = -(INT) ((cf.yHeight * yPerInch) / 1440);
lf.lfWidth = 0;
lf.lfEscapement = 0;
lf.lfOrientation = 0;
lf.lfWeight = (cf.dwEffects & CFE_BOLD) ? FW_BOLD : FW_NORMAL;
lf.lfItalic = (cf.dwEffects & CFE_ITALIC) ? fTrue : fFalse;
lf.lfUnderline = (cf.dwEffects & CFE_UNDERLINE) ? fTrue : fFalse;
lf.lfStrikeOut = (cf.dwEffects & CFE_STRIKEOUT) ? fTrue : fFalse;
lf.lfOutPrecision = OUT_DEFAULT_PRECIS;
lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
lf.lfQuality = DRAFT_QUALITY;
lf.lfCharSet = cf.bCharSet;
lf.lfPitchAndFamily = cf.bPitchAndFamily;
_tcscpy(lf.lfFaceName, cf.szFaceName);
if(!ChooseFont(&csf))
return;
cf.cbSize = sizeof(CHARFORMAT);
// don't change read-only bit
cf.dwMask = CFM_SIZE | CFM_EFFECTS | CFM_COLOR | CFM_FACE | CFM_CHARSET;
cf.yHeight = (LONG) csf.iPointSize * 2;
cf.dwEffects = CFM_EFFECTS;
if(lf.lfWeight < FW_BOLD)
cf.dwEffects &= ~CFE_BOLD;
if(!lf.lfItalic)
cf.dwEffects &= ~CFE_ITALIC;
if(!lf.lfUnderline)
cf.dwEffects &= ~CFE_UNDERLINE;
if(!lf.lfStrikeOut)
cf.dwEffects &= ~CFE_STRIKEOUT;
cf.crTextColor = csf.rgbColors;
cf.bCharSet = lf.lfCharSet;
cf.bPitchAndFamily = lf.lfPitchAndFamily;
_tcscpy(cf.szFaceName, lf.lfFaceName);
if(!SendMessage(predoc->hwndRE, EM_SETCHARFORMAT, predoc->scf,
(LPARAM) &cf))
{
MessageBoxA(hwndMain, "Error setting character format", NULL,
MB_ICONSTOP | MB_OK);
}
}
LOCAL VOID SaveWindowPos(HWND hwnd)
{
WINDOWPLACEMENTwndpl;
HKEY hkey;
wndpl.length = sizeof(wndpl);
GetWindowPlacement(hwnd, &wndpl);
if(RegCreateKeyEx(HKEY_CURRENT_USER, szRegKey, 0, szAppName, 0,
KEY_ALL_ACCESS, NULL, &hkey, NULL) == ERROR_SUCCESS)
{
RegSetValueEx(hkey, szRegValue, 0, REG_BINARY, (LPBYTE) &wndpl,
sizeof(wndpl));
RegCloseKey(hkey);
}
}
LOCAL BOOL FRestoreWindowPos(WINDOWPLACEMENT *pwndpl)
{
BOOL fReturn = fFalse;
DWORD cb;
HKEY hkey = 0;
if(RegOpenKeyEx(HKEY_CURRENT_USER, szRegKey, 0, KEY_READ, &hkey)
== ERROR_SUCCESS)
{
cb = sizeof(*pwndpl);
if(RegQueryValueEx(hkey, szRegValue, 0, 0, (LPBYTE) pwndpl,
&cb) == ERROR_SUCCESS)
{
fReturn = (cb == sizeof(*pwndpl));
}
RegCloseKey(hkey);
}
return fReturn;
}
LOCAL VOID SetAlignment(REDOC *predoc, WORD wAlignment)
{
PARAFORMAT pf;
pf.cbSize = sizeof(PARAFORMAT);
SendMessage(predoc->hwndRE, EM_GETPARAFORMAT, 0, (LPARAM) &pf);
if(!(pf.dwMask & PFM_ALIGNMENT) || pf.wAlignment != wAlignment)
{
pf.dwMask = PFM_ALIGNMENT;// only change the alignment
pf.wAlignment = wAlignment;
SendMessage(predoc->hwndRE, EM_SETPARAFORMAT, 0, (LPARAM) &pf);
}
}
LOCAL VOID IndentFirst(REDOC *predoc, BOOL fIndent)
{
PARAFORMAT pf;
pf.cbSize = sizeof(PARAFORMAT);
SendMessage(predoc->hwndRE, EM_GETPARAFORMAT, 0, (LPARAM) &pf);
pf.dwMask = PFM_OFFSET | PFM_OFFSETINDENT;
if(fIndent)
{
if(pf.dxOffset < 0)
{
pf.dxStartIndent = pf.dxOffset;
pf.dxOffset = 0;
}
else
{
pf.dxOffset = pf.dxOffset ? -pf.dxOffset : -lDefaultTab;
pf.dxStartIndent = -pf.dxOffset;
}
}
else
{
if(pf.dxOffset < 0)
{
pf.dxStartIndent = pf.dxOffset;
pf.dxOffset = -pf.dxOffset;
}
else
{
pf.dxStartIndent = 0;
pf.dxOffset = pf.dxOffset ? 0 : lDefaultTab;
}
}
SendMessage(predoc->hwndRE, EM_SETPARAFORMAT, 0, (LPARAM) &pf);
}
LOCAL VOID ProtectSelection(REDOC *predoc)
{
CHARFORMAT cf;
cf.cbSize = sizeof(CHARFORMAT);
(void) SendMessage(predoc->hwndRE, EM_GETCHARFORMAT, fTrue, (LPARAM) &cf);
cf.dwMask = CFM_PROTECTED;
cf.dwEffects = cf.dwEffects ^ CFE_PROTECTED;
(void) SendMessage(predoc->hwndRE, EM_SETCHARFORMAT, predoc->scf,
(LPARAM) &cf);
}
LOCAL VOID SetWordWrap(REDOC *predoc, BOOL fWysiwyg, BOOL fWrap)
{
HCURSOR hcur;
HDC hdcDel = predoc->hdcTarget;
LONG xWidth;
if(!fWysiwyg == !predoc->fWysiwyg && !fWrap == !predoc->fWrap)
return;
hcur = SetCursor(LoadCursor(NULL, IDC_WAIT));
if(fWysiwyg)
{
POINT pt;
LPDEVMODE pDevMode;
LPDEVNAMES pDevNames;
if(predoc->pd.lStructSize != sizeof(PRINTDLG))
goto done;// error occured getting default printer
pDevMode = (LPDEVMODE) GlobalLock(predoc->pd.hDevMode);
pDevNames = (LPDEVNAMES) GlobalLock(predoc->pd.hDevNames);
predoc->hdcTarget = CreateIC((LPTSTR) pDevNames +
pDevNames->wDriverOffset,
(LPTSTR) pDevNames + pDevNames->wDeviceOffset,
(LPTSTR) pDevNames + pDevNames->wOutputOffset,
pDevMode);
GlobalUnlock(predoc->pd.hDevNames);
GlobalUnlock(predoc->pd.hDevMode);
if(!predoc->hdcTarget)
goto done;
SetMapMode(predoc->hdcTarget, MM_TEXT);
if(Escape(predoc->hdcTarget, GETPHYSPAGESIZE, 0, NULL, &pt) > 0)
{
const LONG xPerInch = GetDeviceCaps(predoc->hdcTarget, LOGPIXELSX);
xWidth = (pt.x * 1440l) / xPerInch;
// leave 1.25" (1800 twips) margins if that will leave >= 1"
if(xWidth >= 1800 + 1440 + 1800)
xWidth -= 1800 + 1800;
}
else
{
const LONG xPerInch = GetDeviceCaps(predoc->hdcTarget, LOGPIXELSX);
xWidth = (GetDeviceCaps(predoc->hdcTarget, HORZRES) * 1440l) /
xPerInch;
}
}
else
{
predoc->hdcTarget = 0;
xWidth = (LONG) !fWrap;
}
predoc->fWysiwyg = fWysiwyg;
predoc->fWrap = fWrap;
SetupWordWrapMenu(predoc);
SendMessage(predoc->hwndRE, EM_SETTARGETDEVICE,
(WPARAM) predoc->hdcTarget, (LPARAM) xWidth);
if(hdcDel)
DeleteDC(hdcDel);
done:
SetCursor(hcur);
}
LOCAL VOID SetupWordWrapMenu(REDOC *predoc)
{
HMENU hmenu = GetMenu(hwndMain);
CheckMenuItem(hmenu, IDM_NOWRAP,
(!predoc->fWysiwyg && !predoc->fWrap) ? MF_CHECKED : MF_UNCHECKED);
CheckMenuItem(hmenu, IDM_WRAP,
(!predoc->fWysiwyg && predoc->fWrap) ? MF_CHECKED : MF_UNCHECKED);
CheckMenuItem(hmenu, IDM_WYSIWYG,
predoc->fWysiwyg ? MF_CHECKED :MF_UNCHECKED);
}
LOCAL VOID SetOffset(REDOC *predoc, BOOL fSuperscript)
{
CHARFORMAT cf;
cf.cbSize = sizeof(CHARFORMAT);
SendMessage(predoc->hwndRE, EM_GETCHARFORMAT, fTrue, (LPARAM) &cf);
cf.dwMask = CFM_OFFSET;// only change the yOffset
if(fSuperscript)
{
if(cf.yOffset > 0)
cf.yOffset = 0;
else
cf.yOffset = 50;
}
else
{
if(cf.yOffset < 0)
cf.yOffset = 0;
else
cf.yOffset = -50;
}
SendMessage(predoc->hwndRE, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM) &cf);
}
VOID PrintREDoc(REDOC *predoc)
{
LONG cchText;
HCURSOR hcur;
POINT pt;
DOCINFO di;
FORMATRANGE fr;
RECT rc;
cchText = SendMessage(predoc->hwndRE, WM_GETTEXTLENGTH, 0, 0);
predoc->pd.nFromPage = 0;
predoc->pd.nToPage = 0;
predoc->pd.nMinPage = 0;
predoc->pd.nMaxPage = 0;
predoc->pd.nCopies = 1;
predoc->pd.Flags =
PD_NOPAGENUMS | PD_NOSELECTION |
PD_USEDEVMODECOPIES | PD_COLLATE | PD_RETURNDC;
if(!PrintDlg(&predoc->pd))
return;
hcur = SetCursor(LoadCursor(NULL, IDC_WAIT));
di.cbSize = sizeof(DOCINFO);
di.lpszDocName = predoc->szTitle;
di.lpszOutput = NULL;
fr.hdc = predoc->pd.hDC;
fr.hdcTarget = 0;
if(Escape(fr.hdc, GETPHYSPAGESIZE, 0, NULL, &pt) > 0)
{
const LONG xPerInch = GetDeviceCaps(fr.hdc, LOGPIXELSX);
const LONG yPerInch = GetDeviceCaps(fr.hdc, LOGPIXELSY);
rc.left = rc.top = 0;
fr.rcPage.left = fr.rcPage.top = 0;
rc.right = (INT) ((pt.x * 1440l) / xPerInch);
fr.rcPage.right = rc.right;
// leave 1.25" (1800 twips) margins if that will leave >= 1"
if(rc.right >= 1800 + 1440 + 1800)
rc.right -= (rc.left = 1800);
rc.bottom = (INT) ((pt.y * 1440l) / yPerInch);
fr.rcPage.bottom = rc.bottom;
// leave 1" (1440 twips) margins if that will leave >= 1"
if(rc.bottom >= 1440 + 1440 + 1440)
rc.bottom -= (rc.top = 1440);
}
else
{
const LONG xPerInch = GetDeviceCaps(fr.hdc, LOGPIXELSX);
const LONG yPerInch = GetDeviceCaps(fr.hdc, LOGPIXELSY);
rc.left = rc.top = 0;
rc.right = (INT) ((GetDeviceCaps(fr.hdc, HORZRES) * 1440l) /
xPerInch);
rc.bottom = (INT) ((GetDeviceCaps(fr.hdc, VERTRES) * 1440l) /
yPerInch);
fr.rcPage = rc;
}
if(StartDoc(fr.hdc, &di) <= 0)
goto err;
// tell RichEdit not to erase before rendering text
SetBkMode(fr.hdc, TRANSPARENT);
fr.chrg.cpMin = 0;
fr.chrg.cpMost = cchText;
do
{
if(StartPage(fr.hdc) <= 0)
goto abort;
fr.rc = rc;
fr.chrg.cpMin = SendMessage(predoc->hwndRE, EM_FORMATRANGE,
(WPARAM) fTrue, (LPARAM) &fr);
if(EndPage(fr.hdc) <= 0)
goto abort;
} while(fr.chrg.cpMin > 0 && fr.chrg.cpMin < fr.chrg.cpMost);
if(fr.chrg.cpMin >= 0 && EndDoc(fr.hdc) > 0)
{
fr.chrg.cpMin = fr.chrg.cpMost = cchText;
// free up RichEdit's format range info
SendMessage(predoc->hwndRE, EM_FORMATRANGE, 0, 0);
(void) SetCursor(hcur);
return;
}
abort:
(void) AbortDoc(fr.hdc);
err:
fr.chrg.cpMin = fr.chrg.cpMost = cchText;
// free up RichEdit's format range info
SendMessage(predoc->hwndRE, EM_FORMATRANGE, 0, 0);
(void) SetCursor(hcur);
MessageBoxA(hwndMain, "An error occurred while printing", NULL,
MB_ICONSTOP | MB_OK);
}
LRESULT CALLBACK PPDlgProc(HWND hdlg, UINT msg, WPARAM wparam, LPARAM lparam)
{
PRINTPREVIEW * ppp = (PRINTPREVIEW *) GetWindowLong(hdlg, DWL_USER);
switch(msg)
{
case WM_INITDIALOG:
// hide the button we use to tell us where the top left is
ShowWindow(GetDlgItem(hdlg, PSB_TopLeft), SW_HIDE);
ppp = (PRINTPREVIEW *) GlobalAllocPtr(GHND, sizeof(PRINTPREVIEW));
SetWindowLong(hdlg, DWL_USER, (LONG) ppp);
if(!ppp)
{
MessageBoxA(hwndMain,
"Not enough memory for Print Preview window.",
NULL, MB_ICONSTOP | MB_OK);
EndDialog(hdlg, 0);
return 0;
}
ppp->hwndDlg = hdlg;
ppp->predoc = (REDOC *) lparam;
AssertSz(ppp->predoc, "print preview: no redoc");
ppp->cchText = -1;
ppp->ipage = -1;
PPChangePage(ppp, fFalse);
if(ppp->ipage < 0)
{
ppp->fDone = fTrue;// prevent any movement
// bail
PostMessage(hdlg, WM_CLOSE, 0, 0);
return 0;
}
return 1;
case WM_PAINT:
PPPaint(ppp);
break;
case WM_SIZE:
// cause complete redraw
InvalidateRect(hdlg, NULL, fTrue);
break;
#if defined(DEBUG) && defined(CLIPMETA)
case WM_LBUTTONDBLCLK:
if(ppp->hmf)
{
HMETAFILE hmf = 0;
HANDLE hMfp = 0;
METAFILEPICT *pmfp;
if(!OpenClipboard(hwndMain))
break;
EmptyClipboard();
hmf = CopyMetaFile(ppp->hmf, NULL);
if(!hmf)
{
MessageBeep(0);
break;
}
hMfp = GlobalAlloc(GHND | GMEM_DDESHARE, sizeof(METAFILEPICT));
if(!hMfp)
goto err;
pmfp = (METAFILEPICT *) GlobalLock(hMfp);
pmfp->mm = MM_ANISOTROPIC;
pmfp->xExt = (INT) ppp->dxPage;
pmfp->yExt = (INT) ppp->dyPage;
pmfp->hMF = hmf;
GlobalUnlock(hMfp);
SetClipboardData(CF_METAFILEPICT, hMfp);
CloseClipboard();
TraceTag(tagNull, "clipped");
break;
err:
if(hmf)
DeleteMetaFile(hmf);
if(hMfp)
GlobalFree(hMfp);
CloseClipboard();
}
break;
#endif// DEBUG && CLIPMETA
case WM_COMMAND:
switch(GET_WM_COMMAND_ID(wparam, lparam))
{
case PSB_NextPage:
PPChangePage(ppp, fFalse);
break;
case PSB_PrevPage:
PPChangePage(ppp, fTrue);
break;
case PSB_Close:
PostMessage(hdlg, WM_CLOSE, 0, 0);
break;
}
break;
case WM_CLOSE:
if(ppp)
{
// free up RichEdit's format range info
SendMessage(ppp->predoc->hwndRE, EM_FORMATRANGE, 0, 0);
#ifdef DEBUG
if(ppp->hmf)
DeleteMetaFile(ppp->hmf);
#endif// DEBUG
if(ppp->fr.hdc)
{
#ifndef NOBLIT
SelectObject(ppp->fr.hdc, ppp->hbmpOld);
#endif// !NOBLIT
DeleteDC(ppp->fr.hdc);
}
#ifndef NOBLIT
if(ppp->hbmp)
DeleteObject(ppp->hbmp);
#endif// !NOBLIT
if(ppp->fr.hdcTarget)
DeleteDC(ppp->fr.hdcTarget);
GlobalFreePtr(ppp);
}
SetWindowLong(hdlg, DWL_USER, 0);
EndDialog(hdlg, 0);
return 1;
}
return 0;
}
LOCAL BOOL FPPInit(PRINTPREVIEW *ppp)
{
LPDEVMODE pDevMode;
LPDEVNAMES pDevNames;
POINT pt;
#ifndef NOBLIT
ppp->hbmp = ppp->hbmpOld = 0;
#endif// !NOBLIT
ppp->fr.hdc = 0;
ppp->cchText = SendMessage(ppp->predoc->hwndRE, WM_GETTEXTLENGTH, 0, 0);
if(ppp->predoc->pd.lStructSize != sizeof(PRINTDLG))
{
MessageBoxA(hwndMain, "No printer selected.", NULL,
MB_ICONSTOP | MB_OK);
return fFalse;
}
ppp->cpage = 0;
ppp->ipage = -1;// first increment will display page 0
ppp->cpageMost = cpageChunk;
ppp->rgcpPages = (LONG *) GlobalAllocPtr(GHND, cpageChunk * sizeof(LONG));
if(!ppp->rgcpPages)
ppp->cpageMost = 0;
pDevMode = (LPDEVMODE) GlobalLock(ppp->predoc->pd.hDevMode);
pDevNames = (LPDEVNAMES) GlobalLock(ppp->predoc->pd.hDevNames);
ppp->fr.hdcTarget = CreateIC((LPTSTR) pDevNames + pDevNames->wDriverOffset,
(LPTSTR) pDevNames + pDevNames->wDeviceOffset,
(LPTSTR) pDevNames + pDevNames->wOutputOffset,
pDevMode);
GlobalUnlock(ppp->predoc->pd.hDevNames);
GlobalUnlock(ppp->predoc->pd.hDevMode);
if(!ppp->fr.hdcTarget)
goto err;
// does this matter?
SetMapMode(ppp->fr.hdcTarget, MM_TEXT);
if(Escape(ppp->fr.hdcTarget, GETPHYSPAGESIZE, 0, NULL, &pt) > 0)
{
const LONG xPerInch = GetDeviceCaps(ppp->fr.hdcTarget, LOGPIXELSX);
const LONG yPerInch = GetDeviceCaps(ppp->fr.hdcTarget, LOGPIXELSY);
ppp->rc.left = ppp->rc.top = 0;
ppp->dxPage = (pt.x * 1440l) / xPerInch;
ppp->rc.right = (INT) ppp->dxPage;
ppp->fr.rcPage.left = 0;
ppp->fr.rcPage.right = ppp->rc.right;
// leave 1.25" (1800 twips) margins if that will leave >= 1"
if(ppp->rc.right >= 1800 + 1440 + 1800)
ppp->rc.right -= (ppp->rc.left = 1800);
ppp->dyPage = (pt.y * 1440l) / yPerInch;
ppp->rc.bottom = (INT) ppp->dyPage;
ppp->fr.rcPage.top = 0;
ppp->fr.rcPage.bottom = ppp->rc.bottom;
// leave 1" (1440 twips) margins if that will leave >= 1"
if(ppp->rc.bottom >= 1440 + 1440 + 1440)
ppp->rc.bottom -= (ppp->rc.top = 1440);
}
else
{
const LONG xPerInch = GetDeviceCaps(ppp->fr.hdcTarget, LOGPIXELSX);
const LONG yPerInch = GetDeviceCaps(ppp->fr.hdcTarget, LOGPIXELSY);
const LONG dxRes = GetDeviceCaps(ppp->fr.hdcTarget, HORZRES);
const LONG dyRes = GetDeviceCaps(ppp->fr.hdcTarget, VERTRES);
ppp->rc.left = ppp->rc.top = 0;
ppp->dxPage = (dxRes * 1440l) / xPerInch;
ppp->rc.right = (INT) ppp->dxPage;
ppp->dyPage = (dyRes * 1440l) / yPerInch;
ppp->rc.bottom = (INT) ppp->dyPage;
ppp->fr.rcPage = ppp->rc;
}
PPInitDialogSize(ppp);
#ifdef DEBUG
if(!QueryCheck(ppp->predoc, IDM_PPMETA))
#endif// DEBUG
{
HDC hdcT;
#ifdef NOBLIT
hdcT = GetDC(ppp->hwndDlg);
ppp->fr.hdc = CreateCompatibleDC(hdcT);
ReleaseDC(ppp->hwndDlg, hdcT);
if(!ppp->fr.hdc)
goto err;
#else// NOBLIT
LONG xPerInch;
LONG yPerInch;
hdcT = GetDC(ppp->hwndDlg);
SaveDC(hdcT);
SetMapMode(hdcT, MM_TEXT);
xPerInch = GetDeviceCaps(hdcT, LOGPIXELSX);
yPerInch = GetDeviceCaps(hdcT, LOGPIXELSY);
ppp->dxBmp = (INT) ((ppp->dxPage * xPerInch) / 1440l);
ppp->dyBmp = (INT) ((ppp->dyPage * yPerInch) / 1440l);
ppp->fr.hdc = CreateCompatibleDC(hdcT);
ppp->hbmp = CreateCompatibleBitmap(hdcT, ppp->dxBmp, ppp->dyBmp);
RestoreDC(hdcT, -1);
ReleaseDC(ppp->hwndDlg, hdcT);
if(!ppp->fr.hdc)
{
if(ppp->hbmp)
DeleteObject(ppp->hbmp);
ppp->hbmp = 0;
goto err;
}
if(!ppp->hbmp)
goto err;
ppp->hbmpOld = SelectObject(ppp->fr.hdc, ppp->hbmp);
#endif// NOBLIT, else
SetMapMode(ppp->fr.hdc, MM_TEXT);
}
ppp->fr.chrg.cpMin = 0;
ppp->fr.chrg.cpMost = ppp->cchText;
return fTrue;
err:
if(ppp->fr.hdcTarget)
{
DeleteDC(ppp->fr.hdcTarget);
ppp->fr.hdcTarget = 0;
}
if(ppp->fr.hdc)
{
DeleteDC(ppp->fr.hdc);
ppp->fr.hdc = 0;
}
#ifndef NOBLIT
Assert(!ppp->hbmp);
Assert(!ppp->hbmpOld);
#endif// !NOBLIT
MessageBoxA(hwndMain,
"An error occurred while processing the print preview",
NULL, MB_ICONSTOP | MB_OK);
return fFalse;
}
LOCAL VOID PPInitDialogSize(PRINTPREVIEW *ppp)
{
LONG dx;
LONG dy;
LONG numer;
LONG denom;
RECT rc;
dx = GetSystemMetrics(SM_CXFULLSCREEN) - 2 * GetSystemMetrics(SM_CXBORDER);
dy = GetSystemMetrics(SM_CYFULLSCREEN) - 2 * GetSystemMetrics(SM_CYBORDER);
// select initial scale
if(dy * ppp->dxPage > dx * ppp->dyPage)
{
numer = dx;
denom = ppp->dxPage;
}
else
{
numer = dy;
denom = ppp->dyPage;
}
rc.top = 0;
rc.left = 0;
rc.bottom = (INT) ((numer * ppp->dyPage) / denom);
rc.right = (INT) ((numer * ppp->dxPage) / denom);
rc.right += 2 * GetSystemMetrics(SM_CXFRAME);
rc.bottom += GetSystemMetrics(SM_CYCAPTION) + GetSystemMetrics(SM_CYFRAME);
MoveWindow(ppp->hwndDlg, rc.left, rc.top, rc.right, rc.bottom, fTrue);
ShowWindow(ppp->hwndDlg, SW_SHOW);
}
LOCAL VOID PPChangePage(PRINTPREVIEW *ppp, BOOL fPrev)
{
HCURSOR hcur;
TCHAR szCaption[40];
if(ppp->cchText < 0 && !FPPInit(ppp))
return;
if(fPrev)
{
// no page before page zero or no page array so we can't go back
if(ppp->ipage <= 0 || !ppp->rgcpPages)
{
MessageBeep(0);
return;
}
Assert(ppp->ipage - 1 < ppp->cpage);
// backup a page
ppp->fr.chrg.cpMin = ppp->rgcpPages[ppp->ipage - 1];
}
else if(ppp->ipage + 1 >= ppp->cpage)
{
if(ppp->fDone)
{
MessageBeep(0);
return;
}
if(!ppp->rgcpPages)
goto doit;
if(ppp->ipage + 1 >= ppp->cpageMost)
{
LONG *pcp;
pcp = (LONG *) GlobalReAllocPtr(ppp->rgcpPages,
(ppp->cpageMost + cpageChunk) * sizeof(LONG), GHND);
if(!pcp)
{
GlobalFreePtr(ppp->rgcpPages);
ppp->rgcpPages = NULL;
ppp->cpage = ppp->cpageMost = 0;
goto doit;
}
ppp->rgcpPages = pcp;
ppp->cpageMost += cpageChunk;
}
ppp->cpage++;
ppp->rgcpPages[ppp->ipage + 1] = ppp->fr.chrg.cpMin;
}
doit:
hcur = SetCursor(LoadCursor(NULL, IDC_WAIT));
#ifndef NOBLIT
if(ppp->fr.hdc)
{
RECT rc;
rc.top = rc.left = 0;
rc.bottom = ppp->dyBmp;
rc.right = ppp->dxBmp;
// erase the background
SetBkColor(ppp->fr.hdc, GetSysColor(COLOR_WINDOW));
ExtTextOut(ppp->fr.hdc, 0, 0, ETO_OPAQUE, &rc, "", 0, NULL);
// tell RichEdit not to bother erasing the background
SetBkMode(ppp->fr.hdc, TRANSPARENT);
}
#endif// !NOBLIT
#ifdef DEBUG
if(ppp->hmf)
{
// delete any metafile left around from the last page
DeleteMetaFile(ppp->hmf);
ppp->hmf = NULL;
}
if(QueryCheck(ppp->predoc, IDM_PPMETA))
{
AssertSz(!ppp->fr.hdc, "How'd that get there?");
ppp->fr.hdc = CreateMetaFile(NULL);
if(!ppp->fr.hdc)
goto err;
TraceTag(tagEnumMF, "Window Ext = %d, %d", ppp->dxPage, ppp->dyPage);
}
#endif// DEBUG
ppp->fr.rc = ppp->rc;
ppp->fr.chrg.cpMin = SendMessage(ppp->predoc->hwndRE, EM_FORMATRANGE,
(WPARAM) fTrue, (LPARAM) &ppp->fr);
if(!fPrev && ppp->fr.chrg.cpMin >= ppp->fr.chrg.cpMost)
{
// free up RichEdit's format range info
ppp->fr.chrg.cpMin = ppp->fr.chrg.cpMost = ppp->cchText;
SendMessage(ppp->predoc->hwndRE, EM_FORMATRANGE, 0, 0);
// setup for a prev
ppp->fr.chrg.cpMost = ppp->cchText;
// done with all pages, ppp->cpage is the max # of pages
ppp->fDone = fTrue;
}
#ifdef DEBUG
if(QueryCheck(ppp->predoc, IDM_PPMETA))
{
//$ REVIEW: what happens to ppp->fr.hdc if this fails?
ppp->hmf = CloseMetaFile(ppp->fr.hdc);
ppp->fr.hdc = 0;
if(!ppp->hmf)
goto err;
}
#endif// DEBUG
// update the current page number
ppp->ipage += fPrev ? -1 : 1;
EnableWindow(GetDlgItem(ppp->hwndDlg, PSB_PrevPage), ppp->ipage > 0);
EnableWindow(GetDlgItem(ppp->hwndDlg, PSB_NextPage),
!ppp->fDone || ppp->ipage + 1 < ppp->cpage);
wsprintf(szCaption, szFmtPrintPreview, ppp->ipage + 1);
SetWindowText(ppp->hwndDlg, szCaption);
// cause redraw
InvalidateRect(ppp->hwndDlg, NULL, fTrue);
(void) SetCursor(hcur);
return;
#ifdef DEBUG
err:
ppp->fDone = fTrue;
// free up RichEdit's format range info
ppp->fr.chrg.cpMin = ppp->fr.chrg.cpMost = ppp->cchText;
SendMessage(ppp->predoc->hwndRE, EM_FORMATRANGE, 0, 0);
// setup for a prev
ppp->fr.chrg.cpMost = ppp->cchText;
(void) SetCursor(hcur);
MessageBoxA(hwndMain,
"An error occurred while processing the print preview",
NULL, MB_ICONSTOP | MB_OK);
#endif// DEBUG
}
LOCAL VOID PPPaint(PRINTPREVIEW *ppp)
{
HDC hdc;
RECT rc;
RECT rcClient;
PAINTSTRUCT ps;
// if we're iconic, don't bother
if(IsIconic(ppp->hwndDlg))
return;
hdc = BeginPaint(ppp->hwndDlg, &ps);
SaveDC(hdc);
GetClientRect(ppp->hwndDlg, &rcClient);
GetWindowRect(GetDlgItem(ppp->hwndDlg, PSB_TopLeft), &rc);
MapWindowPoints(GetDesktopWindow(), ppp->hwndDlg, (LPPOINT) &rc, 2);
rc.bottom = rc.top + GetSystemMetrics(SM_CYBORDER);
rc.right = rcClient.right;
SetBkColor(hdc, GetSysColor(COLOR_WINDOWFRAME));
ExtTextOut(hdc, rc.left, rc.top, ETO_OPAQUE, &rc, "", 0, NULL);
rc.top = rc.bottom;
rc.bottom = rcClient.bottom;
#ifdef DEBUG
if(ppp->hmf)
{
// erase the background
SetBkColor(hdc, GetSysColor(COLOR_WINDOW));
ExtTextOut(hdc, rc.left, rc.top, ETO_OPAQUE, &rc, "", 0, NULL);
// make the window the same logical size as the page
SetMapMode(hdc, MM_ANISOTROPIC);
SetViewportOrgEx(hdc, rc.left, rc.top, NULL);
TraceTag(tagEnumMF, "Viewport Org = %d, %d", rc.left, rc.top);
SetViewportExtEx(hdc, rc.right - rc.left, rc.bottom - rc.top, NULL);
TraceTag(tagEnumMF, "Viewport Ext = %d, %d", rc.right - rc.left, rc.bottom - rc.top);
if(FFromTag(tagEnumMF))
EnumMetaFile(hdc, ppp->hmf, MFEnumCallback, 0);
PlayMetaFile(hdc, ppp->hmf);
}
else
#endif// DEBUG
if(ppp->ipage >= 0)
{
#ifdef NOBLIT
HDC hdcSave = ppp->fr.hdc;
LONG xPerInch = GetDeviceCaps(hdc, LOGPIXELSX);
LONG yPerInch = GetDeviceCaps(hdc, LOGPIXELSY);
// make the window the same logical size as the page
SetMapMode(hdc, MM_ANISOTROPIC);
SetWindowExtEx(hdc, (ppp->dxPage * xPerInch) / 1440,
(ppp->dyPage * yPerInch) / 1440, NULL);
SetViewportExtEx(hdc, rc.right - rc.left, rc.bottom - rc.top, NULL);
// erase the background
SetBkColor(hdc, GetSysColor(COLOR_WINDOW));
ExtTextOut(hdc, rc.left, rc.top, ETO_OPAQUE, &rc, "", 0, NULL);
// tell RichEdit not to bother erasing the background
SetBkMode(hdc, TRANSPARENT);
ppp->fr.hdc = hdc;
ppp->fr.rc = ppp->rc;
ppp->fr.chrg.cpMin = ppp->rgcpPages[ppp->ipage];
ppp->fr.chrg.cpMin = SendMessage(ppp->predoc->hwndRE, EM_FORMATRANGE,
(WPARAM) fTrue, (LPARAM) &ppp->fr);
ppp->fr.hdc = hdcSave;
#else// NOBLIT
// convert RECT to x,y,dx,dy
rc.right -= rc.left;
rc.bottom -= rc.top;
StretchBlt(hdc, rc.left, rc.top, rc.right, rc.bottom,
ppp->fr.hdc, 0, 0, ppp->dxBmp, ppp->dyBmp, SRCCOPY);
#endif// NOBLIT, else
}
RestoreDC(hdc, -1);
EndPaint(ppp->hwndDlg, &ps);
}
#ifdef DEBUG
int CALLBACK MFEnumCallback(HDC hdc, HANDLETABLE *lpHTable, METARECORD *pmfr,
int nObj, LPARAM lparam)
{
switch(pmfr->rdFunction)
{
case META_SETWINDOWORG:
TraceTag(tagEnumMF, "SetWindowOrg(): %d, %d", (INT) (SHORT) pmfr->rdParm[1], (INT) (SHORT) pmfr->rdParm[0]);
break;
case META_SETVIEWPORTORG:
TraceTag(tagEnumMF, "SetViewportOrg(): %d, %d", (INT) (SHORT) pmfr->rdParm[1], (INT) (SHORT) pmfr->rdParm[0]);
break;
case META_OFFSETWINDOWORG:
TraceTag(tagEnumMF, "OffsetWindowOrg(): %d, %d", (INT) (SHORT) pmfr->rdParm[1], (INT) (SHORT) pmfr->rdParm[0]);
break;
case META_OFFSETVIEWPORTORG:
TraceTag(tagEnumMF, "OffsetViewportOrg(): %d, %d", (INT) (SHORT) pmfr->rdParm[1], (INT) (SHORT) pmfr->rdParm[0]);
break;
case META_SETWINDOWEXT:
TraceTag(tagEnumMF, "SetWindowExt(): %d, %d", (INT) (SHORT) pmfr->rdParm[1], (INT) (SHORT) pmfr->rdParm[0]);
break;
case META_SETVIEWPORTEXT:
TraceTag(tagEnumMF, "SetViewportExt(): %d, %d", (INT) (SHORT) pmfr->rdParm[1], (INT) (SHORT) pmfr->rdParm[0]);
break;
case META_SCALEWINDOWEXT:
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]);
break;
case META_SCALEVIEWPORTEXT:
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]);
break;
case META_SAVEDC:
TraceTag(tagEnumMF, "SaveDC()");
break;
case META_RESTOREDC:
TraceTag(tagEnumMF, "RestoreDC()");
break;
case META_SELECTPALETTE:
TraceTag(tagEnumMF, "Select Palette");
break;
case META_SETMAPMODE:
TraceTag(tagEnumMF, "SetMapMode(): %d", (INT) (SHORT) pmfr->rdParm[0]);
break;
case META_EXTTEXTOUT:
TraceTag(tagEnumMF, "ExtTextOut(): %d, %d", (INT) (SHORT) pmfr->rdParm[1], (INT) (SHORT) pmfr->rdParm[0]);
break;
case META_TEXTOUT:
TraceTag(tagEnumMF, "TextOut(): %d, %d", (INT) (SHORT) pmfr->rdParm[3], (INT) (SHORT) pmfr->rdParm[2]);
break;
case META_LINETO:
TraceTag(tagEnumMF, "LineTo(): %d, %d", (INT) (SHORT) pmfr->rdParm[1], (INT) (SHORT) pmfr->rdParm[0]);
break;
case META_RECTANGLE:
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]);
break;
}
return fTrue;
}
#endif// DEBUG
/*
*I T P C A L L I m p l e m e n t a t i o n
*/
/*
*ITPCALL_New
*
*Purpose:
*Creates a new ITPCALL.
*
*Arguments:
*REDOC *Pointer to the document information.
*
*Returns:
*ITPCALL *The newly created ITPCALL.
*/
ITPCALL * ITPCALL_New(REDOC * predoc)
{
#ifndef NO_OLE
ITPCALL * pitpcall;
if(!(pitpcall = (ITPCALL *) GlobalAllocPtr(GHND, sizeof(ITPCALL))))
goto Error;
pitpcall->lpVtbl = &ITPCALL_Vtbl;
pitpcall->cRef = 1;// Start with one reference
pitpcall->predoc = predoc;
if(!(pitpcall->pipframe = ITPOLEINPLACEFRAME_New(predoc)))
GlobalFreePtr(pitpcall);
else
return pitpcall;
Error:
#endif// !NO_OLE
return NULL;
}
/*
*ITPCALL_QueryInterface
*
*Purpose:
*Returns a pointer to the specified site.
*
*Arguments:
*LPUNKNOWN *Object from which we want an interface.
*REFIIDInterface we want.
*LPUNKNOWN *Interface we return.
*
*Returns:
*HRESULT Error status.
*/
STDMETHODIMP ITPCALL_QueryInterface(LPUNKNOWN punk, REFIID riid,
LPUNKNOWN * ppvObj)
{
SCODE sc = S_OK;
if(IsEqualIID(riid, &IID_IUnknown))
ITPCALL_AddRef(*ppvObj = punk);
else if(IsEqualIID(riid, &IID_IRichEditOleCallback))
ITPCALL_AddRef(*ppvObj = punk);
else
sc = E_NOINTERFACE, *ppvObj = NULL;
return sc;
}
/*
*ITPCALL_AddRef
*
*Purpose:
*Increments reference count on the specified site.
*
*Arguments:
*LPUNKNOWN *Object whose count we want to increment.
*
*Returns:
*ULONGNew value of reference count.
*/
STDMETHODIMP_(ULONG) ITPCALL_AddRef(LPUNKNOWN punk)
{
return ++PitpcallFromPunk(punk)->cRef;
}
/*
*ITPCALL_Release
*
*Purpose:
*Decrements reference count on the specified site. If count is
*decremented to zero, the object is freed.
*
*Arguments:
*LPUNKNOWN *Object whose count we want to decrement.
*
*Returns:
*ULONGNew value of reference count.
*/
STDMETHODIMP_(ULONG) ITPCALL_Release(LPUNKNOWN punk)
{
#ifndef NO_OLE
ITPCALL * pitpcall = PitpcallFromPunk(punk);
ULONG cRef = --pitpcall->cRef;
if(!cRef)
{
// Free stuff we own
if(pitpcall->pipframe)
{
pitpcall->pipframe->lpVtbl->Release((LPOLEINPLACEFRAME)
pitpcall->pipframe);
}
// Free memory allocated for us
GlobalFreePtr(pitpcall);
TraceTag(tagITPCALL, "ITPCALL_Release: freeing the itpcall");
}
AssertSz(cRef >= 0, "ITPCALL_Release: negative cRef");
return cRef;
#endif// !NO_OLE
return (ULONG) NULL;
}
/*
*ITPCALL_GetNewStorage
*
*Purpose:
*Gets storage for a new object.
*
*Arguments:
*ITPCALL *Callback object.
*LPSTORAGE FAR *Where to return storage.
*
*Returns:
*HRESULTError status.
*/
STDMETHODIMP ITPCALL_GetNewStorage(ITPCALL * pitpcall, LPSTORAGE FAR * ppstg)
{
SCODE sc = S_OK;
WCHAR szItemW[OLEUI_CCHPATHMAX];
wsprintfW(szItemW, L"REOBJ%ld", ++pitpcall->predoc->cItem);
if(!(*ppstg = OleStdCreateChildStorage(pitpcall->predoc->pstg, szItemW)))
{
MessageBoxW(hwndMain, szItemW, L"No item storage!", MB_OK);
sc = E_FAIL;
}
return sc;
}
/*
*ITPCALL_GetInPlaceContext
*
*Purpose:
*Gets context information for an in place object.
*
*Arguments:
*ITPCALL *Callback object.
*LPOLEINPLACEFRAME *Frame window object.
*LPOLEINPLACEUIWINDOW *Document window object.
*LPOLEINPLACEFRAMEINFOFrame window information.
*
*Returns:
*HRESULTError status.
*/
STDMETHODIMP ITPCALL_GetInPlaceContext(ITPCALL * pitpcall,
LPOLEINPLACEFRAME FAR * ppipframe,
LPOLEINPLACEUIWINDOW FAR* ppipuiDoc,
LPOLEINPLACEFRAMEINFO pipfinfo)
{
#ifndef NO_OLE
// Return window pointers
*ppipframe = (LPOLEINPLACEFRAME) pitpcall->pipframe;
(VOID) (*ppipframe)->lpVtbl->AddRef(*ppipframe);
*ppipuiDoc = NULL;
// Fill in frame window information
pipfinfo->cb = sizeof(OLEINPLACEFRAMEINFO);
pipfinfo->fMDIApp = FALSE;
pipfinfo->hwndFrame = pitpcall->predoc->hwndParent;
pipfinfo->haccel = (long) NULL;
pipfinfo->cAccelEntries = 0;
#endif// !NO_OLE
return S_OK;
}
/*
*ITPCALL_ShowContainerUI
*
*Purpose:
*Displays or hides REITP's container UI.
*
*Arguments:
*ITPCALL *Callback object.
*BOOL
*
*Returns:
*HRESULTError status.
*/
STDMETHODIMP ITPCALL_ShowContainerUI(ITPCALL * pitpcall, BOOL fShow)
{
TraceTag(tagITPCALL, "ITPCALL_ShowContainerUI(%d)", fShow);
// If we're displaying our UI, show our menus
if(fShow)
ITPOLEINPLACEFRAME_SetMenu(pitpcall->pipframe, NULL, NULL, NULL);
return S_OK;
}
STDMETHODIMP ITPCALL_QueryInsertObject(ITPCALL * pitpcall, LPCLSID pclsid,
LPSTORAGE pstg, LONG cp)
{
#if !defined(NO_OLE) && defined(DEBUG)
LPTSTR szProgID;
if(HrProgIDFromCLSIDA(pclsid, &szProgID))
{
TraceTag(tagITPCALL, "QueryInsertObject(): unknown class id");
}
else
{
SCODE sc = S_OK;
TraceTag(tagITPCALL, "QueryInsertObject(): %s object", szProgID);
if(QueryCheck(pitpcall->predoc, IDM_REFUSEGRAPH) &&
!lstrcmpi(szProgID, "MSGraph"))
{
TraceTag(tagITPCALL, "Refusing object");
sc = S_FALSE;
}
OleStdFreeString((LPSTR) szProgID, NULL);
return sc;
}
#endif// !NO_OLE && DEBUG
return NOERROR;
}
STDMETHODIMP ITPCALL_DeleteObject(ITPCALL * pitpcall, LPOLEOBJECT poleobj)
{
TraceTag(tagITPCALL, "DeleteObject()");
return NOERROR;
}
STDMETHODIMP ITPCALL_QueryAcceptData(ITPCALL * pitpcall, LPDATAOBJECT pdataobj,
CLIPFORMAT *pcfFormat, DWORD reco, BOOL fReally,
HGLOBAL hMetaPict)
{
#if !defined(NO_OLE) && defined(DEBUG)
TraceTag(tagITPCALL, "QueryAcceptData(%s) for %s", fReally ? "really" : "test", (reco == RECO_DROP ? "drop" : (reco == RECO_PASTE ? "paste" : "unknown op")));
if(pitpcall->predoc->fReadOnly)
{
BOOL fDoIt = fFalse;
HRESULT hr;
switch(reco)
{
case RECO_DROP:
fDoIt = QueryCheck(pitpcall->predoc, IDM_ENABLEDRAGREADONLY);
break;
case RECO_PASTE:
fDoIt = QueryCheck(pitpcall->predoc, IDM_ENABLEPASTEREADONLY);
break;
default:
TraceTag(tagNull, "QAD: invalid RECO %lx", reco);
AssertSz(fFalse, "QAD: invalid RECO");
break;
}
if(fDoIt)
{
if(fReally)
{
LPRICHEDITOLE const preole = pitpcall->predoc->preole;
// import that sucker
hr = preole->lpVtbl->ImportDataObject(preole, pdataobj,
*pcfFormat, hMetaPict);
TraceError("IRichEditOle::ImportDataObject", hr);
if(SUCCEEDED(hr))
hr = S_FALSE;// we did it ourselves
}
else
{
// return that we'll import it ourselves
hr = S_FALSE;
}
}
else
{
hr = E_FAIL;
}
TraceError("IPCALL_QueryAcceptData", hr);
return hr;
}
if(QueryCheck(pitpcall->predoc, IDM_TEXTONLY))
{
TraceTag(tagITPCALL, "QueryAcceptData(): asking for text only");
*pcfFormat = CF_TEXT;// accept only text
}
else
{
TraceTag(tagITPCALL, "QueryAcceptData(): delegating back to RichEdit");
}
#endif// !NO_OLE && DEBUG
return NOERROR;
}
STDMETHODIMP ITPCALL_ContextSensitiveHelp(ITPCALL * pitpcall, BOOL fEnterMode)
{
return NOERROR;
}
STDMETHODIMP ITPCALL_GetClipboardData(ITPCALL *pitpcall, CHARRANGE *pchrg,
DWORD reco, LPDATAOBJECT *ppdataobj)
{
#if !defined(NO_OLE) && defined(DEBUG)
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")));
if(pitpcall->predoc->fReadOnly)
{
BOOL fDoIt = fFalse;
switch(reco)
{
case RECO_COPY:
// prevent assert in default case
break;
case RECO_CUT:
fDoIt = QueryCheck(pitpcall->predoc, IDM_ENABLECUTREADONLY);
break;
case RECO_DRAG:
fDoIt = QueryCheck(pitpcall->predoc, IDM_ENABLEDRAGREADONLY);
break;
default:
TraceTag(tagNull, "GCD: invalid RECO %lx", reco);
AssertSz(fFalse, "GCD: invalid RECO");
break;
}
if(fDoIt)
{
LPRICHEDITOLE const preole = pitpcall->predoc->preole;
HRESULT hr;
// delegate to IRichEditOle::GetClipboardData()
*ppdataobj = NULL;
hr = preole->lpVtbl->GetClipboardData(preole, pchrg, reco,
ppdataobj);
TraceError("IRichEditOle::GetClipboardData", hr);
if(SUCCEEDED(hr) && *ppdataobj)
hr = S_FALSE;// we did it ourselves
TraceError("IPCALL_GetClipboardData", hr);
return hr;
}
// go return E_NOTIMPL & let RichEdit deal with it itself
}
#endif// !NO_OLE && DEBUG
// *ppdataobj isn't used if E_NOTIMPL is returned
// so we don't need to set it
// tell RichEdit to do it itself
TraceTag(tagITPCALL, "GetClipboardData(): delegating back to RichEdit");
return E_NOTIMPL;
}
STDMETHODIMP ITPCALL_GetDragDropEffect(ITPCALL *pitpcall, BOOL fDrag,
DWORD grfKeyState, LPDWORD pdwEffect)
{
TraceTag(tagITPCALL, "GetDragDropEffect(%s)", fDrag ? "drag" : "drop");
#ifdef DEBUG
if(QueryCheck(pitpcall->predoc, IDM_SWAPDRAGEFFECT))
{
DWORD dwT;
// strip off move, copy, and link
dwT = *pdwEffect &
~(DWORD) (DROPEFFECT_MOVE | DROPEFFECT_COPY | DROPEFFECT_LINK);
if(!pitpcall->predoc->fReadOnly ||
QueryCheck(pitpcall->predoc, IDM_ENABLEDRAGREADONLY))
{
if(fDrag)
dwT = DROPEFFECT_MOVE | DROPEFFECT_COPY;
else if(grfKeyState & MK_CONTROL)
dwT = DROPEFFECT_MOVE;
else
dwT = DROPEFFECT_COPY;
}
*pdwEffect = dwT;
return NOERROR;
}
#endif// DEBUG
// delegate back to RichEdit
return E_NOTIMPL;
}
STDMETHODIMP ITPCALL_GetContextMenu(ITPCALL *pitpcall, WORD seltype,
LPOLEOBJECT poleobj, CHARRANGE * pchrg, HMENU * phmenu)
{
HMENU hmenu;
HMENU hmenuParent = NULL;
HMENU hmenuVerbs = NULL;
UINT uiT;
TraceTag(tagITPCALL, "GetContextMenu");
hmenuParent = CreatePopupMenu();
if(!hmenuParent)
goto Cleanup;
// Put the verbs on the menu
if(poleobj)
{
OleUIAddVerbMenu(poleobj, NULL, hmenuParent, 0, IDM_OBJECTMIN,
0, TRUE, IDM_OBJECTCONVERT, &hmenuVerbs);
}
// Determine which menu to pass back to RichEdit
*phmenu = hmenu = hmenuVerbs ? hmenuVerbs : hmenuParent;
if(poleobj)
AppendMenu(hmenu, MF_SEPARATOR, 0, NULL);
// Add the cut, copy, paste verbs
uiT = MF_STRING | MF_BYCOMMAND;
uiT |= pchrg->cpMin == pchrg->cpMost ? uiMFDisabled : uiMFEnabled;
AppendMenu(hmenu, uiT, IDM_CUT, "Cut");
AppendMenu(hmenu, uiT, IDM_COPY, "Copy");
uiT = MF_STRING | MF_BYCOMMAND;
uiT |= SendMessage(pitpcall->predoc->hwndRE, EM_CANPASTE, 0, 0)
? uiMFEnabled : uiMFDisabled;
AppendMenu(hmenu, uiT, IDM_PASTE, "Paste");
Cleanup:
if(hmenu == hmenuVerbs && hmenuParent)
DestroyMenu(hmenuParent);
else if(hmenu == hmenuParent && hmenuVerbs)
DestroyMenu(hmenuVerbs);
return S_OK;
}
/*
*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
*/
/*
*ITPOLEINPLACEFRAME_New
*
*Purpose:
*Creates a new ITPOLEINPLACEFRAME.
*
*Arguments:
*REDOC *Pointer to the document information.
*
*Returns:
*ITPOLEINPLACEFRAME *The newly created ITPOLEINPLACEFRAME.
*/
ITPOLEINPLACEFRAME * ITPOLEINPLACEFRAME_New(REDOC * predoc)
{
#ifndef NO_OLE
ITPOLEINPLACEFRAME * pipframe;
if(!(pipframe = (ITPOLEINPLACEFRAME *) GlobalAllocPtr(GHND, sizeof(ITPOLEINPLACEFRAME))))
return NULL;
pipframe->lpVtbl = &ITPOLEINPLACEFRAME_Vtbl;
pipframe->cRef = 1;// Start with one reference
pipframe->predoc = predoc;
return pipframe;
#endif// !NO_OLE
return NULL;
}
/*
*ITPOLEINPLACEFRAME_QueryInterface
*
*Purpose:
*Returns a pointer to the specified site.
*
*Arguments:
*LPUNKNOWN *Object from which we want an interface.
*REFIIDInterface we want.
*LPUNKNOWN *Interface we return.
*
*Returns:
*HRESULTError status.
*/
STDMETHODIMP ITPOLEINPLACEFRAME_QueryInterface(LPUNKNOWN punk, REFIID riid,
LPUNKNOWN * ppvObj)
{
SCODE sc = S_OK;
if(IsEqualIID(riid, &IID_IUnknown) ||
IsEqualIID(riid, &IID_IOleWindow) ||
IsEqualIID(riid, &IID_IOleInPlaceUIWindow) ||
IsEqualIID(riid, &IID_IOleInPlaceFrame))
{
ITPOLEINPLACEFRAME_AddRef(*ppvObj = punk);
}
else
{
sc = E_NOINTERFACE, *ppvObj = NULL;
}
return sc;
}
/*
*ITPOLEINPLACEFRAME_AddRef
*
*Purpose:
*Increments reference count on the specified site.
*
*Arguments:
*LPUNKNOWN *Object whose count we want to increment.
*
*Returns:
*ULONGNew value of reference count.
*/
STDMETHODIMP_(ULONG) ITPOLEINPLACEFRAME_AddRef(LPUNKNOWN punk)
{
return ++PipframeFromPunk(punk)->cRef;
}
/*
*ITPOLEINPLACEFRAME_Release
*
*Purpose:
*Decrements reference count on the specified site. If count is
*decremented to zero, the object is freed.
*
*Arguments:
*LPUNKNOWN *Object whose count we want to decrement.
*
*Returns:
*ULONGNew value of reference count.
*/
STDMETHODIMP_(ULONG) ITPOLEINPLACEFRAME_Release(LPUNKNOWN punk)
{
ITPOLEINPLACEFRAME * pipframe = PipframeFromPunk(punk);
ULONG cRef = --pipframe->cRef;
if(!cRef)
{
// Free memory allocated for us
GlobalFreePtr(pipframe);
TraceTag(tagInPlace, "ITPOLEINPLACEFRAME_Release: freeing the ipframe");
}
AssertSz(cRef >= 0, "ITPOLEINPLACEFRAME_Release: negative cRef");
return cRef;
}
/*
*ITPOLEINPLACEFRAME_GetWindow
*
*Purpose:
*Return the window handle of the app-level window for in place use.
*
*Arguments:
*ITPOLEINPLACESITE *Client site.
*
*Returns:
*HRESULTError status.
*/
STDMETHODIMP ITPOLEINPLACEFRAME_GetWindow(ITPOLEINPLACEFRAME * pipframe,
HWND * phwnd)
{
TraceTag(tagInPlace, "ITPOLEINPLACEFRAME_GetWindow: NYI");
return E_NOTIMPL;
}
/*
*ITPOLEINPLACEFRAME_ContextSensitiveHelp
*
*Purpose:
*Notifies the frame that the object has entered Context Help mode.
*
*Arguments:
*ITPOLEINPLACESITE *Client site.
*
*Returns:
*HRESULTError status.
*/
STDMETHODIMP ITPOLEINPLACEFRAME_ContextSensitiveHelp(ITPOLEINPLACEFRAME *pipframe,
BOOL fEnterMode)
{
TraceTag(tagInPlace, "ITPOLEINPLACEFRAME_ContextSensitiveHelp: NYI");
TraceError("ITPOLEINPLACEFRAME_ContextSensitiveHelp()", E_NOTIMPL);
return E_NOTIMPL;
}
/*
*ITPOLEINPLACEFRAME_GetBorder
*
*Purpose:
*Returns a RECT structure in which the object can put toolbars and
*similar controls while an object is active in place.
*
*Arguments:
*ITPOLEINPLACESITE *Client site.
*
*Returns:
*HRESULTError status.
*/
STDMETHODIMP ITPOLEINPLACEFRAME_GetBorder(ITPOLEINPLACEFRAME * pipframe,
LPRECT prcBorder)
{
TraceTag(tagInPlace, "ITPOLEINPLACEFRAME_GetBorder: NYI");
TraceError("ITPOLEINPLACEFRAME_GetBorder()", E_NOTIMPL);
return E_NOTIMPL;
}
/*
*ITPOLEINPLACEFRAME_RequestBorderSpace
*
*Purpose:
*Determines whether tools can be installed around the objects
*window frame while the object is active in place.
*
*Arguments:
*ITPOLEINPLACESITE *Client site.
*
*Returns:
*HRESULTError status.
*/
STDMETHODIMP ITPOLEINPLACEFRAME_RequestBorderSpace(ITPOLEINPLACEFRAME * pipframe,
LPCBORDERWIDTHS pbw)
{
TraceTag(tagInPlace, "ITPOLEINPLACEFRAME_RequestBorderSpace: NYI");
TraceError("ITPOLEINPLACEFRAME_RequestBorderSpace()", E_NOTIMPL);
return E_NOTIMPL;
}
/*
*ITPOLEINPLACEFRAME_SetBorderSpace
*
*Purpose:
*Allocates space for the border requested in the call to the
*RequestBorderSpace member function.
*
*Arguments:
*ITPOLEINPLACESITE *Client site.
*
*Returns:
*HRESULTError status.
*/
STDMETHODIMP ITPOLEINPLACEFRAME_SetBorderSpace(ITPOLEINPLACEFRAME * pipframe,
LPCBORDERWIDTHS pbw)
{
//$ FUTURE: If NULL, then put our tools back
TraceTag(tagInPlace, "ITPOLEINPLACEFRAME_SetBorderSpace: NYI");
TraceError("ITPOLEINPLACEFRAME_SetBorderSpace()", E_NOTIMPL);
return E_NOTIMPL;
}
/*
*ITPOLEINPLACEFRAME_SetActiveObject
*
*Purpose:
*Called by the object to provide the frame window a direct channel
*of communication with the active in-place object.
*
*Arguments:
*ITPOLEINPLACESITE *Client site.
*
*Returns:
*HRESULTError status.
*/
STDMETHODIMP ITPOLEINPLACEFRAME_SetActiveObject(ITPOLEINPLACEFRAME * pipframe,
LPOLEINPLACEACTIVEOBJECT pipaobj,
LPCSTR szObjName)
{
#ifndef NO_OLE
// Free any existing active object
if(pipframe->pipaobj)
pipframe->pipaobj->lpVtbl->Release(pipframe->pipaobj);
// If we're given an object, AddRef it; update our remembered ipaobj
if(pipaobj)
pipaobj->lpVtbl->AddRef(pipaobj);
pipframe->pipaobj = pipaobj;
TraceTag(tagInPlace, "ITPOLEINPLACEFRAME_SetActiveObject: %s", szObjName ? szObjName : "NULL");
#endif// !NO_OLE
return S_OK;
}
/*
*ITPOLEINPLACEFRAME_InsertMenus
*
*Purpose:
*Called by the object server to allow the container to insert
*its menu groups in the composite menu that will be used during
*the in-place session.
*
*Arguments:
*ITPOLEINPLACESITE *Client site.
*
*Returns:
*HRESULTError status.
*/
STDMETHODIMP ITPOLEINPLACEFRAME_InsertMenus(ITPOLEINPLACEFRAME * pipframe,
HMENU hmenuShared,
LPOLEMENUGROUPWIDTHS pmgw)
{
//$ FUTURE: Do something interesting here
// Don't actually put any menus on right now
pmgw->width[0] = pmgw->width[2] = pmgw->width[4] = 0;
TraceTag(tagInPlace, "ITPOLEINPLACEFRAME_InsertMenus: S_OK");
return S_OK;
}
/*
*ITPOLEINPLACEFRAME_SetMenu
*
*Purpose:
*Installs the composite menu into the window frame containing
*the object that is being activated in place.
*
*Arguments:
*ITPOLEINPLACESITE *Client site.
*
*Returns:
*HRESULTError status.
*/
STDMETHODIMP ITPOLEINPLACEFRAME_SetMenu(ITPOLEINPLACEFRAME * pipframe,
HMENU hmenuShared, HOLEMENU holemenu,
HWND hwndActiveObject)
{
#ifndef NO_OLE
HWND hwnd = pipframe->predoc->hwndParent;
TraceTag(tagInPlace, "ITPOLEINPLACEFRAME_SetMenu: hMenuShared=%08lx holemenu=%08lx", (DWORD) (LPVOID) hmenuShared, (DWORD) (LPVOID) holemenu);
// Did OLE give us a menu, or leave us to ourselves?
if(hmenuShared && holemenu)
{
// Put the merged menu OLE gave us on our menu bar
SetMenu(hwnd, hmenuShared);
}
else
{
// Put our regular menu on the menu bar
SetMenu(hwnd, hmenuFull);
SetupWordWrapMenu(pipframe->predoc);
}
DrawMenuBar(hwnd);
# ifdef MAC
DebugStr("\pTry calling OleSetMenuDescriptor()");
# else// MAC
// Pass the menu descriptor to OLE
return OleSetMenuDescriptor(holemenu, pipframe->predoc->hwndParent,
hwndActiveObject, (LPOLEINPLACEFRAME) pipframe,
pipframe->pipaobj);
# endif// MAC, else
#endif// !NO_OLE
return S_OK;
}
/*
*ITPOLEINPLACEFRAME_RemoveMenus
*
*Purpose:
*Called by the object server to give the container a chance to
*remove its menu elements from the in-place composite menu.
*
*Arguments:
*ITPOLEINPLACESITE *Client site.
*
*Returns:
*HRESULTError status.
*/
STDMETHODIMP ITPOLEINPLACEFRAME_RemoveMenus(ITPOLEINPLACEFRAME * pipframe,
HMENU hmenuShared)
{
// We didn't put any menus on!
TraceTag(tagInPlace, "ITPOLEINPLACEFRAME_RemoveMenus: S_OK");
return S_OK;
}
/*
*ITPOLEINPLACEFRAME_SetStatusText
*
*Purpose:
*Sets and displays status text about the in-place object in the
*containers frame window status line.
*
*Arguments:
*ITPOLEINPLACESITE *Client site.
*
*Returns:
*HRESULTError status.
*/
STDMETHODIMP ITPOLEINPLACEFRAME_SetStatusText(ITPOLEINPLACEFRAME * pipframe,
LPCSTR szStatusText)
{
TraceTag(tagInPlace, "ITPOLEINPLACEFRAME_SetStatusText: NYI");
TraceError("ITPOLEINPLACEFRAME_SetStatusText()", E_NOTIMPL);
return E_NOTIMPL;
}
/*
*ITPOLEINPLACEFRAME_EnableModeless
*
*Purpose:
*Enables or disables modeless dialogs of the frame.
*
*Arguments:
*ITPOLEINPLACESITE *Client site.
*
*Returns:
*HRESULTError status.
*/
STDMETHODIMP ITPOLEINPLACEFRAME_EnableModeless(ITPOLEINPLACEFRAME * pipframe,
BOOL fEnable)
{
TraceTag(tagInPlace, "ITPOLEINPLACEFRAME_EnableModeless: NYI");
TraceError("ITPOLEINPLACEFRAME_EnableModeless()", E_NOTIMPL);
return E_NOTIMPL;
}
/*
*ITPOLEINPLACEFRAME_TranslateAccelerator
*
*Purpose:
*Translates keystrokes intended for the container frame while
*an object is active in place.
*
*Arguments:
*ITPOLEINPLACESITE *Client site.
*
*Returns:
*HRESULTError status.
*/
STDMETHODIMP ITPOLEINPLACEFRAME_TranslateAccelerator(ITPOLEINPLACEFRAME *pipframe,
LPMSG pmsg, WORD wID)
{
// REITP doesn't have any accelerators!
return S_FALSE;
}
LOCAL VOID FindReplace(REDOC *predoc, BOOL fReplace)
{
FINDREPLACE *pfr;
if(hwndFR)
return;
if(!(pfr = predoc->pfr))
{
pfr = predoc->pfr = (FINDREPLACE * ) GlobalAllocPtr(GHND,
sizeof(FINDREPLACE) + 2 * 80 * sizeof(TCHAR));
if(!predoc->pfr)
return;
}
else
{
memset(pfr, 0, sizeof(FINDREPLACE));
}
SendMessage(predoc->hwndRE, EM_HIDESELECTION, fFalse, fTrue);
pfr->lStructSize = sizeof(FINDREPLACE);
pfr->hwndOwner = predoc->hwndParent;
pfr->Flags = FR_HIDEUPDOWN;
pfr->lpstrFindWhat = (LPSTR) (((BYTE *) pfr) + sizeof(FINDREPLACE));
pfr->lpstrReplaceWith = pfr->lpstrFindWhat + 80;
pfr->wFindWhatLen = 80 * sizeof(TCHAR);
pfr->wReplaceWithLen = 80 * sizeof(TCHAR);
hwndFR = fReplace ? ReplaceText(pfr) : FindText(pfr);
}
LOCAL VOID ProcessFindReplace(REDOC *predoc, FINDREPLACE *pfr)
{
HCURSOR hcur;
LONG cszReplaced = 0;
LONG cpMatch;
CHARRANGE chrgSave;
FINDTEXTEX ft;
SendMessage(predoc->hwndRE, EM_EXGETSEL, 0, (LPARAM) &chrgSave);
ft.chrg.cpMost = -1;// search through end of the text
ft.chrg.cpMin = chrgSave.cpMin;
if(!(pfr->Flags & (FR_REPLACE | FR_REPLACEALL)))
ft.chrg.cpMin = chrgSave.cpMost;
ft.lpstrText = pfr->lpstrFindWhat;
if(pfr->Flags & FR_REPLACEALL)
{
hcur = SetCursor(LoadCursor(NULL, IDC_WAIT));
SendMessage(predoc->hwndRE, EM_HIDESELECTION, fTrue, fFalse);
}
next:
cpMatch = SendMessage(predoc->hwndRE, EM_FINDTEXTEX,
(WPARAM) (pfr->Flags),
(LPARAM) &ft);
if(cpMatch < 0)
{
if(cszReplaced == 0)
{
MessageBoxA(hwndFR,
"The search text is not found.", szAppName, MB_OK);
}
else
{
char rgch[80];
wsprintfA(rgch, "Replaced %ld occurances.", cszReplaced);
MessageBoxA(hwndFR, rgch, szAppName, MB_OK);
}
SetFocus(hwndFR);
goto done;
}
//ft.chrg.cpMin = cpMatch;
//ft.chrg.cpMost = cpMatch + lstrlen(ft.lpstrText);
ft.chrg.cpMin = ft.chrgText.cpMin;
ft.chrg.cpMost = ft.chrgText.cpMost;
SendMessage(predoc->hwndRE, EM_EXSETSEL, 0, (LPARAM) &ft.chrg);
if(((pfr->Flags & FR_REPLACE) && cszReplaced == 0) ||
(pfr->Flags & FR_REPLACEALL))
{
SendMessage(predoc->hwndRE, EM_REPLACESEL, 0,
(LPARAM) pfr->lpstrReplaceWith);
ft.chrg.cpMin = cpMatch + lstrlen(pfr->lpstrReplaceWith);
ft.chrg.cpMost = -1;// search through end of the text
cszReplaced++;
goto next;
}
done:
if(pfr->Flags & FR_REPLACEALL)
{
SetCursor(hcur);
SendMessage(predoc->hwndRE, EM_HIDESELECTION, fFalse, fFalse);
}
}
VOID UpdateFormatBar(REDOC * predoc)
{
CHARFORMAT cf;
PARAFORMAT pf;
cf.cbSize = sizeof(CHARFORMAT);
pf.cbSize = sizeof(PARAFORMAT);
SendMessage(predoc->hwndRE, EM_GETCHARFORMAT, TRUE, (LPARAM) &cf);
SendMessage(predoc->hwndFormatBar, EM_SETCHARFORMAT, 0, (LPARAM) &cf);
SendMessage(predoc->hwndRE, EM_GETPARAFORMAT, FALSE, (LPARAM) &pf);
SendMessage(predoc->hwndFormatBar, EM_SETPARAFORMAT, 0, (LPARAM) &pf);
}
LOCAL VOID ShowMargins(REDOC *predoc)
{
if(ToggleCheck(predoc, IDM_SHOWMARGINS))
{
RECT rc;
GetClientRect(predoc->hwndParent, &rc);
ResizeRedoc(predoc, rc);
}
else
{
SendMessage(predoc->hwndRE, EM_SETRECT, 0, 0);
}
}
# ifdef DEBUG
LOCAL VOID SetLimit(REDOC *predoc)
{
LONG cchLimit = 32767;
if(ToggleCheck(predoc, IDM_BIGLIMIT))
cchLimit = 1024 * (LONG) 1024 - 1;
SendMessage(predoc->hwndRE, EM_EXLIMITTEXT, 0, cchLimit);
}
static TCHAR szText[] = "Once upon a time there was an edit control. "
"This was a happy edit control until some mean evil tester "
"(who shall remain nameless) came along and started beating on "
"the poor little helpless edit control. The edit control bravely "
"faced it's unprovoked attacker, but an edit control can only take "
"so much. One day when it was being ferociously tortured it thought "
"to itself \"What have I ever done to this poor homely creature to "
"deserve this type of punishment?\". It stirred up it's self esteem "
"and stood up and said to the nasty creature \"I am an edit control, "
"hear me roar! I deserve to be treated with dignity and respect!\". "
"The evil little tester was taken aback by the edit control's sudden "
"show of courage, but being the spawn of hell, he dismissed the edit "
"control's declaration and continued his ghastly attacks. The edit "
"control decided that nothing would ever reform this hideous beast "
"imparting terror upon it so he decided to do something about it. "
"The next day when the heathen was preparing to nuke the edit control "
"the edit control jumped out at the beast and ripped it's heart out. "
"The tester stood shocked for a millisecond and then dropped over dead. "
"The end.\r\n\r\n";
LOCAL VOID FillerUp(REDOC *predoc)
{
const LONG cch = lstrlen(szText);
LONG cchAdded;
LONG cchText;
DWORD dwTicks;
SetWindowText(predoc->hwndRE, TEXT(""));
cchText = 0;
(void) GetAsyncKeyState(VK_ESCAPE);// reset key state
dwTicks = GetTickCount();
do
{
LONG cchT;
SendMessage(predoc->hwndRE, EM_REPLACESEL, 0, (LPARAM) (LPSTR) szText);
cchT = SendMessage(predoc->hwndRE, WM_GETTEXTLENGTH, 0, 0);
cchAdded = cchT - cchText;
if(cchText % 8192 > cchT % 8192)
{
const DWORD dwT = GetTickCount();
TraceTag(tagGeneral, "%ld characters, %ld ticks", cchT, dwT - dwTicks);
dwTicks = dwT;
}
cchText = cchT;
if(GetAsyncKeyState(VK_ESCAPE) & 0x8001)
{
TraceTag(tagGeneral, "stopping for escape");
break;
}
} while(cchAdded > 0 && !fErrSpace);
TraceTag(tagGeneral, "Stopped at %ld character", cchText);
}
#endif// DEBUG