|
|
//****************************************************************************
// 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)); }
|