windows-nt/Source/XPSP1/NT/windows/richedit/re41/reinit.cpp
2020-09-26 16:20:57 +08:00

563 lines
14 KiB
C++

/*
*
* 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