/*++ * * WOW v1.0 * * Copyright (c) 1991, Microsoft Corporation * * WGFONT.C * WOW32 16-bit GDI API support * * History: * Created 07-Mar-1991 by Jeff Parsons (jeffpar) --*/ #include "precomp.h" #pragma hdrstop #include "wingdip.h" MODNAME(wgfont.c); extern int RemoveFontResourceTracking(LPCSTR psz, UINT id); extern int AddFontResourceTracking(LPCSTR psz, UINT id); // for Quickbooks v4 & v5 OCR font support void LoadOCRFont(void); char szOCRA[] = "OCR-A"; char szFonts[] = "\\FONTS"; char szOCRDotTTF[] = "\\OCR-A.TTF"; BOOL gfOCRFontLoaded = FALSE; // a.k.a. WOWAddFontResource ULONG FASTCALL WG32AddFontResource(PVDMFRAME pFrame) { ULONG ul; PSZ psz1; register PADDFONTRESOURCE16 parg16; GETARGPTR(pFrame, sizeof(ADDFONTRESOURCE16), parg16); GETPSZPTR(parg16->f1, psz1); // note: we will never get an hModule in the low word here. // the 16-bit side resolves hModules to an lpsz before calling us if( CURRENTPTD()->dwWOWCompatFlags & WOWCF_UNLOADNETFONTS ) { ul = GETINT16(AddFontResourceTracking(psz1,(UINT)CURRENTPTD())); } else { ul = GETINT16(AddFontResourceA(psz1)); } FREEPSZPTR(psz1); FREEARGPTR(parg16); RETURN(ul); } #define PITCH_MASK ( FIXED_PITCH | VARIABLE_PITCH ) ULONG FASTCALL WG32CreateFont(PVDMFRAME pFrame) { ULONG ul; PSZ psz14; register PCREATEFONT16 parg16; INT iWidth; char achCapString[LF_FACESIZE]; BYTE lfCharSet; BYTE lfPitchAndFamily; #ifdef FE_SB BOOL bUseAlternateFace = FALSE; #endif GETARGPTR(pFrame, sizeof(CREATEFONT16), parg16); GETPSZPTR(parg16->f14, psz14); // take careof compatiblity flags: // if a specific width is specified and GACF_30AVGWIDTH compatiblity // flag is set, scaledown the width by 7/8. // iWidth = INT32(parg16->f2); if (iWidth != 0 && (W32GetAppCompatFlags((HAND16)NULL) & GACF_30AVGWIDTH)) { iWidth = (iWidth * 7) / 8; } lfCharSet = BYTE32(parg16->f9); lfPitchAndFamily = BYTE32(parg16->f13); #ifdef FE_SB if (psz14 && *psz14) #else // !FE_SB if (psz14) #endif // !FE_SB { // Capitalize the string for faster compares. WOW32_strncpy(achCapString, psz14, LF_FACESIZE); achCapString[LF_FACESIZE - 1] = 0; WOW32_strupr(achCapString); // Here we are going to implement a bunch of Win 3.1 hacks rather // than contaminate the 32-bit engine. These same hacks can be found // in WOW (in the CreateFont/CreateFontIndirect code). // // These hacks are keyed off the facename in the LOGFONT. String // comparisons have been unrolled for maximal performance. // Win 3.1 facename-based hack. Some apps, like // Publisher, create a "Helv" font but have the lfPitchAndFamily // set to specify FIXED_PITCH. To work around this, we will patch // the pitch field for a "Helv" font to be variable. if ( !WOW32_strcmp(achCapString, szHelv) ) { lfPitchAndFamily |= ( (lfPitchAndFamily & ~PITCH_MASK) | VARIABLE_PITCH ); } else { // Win 3.1 hack for Legacy 2.0. When a printer does not enumerate // a "Tms Rmn" font, the app enumerates and gets the LOGFONT for // "Script" and then create a font with the name "Tms Rmn" but with // the lfCharSet and lfPitchAndFamily taken from the LOGFONT for // "Script". Here we will over the lfCharSet to be ANSI_CHARSET. if ( !WOW32_strcmp(achCapString, szTmsRmn) ) { lfCharSet = ANSI_CHARSET; } else { // If the lfFaceName is "Symbol", "Zapf Dingbats", or "ZapfDingbats", // enforce lfCharSet to be SYMBOL_CHARSET. Some apps (like Excel) ask // for a "Symbol" font but have the char set set to ANSI. PowerPoint // has the same problem with "Zapf Dingbats". if ( !WOW32_strcmp(achCapString, szSymbol) || !WOW32_strcmp(achCapString, szZapfDingbats) || !WOW32_strcmp(achCapString, szZapf_Dingbats) ) { lfCharSet = SYMBOL_CHARSET; } } } // Win3.1(Win95) hack for Mavis Beacon Teaches Typing 3.0 // The app uses a fixed width of 34*13 for the typing screen. // NT returns 14 from GetTextExtent for Mavis Beacon Courier FP font (width of 14) // while Win95 returns 13, thus long strings won't fit in the typing screen on NT. // Force the width to 13. if ( iWidth==14 && (INT32(parg16->f1)== 20) && !WOW32_strcmp(achCapString, szMavisCourier)) { iWidth = 13; } #ifdef FE_SB // WOWCF_FE_ICHITARO_ITALIC // Ichitaro asks for System Mincho because WIFE fonts aren't installed // we give it a proportional font which is can't handle. If we see // this face name we will replace it with Ms Mincho if (GetSystemDefaultLangID() == 0x411 && CURRENTPTD()->dwWOWCompatFlagsFE & WOWCF_FE_ICHITARO_ITALIC ) { if(!WOW32_strcmp(achCapString, szSystemMincho)) { strcpy(achCapString, szMsMincho); bUseAlternateFace = TRUE; } } #endif // FE_SB } #ifdef FE_SB ul = GETHFONT16(CreateFont(INT32(parg16->f1), iWidth, INT32(parg16->f3), INT32(parg16->f4), INT32(parg16->f5), BYTE32(parg16->f6), BYTE32(parg16->f7), BYTE32(parg16->f8), lfCharSet, BYTE32(parg16->f10), BYTE32(parg16->f11), BYTE32(parg16->f12), lfPitchAndFamily, (bUseAlternateFace ? achCapString : psz14) )); #else ul = GETHFONT16(CreateFont(INT32(parg16->f1), iWidth, INT32(parg16->f3), INT32(parg16->f4), INT32(parg16->f5), BYTE32(parg16->f6), BYTE32(parg16->f7), BYTE32(parg16->f8), lfCharSet, BYTE32(parg16->f10), BYTE32(parg16->f11), BYTE32(parg16->f12), lfPitchAndFamily, psz14)); #endif FREEPSZPTR(psz14); FREEARGPTR(parg16); RETURN(ul); } ULONG FASTCALL WG32CreateFontIndirect(PVDMFRAME pFrame) { ULONG ul; LOGFONT logfont; register PCREATEFONTINDIRECT16 parg16; char achCapString[LF_FACESIZE]; GETARGPTR(pFrame, sizeof(CREATEFONTINDIRECT16), parg16); GETLOGFONT16(parg16->f1, &logfont); // Capitalize the string for faster compares. WOW32_strncpy(achCapString, logfont.lfFaceName, LF_FACESIZE); achCapString[LF_FACESIZE - 1] = 0; CharUpperBuff(achCapString, LF_FACESIZE); // Here we are going to implement a bunch of Win 3.1 hacks rather // than contaminate the 32-bit engine. These same hacks can be found // in WOW (in the CreateFont/CreateFontIndirect code). // // These hacks are keyed off the facename in the LOGFONT. String // comparisons have been unrolled for maximal performance. // Win 3.1 facename-based hack. Some apps, like // Publisher, create a "Helv" font but have the lfPitchAndFamily // set to specify FIXED_PITCH. To work around this, we will patch // the pitch field for a "Helv" font to be variable. if ( !WOW32_strcmp(achCapString, szHelv) ) { logfont.lfPitchAndFamily |= ( (logfont.lfPitchAndFamily & ~PITCH_MASK) | VARIABLE_PITCH ); #ifdef FE_SB // // FE Win 3.1 facename-based hack. Some FE apps // create a "Helv" font but have the lfCharSet // set to DBCS charset (ex. SHIFTJIS_CHARSET). // To work around this, we will wipe out the // lfFaceName[0] with '\0' and let GDI picks a // DBCS font for us. // if (IS_ANY_DBCS_CHARSET(logfont.lfCharSet)) logfont.lfFaceName[0]='\0'; #endif // FE_SB } else { // Win 3.1 hack for Legacy 2.0. When a printer does not enumerate // a "Tms Rmn" font, the app enumerates and gets the LOGFONT for // "Script" and then create a font with the name "Tms Rmn" but with // the lfCharSet and lfPitchAndFamily taken from the LOGFONT for // "Script". Here we will over the lfCharSet to be ANSI_CHARSET. if ( !WOW32_strcmp(achCapString, szTmsRmn) ) { logfont.lfCharSet = ANSI_CHARSET; } // for Quickbooks v4 & v5 OCR font support (see LoadOCRFont for details) else if ( !WOW32_strcmp(achCapString, szOCRA) ) { // Further localize this hack to QuickBooks. Most other apps won't // know about this quirk in this particular font. if(logfont.lfCharSet == SYMBOL_CHARSET) { logfont.lfCharSet = DEFAULT_CHARSET; if(!gfOCRFontLoaded) { LoadOCRFont(); } } } else { // If the lfFaceName is "Symbol", "Zapf Dingbats", or "ZapfDingbats", // enforce lfCharSet to be SYMBOL_CHARSET. Some apps (like Excel) ask // for a "Symbol" font but have the char set set to ANSI. PowerPoint // has the same problem with "Zapf Dingbats". if ( !WOW32_strcmp(achCapString, szSymbol) || !WOW32_strcmp(achCapString, szZapfDingbats) || !WOW32_strcmp(achCapString, szZapf_Dingbats) ) { logfont.lfCharSet = SYMBOL_CHARSET; } #ifdef FE_SB // WOWCF_FE_ICHITARO_ITALIC // Ichitaro asks for System Mincho because WIFE fonts aren't installed // we give it a proportional font which is can't handle. If we see // this face name we will replace it with Ms Mincho if (GetSystemDefaultLangID() == 0x411 && CURRENTPTD()->dwWOWCompatFlagsFE & WOWCF_FE_ICHITARO_ITALIC ) { if(!WOW32_strcmp(achCapString, szSystemMincho)) { strcpy(logfont.lfFaceName, szMsMincho); } } #endif // FE_SB } } ul = GETHFONT16(CreateFontIndirect(&logfont)); FREEARGPTR(parg16); RETURN(ul); } LPSTR lpMSSansSerif = "MS Sans Serif"; LPSTR lpMSSerif = "MS Serif"; LPSTR lpHelvetica = "Helvetica"; INT W32EnumFontFunc(LPENUMLOGFONT pEnumLogFont, LPNEWTEXTMETRIC pNewTextMetric, INT nFontType, PFNTDATA pFntData) { INT iReturn, len; PARM16 Parm16; LPSTR lpFaceNameT = NULL; if((pFntData == NULL) || (pEnumLogFont == NULL)) { WOW32ASSERT(pEnumLogFont && pFntData); return(0); } // take care of compatibility flags: // ORin DEVICE_FONTTYPE bit if the fonttype is truetype and the // Compataibility flag GACF_CALLTTDEVICE is set. // if (nFontType & TRUETYPE_FONTTYPE) { if (W32GetAppCompatFlags((HAND16)NULL) & GACF_CALLTTDEVICE) { nFontType |= DEVICE_FONTTYPE; } } // take care of compatibility flags: // replace Ms Sans Serif with Helv and // replace Ms Serif with Tms Rmn // // only if the facename is NULL and the compat flag GACF_ENUMHELVNTMSRMN // is set. if (pFntData->vpFaceName == (VPVOID)NULL) { if (W32GetAppCompatFlags((HAND16)NULL) & GACF_ENUMHELVNTMSRMN) { if (!WOW32_strcmp(pEnumLogFont->elfLogFont.lfFaceName, lpMSSansSerif)) { strcpy(pEnumLogFont->elfLogFont.lfFaceName, "Helv"); lpFaceNameT = lpMSSansSerif; } else if (!WOW32_strcmp(pEnumLogFont->elfLogFont.lfFaceName, lpHelvetica)) { strcpy(pEnumLogFont->elfLogFont.lfFaceName, "Helv"); lpFaceNameT = lpMSSansSerif; } else if (!WOW32_strcmp(pEnumLogFont->elfLogFont.lfFaceName, lpMSSerif)) { strcpy(pEnumLogFont->elfLogFont.lfFaceName, "Tms Rmn"); lpFaceNameT = lpMSSerif; } } } CallAgain: // be sure allocation size matches stackfree16() size below pFntData->vpLogFont = stackalloc16(sizeof(ENUMLOGFONT16)+sizeof(NEWTEXTMETRIC16)); pFntData->vpTextMetric = (VPVOID)((LPSTR)pFntData->vpLogFont + sizeof(ENUMLOGFONT16)); PUTENUMLOGFONT16(pFntData->vpLogFont, pEnumLogFont); PUTNEWTEXTMETRIC16(pFntData->vpTextMetric, pNewTextMetric); STOREDWORD(Parm16.EnumFontProc.vpLogFont, pFntData->vpLogFont); STOREDWORD(Parm16.EnumFontProc.vpTextMetric, pFntData->vpTextMetric); STOREDWORD(Parm16.EnumFontProc.vpData,pFntData->dwUserFntParam); Parm16.EnumFontProc.nFontType = (SHORT)nFontType; CallBack16(RET_ENUMFONTPROC, &Parm16, pFntData->vpfnEnumFntProc, (PVPVOID)&iReturn); if(pFntData->vpLogFont) { stackfree16(pFntData->vpLogFont, (sizeof(ENUMLOGFONT16) + sizeof(NEWTEXTMETRIC16))); } if (((SHORT)iReturn) && lpFaceNameT) { // if the callback returned true, now call with the actual facename // Just to be sure, we again copy all the data for callback. This will // take care of any apps which modify the passed in structures. len = min(LF_FACESIZE-1, strlen(lpFaceNameT)); strncpy(pEnumLogFont->elfLogFont.lfFaceName, lpFaceNameT, len); pEnumLogFont->elfLogFont.lfFaceName[len] = '\0'; lpFaceNameT = (LPSTR)NULL; goto CallAgain; } return (SHORT)iReturn; } ULONG W32EnumFontHandler( PVDMFRAME pFrame, BOOL fEnumFontFamilies ) { ULONG ul = 0; PSZ psz2; FNTDATA FntData; register PENUMFONTS16 parg16; GETARGPTR(pFrame, sizeof(ENUMFONTS16), parg16); GETPSZPTR(parg16->f2, psz2); FntData.vpfnEnumFntProc = DWORD32(parg16->f3); FntData.dwUserFntParam = DWORD32(parg16->f4); FntData.vpFaceName = DWORD32(parg16->f2); if ( fEnumFontFamilies ) { ul = GETINT16(EnumFontFamilies(HDC32(parg16->f1), psz2, (FONTENUMPROC)W32EnumFontFunc, (LPARAM)&FntData)); } else { ul = GETINT16(EnumFonts(HDC32(parg16->f1), psz2, (FONTENUMPROC)W32EnumFontFunc, (LPARAM)&FntData)); } FREEPSZPTR(psz2); FREEARGPTR(parg16); RETURN(ul); } ULONG FASTCALL WG32EnumFonts(PVDMFRAME pFrame) { return( W32EnumFontHandler( pFrame, FALSE ) ); } ULONG FASTCALL WG32GetAspectRatioFilter(PVDMFRAME pFrame) { ULONG ul = 0; SIZE size2; register PGETASPECTRATIOFILTER16 parg16; GETARGPTR(pFrame, sizeof(GETASPECTRATIOFILTER16), parg16); if (GETDWORD16(GetAspectRatioFilterEx(HDC32(parg16->f1), &size2))) { ul = (WORD)size2.cx | (size2.cy << 16); } FREEARGPTR(parg16); RETURN(ul); } ULONG FASTCALL WG32GetCharWidth(PVDMFRAME pFrame) { ULONG ul = 0L; INT ci; PINT pi4; register PGETCHARWIDTH16 parg16; INT BufferT[256]; GETARGPTR(pFrame, sizeof(GETCHARWIDTH16), parg16); ci = WORD32(parg16->wLastChar) - WORD32(parg16->wFirstChar) + 1; pi4 = STACKORHEAPALLOC(ci * sizeof(INT), sizeof(BufferT), BufferT); if (pi4) { ULONG ulLast = WORD32(parg16->wLastChar); #ifdef FE_SB /* * If ulLast sets DBCS code (0x82xx), then below code is illigal. */ if (ulLast > 0xff && !(IsDBCSLeadByte(HIBYTE(ulLast)))) #else // !FE_SB if (ulLast > 0xff) #endif // !FE_SB ulLast = 0xff; ul = GETBOOL16(GetCharWidth(HDC32(parg16->hDC), WORD32(parg16->wFirstChar), ulLast, pi4)); PUTINTARRAY16(parg16->lpIntBuffer, ci, pi4); STACKORHEAPFREE(pi4, BufferT); } FREEARGPTR(parg16); RETURN(ul); } // a.k.a. WOWRemoveFontResource ULONG FASTCALL WG32RemoveFontResource(PVDMFRAME pFrame) { ULONG ul; PSZ psz1; register PREMOVEFONTRESOURCE16 parg16; GETARGPTR(pFrame, sizeof(REMOVEFONTRESOURCE16), parg16); GETPSZPTR(parg16->f1, psz1); // note: we will never get an hModule in the low word here. // the 16-bit side resolves hModules to an lpsz before calling us if( CURRENTPTD()->dwWOWCompatFlags & WOWCF_UNLOADNETFONTS ) { ul = GETBOOL16(RemoveFontResourceTracking(psz1,(UINT)CURRENTPTD())); } else { ul = GETBOOL16(RemoveFontResource(psz1)); } FREEPSZPTR(psz1); FREEARGPTR(parg16); RETURN(ul); } /* WG32GetCurLogFont * * This thunk implements the undocumented Win3.0 and Win3.1 API * GetCurLogFont (GDI.411). Symantec QA4.0 uses it. * * HFONT GetCurLogFont (HDC) * HDC hDC; // Device Context * * This function returns the current Logical font selected for the * specified device context. * * To implement this undocumented API we will use the NT undocumented API * GetHFONT. * * SudeepB 08-Mar-1996 * */ extern HFONT APIENTRY GetHFONT (HDC hdc); ULONG FASTCALL WG32GetCurLogFont(PVDMFRAME pFrame) { ULONG ul; register PGETCURLOGFONT16 parg16; GETARGPTR(pFrame, sizeof(GETCURLOGFONT16), parg16); ul = GETHFONT16 (GetHFONT(HDC32 (parg16->hDC))); FREEARGPTR(parg16); return (ul); } // // This allows Quickbooks v4 & v5 to use their OCR-A.TTF font right after they // install. At the end of installation on both versions, you are asked if you // want to "restart" windows. If you click OK it logs you off of NT5, but does // *not* reboot the system -- which the app is counting on to cause the OCR-A // font to be loaded. The result on W2K is that whenever the app uses the OCR-A // font, it will get mapped to wingdings instead. // // This is further complicated by the fact that the font file OCR-A.TTF doesn't // specify the charset in the header. On Win3.1, Win95, & pre-NT5, unspecified // charset's got mapped to the SYMBOL_CHARSET - therefore, Quickbooks specifies // SYMBOL_CHARSET in its LOGFONT struct to accomodate this. (OCR-A apparently // is licenced from Monotype Typography, Ltd. which presumably is why Intuit // didn't fix the header issue in the font file). // // This changed on Win98 and W2K, unspecified charset's now get mapped to the // DEFAULT_CHARSET. This was done so these fonts will always map to a default // localized font that will always be readable. Hence, the hack where we change // the charset from SYMBOL_CHARSET to DEFAULT_CHARSET in the LOGFONT struct. // // On v4, the install program copies OCR-A.FOT & OCR-A.TTF to the SYSTEM dir. // Once you "restart" (not reboot) the system & log back on, the OCR-A font is // added to the registry (as OCR-A.FOT) but the font files are still in the // SYSTEM dir. Rebooting causes the fonts files to be moved to the FONTS dir, // the registry entry is changed to OCR-A.TTF. (done by the "Font Sweeper") // // On v5, the install program copies the .ttf & .fot files to the FONTS dir // but again, counts on the reboot to cause the fonts to be loaded. It puts // correct registry entry (OCR-A.TTF) in the registry fonts section. // // The result of all this is: // For either version of the app, without the charset hack, you will always get // a wingding font instead of OCR-A. With the charset hack, you will get a // readable font, such as Arial, until you reboot -- after which you will get // OCR-A for v5 but Arial for v4. With this function (in conjunction with the // charset hack) both version will always get OCR-A with or without rebooting. // // This function explicitly loads the OCR-A from the font files located in // either the FONTS dir or the SYSTEM dir. // void LoadOCRFont(void) { char szFontPath[MAX_PATH]; DWORD dw; int cb; DWORD FontPathSize; FontPathSize = strlen(szOCRDotTTF) + max(strlen(szFonts), strlen(szSystem)); // get equivalent of "c:\windows" for this system dw = GetWindowsDirectory(szFontPath, MAX_PATH); // we're going to add a maximum of 18 chars "\SYSTEM\OCR-A.TTF" if(dw && ((MAX_PATH - FontPathSize) >= dw)) { // build "c:\windows\FONTS\OCR-A.TTF" (QuickBooks v5) strcat(szFontPath, szFonts); strcat(szFontPath, szOCRDotTTF); // If font file doesn't exist in FONTS dir, this must be QuickBooks v4 // The FR_PRIVATE flag means that the font will be unloaded when the vdm // process goes away. The FR_NO_ENUM flag means that this instance of // the font can't be enumerated by other processes (it might go away // while the other processes are trying to use it). cb = AddFontResourceEx(szFontPath, FR_PRIVATE | FR_NOT_ENUM, NULL); if(!cb) { // reset path to "c:\windows" szFontPath[dw] = '\0'; // build "c:\windows\SYSTEM\OCR-A.TTF" strcat(szFontPath, szSystem); strcat(szFontPath, szOCRDotTTF); cb = AddFontResourceEx(szFontPath, FR_PRIVATE | FR_NOT_ENUM, NULL); // if it wasn't loaded from the SYSTEM dir either, punt } if(cb) { // specify that the font is already loaded for the life of this VDM gfOCRFontLoaded = TRUE; } } }