1569 lines
59 KiB
C
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));
|
||
|
}
|
||
|
|