//**************************************************************************** // WOW32 fax support. // // History: // 02-jan-95 nandurir created. // 01-feb-95 reedb Clean-up, support printer install and bug fixes. // //**************************************************************************** //**************************************************************************** // This expalins how all this works (sort of) using WinFax as example. // Install: // 1. App calls WriteProfileString("devices","WINFAX","WINFAX,Com1:") // to register a "printer" in Win.ini a-la Win3.1 // 2. Our thunks of WritexxxProfileString() look for the "devices" string // and pass the call to IsFaxPrinterWriteProfileString(lpszSection,lpszKey, // lpszString). // 3. If lpszKey ("WINFAX" in this case) is in our supported fax drivers list // (See Reg\SW\MS\WinNT\CurrentVersion\WOW\WOWFax\SupportedFaxDrivers) // (by call to IsFaxPrinterSupportedDevice()), we call InstallWowFaxPrinter // to add the printer the NT way -- via AddPrinter(). // 4. To set up the call to AddPrinter, we copy WOWFAX.DLL and WOWFAXUI.DLL to // the print spooler driver directory (\NT\system32\spool\drivers\w32x86\2) // 5. We next call AddPrinterDriver to register the wowfax driver. // 6. We then call wow32!DoAddPrinterStuff which launches a new thread, // wow32!AddPrinterThread, which calls winspool.drv!AddPrinter() for us. The // PrinterInfo.pPrinterName = the 16-bit fax driver name,"WINFAX" in this // case. WinSpool.drv then does a RPC call into the spooler. // 7. During the AddPrinter() call, the spooler calls back into the driver to // get driver specific info. These callbacks are handled by our WOWFAX // driver in the spooler's process. They essentially callback into WOW // via wow32!WOWFaxWndProc(). // 8. WOWFaxWndProc() passes the callback onto WOW32FaxHandler, which calls // back to wowexec!FaxWndProc(). // 9. FaxWndProc then calls the 16-bit LoadLibrary() to open the 16-bit fax // driver (WinFax.drv in this case). // 10. The messages sent to FaxWndProc tell it which exported function it needs // call in the 16-bit driver on behalf of the spooler. // 11. Any info the spooler wants to pass to the 16-bit driver or get from it // essentially goes through the mechanism in steps 7 - 10. // Now you know (sort of). //**************************************************************************** // // Notes on what allows us to support a 16-bit fax driver: // Essentially we have to know in advance which API's an app will call in the // driver so we can handle the thunks. It turns out that fax drivers only // need to export a small essential list of API's: // Control, Disable, Enable, BitBlt, ExtDeviceMode, DeviceCapabilities // (see mvdm\inc\wowfax.h\_WOWFAXINFO16 struct (all the PASCAL declarations) // and mvdm\wow16\test\shell\wowexfax.c\FaxWndProc() ) // The list is way too big to support 16-bit printer & display drivers. // If a 16-bit fax driver exports these API's there's a pretty good chance // we can support it in WOW. Other issues to look into: the dlgproc's the // driver export's, any obsolete Win 3.0 API's that the NT spooler won't know // how to call. // //**************************************************************************** #include "precomp.h" #pragma hdrstop #define WOWFAX_INC_COMMON_CODE #include "wowgdip.h" #define DEFINE_DDRV_DEBUG_STRINGS #include "wowfax.h" #include "winddi.h" #include "winspool.h" MODNAME(wowfax.c); typedef struct _WOWADDPRINTER { LPVOID pPrinterStuff; INT iCode; BOOL bRet; } WOWADDPRINTER, *PWOWADDPRINTER; //**************************************************************************** // globals - // //**************************************************************************** DWORD DeviceCapsHandler(LPWOWFAXINFO lpfaxinfo); DWORD ExtDevModeHandler(LPWOWFAXINFO lpfaxinfo); BOOL ConvertDevMode(PDEVMODE16 lpdm16, LPDEVMODEW lpdmW, BOOL fTo16); BOOL ConvertGdiInfo(LPGDIINFO16 lpginfo16, PGDIINFO lpginfo, BOOL fTo16); extern HANDLE hmodWOW32; LPWOWFAXINFO glpfaxinfoCur = 0; WOWFAXINFO gfaxinfo; UINT uNumSupFaxDrv; LPSTR *SupFaxDrv; //**************************************************************************** // SortedInsert - Alpha sort. //**************************************************************************** VOID SortedInsert(LPSTR lpElement, LPSTR *alpList) { LPSTR lpTmp, lpSwap; while (*alpList) { if (WOW32_stricmp(lpElement, *alpList) < 0) { break; } alpList++; } lpTmp = *alpList; *alpList++ = lpElement; while (lpTmp) { // SWAP(*alpList, lpTmp); lpSwap = *alpList; *alpList = lpTmp; lpTmp = lpSwap; alpList++; } } //**************************************************************************** // BuildStrList - Find the starting point of strings in a list (lpList) of // NULL terminated strings which is double NULL terminated. // If a non-NULL alpList parameter is passed, it will be // filled with an array of pointers to the starting point // of each string in the list. The number of strings in the // list is always returned. //**************************************************************************** UINT BuildStrList(LPSTR lpList, LPSTR *alpList) { LPSTR lp; TCHAR cLastChar = 1; UINT uCount = 0; lp = lpList; while ((cLastChar) || (*lp)) { if ((*lp == 0) && (lp != lpList)) { uCount++; } if ((lpList == lp) || (cLastChar == 0)) { if ((*lp) && (alpList)) { SortedInsert(lp, alpList); } } cLastChar = *lp++; } return uCount; } //**************************************************************************** // GetSupportedFaxDrivers - Read in the SupFaxDrv name list from the // registry. This list is used to determine if we will // install a 16-bit fax printer driver during // WriteProfileString and WritePrivateProfileString. //**************************************************************************** LPSTR *GetSupportedFaxDrivers(UINT *uCount) { HKEY hKey = 0; DWORD dwType; DWORD cbBufSize=0; LPSTR lpSupFaxDrvBuf; LPSTR *alpSupFaxDrvList = NULL; *uCount = 0; // Open the registry key. if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\WOW\\WowFax\\SupportedFaxDrivers", 0, KEY_READ, &hKey ) != ERROR_SUCCESS) { goto GSFD_error; } // Query value for size of buffer and allocate. if (RegQueryValueEx(hKey, "DriverNames", 0, &dwType, NULL, &cbBufSize) != ERROR_SUCCESS) { goto GSFD_error; } if ((dwType != REG_MULTI_SZ) || ((lpSupFaxDrvBuf = (LPSTR) malloc_w(cbBufSize)) == NULL)) { goto GSFD_error; } if (RegQueryValueEx(hKey, "DriverNames", 0, &dwType, lpSupFaxDrvBuf, &cbBufSize) != ERROR_SUCCESS) { goto GSFD_error; } // Get the number of elements in the list if (*uCount = BuildStrList(lpSupFaxDrvBuf, NULL)) { // Build an array of pointers to the start of the strings in the list. alpSupFaxDrvList = (LPSTR *) malloc_w(*uCount * sizeof(LPSTR)); if (alpSupFaxDrvList) { // Fill the array with string starting points. RtlZeroMemory(alpSupFaxDrvList, *uCount * sizeof(LPSTR)); BuildStrList(lpSupFaxDrvBuf, alpSupFaxDrvList); } else { goto GSFD_error; } } goto GSFD_exit; GSFD_error: LOGDEBUG(0,("WOW32!GetSupportedFaxDrivers failed!\n")); GSFD_exit: if (hKey) { RegCloseKey(hKey); } return alpSupFaxDrvList; } //**************************************************************************** // WowFaxWndProc - This is the 32-bit WndProc which will SubClass the 16-bit // FaxWndProc in WOWEXEC.EXE. It's main function is to // convert 32-bit data passed from the WOW 32-bit generic // fax driver to 16-bit data to be used by the various 16-bit // fax printer drivers. //**************************************************************************** LONG WowFaxWndProc(HWND hwnd, UINT uMsg, UINT uParam, LONG lParam) { TCHAR lpPath[MAX_PATH]; HANDLE hMap; if ((uMsg >= WM_DDRV_FIRST) && (uMsg <= WM_DDRV_LAST)) { // // WM_DDRV_* message: uParam = idMap // lParam = unused. // // The corresponding data is obtained from the shared memory. // GetFaxDataMapName(uParam, lpPath); hMap = OpenFileMapping(FILE_MAP_ALL_ACCESS, FALSE, lpPath); if (hMap) { LPWOWFAXINFO lpT; if (lpT = (LPWOWFAXINFO)MapViewOfFile(hMap, FILE_MAP_ALL_ACCESS, 0, 0, 0)) { WOW32FaxHandler(lpT->msg, (LPSTR)lpT); // Set the status to TRUE indicating that the message // has been 'processed' by WOW. This doesnot indicate // the success or the failure of the actual processing // of the message. lpT->status = TRUE; UnmapViewOfFile(lpT); CloseHandle(hMap); return(TRUE); } CloseHandle(hMap); } LOGDEBUG(0,("WowFaxWndProc failed to setup shared data mapping!\n")); // WOW32ASSERT(FALSE); // turn this off - Procomm tries to install // this many times. } else { // Not a WM_DDRV_* message. Pass it on to the original proc. return CallWindowProc(gfaxinfo.proc16, hwnd, uMsg, uParam, lParam); } return(TRUE); } //************************************************************************** // WOW32FaxHandler - // // Handles various WowFax related operations. // //************************************************************************** ULONG WOW32FaxHandler(UINT iFun, LPSTR lpIn) { LPWOWFAXINFO lpT = (LPWOWFAXINFO)lpIn; LPWOWFAXINFO16 lpT16; HWND hwnd = gfaxinfo.hwnd; LPBYTE lpData; VPVOID vp; #ifdef DEBUG int DebugStringIndex = iFun - (WM_USER+0x100+1); if ((DebugStringIndex >= WM_DDRV_FIRST) && (DebugStringIndex <= WM_DDRV_LAST) ) { LOGDEBUG(0,("WOW32FaxHandler, %s, 0x%lX\n", (LPSTR)szWmDdrvDebugStrings[DebugStringIndex], (LPSTR) lpIn)); } #endif switch (iFun) { case WM_DDRV_SUBCLASS: // // Subclass the window - This is so that we get a chance to // transform the 32bit data to 16bit data and vice versa. A // NULL HWND, passed in lpIn, indicates don't subclass. // if (gfaxinfo.hwnd = (HWND)lpIn) { gfaxinfo.proc16 = (WNDPROC)SetWindowLong((HWND)lpIn, GWL_WNDPROC, (DWORD)WowFaxWndProc); gfaxinfo.tid = GetWindowThreadProcessId((HWND)lpIn, NULL); } WOW32ASSERT(sizeof(DEVMODE16) + 4 == sizeof(DEVMODE31)); // // Read in the SupFaxDrv name list from the registry. // SupFaxDrv = GetSupportedFaxDrivers(&uNumSupFaxDrv); break; case WM_DDRV_ENABLE: // Enable the driver: // . first intialize the 16bit faxinfo datastruct // . then inform the driver (dll name) to be loaded // // format of ddrv_message: // wParam = hdc (just a unique id) // lparam = 16bit faxinfo struct with relevant data // Must call 'callwindowproc' not 'sendmessage' because // WowFaxWndProc is a subclass of the 16-bit FaxWndProc. // WOW32ASSERT(lpT->lpinfo16 == (LPSTR)NULL); lpT->lpinfo16 = (LPSTR)CallWindowProc( gfaxinfo.proc16, hwnd, WM_DDRV_INITFAXINFO16, lpT->hdc, (LPARAM)0); if (lpT->lpinfo16) { vp = malloc16(lpT->cData); GETVDMPTR(vp, lpT->cData, lpData); if (lpData == 0) { break; } GETVDMPTR(lpT->lpinfo16, sizeof(WOWFAXINFO16), lpT16); if (lpT16) { if (lstrlenW(lpT->szDeviceName) < sizeof(lpT16->szDeviceName)) { WideCharToMultiByte(CP_ACP, 0, lpT->szDeviceName, lstrlenW(lpT->szDeviceName) + 1, lpT16->szDeviceName, sizeof(lpT16->szDeviceName), NULL, NULL); lpT16->lpDriverName = lpT->lpDriverName; if (lpT->lpDriverName) { lpT16->lpDriverName = (LPBYTE)vp + (DWORD)lpT->lpDriverName; WideCharToMultiByte(CP_ACP, 0, (PWSTR)((LPSTR)lpT + (DWORD)lpT->lpDriverName), lstrlenW((LPWSTR)((LPSTR)lpT + (DWORD)lpT->lpDriverName)) + 1, lpData + (DWORD)lpT->lpDriverName, lstrlenW((LPWSTR)((LPSTR)lpT + (DWORD)lpT->lpDriverName)) + 1, NULL, NULL); } lpT16->lpPortName = lpT->lpPortName; if (lpT->lpPortName) { lpT16->lpPortName = (LPBYTE)vp + (DWORD)lpT->lpPortName; WideCharToMultiByte(CP_ACP, 0, (PWSTR)((LPSTR)lpT + (DWORD)lpT->lpPortName), lstrlenW((LPWSTR)((LPSTR)lpT + (DWORD)lpT->lpPortName)) + 1, lpData + (DWORD)lpT->lpPortName, lstrlenW((LPWSTR)((LPSTR)lpT + (DWORD)lpT->lpPortName)) + 1, NULL, NULL); } lpT16->lpIn = lpT->lpIn; if (lpT->lpIn) { lpT16->lpIn = (LPBYTE)vp + (DWORD)lpT->lpIn; ConvertDevMode((PDEVMODE16)(lpData + (DWORD)lpT->lpIn), (LPDEVMODEW)((LPSTR)lpT + (DWORD)lpT->lpIn), TRUE); } WOW32ASSERT((sizeof(GDIINFO16) + sizeof(POINT16)) <= sizeof(GDIINFO)); lpT16->lpOut = (LPBYTE)vp + (DWORD)lpT->lpOut; FREEVDMPTR(lpData); FREEVDMPTR(lpT16); lpT->retvalue = CallWindowProc( gfaxinfo.proc16, hwnd, lpT->msg, lpT->hdc, (LPARAM)lpT->lpinfo16); if (lpT->retvalue) { GETVDMPTR(vp, lpT->cData, lpData); ConvertGdiInfo((LPGDIINFO16)(lpData + (DWORD)lpT->lpOut), (PGDIINFO)((LPSTR)lpT + (DWORD)lpT->lpOut), FALSE); } } } free16(vp); } break; case WM_DDRV_ESCAPE: GETVDMPTR(lpT->lpinfo16, sizeof(WOWFAXINFO16), lpT16); if (lpT16) { lpT16->wCmd = lpT->wCmd; } FREEVDMPTR(lpT16); lpT->retvalue = CallWindowProc( gfaxinfo.proc16, hwnd, lpT->msg, lpT->hdc, (LPARAM)lpT->lpinfo16); break; case WM_DDRV_PRINTPAGE: // // set the global variable. When the 16bit driver calls DMBitBlt we // get the bitmap info from here. Since WOW is single threaded we // won't receive another printpage msg before we return from here. // // All pointers in the faxinfo structure are actually // 'offsets from the start of the mapfile' to relevant data. // glpfaxinfoCur = lpT; lpT->lpbits = (LPBYTE)lpT + (DWORD)lpT->lpbits; // fall through; case WM_DDRV_STARTDOC: // WowFax (EasyFax Ver2.0) support... GETVDMPTR(lpT->lpinfo16, sizeof(WOWFAXINFO16), lpT16); if (lpT16) { WideCharToMultiByte(CP_ACP, 0, lpT->szDocName, lstrlenW(lpT->szDocName) + 1, lpT16->szDocName, sizeof(lpT16->szDocName), NULL, NULL); } lpT->retvalue = CallWindowProc( gfaxinfo.proc16, hwnd, lpT->msg, lpT->hdc, (LPARAM)lpT->lpinfo16); break; case WM_DDRV_ENDDOC: lpT->retvalue = CallWindowProc( gfaxinfo.proc16, hwnd, lpT->msg, lpT->hdc, (LPARAM)lpT->lpinfo16); break; case WM_DDRV_DISABLE: CallWindowProc( gfaxinfo.proc16, hwnd, lpT->msg, lpT->hdc, (LPARAM)lpT->lpinfo16); lpT->retvalue = TRUE; break; case WM_DDRV_EXTDMODE: case WM_DDRV_DEVCAPS: WOW32ASSERT(lpT->lpinfo16 == (LPSTR)NULL); lpT->lpinfo16 = (LPSTR)CallWindowProc( gfaxinfo.proc16, hwnd, WM_DDRV_INITFAXINFO16, lpT->hdc, (LPARAM)0); if (lpT->lpinfo16) { vp = malloc16(lpT->cData); GETVDMPTR(vp, lpT->cData, lpData); if (lpData == 0) { break; } GETVDMPTR(lpT->lpinfo16, sizeof(WOWFAXINFO16), lpT16); if (lpT16) { if (lstrlenW(lpT->szDeviceName) < sizeof(lpT16->szDeviceName)) { WideCharToMultiByte(CP_ACP, 0, lpT->szDeviceName, lstrlenW(lpT->szDeviceName) + 1, lpT16->szDeviceName, sizeof(lpT16->szDeviceName), NULL, NULL); lpT16->lpDriverName = lpT->lpDriverName; if (lpT->lpDriverName) { lpT16->lpDriverName = (LPBYTE)vp + (DWORD)lpT->lpDriverName; WideCharToMultiByte(CP_ACP, 0, (PWSTR)((LPSTR)lpT + (DWORD)lpT->lpDriverName), lstrlenW((LPWSTR)((LPSTR)lpT + (DWORD)lpT->lpDriverName)) + 1, lpData + (DWORD)lpT->lpDriverName, lstrlenW((LPWSTR)((LPSTR)lpT + (DWORD)lpT->lpDriverName)) + 1, NULL, NULL); } FREEVDMPTR(lpData); FREEVDMPTR(lpT16); lpT->retvalue = CallWindowProc( gfaxinfo.proc16, hwnd, WM_DDRV_LOAD, lpT->hdc, (LPARAM)lpT->lpinfo16); if (lpT->retvalue) { lpT->retvalue = (iFun == WM_DDRV_DEVCAPS) ? DeviceCapsHandler(lpT) : ExtDevModeHandler(lpT) ; } CallWindowProc( gfaxinfo.proc16, hwnd, WM_DDRV_UNLOAD, lpT->hdc, (LPARAM)lpT->lpinfo16); } } free16(vp); } break; } return TRUE; } //************************************************************************** // gDC_CopySize - // // Indicates the size of a list item in bytes for use during // the DeviceCapsHandler thunk. A zero entry indicates that an // allocate and copy is not needed for the query. // //************************************************************************** BYTE gDC_ListItemSize[DC_COPIES + 1] = { 0, 0, // DC_FIELDS 1 sizeof(WORD), // DC_PAPERS 2 sizeof(POINT), // DC_PAPERSIZE 3 sizeof(POINT), // DC_MINEXTENT 4 sizeof(POINT), // DC_MAXEXTENT 5 sizeof(WORD), // DC_BINS 6 0, // DC_DUPLEX 7 0, // DC_SIZE 8 0, // DC_EXTRA 9 0, // DC_VERSION 10 0, // DC_DRIVER 11 24, // DC_BINNAMES 12 //ANSI sizeof(LONG) * 2, // DC_ENUMRESOLUTIONS 13 64, // DC_FILEDEPENDENCIES 14 //ANSI 0, // DC_TRUETYPE 15 64, // DC_PAPERNAMES 16 //ANSI 0, // DC_ORIENTATION 17 0 // DC_COPIES 18 }; //************************************************************************** // DeviceCapsHandler - // // Makes a single call down to the 16-bit printer driver for queries // which don't need to allocate and copy. For queries which do, two // calls to the 16-bit printer driver are made. One to get the number // of items, and a second to get the actual data. // //************************************************************************** DWORD DeviceCapsHandler(LPWOWFAXINFO lpfaxinfo) { LPWOWFAXINFO16 lpWFI16; LPSTR lpSrc; LPBYTE lpDest; INT i; DWORD cbData16; // Size of data items. UINT cbUni; LOGDEBUG(0,("DeviceCapsHandler, lpfaxinfo: %X, wCmd: %X\n", lpfaxinfo, lpfaxinfo->wCmd)); GETVDMPTR(lpfaxinfo->lpinfo16, sizeof(WOWFAXINFO16), lpWFI16); // Get the number of data items with a call to the 16-bit printer driver. lpWFI16->lpDriverName = 0; lpWFI16->lpPortName = 0; lpWFI16->wCmd = lpfaxinfo->wCmd; lpWFI16->cData = 0; lpWFI16->lpOut = 0; lpfaxinfo->cData = 0; lpfaxinfo->retvalue = CallWindowProc(gfaxinfo.proc16, gfaxinfo.hwnd, lpfaxinfo->msg, lpfaxinfo->hdc, (LPARAM)lpfaxinfo->lpinfo16); cbData16 = gDC_ListItemSize[lpfaxinfo->wCmd]; if (lpfaxinfo->lpOut && cbData16 && lpfaxinfo->retvalue) { // We need to allocate and copy for this query lpWFI16->cData = cbData16 * lpfaxinfo->retvalue; // assert the size of output buffer - and set it the actual data size switch (lpfaxinfo->wCmd) { case DC_BINNAMES: case DC_PAPERNAMES: // These fields need extra room for ANSI to UNICODE conversion. WOW32ASSERT((lpfaxinfo->cData - (DWORD)lpfaxinfo->lpOut) >= lpWFI16->cData * sizeof(WCHAR)); lpfaxinfo->cData = lpWFI16->cData * sizeof(WCHAR); break; default: WOW32ASSERT((lpfaxinfo->cData - (DWORD)lpfaxinfo->lpOut) >= lpWFI16->cData); lpfaxinfo->cData = lpWFI16->cData; break; } if ((lpWFI16->lpOut = (LPSTR)malloc16(lpWFI16->cData)) == NULL) { lpfaxinfo->retvalue = 0; goto LeaveDeviceCapsHandler; } // Get the list data with a call to the 16-bit printer driver. lpfaxinfo->retvalue = CallWindowProc(gfaxinfo.proc16, gfaxinfo.hwnd, lpfaxinfo->msg, lpfaxinfo->hdc, (LPARAM)lpfaxinfo->lpinfo16); GETVDMPTR(lpWFI16->lpOut, 0, lpSrc); lpDest = (LPBYTE)lpfaxinfo + (DWORD)lpfaxinfo->lpOut; switch (lpfaxinfo->wCmd) { case DC_BINNAMES: case DC_PAPERNAMES: for (i = 0; i < (INT)lpfaxinfo->retvalue; i++) { RtlMultiByteToUnicodeN((LPWSTR)lpDest, cbData16 * sizeof(WCHAR), (PULONG)&cbUni, (LPBYTE)lpSrc, cbData16); lpDest += cbData16 * sizeof(WCHAR); lpSrc += cbData16; } break; default: #ifdef FE_SB // for buggy fax driver such as CB-FAX Pro (Bother Corp.) try { RtlCopyMemory(lpDest, lpSrc, lpWFI16->cData); } except(EXCEPTION_EXECUTE_HANDLER) { // What can I do for the exception... ???? // Anyway, we don't want to die..... #if DBG LOGDEBUG(0,("Exception during copying some data\n")); #endif } #else // !FE_SB RtlCopyMemory(lpDest, lpSrc, lpWFI16->cData); #endif // !FE_SB break; } free16((VPVOID)lpWFI16->lpOut); FREEVDMPTR(lpSrc); } LeaveDeviceCapsHandler: FREEVDMPTR(lpWFI16); return lpfaxinfo->retvalue; } //************************************************************************** // ExtDevModeHandler // //************************************************************************** DWORD ExtDevModeHandler(LPWOWFAXINFO lpfaxinfo) { LPWOWFAXINFO16 lpT16; LPSTR lpT; VPVOID vp; LOGDEBUG(0,("ExtDevModeHandler\n")); (LONG)lpfaxinfo->retvalue = -1; GETVDMPTR(lpfaxinfo->lpinfo16, sizeof(WOWFAXINFO16), lpT16); if (lpT16) { // assumption that 16bit data won't be larger than 32bit data. // this makes life easy in two ways; first we don't need to calculate // the exact size and secondly the 16bit pointers can be set to same // relative offsets as input(32 bit) pointers vp = malloc16(lpfaxinfo->cData); if (vp) { GETVDMPTR(vp, lpfaxinfo->cData, lpT); if (lpT) { lpT16->wCmd = lpfaxinfo->wCmd; lpT16->lpOut = (LPSTR)lpfaxinfo->lpOut; lpT16->lpIn = (LPSTR)lpfaxinfo->lpIn; lpT16->lpDriverName = (LPBYTE)vp + (DWORD)lpfaxinfo->lpDriverName; lpT16->lpPortName = (LPBYTE)vp + (DWORD)lpfaxinfo->lpPortName; WideCharToMultiByte(CP_ACP, 0, (PWSTR)((LPSTR)lpfaxinfo + (DWORD)lpfaxinfo->lpDriverName), lstrlenW((LPWSTR)((LPSTR)lpfaxinfo + (DWORD)lpfaxinfo->lpDriverName)) + 1, lpT + (DWORD)lpfaxinfo->lpDriverName, lstrlenW((LPWSTR)((LPSTR)lpfaxinfo + (DWORD)lpfaxinfo->lpDriverName)) + 1, NULL, NULL); WideCharToMultiByte(CP_ACP, 0, (PWSTR)((LPSTR)lpfaxinfo + (DWORD)lpfaxinfo->lpPortName), lstrlenW((LPWSTR)((LPSTR)lpfaxinfo + (DWORD)lpfaxinfo->lpPortName)) + 1, lpT + (DWORD)lpfaxinfo->lpPortName, lstrlenW((LPWSTR)((LPSTR)lpfaxinfo + (DWORD)lpfaxinfo->lpPortName)) + 1, NULL, NULL); if (lpfaxinfo->lpIn) { lpT16->lpIn = (LPBYTE)vp + (DWORD)lpfaxinfo->lpIn; ConvertDevMode((PDEVMODE16)(lpT + (DWORD)lpfaxinfo->lpIn), (LPDEVMODEW)((LPSTR)lpfaxinfo + (DWORD)lpfaxinfo->lpIn), TRUE); } if (lpfaxinfo->lpOut) { lpT16->lpOut = (LPBYTE)vp + (DWORD)lpfaxinfo->lpOut; } lpT16->hwndui = GETHWND16(lpfaxinfo->hwndui); FREEVDMPTR(lpT); lpfaxinfo->retvalue = CallWindowProc( gfaxinfo.proc16, gfaxinfo.hwnd, lpfaxinfo->msg, lpfaxinfo->hdc, (LPARAM)lpfaxinfo->lpinfo16); if ((lpfaxinfo->wCmd == 0) && (lpfaxinfo->retvalue > 0)) { // the 16bit driver has returned 16bit struct size. change // the return value to correspond to the devmodew struct. // // since devmode16 (the 3.0 version) is smaller than devmode31 // the retvalue will take careof both win30/win31 devmode WOW32ASSERT(sizeof(DEVMODE16) < sizeof(DEVMODE31)); lpfaxinfo->retvalue += (sizeof(DEVMODEW) - sizeof(DEVMODE16)); } GETVDMPTR(vp, lpfaxinfo->cData, lpT); if ((lpfaxinfo->wCmd & DM_COPY) && lpfaxinfo->lpOut && (lpfaxinfo->retvalue == IDOK)) { ConvertDevMode((PDEVMODE16)(lpT + (DWORD)lpfaxinfo->lpOut), (LPDEVMODEW)((LPSTR)lpfaxinfo + (DWORD)lpfaxinfo->lpOut), FALSE); } } free16(vp); } } FREEVDMPTR(lpT16); return lpfaxinfo->retvalue; } //*************************************************************************** // ConvertDevMode //*************************************************************************** BOOL ConvertDevMode(PDEVMODE16 lpdm16, LPDEVMODEW lpdmW, BOOL fTo16) { LOGDEBUG(0,("ConvertDevMode\n")); if (!lpdm16 || !lpdmW) return TRUE; if (fTo16) { RtlZeroMemory(lpdm16, sizeof(DEVMODE16)); WideCharToMultiByte(CP_ACP, 0, lpdmW->dmDeviceName, sizeof(lpdmW->dmDeviceName) / sizeof(lpdmW->dmDeviceName[0]), lpdm16->dmDeviceName, sizeof(lpdm16->dmDeviceName) / sizeof(lpdm16->dmDeviceName[0]), NULL, NULL); lpdm16->dmSpecVersion = lpdmW->dmSpecVersion; lpdm16->dmDriverVersion = lpdmW->dmDriverVersion; lpdm16->dmSize = lpdmW->dmSize; lpdm16->dmDriverExtra = lpdmW->dmDriverExtra; lpdm16->dmFields = lpdmW->dmFields; lpdm16->dmOrientation = lpdmW->dmOrientation; lpdm16->dmPaperSize = lpdmW->dmPaperSize; lpdm16->dmPaperLength = lpdmW->dmPaperLength; lpdm16->dmPaperWidth = lpdmW->dmPaperWidth; lpdm16->dmScale = lpdmW->dmScale; lpdm16->dmCopies = lpdmW->dmCopies; lpdm16->dmDefaultSource = lpdmW->dmDefaultSource; lpdm16->dmPrintQuality = lpdmW->dmPrintQuality; lpdm16->dmColor = lpdmW->dmColor; lpdm16->dmDuplex = lpdmW->dmDuplex; // adjust lpdm16->dmSize (between win30 and win31 version) lpdm16->dmSize = (lpdm16->dmSpecVersion > 0x300) ? sizeof(DEVMODE31) : sizeof(DEVMODE16); if (lpdm16->dmSize >= sizeof(DEVMODE31)) { ((PDEVMODE31)lpdm16)->dmYResolution = lpdmW->dmYResolution; ((PDEVMODE31)lpdm16)->dmTTOption = lpdmW->dmTTOption; } RtlCopyMemory((LPBYTE)lpdm16 + (DWORD)lpdm16->dmSize, (lpdmW + 1), lpdmW->dmDriverExtra); } else { // LATER: should specversion be NT version rather than win30 driver version? MultiByteToWideChar(CP_ACP, 0, lpdm16->dmDeviceName, sizeof(lpdm16->dmDeviceName) / sizeof(lpdm16->dmDeviceName[0]), lpdmW->dmDeviceName, sizeof(lpdmW->dmDeviceName) / sizeof(lpdmW->dmDeviceName[0])); lpdmW->dmSpecVersion = lpdm16->dmSpecVersion; lpdmW->dmDriverVersion = lpdm16->dmDriverVersion; lpdmW->dmSize = lpdm16->dmSize; lpdmW->dmDriverExtra = lpdm16->dmDriverExtra; lpdmW->dmFields = lpdm16->dmFields; lpdmW->dmOrientation = lpdm16->dmOrientation; lpdmW->dmPaperSize = lpdm16->dmPaperSize; lpdmW->dmPaperLength = lpdm16->dmPaperLength; lpdmW->dmPaperWidth = lpdm16->dmPaperWidth; lpdmW->dmScale = lpdm16->dmScale; lpdmW->dmCopies = lpdm16->dmCopies; lpdmW->dmDefaultSource = lpdm16->dmDefaultSource; lpdmW->dmPrintQuality = lpdm16->dmPrintQuality; lpdmW->dmColor = lpdm16->dmColor; lpdmW->dmDuplex = lpdm16->dmDuplex; if (lpdm16->dmSize >= sizeof(DEVMODE31)) { lpdmW->dmYResolution = ((PDEVMODE31)lpdm16)->dmYResolution; lpdmW->dmTTOption = ((PDEVMODE31)lpdm16)->dmTTOption; } // 16bit world doesnot know anything about the fields like // formname etc. RtlCopyMemory(lpdmW + 1, (LPBYTE)lpdm16 + lpdm16->dmSize, lpdm16->dmDriverExtra); // adjust size for 32bit world lpdmW->dmSize = sizeof(*lpdmW); } return TRUE; } //************************************************************************** // ConvertGdiInfo // //************************************************************************** BOOL ConvertGdiInfo(LPGDIINFO16 lpginfo16, PGDIINFO lpginfo, BOOL fTo16) { LOGDEBUG(0,("ConvertGdiInfo\n")); if (!lpginfo16 || !lpginfo) return FALSE; if (!fTo16) { lpginfo->ulTechnology = lpginfo16->dpTechnology; lpginfo->ulLogPixelsX = lpginfo16->dpLogPixelsX; lpginfo->ulLogPixelsY = lpginfo16->dpLogPixelsY; lpginfo->ulDevicePelsDPI = lpginfo->ulLogPixelsX; lpginfo->ulHorzSize = lpginfo16->dpHorzSize; lpginfo->ulVertSize = lpginfo16->dpVertSize; lpginfo->ulHorzRes = lpginfo16->dpHorzRes; lpginfo->ulVertRes = lpginfo16->dpVertRes; lpginfo->cBitsPixel = lpginfo16->dpBitsPixel; lpginfo->cPlanes = lpginfo16->dpPlanes; lpginfo->ulNumColors = lpginfo16->dpNumColors; lpginfo->ptlPhysOffset.x = ((PPOINT16)(lpginfo16+1))->x; lpginfo->ptlPhysOffset.y = ((PPOINT16)(lpginfo16+1))->y; lpginfo->szlPhysSize.cx = lpginfo->ulHorzRes; lpginfo->szlPhysSize.cy = lpginfo->ulVertRes; lpginfo->ulPanningHorzRes = lpginfo->ulHorzRes; lpginfo->ulPanningVertRes = lpginfo->ulVertRes; lpginfo->ulAspectX = lpginfo16->dpAspectX; lpginfo->ulAspectY = lpginfo16->dpAspectY; lpginfo->ulAspectXY = lpginfo16->dpAspectXY; // // RASDD tries to be smart as to whether the x and y DPI are equal or // not. In the case of 200dpi in the x direction and 100dpi in the // y direction, you may want to adjust this to 2 for xStyleStep, 1 for // yStyleStep and dpi/50 for denStyleStep. This basicaly determines // how long dashes/dots will be when drawing with styled pens. // Since we just hard code denStyleStep to 3, we get different lines // at 100dpi vs 200dpi // lpginfo->xStyleStep = 1; lpginfo->yStyleStep = 1; lpginfo->denStyleStep = 3; } return TRUE; } //************************************************************************** // DMBitBlt - // The 16bit winfax.drv calls this , in response to a device driver // 'bitblt' call. // //************************************************************************** ULONG FASTCALL WG32DMBitBlt( PVDMFRAME pFrame) { register PDMBITBLT16 parg16; #ifdef DBCS /* wowfax support */ register PDEV_BITMAP16 pbm16; #else // !DBCS register PBITMAP16 pbm16; #endif /* !DBCS */ LPBYTE lpDest, lpSrc; UINT cBytes; LPBYTE lpbits, lpbitsEnd; LOGDEBUG(0,("WG32DMBitBlt\n")); GETARGPTR(pFrame, sizeof(DMBITBLT16), parg16); #ifdef DBCS /* wowfax support */ GETVDMPTR(parg16->pbitmapdest, sizeof(DEV_BITMAP16), pbm16); #else // !DBCS GETVDMPTR(parg16->pbitmapdest, sizeof(BITMAP16), pbm16); #endif /* !DBCS */ GETVDMPTR(pbm16->bmBits, 0, lpDest); WOW32ASSERT(glpfaxinfoCur != NULL); lpbits = glpfaxinfoCur->lpbits; lpbitsEnd = (LPBYTE)lpbits + glpfaxinfoCur->bmHeight * glpfaxinfoCur->bmWidthBytes; #ifdef DBCS /* wowfax support */ lpSrc = (LPBYTE)lpbits + (parg16->srcx / glpfaxinfoCur->bmPixPerByte) + (parg16->srcy * glpfaxinfoCur->bmWidthBytes); if (lpSrc >= lpbits) { WORD extx,exty,srcx,srcy,desty,destx; extx = FETCHWORD(parg16->extx); exty = FETCHWORD(parg16->exty); srcx = FETCHWORD(parg16->srcx); srcy = FETCHWORD(parg16->srcy); destx = FETCHWORD(parg16->destx); desty = FETCHWORD(parg16->desty); #if DBG LOGDEBUG(10,("\n")); LOGDEBUG(10,("bmType = %d\n",pbm16->bmType)); LOGDEBUG(10,("bmWidth = %d\n",pbm16->bmWidth)); LOGDEBUG(10,("bmHeight = %d\n",pbm16->bmHeight)); LOGDEBUG(10,("bmWidthBytes = %d\n",pbm16->bmWidthBytes)); LOGDEBUG(10,("bmPlanes = %d\n",pbm16->bmPlanes)); LOGDEBUG(10,("bmBitsPixel = %d\n",pbm16->bmBitsPixel)); LOGDEBUG(10,("bmBits = %x\n",pbm16->bmBits)); LOGDEBUG(10,("bmWidthPlances = %d\n",pbm16->bmWidthPlanes)); LOGDEBUG(10,("bmlpPDevice = %x\n",pbm16->bmlpPDevice)); LOGDEBUG(10,("bmSegmentIndex = %d\n",pbm16->bmSegmentIndex)); LOGDEBUG(10,("bmScanSegment = %d\n",pbm16->bmScanSegment)); LOGDEBUG(10,("bmFillBytes = %d\n",pbm16->bmFillBytes)); LOGDEBUG(10,("\n")); LOGDEBUG(10,("bmWidthBytesSrc= %d\n",glpfaxinfoCur->bmWidthBytes)); LOGDEBUG(10,("\n")); LOGDEBUG(10,("extx = %d\n",extx)); LOGDEBUG(10,("exty = %d\n",exty)); LOGDEBUG(10,("srcx = %d\n",srcx)); LOGDEBUG(10,("srcy = %d\n",srcy)); LOGDEBUG(10,("destx = %d\n",destx)); LOGDEBUG(10,("desty = %d\n",desty)); LOGDEBUG(10,("\n")); #endif if (pbm16->bmSegmentIndex) { SHORT WriteSegment; SHORT WriteOffset; SHORT Segment=0,SegmentMax=0; LPBYTE DstScan0,SrcScan0; UINT cBytesInLastSegment; INT RestLine = (INT) exty; WriteSegment = desty / pbm16->bmScanSegment; WriteOffset = desty % pbm16->bmScanSegment; if (WriteOffset) { WriteSegment += 1; } #if DBG LOGDEBUG(10,("WriteSegment = %d\n",WriteSegment)); LOGDEBUG(10,("WriteOffset = %d\n",WriteOffset)); LOGDEBUG(10,("\n")); LOGDEBUG(10,("lpDest = %x\n",lpDest)); LOGDEBUG(10,("\n")); #endif SegmentMax = exty / pbm16->bmScanSegment; if ( exty % pbm16->bmScanSegment) { SegmentMax += 1; } cBytes = glpfaxinfoCur->bmWidthBytes * pbm16->bmScanSegment; lpDest = lpDest + destx + (WriteSegment * 0x10000L) + (WriteOffset * pbm16->bmWidthBytes); #if DBG LOGDEBUG(10,("SourceBitmap = %x\n",lpSrc)); LOGDEBUG(10,("DestinationBitmap = %x\n",lpDest)); LOGDEBUG(10,("SegmentMax = %d\n",SegmentMax)); LOGDEBUG(10,("\n")); LOGDEBUG(10,("cBytes = %d\n",cBytes)); LOGDEBUG(10,("\n")); #endif if ((DWORD)glpfaxinfoCur->bmWidthBytes == (DWORD)pbm16->bmWidthBytes) { try { for( Segment = 1,DstScan0 = lpDest,SrcScan0 = lpSrc; Segment < SegmentMax; Segment++,DstScan0 += 0x10000L, SrcScan0 += cBytes,RestLine -= pbm16->bmScanSegment ) { #if DBG LOGDEBUG(10,("%d ",Segment-1)); #endif RtlCopyMemory(DstScan0,SrcScan0,cBytes); RtlZeroMemory(DstScan0+cBytes,pbm16->bmFillBytes); } #if DBG LOGDEBUG(10,("%d\n",Segment-1)); #endif if( RestLine > 0 ) { cBytesInLastSegment = RestLine * pbm16->bmWidthBytes; #if DBG LOGDEBUG(10,("RestLine = %d\n",RestLine)); LOGDEBUG(10,("cBytesInLastSegment = %d\n",cBytes)); #endif // do for last segment.. RtlCopyMemory(DstScan0,SrcScan0,cBytesInLastSegment); } } except(EXCEPTION_EXECUTE_HANDLER) { #if DBG LOGDEBUG(10,("Exception during copying image\n")); #endif } } else if ((DWORD)glpfaxinfoCur->bmWidthBytes > (DWORD)pbm16->bmWidthBytes) { SHORT Line; UINT cSrcAdvance = glpfaxinfoCur->bmWidthBytes; UINT cDstAdvance = pbm16->bmWidthBytes; try { for( Segment = 1,DstScan0 = lpDest,SrcScan0 = lpSrc; Segment < SegmentMax; Segment++,DstScan0 += 0x10000L, SrcScan0 += cBytes,RestLine -= pbm16->bmScanSegment ) { LPBYTE DstScanl = DstScan0; LPBYTE SrcScanl = SrcScan0; #if DBG LOGDEBUG(10,("%d ",Segment-1)); #endif for( Line = 0; Line < pbm16->bmScanSegment; Line++,DstScanl += cDstAdvance,SrcScanl += cSrcAdvance ) { RtlCopyMemory(DstScanl,SrcScanl,cDstAdvance); } } #if DBG LOGDEBUG(10,("%d\n",Segment-1)); #endif if( RestLine > 0 ) { LPBYTE DstScanl = DstScan0; LPBYTE SrcScanl = SrcScan0; for( Line = 0; Line < RestLine; Line++,DstScanl += cDstAdvance,SrcScanl += cSrcAdvance ) { RtlCopyMemory(DstScanl,SrcScanl,cDstAdvance); } } } except(EXCEPTION_EXECUTE_HANDLER) { #if DBG LOGDEBUG(10,("Exception during copying image\n")); #endif } } else { WOW32ASSERT(FALSE); } } else { lpDest = lpDest + destx + desty * pbm16->bmWidthBytes; if ((DWORD)glpfaxinfoCur->bmWidthBytes == (DWORD)pbm16->bmWidthBytes) { cBytes = parg16->exty * glpfaxinfoCur->bmWidthBytes; if (cBytes > (UINT)(pbm16->bmHeight * pbm16->bmWidthBytes)) { cBytes = pbm16->bmHeight * pbm16->bmWidthBytes; WOW32ASSERT(FALSE); } if ((lpSrc + cBytes) <= lpbitsEnd) { RtlCopyMemory(lpDest, lpSrc, cBytes); } } else { int i; // we need to transfer bits one partial scanline at a time WOW32ASSERT((DWORD)pbm16->bmHeight <= (DWORD)glpfaxinfoCur->bmHeight); WOW32ASSERT((DWORD)parg16->exty <= (DWORD)pbm16->bmHeight); cBytes = ((DWORD)pbm16->bmWidthBytes < (DWORD)glpfaxinfoCur->bmWidthBytes) ? pbm16->bmWidthBytes : glpfaxinfoCur->bmWidthBytes; for (i = 0; i < parg16->exty; i++) { if ((lpSrc + cBytes) <= lpbitsEnd) { RtlCopyMemory(lpDest, lpSrc, cBytes); } lpDest += pbm16->bmWidthBytes; lpSrc += glpfaxinfoCur->bmWidthBytes; } } } } #else // !DBCS lpDest = lpDest + parg16->destx + parg16->desty * pbm16->bmWidthBytes; lpSrc = (LPBYTE)lpbits + (parg16->srcx / glpfaxinfoCur->bmPixPerByte) + parg16->srcy * glpfaxinfoCur->bmWidthBytes; if (lpSrc >= lpbits) { if ((DWORD)glpfaxinfoCur->bmWidthBytes == (DWORD)pbm16->bmWidthBytes) { cBytes = parg16->exty * glpfaxinfoCur->bmWidthBytes; if (cBytes > (UINT)(pbm16->bmHeight * pbm16->bmWidthBytes)) { cBytes = pbm16->bmHeight * pbm16->bmWidthBytes; WOW32ASSERT(FALSE); } if ((lpSrc + cBytes) <= lpbitsEnd) { RtlCopyMemory(lpDest, lpSrc, cBytes); } } else if ((DWORD)glpfaxinfoCur->bmWidthBytes > (DWORD)pbm16->bmWidthBytes) { int i; // we need to transfer bits one partial scanline at a time WOW32ASSERT((DWORD)pbm16->bmHeight <= (DWORD)glpfaxinfoCur->bmHeight); WOW32ASSERT((DWORD)parg16->exty <= (DWORD)pbm16->bmHeight); for (i = 0; i < parg16->exty; i++) { if ((lpSrc + pbm16->bmWidthBytes) <= lpbitsEnd) { RtlCopyMemory(lpDest, lpSrc, pbm16->bmWidthBytes); } lpDest += pbm16->bmWidthBytes; lpSrc += glpfaxinfoCur->bmWidthBytes; } } else { WOW32ASSERT(FALSE); } } #endif /* !DBCS */ return (ULONG)TRUE; } PSZ StrDup(PSZ szStr) { PSZ pszTmp; pszTmp = malloc_w(strlen(szStr)+1); if(pszTmp ) { return(strcpy(pszTmp, szStr)); } return NULL; } PSZ BuildPath(PSZ szPath, PSZ szFileName) { char szTmp[MAX_PATH]; strcpy(szTmp, szPath); strcat(szTmp, "\\"); strcat(szTmp, szFileName); return(StrDup(szTmp)); } //************************************************************************** // AddPrinterThread - // // Worker thread to make the AddPrinter call into the spooler. // //************************************************************************** VOID AddPrinterThread(PWOWADDPRINTER pWowAddPrinter) { if ((*spoolerapis[pWowAddPrinter->iCode].lpfn)(NULL, 2, pWowAddPrinter->pPrinterStuff)) { pWowAddPrinter->bRet = TRUE; } else { if (GetLastError() == ERROR_PRINTER_ALREADY_EXISTS) { pWowAddPrinter->bRet = TRUE; } else { #ifdef DBG LOGDEBUG(0,("AddPrinterThread, AddPrinterxxx call failed: 0x%X\n", GetLastError())); #endif pWowAddPrinter->bRet = FALSE; } } } //************************************************************************** // DoAddPrinterStuff - // // Spin a worker thread to make the AddPrinterxxx calls into // spooler. This is needed to prevent a deadlock when spooler // RPC's to spoolss. // // This thread added for bug #107426. //************************************************************************** BOOL DoAddPrinterStuff(LPVOID pPrinterStuff, INT iCode) { WOWADDPRINTER WowAddPrinter; HANDLE hWaitObjects; DWORD dwEvent, dwUnused; MSG msg; // Spin the worker thread. WowAddPrinter.pPrinterStuff = pPrinterStuff; WowAddPrinter.iCode = iCode; WowAddPrinter.bRet = FALSE; if (hWaitObjects = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)AddPrinterThread, &WowAddPrinter, 0, &dwUnused)) { // Pump messages while we wait for AddPrinterThread to finish. for (;;) { dwEvent = MsgWaitForMultipleObjects(1, &hWaitObjects, FALSE, INFINITE, QS_ALLEVENTS | QS_SENDMESSAGE); if (dwEvent == WAIT_OBJECT_0 + 0) { // Worker thread done. break; } else { // pump messages so the callback into wowexec!FaxWndProc doesn't // get hung while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) { TranslateMessage(&msg); DispatchMessage(&msg); } } } CloseHandle(hWaitObjects); } else { LOGDEBUG(0, ("DoAddPrinterStuff, CreateThread on AddPrinterThread failed\n")); } return WowAddPrinter.bRet; } //************************************************************************** // InstallWowFaxPrinter - // // Installs the WowFax 32-bit print driver when a 16-bit fax printer // installation is detected. // //************************************************************************** BOOL InstallWowFaxPrinter(PSZ szSection, PSZ szKey, PSZ szString) { CHAR szTmp[MAX_PATH]; PSZ szSrcPath; DWORD dwNeeded; DRIVER_INFO_2 DriverInfo; PRINTER_INFO_2 PrinterInfo; PORT_INFO_1 PortInfo; HKEY hKey = 0, hSubKey = 0; BOOL bRetVal=FALSE; LOGDEBUG(0,("InstallWowFaxPrinter, Section = %s, Key = %s, String = %s\n", szSection, szKey, szString)); // Write the entry to the registry. We'll keep shadow entries // in the registry for the WOW fax applications and drivers to // read, since the entries that the spooler writes pertain // to winspool, not the 16-bit fax driver. if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\WOW\\WowFax", 0, KEY_WRITE, &hKey ) == ERROR_SUCCESS) { if (RegCreateKey(hKey, szSection, &hSubKey) == ERROR_SUCCESS) { RegSetValueEx(hSubKey, szKey, 0, REG_SZ, szString, strlen(szString)+1); RegCloseKey(hKey); RegCloseKey(hSubKey); // Dynamically link to spooler API's if (!(spoolerapis[WOW_GetPrinterDriverDirectory].lpfn)) { if (!LoadLibraryAndGetProcAddresses("WINSPOOL.DRV", spoolerapis, WOW_SPOOLERAPI_COUNT)) { LOGDEBUG(0,("InstallWowFaxPrinter, Unable to load WINSPOOL API's\n")); return(FALSE); } } // Copy the printer driver files. RtlZeroMemory(&DriverInfo, sizeof(DRIVER_INFO_2)); RtlZeroMemory(&PrinterInfo, sizeof(PRINTER_INFO_2)); if (!(*spoolerapis[WOW_GetPrinterDriverDirectory].lpfn)(NULL, NULL, 1, szTmp, MAX_PATH, &dwNeeded)) { LOGDEBUG(0,("InstallWowFaxPrinter, GetPrinterDriverDirectory failed: 0x%X\n", GetLastError())); return(FALSE); } // This is a dummy. We've no data file, but spooler won't take NULL. DriverInfo.pDataFile = BuildPath(szTmp, WOWFAX_DLL_NAME_A); if ( !DriverInfo.pDataFile ) { goto IWFP_error; } DriverInfo.pDriverPath = BuildPath(szTmp, WOWFAX_DLL_NAME_A); if ( !DriverInfo.pDriverPath ) { goto IWFP_error; } LOGDEBUG(0,("InstallWowFaxPrinter, pDriverPath = %s\n", DriverInfo.pDataFile)); szSrcPath = BuildPath(pszSystemDirectory, WOWFAX_DLL_NAME_A); if ( !szSrcPath ) { goto IWFP_error; } CopyFile(szSrcPath, DriverInfo.pDriverPath, FALSE); free_w(szSrcPath); DriverInfo.pConfigFile = BuildPath(szTmp, WOWFAXUI_DLL_NAME_A); szSrcPath = BuildPath(pszSystemDirectory, WOWFAXUI_DLL_NAME_A); if ( !szSrcPath ) { goto IWFP_error; } CopyFile(szSrcPath, DriverInfo.pConfigFile, FALSE); free_w(szSrcPath); // Install the printer driver. DriverInfo.cVersion = 1; DriverInfo.pName = "Windows 3.1 Compatible Fax Driver"; if ((bRetVal = DoAddPrinterStuff((LPVOID)&DriverInfo, WOW_AddPrinterDriver)) == FALSE) { // if the driver is already installed, it won't hurt to install // it a second time. This might be necessary if the user is // upgrading from WinFax Lite to WinFax Pro. bRetVal = (GetLastError() == ERROR_PRINTER_DRIVER_ALREADY_INSTALLED); } if (bRetVal) { // Parse out the printer name. RtlZeroMemory(&PrinterInfo, sizeof(PRINTER_INFO_2)); PrinterInfo.pPrinterName = szKey; LOGDEBUG(0,("InstallWowFaxPrinter, pPrinterName = %s\n", PrinterInfo.pPrinterName)); // Use private API to add a NULL port. Printer guys need to fix // redirection to NULL bug. RtlZeroMemory(&PortInfo, sizeof(PORT_INFO_1)); PrinterInfo.pPortName = "NULL"; PortInfo.pName = PrinterInfo.pPortName; // Get "Local Port" string. LoadString(hmodWOW32, iszWowFaxLocalPort, szTmp, sizeof szTmp); (*spoolerapis[WOW_AddPortEx].lpfn)(NULL, 1, &PortInfo, szTmp); // Set the other defaults and install the printer. PrinterInfo.pDriverName = "Windows 3.1 Compatible Fax Driver"; PrinterInfo.pPrintProcessor = "WINPRINT"; PrinterInfo.pDatatype = "RAW"; bRetVal = DoAddPrinterStuff((LPVOID)&PrinterInfo, WOW_AddPrinter); #ifdef DBG if (!bRetVal) { LOGDEBUG(0,("InstallWowFaxPrinter, AddPrinter failed: 0x%X\n", GetLastError())); } #endif } else { LOGDEBUG(0,("InstallWowFaxPrinter, AddPrinterDriver failed: 0x%X\n", GetLastError())); } IWFP_error: if ( DriverInfo.pDataFile ) { free_w(DriverInfo.pDataFile); } if ( DriverInfo.pDriverPath ) { free_w(DriverInfo.pDriverPath); } if ( DriverInfo.pConfigFile) { free_w(DriverInfo.pConfigFile); } return(bRetVal); } else { LOGDEBUG(0,("InstallWowFaxPrinter, Unable to create Key: %s\n", szSection)); } } else { LOGDEBUG(0,("InstallWowFaxPrinter, Unable to open key: HKEY_LOCAL_MACHINE\\Software\\Microsoft\\Windows NT\\CurrentVersion\\WOW\\WowFax\n")); } if (hKey) { RegCloseKey(hKey); if (hSubKey) { RegCloseKey(hSubKey); } } return(FALSE); } // Come here if szSection=="devices" or if gbWinFaxHack==TRUE BOOL IsFaxPrinterWriteProfileString(PSZ szSection, PSZ szKey, PSZ szString) { BOOL Result = FALSE; // Don't install if trying to clear an entry. if (*szString == '\0') { goto Done; } // Trying to install a fax printer? LOGDEBUG(0,("IsFaxPrinterWriteProfileString, Section = devices, Key = %s\n", szKey)); // Is the WinFax Lite hack enabled? if(gbWinFaxHack) { // if ("WINFAX", "modem", "xxx") we know the WinFax install program // has had a chance to copy "WinFax.drv" to the hard drive. So // now we can call AddPrinter which can callback into WinFax.drv to // its hearts content. if(!WOW32_strcmp(szSection, szWINFAX) && !WOW32_stricmp(szKey, szModem)) { // Our hack has run its course. We set this before making the call // to AddPrinter because it calls back into WinFax.drv which calls // WriteProfileString()! gbWinFaxHack = FALSE; // Call into the spooler to add our driver to the registry. if (!InstallWowFaxPrinter(szDevices, szWINFAX, szWINFAXCOMx)) { WOW32ASSERTMSG(FALSE, "Install of generic fax printer failed.\n"); } } Result = TRUE; goto Done; } // Is it one of the fax drivers we recognize? if (IsFaxPrinterSupportedDevice(szKey)) { // Time to enable the WinFax Lite hack? // if("devices", "WINFAX", "WINFAX,COMx:") we need to avoid the call to // InstallWOWFaxPrinter() at this time -- the install program hasn't // copied the driver to the hard drive yet!! This causes loadLibrary // of WinFax.drv to fail when the spooler tries to callback into it. // We also don't want this particular call to WriteProfileString to // really be written to the registry -- we let the later call to // AddPrinter take care of all the registration stuff. if(!WOW32_strcmp(szKey, szWINFAX) && !WOW32_strncmp(szString, szWINFAX, 6) && (szString[6] == ',')) { VPVOID vpPathName; PSZ pszPathName; char szFileName[32]; // get the install program file name // be sure allocation size matches stackfree16() size below if(vpPathName = stackalloc16(MAX_PATH)) { GetModuleFileName16(CURRENTPTD()->hMod16, vpPathName, MAX_PATH); GETVDMPTR(vpPathName, MAX_PATH, pszPathName); _splitpath(pszPathName,NULL,NULL,szFileName,NULL); // WinFax Lite is "INSTALL", WinFax Pro 4.0 is "SETUP" if(!WOW32_stricmp(szINSTALL, szFileName)) { strcpy(szWINFAXCOMx, szString); // save the port string gbWinFaxHack = TRUE; // enable the hack Result = TRUE; stackfree16(vpPathName, MAX_PATH); goto Done; // skip the call to InstallWowFaxPrinter } // No hack needed for WinFax Pro 4.0, the driver is copied // to the hard disk long before they update win.ini else { stackfree16(vpPathName, MAX_PATH); } } } if (!InstallWowFaxPrinter(szSection, szKey, szString)) { WOW32ASSERTMSG(FALSE, "Install of generic fax printer failed.\n"); } Result = TRUE; } Done: return Result; } BOOL IsFaxPrinterSupportedDevice(PSZ pszDevice) { UINT i, iNotFound; // Trying to read from a fax printer entry? LOGDEBUG(0,("IsFaxPrinterSupportedDevice, Device = %s\n", pszDevice)); //If initialization of SupFaxDrv failed with memory exhaust //which isn't very likely to happen if (!SupFaxDrv ) { return FALSE; } // Is it one of the fax drivers we recognize? for (i = 0; i < uNumSupFaxDrv; i++) { iNotFound = WOW32_stricmp(pszDevice, SupFaxDrv[i]); if (iNotFound > 0) continue; if (iNotFound == 0) { LOGDEBUG(0,("IsFaxPrinterSupportedDevice returns TRUE\n")); return(TRUE); } else { break; } } return(FALSE); } DWORD GetFaxPrinterProfileString(PSZ szSection, PSZ szKey, PSZ szDefault, PSZ szRetBuf, DWORD cbBufSize) { char szTmp[MAX_PATH]; HKEY hKey = 0; DWORD dwType; // Read the entry from the shadow entries in registry. strcpy(szTmp, "Software\\Microsoft\\Windows NT\\CurrentVersion\\WOW\\WowFax\\"); strcat(szTmp, szSection); if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, szTmp, 0, KEY_READ, &hKey ) == ERROR_SUCCESS) { if (RegQueryValueEx(hKey, szKey, 0, &dwType, szRetBuf, &cbBufSize) == ERROR_SUCCESS) { RegCloseKey(hKey); return(cbBufSize); } } if (hKey) { RegCloseKey(hKey); } WOW32WARNMSG(FALSE, ("GetFaxPrinterProfileString Failed. Section = %s, Key = %s\n", szSection, szKey)); strcpy(szRetBuf, szDefault); return(strlen(szDefault)); }