windows-nt/Source/XPSP1/NT/base/mvdm/wow32/wow32fax.c
2020-09-26 16:20:57 +08:00

1569 lines
59 KiB
C

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