/* * * 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 #endif #endif #include "_host.h" #ifndef NOVERSIONINFO #include #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