You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
562 lines
14 KiB
562 lines
14 KiB
/*
|
|
*
|
|
* REINIT.CPP
|
|
*
|
|
* Purpose:
|
|
* RICHEDIT initialization routines
|
|
*
|
|
* Copyright (c) 1995-2001, Microsoft Corporation. All rights reserved.
|
|
*/
|
|
|
|
#include "_common.h"
|
|
#include "_font.h"
|
|
#include "_format.h"
|
|
#include "_disp.h"
|
|
#include "_clasfyc.h"
|
|
#include "zmouse.h"
|
|
#include "_rtfconv.h"
|
|
#ifndef NOLINESERVICES
|
|
#include "_ols.h"
|
|
#ifndef NODELAYLOAD
|
|
#include <delayimp.h>
|
|
#endif
|
|
#endif
|
|
#include "_host.h"
|
|
#ifndef NOVERSIONINFO
|
|
#include <shlwapi.h>
|
|
#include "_version.h"
|
|
#endif
|
|
|
|
ASSERTDATA
|
|
|
|
class CTxtEdit;
|
|
class CCmbBxWinHost;
|
|
|
|
extern void ReleaseTypeInfoPtrs();
|
|
|
|
static WCHAR wszClassREW[sizeof(MSFTEDIT_CLASS)/sizeof(WCHAR)];
|
|
|
|
static WCHAR wszClassLBW[] = LISTBOX_CLASSW;
|
|
static WCHAR wszClassCBW[] = COMBOBOX_CLASSW;
|
|
#define REGISTERED_LISTBOX 1
|
|
#define REGISTERED_COMBOBOX 2
|
|
|
|
// a critical section for multi-threading support.
|
|
CRITICAL_SECTION g_CriticalSection;
|
|
|
|
HINSTANCE hinstRE = 0;
|
|
|
|
static BOOL RichFRegisterClass(VOID);
|
|
|
|
#ifdef DEBUG
|
|
BOOL fInDllMain = FALSE; // used to ensure that GDI calls are not made during
|
|
// DLL_PROCESS_ATTACH
|
|
#endif
|
|
|
|
void FreeFontCache(); // Defined in font.cpp
|
|
void ReleaseOutlineBitmaps(); // Defined in render.cpp
|
|
|
|
#ifdef DEBUG
|
|
void CatchLeaks(void);
|
|
#endif
|
|
|
|
extern HANDLE g_hHeap;
|
|
|
|
void FreeHyphCache(void);
|
|
|
|
#ifndef NODELAYLOAD
|
|
static inline
|
|
void WINAPI
|
|
OverlayIAT(PImgThunkData pitdDst, PCImgThunkData pitdSrc) {
|
|
memcpy(pitdDst, pitdSrc, CountOfImports(pitdDst) * sizeof IMAGE_THUNK_DATA);
|
|
}
|
|
|
|
void OurUnloadDelayLoadedDlls(void)
|
|
{
|
|
PUnloadInfo pui = __puiHead;
|
|
|
|
for (;pui;)
|
|
{
|
|
#ifdef _WIN64
|
|
if (pui->pidd->rvaUnloadIAT)
|
|
{
|
|
PCImgDelayDescr pidd = pui->pidd;
|
|
HMODULE* phmod = PFromRva(pidd->rvaHmod, (HMODULE *)NULL);
|
|
HMODULE hmod = *phmod;
|
|
|
|
if (hmod)
|
|
{
|
|
// NOTE: (honwch 3/6/01) We don't need to reset pIAT since this
|
|
// routine is being called on DLL_PROCESS_DETACH. We only need to reset
|
|
// pIAT iff RE is staying around and we need to re-load this DLL again.
|
|
// The following line would crash because of a bug in BBT3.0 and delayed load.
|
|
// If RE is loaded into a different address space, pUnloadIAT is not fixed up
|
|
// correctly. (RE Bug 9292)
|
|
// OverlayIAT(pidd->pIAT, pidd->pUnloadIAT);
|
|
::FreeLibrary(hmod);
|
|
*phmod = NULL;
|
|
}
|
|
#else
|
|
if (pui->pidd->pUnloadIAT)
|
|
{
|
|
PCImgDelayDescr pidd = pui->pidd;
|
|
HMODULE hmod = *pidd->phmod;
|
|
|
|
if (hmod)
|
|
{
|
|
// NOTE: (honwch 3/6/01) We don't need to reset pIAT since this
|
|
// routine is being called on DLL_PROCESS_DETACH. We only need to reset
|
|
// pIAT iff RE is staying around and we need to re-load this DLL again.
|
|
// The following line would crash because of a bug in BBT3.0 and delayed load.
|
|
// If RE is loaded into a different address space, pUnloadIAT is not fixed up
|
|
// correctly. (RE Bug 9292)
|
|
// OverlayIAT(pidd->pIAT, pidd->pUnloadIAT);
|
|
::FreeLibrary(hmod);
|
|
*pidd->phmod = NULL;
|
|
}
|
|
#endif
|
|
PUnloadInfo puiT = pui->puiNext;
|
|
::LocalFree(pui);
|
|
pui = puiT;
|
|
}
|
|
|
|
}
|
|
}
|
|
#endif
|
|
|
|
//CLEARTYPE test code Turn this flag on to test.
|
|
//#define CLEARTYPE_DEBUG
|
|
|
|
#ifdef CLEARTYPE_DEBUG
|
|
#include "ct_ras_win.h"
|
|
|
|
class CCustomTextOut:public ICustomTextOut
|
|
{
|
|
virtual BOOL WINAPI ExtTextOutW(HDC hdc, int X, int Y, UINT fuOptions,
|
|
CONST RECT *lprc, LPCWSTR lpString, UINT cbCount, CONST INT *lpDx);
|
|
virtual BOOL WINAPI GetCharWidthW(HDC hdc,UINT iFirstChar, UINT iLastChar,
|
|
LPINT lpBuffer);
|
|
virtual BOOL WINAPI NotifyCreateFont(HDC hdc);
|
|
virtual void WINAPI NotifyDestroyFont(HFONT hFont);
|
|
};
|
|
|
|
|
|
extern "C" HINSTANCE g_hRE;
|
|
typedef HRESULT (*PFNPROC)(ICustomTextOut**);
|
|
PFNPROC _pfnProc = NULL;
|
|
CCustomTextOut *pCTO;
|
|
HINSTANCE _hctras = NULL;
|
|
EXTERN_C long g_ClearTypeNum=0;
|
|
typedef BOOL (WINAPI *PFNEXTTEXTOUTW)(HDC, LONG, LONG, DWORD,
|
|
CONST RECT*, PWSTR, ULONG, CONST LONG*);
|
|
typedef BOOL (WINAPI *PFNGETCHARWIDTHW)(HDC, WCHAR, WCHAR, PLONG);
|
|
typedef BOOL (WINAPI *PFNCREATEFONTINSTANCE)(HDC, DWORD);
|
|
typedef BOOL (WINAPI *PFNDELETEFONTINSTANCE)(HFONT);
|
|
PFNEXTTEXTOUTW _pfnExtTextOutW = NULL;
|
|
PFNGETCHARWIDTHW _pfnGetCharWidthW = NULL;
|
|
PFNCREATEFONTINSTANCE _pfnCreateFontInstance = NULL;
|
|
PFNDELETEFONTINSTANCE _pfnDeleteFontInstance = NULL;
|
|
|
|
|
|
|
|
BOOL CCustomTextOut::ExtTextOutW(HDC hdc, int X, int Y, UINT fuOptions,
|
|
CONST RECT *lprc, LPCWSTR lpString, UINT cbCount, CONST INT *lpDx)
|
|
{
|
|
return _pfnExtTextOutW(hdc, X, Y, fuOptions, lprc, (USHORT*) lpString, cbCount, (LONG*) lpDx);
|
|
}
|
|
|
|
BOOL CCustomTextOut::GetCharWidthW(HDC hdc,UINT iFirstChar, UINT iLastChar,
|
|
LPINT lpBuffer)
|
|
{
|
|
return _pfnGetCharWidthW(hdc, iFirstChar, iLastChar, (LONG*) lpBuffer);
|
|
}
|
|
|
|
|
|
BOOL CCustomTextOut::NotifyCreateFont(HDC hdc)
|
|
{
|
|
return _pfnCreateFontInstance(hdc, 0);
|
|
}
|
|
|
|
|
|
void CCustomTextOut::NotifyDestroyFont(HFONT hFont)
|
|
{
|
|
_pfnDeleteFontInstance(hFont);
|
|
}
|
|
|
|
extern "C" void ClearTypeUnInitialize();
|
|
|
|
extern "C" HRESULT ClearTypeInitialize()
|
|
{
|
|
_hctras=LoadLibraryA("ctras.dll");
|
|
// check - cleartype dll is not gauranteed to be present
|
|
if (!_hctras)
|
|
{
|
|
ClearTypeUnInitialize();
|
|
return E_NOINTERFACE;
|
|
}
|
|
_pfnExtTextOutW=(PFNEXTTEXTOUTW)GetProcAddress(_hctras, "WAPI_EZCTExtTextOutW");
|
|
_pfnGetCharWidthW=(PFNGETCHARWIDTHW)GetProcAddress(_hctras, "WAPI_EZCTGetCharWidthW");
|
|
_pfnCreateFontInstance=(PFNCREATEFONTINSTANCE)GetProcAddress(_hctras, "WAPI_EZCTCreateFontInstance");
|
|
_pfnDeleteFontInstance=(PFNDELETEFONTINSTANCE)GetProcAddress(_hctras, "WAPI_EZCTDeleteFontInstance");
|
|
|
|
// check that we got these correctly
|
|
// future versions of cleartype could change this API
|
|
if(!_pfnExtTextOutW || !_pfnGetCharWidthW || !_pfnCreateFontInstance || !_pfnDeleteFontInstance)
|
|
{
|
|
ClearTypeUnInitialize();
|
|
return E_NOINTERFACE;
|
|
}
|
|
|
|
pCTO=new CCustomTextOut;
|
|
ICustomTextOut *pICTO=pCTO;
|
|
|
|
SetCustomTextOutHandlerEx(&pICTO, 0);
|
|
return NOERROR;
|
|
}
|
|
|
|
extern "C" void ClearTypeUnInitialize()
|
|
{
|
|
if(_hctras)
|
|
{
|
|
FreeLibrary(_hctras);
|
|
_hctras = NULL;
|
|
}
|
|
|
|
if(pCTO)
|
|
{
|
|
delete pCTO;
|
|
pCTO = NULL;
|
|
}
|
|
|
|
_pfnExtTextOutW = NULL;
|
|
_pfnGetCharWidthW = NULL;
|
|
_pfnCreateFontInstance = NULL;
|
|
_pfnDeleteFontInstance = NULL;
|
|
}
|
|
|
|
#endif
|
|
|
|
extern "C"
|
|
{
|
|
|
|
BOOL WINAPI DllMain(HANDLE hmod, DWORD dwReason, LPVOID lpvReserved)
|
|
{
|
|
DebugMain ((HINSTANCE) hmod, dwReason, lpvReserved);
|
|
|
|
if(dwReason == DLL_PROCESS_DETACH) // We are unloading
|
|
{
|
|
#ifndef NOWINDOWHOSTS
|
|
DeleteDanglingHosts();
|
|
#endif
|
|
CRTFConverter::FreeFontSubInfo();
|
|
FreeFontCache();
|
|
DestroyFormatCaches();
|
|
ReleaseTypeInfoPtrs();
|
|
UninitKinsokuClassify();
|
|
FreeHyphCache();
|
|
|
|
|
|
// Release various resouces allocated during running...
|
|
#ifndef NOLINESERVICES
|
|
delete g_pols;
|
|
#endif
|
|
|
|
#ifndef NOCOMPLEXSCRIPTS
|
|
delete g_pusp;
|
|
g_pusp = NULL;
|
|
#endif
|
|
|
|
ReleaseOutlineBitmaps();
|
|
|
|
#ifdef CLEARTYPE_DEBUG
|
|
ClearTypeUnInitialize();
|
|
#endif
|
|
|
|
if(hinstRE)
|
|
{
|
|
W32->UnregisterClass(wszClassREW, hinstRE);
|
|
if (W32->_fRegisteredXBox)
|
|
{
|
|
// There may be cases where these window classes
|
|
// are still in memory in which case UnregisterClass
|
|
// will fail. So keep track of that
|
|
if (W32->UnregisterClass(wszClassLBW, hinstRE))
|
|
W32->_fRegisteredXBox &= ~REGISTERED_LISTBOX;
|
|
if (W32->UnregisterClass(wszClassCBW, hinstRE))
|
|
W32->_fRegisteredXBox &= ~REGISTERED_COMBOBOX;
|
|
}
|
|
}
|
|
delete W32;
|
|
|
|
#if defined(DEBUG) && !defined(NOFULLDEBUG)
|
|
CatchLeaks();
|
|
#endif
|
|
|
|
#ifndef NODELAYLOAD
|
|
// lpvReserved is not NULL when DllMain DLL_PROCESS_DETACH is being called during process exit.
|
|
// In such case, we should not mess around with the delay loaded dll thunks
|
|
if (!lpvReserved)
|
|
OurUnloadDelayLoadedDlls();
|
|
#endif
|
|
HeapDestroy(g_hHeap);
|
|
DeleteCriticalSection(&g_CriticalSection);
|
|
}
|
|
else if(dwReason == DLL_PROCESS_ATTACH) // We have just loaded
|
|
{
|
|
#ifdef DEBUG
|
|
fInDllMain = TRUE;
|
|
#endif
|
|
InitializeCriticalSection(&g_CriticalSection);
|
|
#if !defined(DEBUG) && !defined(UNDER_CE)
|
|
// REVIEW (gheino) We should investigate if there is another
|
|
// way to do this on CE
|
|
DisableThreadLibraryCalls((HINSTANCE) hmod);
|
|
#endif
|
|
hinstRE = (HINSTANCE) hmod;
|
|
|
|
W32 = new CW32System;
|
|
|
|
CopyMemory(wszClassREW, MSFTEDIT_CLASS, sizeof(MSFTEDIT_CLASS));
|
|
|
|
if(!RichFRegisterClass())
|
|
return FALSE;
|
|
|
|
#ifdef CLEARTYPE_DEBUG
|
|
ClearTypeInitialize();
|
|
#endif
|
|
|
|
#ifdef DEBUG
|
|
fInDllMain = FALSE;
|
|
#endif
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
#ifndef NOVERSIONINFO
|
|
HRESULT CALLBACK DllGetVersion(
|
|
DLLVERSIONINFO *pdvi
|
|
)
|
|
{
|
|
if (pdvi->cbSize != sizeof(DLLVERSIONINFO))
|
|
return E_INVALIDARG;
|
|
pdvi->dwBuildNumber = RICHEDIT_VERBUILD;
|
|
pdvi->dwMajorVersion = RICHEDIT_VERMAJ;
|
|
pdvi->dwMinorVersion = RICHEDIT_VERMIN;
|
|
pdvi->dwPlatformID = DLLVER_PLATFORM_WINDOWS ;
|
|
return NOERROR;
|
|
}
|
|
#endif
|
|
|
|
} // extern "C"
|
|
|
|
/*
|
|
* RichFRegisterClass
|
|
*
|
|
* Purpose:
|
|
* registers the window classes used by richedit
|
|
*
|
|
* Algorithm:
|
|
* register two window classes, a Unicode one and an ANSI
|
|
* one. This enables clients to optimize their use of
|
|
* the edit control w.r.t to ANSI/Unicode data
|
|
*/
|
|
|
|
static BOOL RichFRegisterClass(VOID)
|
|
{
|
|
#ifndef NOWINDOWHOSTS
|
|
TRACEBEGIN(TRCSUBSYSHOST, TRCSCOPEINTERN, "RichFRegisterClass");
|
|
WNDCLASS wc;
|
|
|
|
wc.style = CS_DBLCLKS | CS_GLOBALCLASS | CS_PARENTDC;
|
|
wc.lpfnWndProc = RichEditWndProc;
|
|
wc.cbClsExtra = 0;
|
|
wc.cbWndExtra = sizeof(CTxtEdit FAR *);
|
|
wc.hInstance = hinstRE;
|
|
wc.hIcon = 0;
|
|
wc.hCursor = 0;
|
|
wc.hbrBackground = (HBRUSH) (COLOR_WINDOW + 1);
|
|
wc.lpszMenuName = NULL;
|
|
wc.lpszClassName = wszClassREW;
|
|
|
|
if( W32->RegisterREClass(&wc) == NULL )
|
|
return FALSE;
|
|
#endif // NOWINDOWHOSTS
|
|
return TRUE;
|
|
}
|
|
|
|
#ifndef NOLISTCOMBOBOXES
|
|
|
|
extern "C" LRESULT CALLBACK RichListBoxWndProc(HWND, UINT, WPARAM, LPARAM);
|
|
extern "C" LRESULT CALLBACK RichComboBoxWndProc(HWND, UINT, WPARAM, LPARAM);
|
|
__declspec(dllexport) BOOL WINAPI REExtendedRegisterClass(VOID)
|
|
{
|
|
TRACEBEGIN(TRCSUBSYSHOST, TRCSCOPEINTERN, "REExtendedRegisterClass");
|
|
|
|
WNDCLASS wc;
|
|
|
|
if (!(W32->_fRegisteredXBox & REGISTERED_LISTBOX))
|
|
{
|
|
// Globally register the listbox
|
|
wc.style = CS_DBLCLKS | CS_GLOBALCLASS | CS_PARENTDC;
|
|
wc.lpfnWndProc = RichListBoxWndProc;
|
|
wc.cbClsExtra = 0;
|
|
wc.cbWndExtra = sizeof(CTxtEdit FAR *);
|
|
wc.hInstance = hinstRE;
|
|
wc.hIcon = 0;
|
|
wc.hCursor = 0;
|
|
wc.hbrBackground = (HBRUSH) (COLOR_WINDOW + 1);
|
|
wc.lpszMenuName = NULL;
|
|
wc.lpszClassName = wszClassLBW;
|
|
|
|
if(W32->RegisterREClass(&wc))
|
|
W32->_fRegisteredXBox |= REGISTERED_LISTBOX;
|
|
}
|
|
|
|
if (!(W32->_fRegisteredXBox & REGISTERED_COMBOBOX))
|
|
{
|
|
// globally register the combobox
|
|
wc.style = CS_DBLCLKS | CS_GLOBALCLASS | CS_PARENTDC | CS_VREDRAW | CS_HREDRAW;
|
|
wc.lpfnWndProc = RichComboBoxWndProc;
|
|
wc.cbClsExtra = 0;
|
|
wc.cbWndExtra = sizeof(CCmbBxWinHost FAR *);
|
|
wc.hInstance = hinstRE;
|
|
wc.hIcon = 0;
|
|
wc.hCursor = 0;
|
|
wc.hbrBackground = (HBRUSH) (COLOR_WINDOW + 1);
|
|
wc.lpszMenuName = NULL;
|
|
wc.lpszClassName = wszClassCBW;
|
|
|
|
if(W32->RegisterREClass(&wc))
|
|
W32->_fRegisteredXBox |= REGISTERED_COMBOBOX;
|
|
}
|
|
|
|
//Set flag so we unregister the window class
|
|
return W32->_fRegisteredXBox;
|
|
}
|
|
#else // NOLISTCOMBOBOXES
|
|
__declspec(dllexport) BOOL WINAPI REExtendedRegisterClass(VOID)
|
|
{
|
|
return FALSE;
|
|
}
|
|
#endif // NOLISTCOMBOBOXES
|
|
|
|
#if !defined(NOLINESERVICES)
|
|
BOOL g_fNoLS = FALSE;
|
|
#endif
|
|
|
|
#if !defined(NOCOMPLEXSCRIPTS)
|
|
BOOL g_fNoUniscribe = FALSE;
|
|
#endif
|
|
|
|
#if !defined(NOLINESERVICES) && !defined(NOCOMPLEXSCRIPTS)
|
|
char *g_szMsgBox = NULL;
|
|
|
|
//This is a stub function which we call when we can't find LineServices.
|
|
//The stub function needs to be the the first function we call in LS.
|
|
LSERR WINAPI LsGetReverseLsimethodsStub(LSIMETHODS *plsim)
|
|
{
|
|
return lserrOutOfMemory;
|
|
}
|
|
|
|
//Ugly, but good enough
|
|
BOOL FIsUniscribeDll (const char *szDll)
|
|
{
|
|
return (*szDll == 'u' || *szDll == 'U');
|
|
}
|
|
|
|
BOOL FIsLineServicesDll (const char *szDll)
|
|
{
|
|
return (*szDll == 'm' || *szDll == 'M') &&
|
|
(*(szDll+1) == 's' || *(szDll+1) == 'S') &&
|
|
(*(szDll+2) == 'l' || *(szDll+2) == 'L');
|
|
}
|
|
|
|
HRESULT WINAPI ScriptGetPropertiesStub(const SCRIPT_PROPERTIES ***ppSp,int *piNumScripts)
|
|
{
|
|
return E_FAIL;
|
|
}
|
|
|
|
const SCRIPT_LOGATTR* WINAPI ScriptString_pLogAttrStub(SCRIPT_STRING_ANALYSIS ssa)
|
|
{
|
|
// USP build 0175 (shipped with IE5 and Office2K) doesnt support this API.
|
|
return NULL;
|
|
}
|
|
|
|
// Get Uniscibe's fake entry points
|
|
|
|
FARPROC WINAPI GetUniscribeStubs(LPCSTR szProcName)
|
|
{
|
|
if (!lstrcmpiA(szProcName, "ScriptGetProperties"))
|
|
return (FARPROC)ScriptGetPropertiesStub;
|
|
|
|
if (!lstrcmpiA(szProcName, "ScriptString_pLogAttr"))
|
|
return (FARPROC)ScriptString_pLogAttrStub;
|
|
|
|
#ifdef DEBUG
|
|
char szAssert[128];
|
|
|
|
wsprintfA(szAssert, "Uniscribe API =%s= is missing. Fix it NOW!", szProcName);
|
|
|
|
AssertSz(FALSE, szAssert);
|
|
#endif
|
|
|
|
return (FARPROC)ScriptGetPropertiesStub; // we're dying...
|
|
}
|
|
|
|
#ifndef NODELAYLOAD
|
|
|
|
FARPROC WINAPI DliHook(unsigned dliNotify, PDelayLoadInfo pdli)
|
|
{
|
|
FARPROC fp = 0;
|
|
|
|
switch (dliNotify)
|
|
{
|
|
// Handy for debugging for now.
|
|
case dliNotePreGetProcAddress:
|
|
if (FIsLineServicesDll(pdli->szDll))
|
|
fp = 0;
|
|
break;
|
|
|
|
case dliFailLoadLib:
|
|
{
|
|
if (FIsUniscribeDll(pdli->szDll))
|
|
g_fNoUniscribe = TRUE;
|
|
else
|
|
g_fNoLS = TRUE;
|
|
|
|
fp = (FARPROC)(HMODULE)hinstRE;
|
|
|
|
CLock lock;
|
|
if(!g_szMsgBox)
|
|
{
|
|
g_szMsgBox = (char *)PvAlloc(255, GMEM_ZEROINIT);
|
|
|
|
FormatMessageA(FORMAT_MESSAGE_ARGUMENT_ARRAY | FORMAT_MESSAGE_FROM_SYSTEM, NULL,
|
|
ERROR_MOD_NOT_FOUND,
|
|
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
|
|
(char *)g_szMsgBox, 255, NULL);
|
|
|
|
CopyMemory(g_szMsgBox + lstrlenA(g_szMsgBox), " (", 3);
|
|
CopyMemory(g_szMsgBox + lstrlenA(g_szMsgBox), pdli->szDll, lstrlenA(pdli->szDll) + 1);
|
|
CopyMemory(g_szMsgBox + lstrlenA(g_szMsgBox), ")", 2);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case dliFailGetProc:
|
|
if (FIsUniscribeDll(pdli->szDll))
|
|
fp = (FARPROC)GetUniscribeStubs(pdli->dlp.szProcName);
|
|
else
|
|
fp = (FARPROC)LsGetReverseLsimethodsStub;
|
|
break;
|
|
}
|
|
|
|
return fp;
|
|
}
|
|
|
|
PfnDliHook __pfnDliFailureHook = DliHook;
|
|
PfnDliHook __pfnDliNotifyHook = DliHook;
|
|
#endif // NODELAYLOAD
|
|
|
|
#endif // NOLINESERVICES
|