//**************************************************************************** // WOW32 fax support. // // History: // 02-jan-95 nandurir created. // 01-feb-95 reedb Clean-up, support printer install and bug fixes. // //**************************************************************************** #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); //**************************************************************************** // 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 (_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; LPSTR lpSupFaxDrvBuf; LPSTR *alpSupFaxDrvList; *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)); RtlZeroMemory(alpSupFaxDrvList, *uCount * sizeof(LPSTR)); if (alpSupFaxDrvList) { // Fill the array with string starting points. BuildStrList(lpSupFaxDrvBuf, alpSupFaxDrvList); } } 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); } 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: 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: RtlCopyMemory(lpDest, lpSrc, lpWFI16->cData); 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; register PBITMAP16 pbm16; LPBYTE lpDest, lpSrc; UINT cBytes; LPBYTE lpbits, lpbitsEnd; LOGDEBUG(0,("WG32DMBitBlt\n")); GETARGPTR(pFrame, sizeof(DMBITBLT16), parg16); GETVDMPTR(parg16->pbitmapdest, sizeof(BITMAP16), pbm16); GETVDMPTR(pbm16->bmBits, 0, lpDest); WOW32ASSERT(glpfaxinfoCur != NULL); lpbits = glpfaxinfoCur->lpbits; lpbitsEnd = (LPBYTE)lpbits + glpfaxinfoCur->bmHeight * glpfaxinfoCur->bmWidthBytes; 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); } } return (ULONG)TRUE; } PSZ StrDup(PSZ szStr) { PSZ pszTmp; pszTmp = malloc_w(strlen(szStr)+1); return(strcpy(pszTmp, szStr)); } PSZ BuildPath(PSZ szPath, PSZ szFileName) { char szTmp[MAX_PATH]; strcpy(szTmp, szPath); strcat(szTmp, "\\"); strcat(szTmp, szFileName); return(StrDup(szTmp)); } 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; 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); DriverInfo.pDriverPath = BuildPath(szTmp, WOWFAX_DLL_NAME_A); LOGDEBUG(0,("InstallWowFaxPrinter, pDriverPath = %s\n", DriverInfo.pDataFile)); szSrcPath = BuildPath(pszSystemDirectory, WOWFAX_DLL_NAME_A); CopyFile(szSrcPath, DriverInfo.pDriverPath, FALSE); free_w(szSrcPath); DriverInfo.pConfigFile = BuildPath(szTmp, WOWFAXUI_DLL_NAME_A); szSrcPath = BuildPath(pszSystemDirectory, WOWFAXUI_DLL_NAME_A); CopyFile(szSrcPath, DriverInfo.pConfigFile, FALSE); free_w(szSrcPath); // Install the printer driver. DriverInfo.cVersion = 1; DriverInfo.pName = "Windows 3.1 Compatible Fax Driver"; if ((*spoolerapis[WOW_AddPrinterDriver].lpfn)(NULL, 2, &DriverInfo) == FALSE) { 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"; if ((*spoolerapis[WOW_AddPrinter].lpfn)(NULL, 2, &PrinterInfo) == 0) { bRetVal = (GetLastError() == ERROR_PRINTER_ALREADY_EXISTS); } #ifdef DBG if (!bRetVal) { LOGDEBUG(0,("InstallWowFaxPrinter, AddPrinter failed: 0x%X\n", GetLastError())); } #endif } else { LOGDEBUG(0,("InstallWowFaxPrinter, AddPrinterDriver failed: 0x%X\n", GetLastError())); } free_w(DriverInfo.pDataFile); free_w(DriverInfo.pDriverPath); 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); } BOOL IsFaxPrinterWriteProfileString(PSZ szSection, PSZ szKey, PSZ szString) { BOOL Result; // Don't install if trying to clear an entry. if (*szString == '\0') { Result = FALSE; goto Done; } // Trying to install a fax printer? LOGDEBUG(0,("IsFaxPrinterWriteProfileString, Section = devices, Key = %s\n", szKey)); // Is it one of the fax drivers we recognize? if (IsFaxPrinterSupportedDevice(szKey)) { if (!InstallWowFaxPrinter(szSection, szKey, szString)) { WOW32ASSERTMSG(FALSE, "Install of generic fax printer failed.\n"); } Result = TRUE; } else { Result = FALSE; } 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)); // Is it one of the fax drivers we recognize? for (i = 0; i < uNumSupFaxDrv; i++) { iNotFound = _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); } WOW32ASSERTMSGF(FALSE, ("GetFaxPrinterProfileString Failed. Section = %s, Key = %s\n", szSection, szKey)); strcpy(szRetBuf, szDefault); return(strlen(szDefault)); }