📄 host.cpp
字号:
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
//
// Use of this source code is subject to the terms of the Microsoft shared
// source or premium shared source license agreement under which you licensed
// this source code. If you did not accept the terms of the license agreement,
// you are not authorized to use this source code. For the terms of the license,
// please see the license agreement between you and Microsoft or, if applicable,
// see the SOURCE.RTF on your install media or the root of your tools installation.
// THE SOURCE CODE IS PROVIDED "AS IS", WITH NO WARRANTIES.
//
/*
* @doc INTERNAL
*
* @module HOST.C -- Text Host for CreateWindow() Rich Edit Control |
* Implements CTxtWinHost message and ITextHost interfaces
*
* Original Author: <nl>
* Original RichEdit code: David R. Fulmer
* Christian Fortini
* Murray Sargent
*
* History: <nl>
* 8/1/95 ricksa Documented and brought to new ITextHost definition
* 10/28/95 murrays cleaned up and moved default char/paraformat cache
* cache code into text services
*
* Set tabs every four (4) columns
*/
#include "_common.h"
#include "_host.h"
#include "imm.h"
#include "_format.h"
#include "_edit.h"
#include "_cfpf.h"
#include "_ime.h"
ASSERTDATA
LONG CTxtWinHost::_xWidthSys = 0; // Average char width of system font
LONG CTxtWinHost::_yHeightSys = 0; // Height of system font
LOCAL BOOL GetIconic(
HWND hwnd)
{
TRACEBEGIN(TRCSUBSYSHOST, TRCSCOPEINTERN, "GetIconic");
while(hwnd)
{
if(IsIconic(hwnd))
return TRUE;
hwnd = GetParent(hwnd);
}
return FALSE;
}
//////////////// CTxtWinHost Creation/Initialization/Destruction ///////////////////////
/*
* CTxtWinHost::OnNCCreate (hwnd, pcs)
*
* @mfunc
* Static global method to handle WM_NCCREATE message (see remain.c)
*/
LRESULT CTxtWinHost::OnNCCreate(
HWND hwnd,
const CREATESTRUCT *pcs)
{
TRACEBEGIN(TRCSUBSYSHOST, TRCSCOPEINTERN, "CTxtWinHost::OnNCCreate");
#if defined DEBUG && !defined(PEGASUS)
GdiSetBatchLimit(1);
#endif
CTxtWinHost *phost = new CTxtWinHost();
if(!phost)
return 0;
if (!phost->Init(hwnd, pcs)) // Stores phost in associated
{ // window data
phost->Shutdown();
delete phost;
return 0;
}
return TRUE;
}
/*
* CTxtWinHost::OnNCDestroy (phost)
*
* @mfunc
* Static global method to handle WM_CREATE message
*
* @devnote
* phost ptr is stored in window data (GetWindowLong())
*/
void CTxtWinHost::OnNCDestroy(
CTxtWinHost *phost)
{
TRACEBEGIN(TRCSUBSYSHOST, TRCSCOPEINTERN, "CTxtWinHost::OnNCDestroy");
phost->Shutdown();
phost->Release();
}
/*
* CTxtWinHost::CTxtWinHost()
*
* @mfunc
* constructor
*/
CTxtWinHost::CTxtWinHost() :
_fBorder(0),
_fInBottomless(0),
_fInDialogBox(0),
_fEnableAutoWordSel(1),
_fIconic(0),
_fHidden(0),
_fNotSysBkgnd(0),
_fWindowLocked(0),
_fRegisteredForDrop(1),
_fVisible(1),
_fResized(0),
_fDisabled(0),
_fKeyMaskSet(1),
_fMouseMaskSet(1),
_fScrollMaskSet(1),
_fUseSpecialSetSel(1),
_fEmSetRectCalled(1),
_fAccumulateDBC(0)
{
TRACEBEGIN(TRCSUBSYSHOST, TRCSCOPEINTERN, "CTxtWinHost::CTxtWinHost");
_fRegisteredForDrop = FALSE;
_crefs = 1;
if ( !_fNotSysBkgnd)
_crBackground = GetSysColor(COLOR_WINDOW);
}
/*
* CTxtWinHost::~CTxtWinHost()
*
* @mfunc
* destructor
*/
CTxtWinHost::~CTxtWinHost()
{
if( _pserv )
{
Shutdown();
}
}
/*
* CTxtWinHost::Shutdown()
*
* @mfunc shuts down this object, but doesn't delete memory
*/
void CTxtWinHost::Shutdown()
{
TRACEBEGIN(TRCSUBSYSHOST, TRCSCOPEINTERN, "CTxtWinHost::Shutdown");
RevokeDragDrop(); // Revoke our drop target
if( _pserv )
{
_pserv->OnTxInPlaceDeactivate();
_pserv->Release();
_pserv = NULL;
}
ImmTerminate(); // terminate only useful on Mac.
if(_hwnd)
SetWindowLong(_hwnd, ibPed, 0);
}
/*
* CTxtWinHost::Init (hwnd, pcs)
*
* @mfunc
* Initialize this CTxtWinHost
*/
BOOL CTxtWinHost::Init(
HWND hwnd, //@parm Window handle for this control
const CREATESTRUCT *pcs) //@parm Corresponding CREATESTRUCT
{
TRACEBEGIN(TRCSUBSYSHOST, TRCSCOPEINTERN, "CTxtWinHost::Init");
HDC hdc;
HFONT hfontOld;
HRESULT hr;
IUnknown * pUnk;
TEXTMETRIC tm;
if( pcs->lpszClass == NULL )
return FALSE;
// Set pointer back to CTxtWinHost from the window
if(hwnd)
SetWindowLong(hwnd, ibPed, (LONG)this);
_hwnd = hwnd;
// Edit controls created without a window are multiline by default
// so that paragraph formats can be
_dwStyle = ES_MULTILINE;
_fHidden = TRUE;
if(pcs)
{
_hwndParent = pcs->hwndParent;
_dwExStyle = pcs->dwExStyle;
_dwStyle = pcs->style;
// According to the edit control documentation WS_HSCROLL implies that
// ES_AUTOSCROLL is set and WS_VSCROLL implies that ES_AUTOVSCROLL is
// set. Here, we make this so.
if(_dwStyle & WS_HSCROLL)
_dwStyle |= ES_AUTOHSCROLL;
if(_dwStyle & WS_VSCROLL)
_dwStyle |= ES_AUTOVSCROLL;
_fBorder = !!(_dwStyle & WS_BORDER);
if((_dwStyle & ES_SUNKEN) || (_dwExStyle & WS_EX_CLIENTEDGE))
_fBorder = TRUE;
// handle default passwords
if(_dwStyle & ES_PASSWORD)
_chPassword = TEXT('*');
// handle default disabled
if(_dwStyle & WS_DISABLED)
_fDisabled = TRUE;
// On Win95 ES_SUNKEN and WS_BORDER get mapped to WS_EX_CLIENTEDGE
if(_fBorder && (dwMajorVersion >= VERS4))
{
_dwExStyle |= WS_EX_CLIENTEDGE;
SetWindowLong(_hwnd, GWL_EXSTYLE, _dwExStyle);
}
}
if (0 == _xWidthSys)
{
// Init system metrics
hdc = GetDC(hwnd);
if(!hdc)
return FALSE;
hfontOld = (HFONT)SelectObject(hdc, GetStockObject(SYSTEM_FONT));
if(!hfontOld)
return FALSE;
W32->GetTextMetrics(hdc, &tm);
SelectObject(hdc, hfontOld);
_xWidthSys = (INT) tm.tmAveCharWidth;
_yHeightSys = (INT) tm.tmHeight;
ReleaseDC(hwnd, hdc);
}
_xInset = _xWidthSys / 2;
_yInset = _yHeightSys / 4;
// At this point the border flag is set and so is the pixels per inch
// so we can initalize the inset.
SetDefaultInset();
// Create Text Services component
if(FAILED(CreateTextServices(NULL, this, &pUnk)))
return FALSE;
// Get text services interface
hr = pUnk->QueryInterface(IID_ITextServices, (void **)&_pserv);
// Regardless of whether the previous call succeeded or failed, we are
// done with the private interface.
pUnk->Release();
if(FAILED(hr))
return FALSE;
// If the class name is "RichEdit", then we need to turn on the
// RichEdit 1.0 compatibility bit. Otherwise, we can use the normal
// version.
#if 0 // Need to figure out how to test for atoms.
if( IsAtom wcsicmp(pcs->lpszClass, L"RICHEDIT") == 0 )
{
((CTxtEdit *)_pserv)->Set10Mode();
}
#endif
// Set window text
if(pcs && pcs->lpszName)
{
if(FAILED(_pserv->TxSetText((TCHAR *)pcs->lpszName)))
{
SafeReleaseAndNULL((IUnknown **)&_pserv);
return FALSE;
}
}
PARAFORMAT PF; // If center or right alignment,
if(_dwStyle & (ES_CENTER | ES_RIGHT)) // tell text services
{
PF.cbSize = sizeof(PARAFORMAT);
PF.dwMask = PFM_ALIGNMENT;
PF.wAlignment = (_dwStyle & ES_RIGHT) ? PFA_RIGHT : PFA_CENTER;
_pserv->TxSendMessage(EM_SETPARAFORMAT, SPF_SETDEFAULT, (LPARAM)&PF, NULL);
}
if( !ImmInitialize() ) // Mac Only
{
#if defined(DEBUG) && defined(MACPORT)
OutputDebugString(TEXT("Could not register Imm ImmInitializeForMac.\r\n"));
#endif // DEBUG
}
return TRUE;
}
/*
* CTxtWinHost::OnCreate (pcs)
*
* @mfunc
* Handle WM_CREATE message
*
* @rdesc
* LRESULT = -1 if failed to in-place activate; else 0
*/
LRESULT CTxtWinHost::OnCreate(
const CREATESTRUCT *pcs)
{
TRACEBEGIN(TRCSUBSYSHOST, TRCSCOPEINTERN, "CTxtWinHost::OnCreate");
RECT rcClient;
// sometimes, these values are -1 (from windows itself); just treat them
// as zero in that case
LONG cy = ( pcs->cy < 0 ) ? 0 : pcs->cy;
LONG cx = ( pcs->cx < 0 ) ? 0 : pcs->cx;
rcClient.top = pcs->y;
rcClient.bottom = rcClient.top + cy;
rcClient.left = pcs->x;
rcClient.right = rcClient.left + cx;
// Notify Text Services that we are in place active
if(FAILED(_pserv->OnTxInPlaceActivate(&rcClient)))
return -1;
DWORD dwStyle = GetWindowLong(_hwnd, GWL_STYLE);
// Hide all scrollbars to start
if(_hwnd && !(_dwStyle & ES_DISABLENOSCROLL))
{
SetScrollRange(_hwnd, SB_VERT, 0, 0, TRUE);
SetScrollRange(_hwnd, SB_HORZ, 0, 0, TRUE);
dwStyle &= ~(WS_VSCROLL | WS_HSCROLL);
SetWindowLong(_hwnd, GWL_STYLE, dwStyle);
}
if (!(dwStyle & (ES_READONLY | ES_NOOLEDRAGDROP)) )
{
// This isn't a read only window or a no drop window,
// so we need a drop target.
RegisterDragDrop();
}
_usIMEMode = 0;
if (dwStyle & ES_NOIME)
_usIMEMode = ES_NOIME;
else if (dwStyle & ES_SELFIME)
_usIMEMode = ES_SELFIME;
return 0;
}
///////////////////////////////// IUnknown ////////////////////////////////
HRESULT CTxtWinHost::QueryInterface(REFIID riid, void **ppv)
{
TRACEBEGIN(TRCSUBSYSHOST, TRCSCOPEINTERN, "CTxtWinHost::QueryInterface");
if( IsEqualIID(riid, IID_IUnknown) )
{
*ppv = (IUnknown *)this;
}
else if( IsEqualIID(riid, IID_ITextHost) )
{
*ppv = (ITextHost *)this;
}
else if( IsEqualIID(riid, IID_ITextHost2) )
{
*ppv = (ITextHost2 *)this;
}
else
{
*ppv = NULL;
}
if( *ppv )
{
AddRef();
return NOERROR;
}
return E_NOINTERFACE;
}
ULONG CTxtWinHost::AddRef(void)
{
TRACEBEGIN(TRCSUBSYSHOST, TRCSCOPEINTERN, "CTxtWinHost::AddRef");
return ++_crefs;
}
ULONG CTxtWinHost::Release(void)
{
TRACEBEGIN(TRCSUBSYSHOST, TRCSCOPEINTERN, "CTxtWinHost::Release");
--_crefs;
if( _crefs == 0 )
{
delete this;
return 0;
}
return _crefs;
}
//////////////////////////////// Activation ////////////////////////////////
//////////////////////////////// Properties ////////////////////////////////
TXTEFFECT CTxtWinHost::TxGetEffects() const
{
TRACEBEGIN(TRCSUBSYSHOST, TRCSCOPEINTERN, "CTxtWinHost::TxGetEffects");
if( (_dwStyle & ES_SUNKEN) || (_dwExStyle & WS_EX_CLIENTEDGE) )
{
return TXTEFFECT_SUNKEN;
}
else
{
return TXTEFFECT_NONE;
}
}
//////////////////////////// System API wrapper ////////////////////////////
/////////////////////// Windows message dispatch methods ///////////////////////////////
/*
* CTxtWinHost::TxWindowProc (hwnd, msg, wparam, lparam)
*
* @mfunc
* Handle window messages pertinent to the host and pass others on to
* text services. Called by RichEditWndProc() in remain.c.
*
* #rdesc
* LRESULT = (code processed) ? 0 : 1
*/
LRESULT CTxtWinHost::TxWindowProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
{
TRACEBEGIN(TRCSUBSYSHOST, TRCSCOPEINTERN, "CTxtWinHost::TxWindowProc");
LRESULT lres = 0;
HRESULT hr;
// in certain out-of-memory situations, clients may try to re-enter us
// with calls. Just bail on the call if we don't have a text services
// pointer.
if( !_pserv )
{
return 0;
}
// stabilize ourselves
AddRef();
// Handle mouse/keyboard message filter notifications
if( _fKeyMaskSet || _fMouseMaskSet || _fScrollMaskSet )
{
// We may need to fire a MSGFILTER notification. In
// the tests below, we check to see if either mouse
// or key events are hit. If so, then we fire the msgfilter
// notification. The list of events was generated from
// RichEdit 1.0 sources.
MSGFILTER msgfltr;
/* RichEdit Compatibility issue: The following code gets all
* keyboard and mouse actions, but the RichEdit 1.0 code only got
* WM_KEYDOWN, WM_KEYUP, WM_CHAR, WM_SYSKEYDOWN, WM_SYSKEYUP,
* WM_MOUSEACTIVATE, WM_LBUTTONDOWN, WM_LBUTTONUP, WM_MOUSEMOVE,
* WM_RBUTTONDBLCLK, WM_RBUTTONDOWN, WM_RBUTTONUP
*/
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -