diff --git a/win32ss/printing/base/printui/printui.spec b/win32ss/printing/base/printui/printui.spec index 2f2db27e1a6..e6ff2fd85da 100644 --- a/win32ss/printing/base/printui/printui.spec +++ b/win32ss/printing/base/printui/printui.spec @@ -1,6 +1,6 @@ @ stub ConnectToPrinterDlg @ stub ConnectToPrinterPropertyPage -@ stub ConstructPrinterFriendlyName +@ stdcall -stub ConstructPrinterFriendlyName(wstr wstr ptr) @ stub -private DllCanUnloadNow @ stub -private DllGetClassObject @ stub DocumentPropertiesWrap diff --git a/win32ss/printing/base/spoolss/memory.c b/win32ss/printing/base/spoolss/memory.c index 2eeed654886..d7f64d290c2 100644 --- a/win32ss/printing/base/spoolss/memory.c +++ b/win32ss/printing/base/spoolss/memory.c @@ -111,6 +111,7 @@ DllAllocSplMem(DWORD dwBytes) BOOL WINAPI DllFreeSplMem(PVOID pMem) { + if ( !pMem ) return TRUE; return HeapFree(hProcessHeap, 0, pMem); } @@ -128,7 +129,9 @@ DllFreeSplMem(PVOID pMem) BOOL WINAPI DllFreeSplStr(PWSTR pwszString) { - return HeapFree(hProcessHeap, 0, pwszString); + if ( pwszString ) + return HeapFree(hProcessHeap, 0, pwszString); + return FALSE; } /** diff --git a/win32ss/printing/base/spoolss/precomp.h b/win32ss/printing/base/spoolss/precomp.h index ee373e267d3..3a859aa2d7c 100644 --- a/win32ss/printing/base/spoolss/precomp.h +++ b/win32ss/printing/base/spoolss/precomp.h @@ -52,12 +52,4 @@ SPOOLSS_PRINTER_HANDLE, *PSPOOLSS_PRINTER_HANDLE; extern HANDLE hProcessHeap; extern LIST_ENTRY PrintProviderList; -// spoolfile.c -typedef struct _FILE_INFO_1 -{ - BOOL bInheritHandle; - HANDLE hSpoolFileHandle; - DWORD dwOptions; -} FILE_INFO_1, *PFILE_INFO_1; - #endif diff --git a/win32ss/printing/base/spoolsv/precomp.h b/win32ss/printing/base/spoolsv/precomp.h index 79febdd6392..5ab518a43c6 100644 --- a/win32ss/printing/base/spoolsv/precomp.h +++ b/win32ss/printing/base/spoolsv/precomp.h @@ -28,27 +28,4 @@ WINE_DEFAULT_DEBUG_CHANNEL(spoolsv); // rpcserver.c DWORD WINAPI LrpcThreadProc(LPVOID lpParameter); -// spoolfile.c -BOOL WINAPI -SplGetSpoolFileInfo( - HANDLE hPrinter, - HANDLE hProcessHandle, - DWORD Level, - WINSPOOL_FILE_INFO_1 *pFileInfo, - DWORD dwSize, - DWORD* dwNeeded ); - -BOOL WINAPI -SplCommitSpoolData( - HANDLE hPrinter, - HANDLE hProcessHandle, - DWORD cbCommit, - DWORD Level, - WINSPOOL_FILE_INFO_1 *pFileInfo, - DWORD dwSize, - DWORD* dwNeeded ); - -BOOL WINAPI -SplCloseSpoolFileHandle( HANDLE hPrinter ); - #endif diff --git a/win32ss/printing/base/spoolsv/spoolfile.c b/win32ss/printing/base/spoolsv/spoolfile.c index 67e808525d0..fee89ecf14b 100644 --- a/win32ss/printing/base/spoolsv/spoolfile.c +++ b/win32ss/printing/base/spoolsv/spoolfile.c @@ -19,7 +19,7 @@ _RpcGetSpoolFileInfo( WINSPOOL_PRINTER_HANDLE hPrinter, WINSPOOL_HANDLE hProcess return dwErrorCode; } - if (!SplGetSpoolFileInfo( hPrinter, hProcessHandle, Level, pFileInfo, dwSize, dwNeeded ) ) + if (!SplGetSpoolFileInfo( hPrinter, hProcessHandle, Level, (FILE_INFO_1*)pFileInfo, dwSize, dwNeeded ) ) dwErrorCode = GetLastError(); RpcRevertToSelf(); @@ -38,7 +38,7 @@ _RpcCommitSpoolData( WINSPOOL_PRINTER_HANDLE hPrinter, WINSPOOL_HANDLE hProcessH return dwErrorCode; } - if (!SplCommitSpoolData( hPrinter, hProcessHandle, cbCommit, Level, pFileInfo, dwSize, dwNeeded ) ) + if (!SplCommitSpoolData( hPrinter, hProcessHandle, cbCommit, Level, (FILE_INFO_1*)pFileInfo, dwSize, dwNeeded ) ) dwErrorCode = GetLastError(); RpcRevertToSelf(); @@ -61,7 +61,7 @@ _RpcGetSpoolFileInfo2( WINSPOOL_PRINTER_HANDLE hPrinter, DWORD dwProcessId, DWOR hProcessHandle = OpenProcess( PROCESS_DUP_HANDLE, FALSE, dwProcessId ); - if (!SplGetSpoolFileInfo( hPrinter, hProcessHandle, Level, pFileInfoContainer->FileInfo.pFileInfo1, sizeof(WINSPOOL_FILE_INFO_1), &dwNeeded ) ) + if (!SplGetSpoolFileInfo( hPrinter, hProcessHandle, Level, (FILE_INFO_1*)pFileInfoContainer->FileInfo.pFileInfo1, sizeof(FILE_INFO_1), &dwNeeded ) ) dwErrorCode = GetLastError(); if ( hProcessHandle ) @@ -88,7 +88,7 @@ _RpcCommitSpoolData2( WINSPOOL_PRINTER_HANDLE hPrinter, DWORD dwProcessId, DWORD hProcessHandle = OpenProcess( PROCESS_DUP_HANDLE, FALSE, dwProcessId ); - if (!SplCommitSpoolData( hPrinter, hProcessHandle, cbCommit, Level, pFileInfoContainer->FileInfo.pFileInfo1, sizeof(WINSPOOL_FILE_INFO_1), &dwNeeded ) ) + if (!SplCommitSpoolData( hPrinter, hProcessHandle, cbCommit, Level, (FILE_INFO_1*)pFileInfoContainer->FileInfo.pFileInfo1, sizeof(FILE_INFO_1), &dwNeeded ) ) dwErrorCode = GetLastError(); if ( hProcessHandle ) diff --git a/win32ss/printing/base/winspool/CMakeLists.txt b/win32ss/printing/base/winspool/CMakeLists.txt index b557db8d0df..a0a838857cb 100644 --- a/win32ss/printing/base/winspool/CMakeLists.txt +++ b/win32ss/printing/base/winspool/CMakeLists.txt @@ -16,6 +16,7 @@ list(APPEND SOURCE printers.c printprocessors.c printproviders.c + spoolfile.c utils.c ${CMAKE_CURRENT_BINARY_DIR}/winspool_c.c) @@ -31,6 +32,6 @@ add_library(winspool MODULE set_target_properties(winspool PROPERTIES SUFFIX ".drv") set_module_type(winspool win32dll UNICODE) target_link_libraries(winspool wine ${PSEH_LIB}) -add_importlibs(winspool advapi32 gdi32 rpcrt4 msvcrt kernel32 ntdll) +add_importlibs(winspool advapi32 gdi32 user32 rpcrt4 msvcrt kernel32 ntdll) add_pch(winspool precomp.h "${PCH_SKIP_SOURCE}") add_cd_file(TARGET winspool DESTINATION reactos/system32 FOR all) diff --git a/win32ss/printing/base/winspool/devmode.c b/win32ss/printing/base/winspool/devmode.c index c97f0e9ff58..fd1a615e3f4 100644 --- a/win32ss/printing/base/winspool/devmode.c +++ b/win32ss/printing/base/winspool/devmode.c @@ -234,7 +234,55 @@ Failure: return FALSE; } -void RosConvertAnsiDevModeToUnicodeDevmode(PDEVMODEA pDevModeInput, PDEVMODEW pDevModeOutput) +BOOL WINAPI +IsValidDevmodeNoSizeW(PDEVMODEW pDevmode) +{ + PMINIMUM_SIZE_TABLE pTable = MinimumSizeW; + WORD wRequiredSize; + + TRACE("IsValidDevmodeNoSizeW(%p)\n", pDevmode); + + // Check if a Devmode was given at all. + if (!pDevmode) + goto Failure; + + // If the structure has private members, the public structure must be 32-bit packed. + if (pDevmode->dmDriverExtra && pDevmode->dmSize % 4) + goto Failure; + + // Now determine the minimum possible dmSize based on the given fields in dmFields. + wRequiredSize = FIELD_OFFSET(DEVMODEW, dmFields) + RTL_FIELD_SIZE(DEVMODEW, dmFields); + + while (pTable->dwField) + { + if (pDevmode->dmFields & pTable->dwField) + { + wRequiredSize = pTable->wSize; + break; + } + + pTable++; + } + + // Verify that the value in dmSize is big enough for the used fields. + if (pDevmode->dmSize < wRequiredSize) + goto Failure; + + // Check if dmDeviceName and (if used) dmFormName are null-terminated. + // Fix this if they aren't. + _FixStringW(pDevmode->dmDeviceName, sizeof(pDevmode->dmDeviceName)); + if (pDevmode->dmFields & DM_FORMNAME) + _FixStringW(pDevmode->dmFormName, sizeof(pDevmode->dmFormName)); + + // Return success without setting the error code. + return TRUE; + +Failure: + SetLastError(ERROR_INVALID_DATA); + return FALSE; +} + +void RosConvertAnsiDevModeToUnicodeDevmode(PDEVMODEA pDevModeInput, PDEVMODEW *pDevModeOutput) { // FIXME: This function should become ConvertAnsiDevModeToUnicodeDevmode when its parameters are known! @@ -242,7 +290,7 @@ void RosConvertAnsiDevModeToUnicodeDevmode(PDEVMODEA pDevModeInput, PDEVMODEW pD if (!pDevModeInput || !pDevModeOutput) return; - pDevModeOutput = GdiConvertToDevmodeW(pDevModeInput); + *pDevModeOutput = GdiConvertToDevmodeW(pDevModeInput); } // Internal counterpart to GdiConvertToDevmodeW from gdi32 @@ -304,11 +352,15 @@ _ConvertToDevmodeA(const DEVMODEW *dmW) void RosConvertUnicodeDevModeToAnsiDevmode(PDEVMODEW pDevModeInput, PDEVMODEA pDevModeOutput) { + PDEVMODEA pTmp; + // FIXME: This function should become ConvertUnicodeDevModeToAnsiDevmode when its parameters are known! // Check if a pDevModeInput and pDevModeOutput are both not NULL. if (!pDevModeInput || !pDevModeOutput) return; - pDevModeOutput = _ConvertToDevmodeA(pDevModeInput); + pTmp = _ConvertToDevmodeA(pDevModeInput); + memcpy( pDevModeOutput, pTmp, pTmp->dmSize + pTmp->dmDriverExtra); // Copy into a Wide char (Larger) buffer. + HeapFree(hProcessHeap, 0, pTmp); } diff --git a/win32ss/printing/base/winspool/forms.c b/win32ss/printing/base/winspool/forms.c index 50ce5613387..7d8a0e65d9e 100644 --- a/win32ss/printing/base/winspool/forms.c +++ b/win32ss/printing/base/winspool/forms.c @@ -6,83 +6,486 @@ */ #include "precomp.h" +#include BOOL WINAPI AddFormA(HANDLE hPrinter, DWORD Level, PBYTE pForm) { + FORM_INFO_2W pfi2W; + PFORM_INFO_2A pfi2A; + DWORD len; + BOOL res; + + pfi2A = (PFORM_INFO_2A)pForm; + TRACE("AddFormA(%p, %lu, %p)\n", hPrinter, Level, pForm); - UNIMPLEMENTED; - return FALSE; + + if ((Level < 1) || (Level > 2)) + { + ERR("Level = %d, unsupported!\n", Level); + SetLastError(ERROR_INVALID_LEVEL); + return FALSE; + } + + if (!pfi2A) + { + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + + ZeroMemory(&pfi2W, sizeof(FORM_INFO_2W)); + + if (pfi2A->pName) + { + len = MultiByteToWideChar(CP_ACP, 0, pfi2A->pName, -1, NULL, 0); + pfi2W.pName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); + MultiByteToWideChar(CP_ACP, 0, pfi2A->pName, -1, pfi2W.pName, len); + } + + pfi2W.Flags = pfi2A->Flags; + pfi2W.Size = pfi2A->Size; + pfi2W.ImageableArea = pfi2A->ImageableArea; + + if (Level > 1) + { + if (pfi2A->pKeyword) + { + len = MultiByteToWideChar(CP_ACP, 0, pfi2A->pKeyword, -1, NULL, 0); + pfi2W.pKeyword = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); + MultiByteToWideChar(CP_ACP, 0, pfi2A->pKeyword, -1, (LPWSTR)pfi2W.pKeyword, len); + } + + if (pfi2A->pMuiDll) + { + len = MultiByteToWideChar(CP_ACP, 0, pfi2A->pMuiDll, -1, NULL, 0); + pfi2W.pMuiDll = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); + MultiByteToWideChar(CP_ACP, 0, pfi2A->pMuiDll, -1, (LPWSTR)pfi2W.pMuiDll, len); + } + + if (pfi2A->pDisplayName) + { + len = MultiByteToWideChar(CP_ACP, 0, pfi2A->pDisplayName, -1, NULL, 0); + pfi2W.pDisplayName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); + MultiByteToWideChar(CP_ACP, 0, pfi2A->pDisplayName, -1, (LPWSTR)pfi2W.pDisplayName, len); + } + pfi2W.StringType = pfi2A->StringType; + pfi2W.dwResourceId = pfi2A->dwResourceId; + pfi2W.wLangId = pfi2A->wLangId; + } + + res = AddFormW( hPrinter, Level, (PBYTE)&pfi2W ); + + if (pfi2W.pName) HeapFree(GetProcessHeap(), 0, pfi2W.pName); + if (pfi2W.pKeyword) HeapFree(GetProcessHeap(), 0, (LPWSTR)pfi2W.pKeyword); + if (pfi2W.pMuiDll) HeapFree(GetProcessHeap(), 0, (LPWSTR)pfi2W.pMuiDll); + if (pfi2W.pDisplayName) HeapFree(GetProcessHeap(), 0, (LPWSTR)pfi2W.pDisplayName); + + return res; } BOOL WINAPI AddFormW(HANDLE hPrinter, DWORD Level, PBYTE pForm) { + DWORD dwErrorCode; + WINSPOOL_FORM_CONTAINER FormInfoContainer; + PSPOOLER_HANDLE pHandle = (PSPOOLER_HANDLE)hPrinter; + TRACE("AddFormW(%p, %lu, %p)\n", hPrinter, Level, pForm); - UNIMPLEMENTED; - return FALSE; + + // Sanity checks. + if (!pHandle) + { + dwErrorCode = ERROR_INVALID_HANDLE; + return FALSE; + } + + if ((Level < 1) || (Level > 2)) + { + ERR("Level = %d, unsupported!\n", Level); + SetLastError(ERROR_INVALID_LEVEL); + return FALSE; + } + + FormInfoContainer.FormInfo.pFormInfo1 = (WINSPOOL_FORM_INFO_1*)pForm; + FormInfoContainer.Level = Level; + + // Do the RPC call + RpcTryExcept + { + dwErrorCode = _RpcAddForm(pHandle->hPrinter, &FormInfoContainer); + } + RpcExcept(EXCEPTION_EXECUTE_HANDLER) + { + dwErrorCode = RpcExceptionCode(); + ERR("_RpcAddForm failed with exception code %lu!\n", dwErrorCode); + } + RpcEndExcept; + + SetLastError(dwErrorCode); + return (dwErrorCode == ERROR_SUCCESS); } BOOL WINAPI DeleteFormA(HANDLE hPrinter, PSTR pFormName) { + UNICODE_STRING FormNameW; + BOOL Ret; + TRACE("DeleteFormA(%p, %s)\n", hPrinter, pFormName); - UNIMPLEMENTED; - return FALSE; + + AsciiToUnicode(&FormNameW, pFormName); + + Ret = DeleteFormW( hPrinter, FormNameW.Buffer ); + + RtlFreeUnicodeString(&FormNameW); + + return Ret; } BOOL WINAPI DeleteFormW(HANDLE hPrinter, PWSTR pFormName) { + DWORD dwErrorCode; + PSPOOLER_HANDLE pHandle = (PSPOOLER_HANDLE)hPrinter; + TRACE("DeleteFormW(%p, %S)\n", hPrinter, pFormName); - UNIMPLEMENTED; - return FALSE; + + // Sanity checks. + if (!pHandle) + { + dwErrorCode = ERROR_INVALID_HANDLE; + return FALSE; + } + + // Do the RPC call + RpcTryExcept + { + dwErrorCode = _RpcDeleteForm(pHandle->hPrinter, pFormName); + } + RpcExcept(EXCEPTION_EXECUTE_HANDLER) + { + dwErrorCode = RpcExceptionCode(); + ERR("_RpcDeleteForm failed with exception code %lu!\n", dwErrorCode); + } + RpcEndExcept; + + SetLastError(dwErrorCode); + return (dwErrorCode == ERROR_SUCCESS); } BOOL WINAPI EnumFormsA(HANDLE hPrinter, DWORD Level, PBYTE pForm, DWORD cbBuf, PDWORD pcbNeeded, PDWORD pcReturned) { + DWORD dwErrorCode, i; + PFORM_INFO_2W pfi2w = (PFORM_INFO_2W)pForm; + TRACE("EnumFormsA(%p, %lu, %p, %lu, %p, %p)\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned); - UNIMPLEMENTED; + + if ( EnumFormsW( hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned ) ) + { + for ( i = 0; i < *pcReturned; i++ ) + { + switch ( Level ) + { + case 2: + dwErrorCode = UnicodeToAnsiInPlace((LPWSTR)pfi2w[i].pKeyword); + if (dwErrorCode != ERROR_SUCCESS) + { + goto Cleanup; + } + dwErrorCode = UnicodeToAnsiInPlace((LPWSTR)pfi2w[i].pMuiDll); + if (dwErrorCode != ERROR_SUCCESS) + { + goto Cleanup; + } + dwErrorCode = UnicodeToAnsiInPlace((LPWSTR)pfi2w[i].pDisplayName); + if (dwErrorCode != ERROR_SUCCESS) + { + goto Cleanup; + } + // Fall through... + case 1: + dwErrorCode = UnicodeToAnsiInPlace(pfi2w[i].pName); + if (dwErrorCode != ERROR_SUCCESS) + { + goto Cleanup; + } + } + } + return TRUE; + } +Cleanup: return FALSE; } BOOL WINAPI EnumFormsW(HANDLE hPrinter, DWORD Level, PBYTE pForm, DWORD cbBuf, PDWORD pcbNeeded, PDWORD pcReturned) { + DWORD dwErrorCode; + PSPOOLER_HANDLE pHandle = (PSPOOLER_HANDLE)hPrinter; + TRACE("EnumFormsW(%p, %lu, %p, %lu, %p, %p)\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned); - UNIMPLEMENTED; - return FALSE; + + // Sanity checks. + if (!pHandle) + { + dwErrorCode = ERROR_INVALID_HANDLE; + goto Cleanup; + } + + if ((Level < 1) || (Level > 2)) + { + ERR("Level = %d, unsupported!\n", Level); + dwErrorCode = ERROR_INVALID_LEVEL; + goto Cleanup; + } + + // Do the RPC call + RpcTryExcept + { + dwErrorCode = _RpcEnumForms(pHandle->hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned); + } + RpcExcept(EXCEPTION_EXECUTE_HANDLER) + { + dwErrorCode = RpcExceptionCode(); + ERR("_RpcEnumForms failed with exception code %lu!\n", dwErrorCode); + } + RpcEndExcept; + + if (dwErrorCode == ERROR_SUCCESS) + { + // Replace relative offset addresses in the output by absolute pointers. + ASSERT(Level >= 1 && Level <= 2); + MarshallUpStructuresArray(cbBuf, pForm, *pcReturned, pFormInfoMarshalling[Level]->pInfo, pFormInfoMarshalling[Level]->cbStructureSize, TRUE); + } + +Cleanup: + SetLastError(dwErrorCode); + return (dwErrorCode == ERROR_SUCCESS); } BOOL WINAPI GetFormA(HANDLE hPrinter, PSTR pFormName, DWORD Level, PBYTE pForm, DWORD cbBuf, PDWORD pcbNeeded) { + DWORD dwErrorCode, len; + LPWSTR FormNameW = NULL; + FORM_INFO_2W* pfi2w = (FORM_INFO_2W*)pForm; + TRACE("GetFormA(%p, %s, %lu, %p, %lu, %p)\n", hPrinter, pFormName, Level, pForm, cbBuf, pcbNeeded); - UNIMPLEMENTED; - return FALSE; + + if (pFormName) + { + len = MultiByteToWideChar(CP_ACP, 0, pFormName, -1, NULL, 0); + FormNameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); + MultiByteToWideChar(CP_ACP, 0, pFormName, -1, FormNameW, len); + } + + if ( GetFormW( hPrinter, FormNameW, Level, pForm, cbBuf, pcbNeeded ) ) + { + switch ( Level ) + { + case 2: + dwErrorCode = UnicodeToAnsiInPlace((LPWSTR)pfi2w->pKeyword); + if (dwErrorCode != ERROR_SUCCESS) + { + goto Cleanup; + } + dwErrorCode = UnicodeToAnsiInPlace((LPWSTR)pfi2w->pMuiDll); + if (dwErrorCode != ERROR_SUCCESS) + { + goto Cleanup; + } + dwErrorCode = UnicodeToAnsiInPlace((LPWSTR)pfi2w->pDisplayName); + if (dwErrorCode != ERROR_SUCCESS) + { + goto Cleanup; + } + // Fall through... + case 1: + dwErrorCode = UnicodeToAnsiInPlace(pfi2w->pName); + if (dwErrorCode != ERROR_SUCCESS) + { + goto Cleanup; + } + break; + + default: + ERR("Level = %d, unsupported!\n", Level); + dwErrorCode = ERROR_INVALID_HANDLE; + SetLastError(dwErrorCode); + break; + } + } +Cleanup: + if (FormNameW) HeapFree(GetProcessHeap(), 0, FormNameW); + return (dwErrorCode == ERROR_SUCCESS); } BOOL WINAPI GetFormW(HANDLE hPrinter, PWSTR pFormName, DWORD Level, PBYTE pForm, DWORD cbBuf, PDWORD pcbNeeded) { + DWORD dwErrorCode; + PSPOOLER_HANDLE pHandle = (PSPOOLER_HANDLE)hPrinter; + TRACE("GetFormW(%p, %S, %lu, %p, %lu, %p)\n", hPrinter, pFormName, Level, pForm, cbBuf, pcbNeeded); - UNIMPLEMENTED; - return FALSE; + + // Sanity checks. + if (!pHandle) + { + dwErrorCode = ERROR_INVALID_HANDLE; + goto Cleanup; + } + + // Dismiss invalid levels already at this point. + if ((Level < 1) || (Level > 2)) + { + ERR("Level = %d, unsupported!\n", Level); + dwErrorCode = ERROR_INVALID_LEVEL; + goto Cleanup; + } + + if (cbBuf && pForm) + ZeroMemory(pForm, cbBuf); + + // Do the RPC call + RpcTryExcept + { + dwErrorCode = _RpcGetForm(pHandle->hPrinter, pFormName, Level, pForm, cbBuf, pcbNeeded); + } + RpcExcept(EXCEPTION_EXECUTE_HANDLER) + { + dwErrorCode = RpcExceptionCode(); + ERR("_RpcGetForm failed with exception code %lu!\n", dwErrorCode); + } + RpcEndExcept; + + if (dwErrorCode == ERROR_SUCCESS) + { + // Replace relative offset addresses in the output by absolute pointers. + ASSERT(Level >= 1 && Level <= 2); + MarshallUpStructure(cbBuf, pForm, pFormInfoMarshalling[Level]->pInfo, pFormInfoMarshalling[Level]->cbStructureSize, TRUE); + } + +Cleanup: + SetLastError(dwErrorCode); + return (dwErrorCode == ERROR_SUCCESS); } BOOL WINAPI SetFormA(HANDLE hPrinter, PSTR pFormName, DWORD Level, PBYTE pForm) { + FORM_INFO_2W pfi2W; + FORM_INFO_2A * pfi2A; + LPWSTR FormNameW = NULL; + DWORD len; + BOOL res; + + pfi2A = (FORM_INFO_2A *) pForm; + TRACE("SetFormA(%p, %s, %lu, %p)\n", hPrinter, pFormName, Level, pForm); - UNIMPLEMENTED; - return FALSE; + + if ((Level < 1) || (Level > 2)) + { + ERR("Level = %d, unsupported!\n", Level); + SetLastError(ERROR_INVALID_LEVEL); + return FALSE; + } + + if (!pfi2A) + { + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + + if (pFormName) + { + len = MultiByteToWideChar(CP_ACP, 0, pFormName, -1, NULL, 0); + FormNameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); + MultiByteToWideChar(CP_ACP, 0, pFormName, -1, FormNameW, len); + } + + ZeroMemory(&pfi2W, sizeof(FORM_INFO_2W)); + + if (pfi2A->pName) + { + len = MultiByteToWideChar(CP_ACP, 0, pfi2A->pName, -1, NULL, 0); + pfi2W.pName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); + MultiByteToWideChar(CP_ACP, 0, pfi2A->pName, -1, pfi2W.pName, len); + } + + pfi2W.Flags = pfi2A->Flags; + pfi2W.Size = pfi2A->Size; + pfi2W.ImageableArea = pfi2A->ImageableArea; + + if (Level > 1) + { + if (pfi2A->pKeyword) + { + len = MultiByteToWideChar(CP_ACP, 0, pfi2A->pKeyword, -1, NULL, 0); + pfi2W.pKeyword = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); + MultiByteToWideChar(CP_ACP, 0, pfi2A->pKeyword, -1, (LPWSTR)pfi2W.pKeyword, len); + } + + if (pfi2A->pMuiDll) + { + len = MultiByteToWideChar(CP_ACP, 0, pfi2A->pMuiDll, -1, NULL, 0); + pfi2W.pMuiDll = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); + MultiByteToWideChar(CP_ACP, 0, pfi2A->pMuiDll, -1, (LPWSTR)pfi2W.pMuiDll, len); + } + + if (pfi2A->pDisplayName) + { + len = MultiByteToWideChar(CP_ACP, 0, pfi2A->pDisplayName, -1, NULL, 0); + pfi2W.pDisplayName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); + MultiByteToWideChar(CP_ACP, 0, pfi2A->pDisplayName, -1, (LPWSTR)pfi2W.pDisplayName, len); + } + pfi2W.StringType = pfi2A->StringType; + pfi2W.dwResourceId = pfi2A->dwResourceId; + pfi2W.wLangId = pfi2A->wLangId; + } + + res = SetFormW( hPrinter, FormNameW, Level, (PBYTE)&pfi2W ); + + if (FormNameW) HeapFree(GetProcessHeap(), 0, FormNameW); + if (pfi2W.pName) HeapFree(GetProcessHeap(), 0, pfi2W.pName); + if (pfi2W.pKeyword) HeapFree(GetProcessHeap(), 0, (LPWSTR)pfi2W.pKeyword); + if (pfi2W.pMuiDll) HeapFree(GetProcessHeap(), 0, (LPWSTR)pfi2W.pMuiDll); + if (pfi2W.pDisplayName) HeapFree(GetProcessHeap(), 0, (LPWSTR)pfi2W.pDisplayName); + + return res; } BOOL WINAPI SetFormW(HANDLE hPrinter, PWSTR pFormName, DWORD Level, PBYTE pForm) { + DWORD dwErrorCode; + WINSPOOL_FORM_CONTAINER FormInfoContainer; + PSPOOLER_HANDLE pHandle = (PSPOOLER_HANDLE)hPrinter; + TRACE("SetFormW(%p, %S, %lu, %p)\n", hPrinter, pFormName, Level, pForm); - UNIMPLEMENTED; - return FALSE; + + // Sanity checks. + if (!pHandle) + { + ERR("Level = %d, unsupported!\n", Level); + dwErrorCode = ERROR_INVALID_HANDLE; + return FALSE; + } + + FormInfoContainer.FormInfo.pFormInfo1 = (WINSPOOL_FORM_INFO_1*)pForm; + FormInfoContainer.Level = Level; + + // Do the RPC call + RpcTryExcept + { + dwErrorCode = _RpcSetForm(pHandle->hPrinter, pFormName, &FormInfoContainer); + } + RpcExcept(EXCEPTION_EXECUTE_HANDLER) + { + dwErrorCode = RpcExceptionCode(); + } + RpcEndExcept; + + SetLastError(dwErrorCode); + return (dwErrorCode == ERROR_SUCCESS); } diff --git a/win32ss/printing/base/winspool/jobs.c b/win32ss/printing/base/winspool/jobs.c index e3cea6500cc..7cc17d40470 100644 --- a/win32ss/printing/base/winspool/jobs.c +++ b/win32ss/printing/base/winspool/jobs.c @@ -11,9 +11,30 @@ BOOL WINAPI AddJobA(HANDLE hPrinter, DWORD Level, PBYTE pData, DWORD cbBuf, PDWORD pcbNeeded) { - TRACE("AddJobA(%p, %lu, %p, %lu, %p)\n", hPrinter, Level, pData, cbBuf, pcbNeeded); - UNIMPLEMENTED; - return FALSE; + BOOL ret; + + FIXME("AddJobA(%p, %lu, %p, %lu, %p)\n", hPrinter, Level, pData, cbBuf, pcbNeeded); + + if (Level != 1) + { + ERR("Level = %d, unsupported!\n", Level); + SetLastError(ERROR_INVALID_LEVEL); + return FALSE; + } + + ret = AddJobW(hPrinter, Level, pData, cbBuf, pcbNeeded); + + if (ret) + { + DWORD dwErrorCode; + ADDJOB_INFO_1W *addjobW = (ADDJOB_INFO_1W*)pData; + dwErrorCode = UnicodeToAnsiInPlace(addjobW->Path); + if (dwErrorCode != ERROR_SUCCESS) + { + ret = FALSE; + } + } + return ret; } BOOL WINAPI @@ -22,7 +43,7 @@ AddJobW(HANDLE hPrinter, DWORD Level, PBYTE pData, DWORD cbBuf, PDWORD pcbNeeded DWORD dwErrorCode; PSPOOLER_HANDLE pHandle = (PSPOOLER_HANDLE)hPrinter; - TRACE("AddJobW(%p, %lu, %p, %lu, %p)\n", hPrinter, Level, pData, cbBuf, pcbNeeded); + FIXME("AddJobW(%p, %lu, %p, %lu, %p)\n", hPrinter, Level, pData, cbBuf, pcbNeeded); if (!pHandle) { @@ -46,6 +67,8 @@ AddJobW(HANDLE hPrinter, DWORD Level, PBYTE pData, DWORD cbBuf, PDWORD pcbNeeded { // Replace relative offset addresses in the output by absolute pointers. MarshallUpStructure(cbBuf, pData, AddJobInfo1Marshalling.pInfo, AddJobInfo1Marshalling.cbStructureSize, TRUE); + pHandle->bJob = TRUE; + FIXME("Notify Tray Icon\n"); } Cleanup: @@ -56,8 +79,118 @@ Cleanup: BOOL WINAPI EnumJobsA(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs, DWORD Level, PBYTE pJob, DWORD cbBuf, PDWORD pcbNeeded, PDWORD pcReturned) { + DWORD dwErrorCode, i; + JOB_INFO_1W* pji1w = (JOB_INFO_1W*)pJob; + JOB_INFO_2A* pji2a = (JOB_INFO_2A*)pJob; + JOB_INFO_2W* pji2w = (JOB_INFO_2W*)pJob; + TRACE("EnumJobsA(%p, %lu, %lu, %lu, %p, %lu, %p, %p)\n", hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned); - UNIMPLEMENTED; + + if ( Level == 3 ) + return EnumJobsW( hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned ); + + if ( EnumJobsW( hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned ) ) + { + switch ( Level ) + { + case 1: + { + for ( i = 0; i < *pcReturned; i++ ) + { + dwErrorCode = UnicodeToAnsiInPlace(pji1w[i].pPrinterName); + if (dwErrorCode != ERROR_SUCCESS) + { + goto Cleanup; + } + dwErrorCode = UnicodeToAnsiInPlace(pji1w[i].pMachineName); + if (dwErrorCode != ERROR_SUCCESS) + { + goto Cleanup; + } + dwErrorCode = UnicodeToAnsiInPlace(pji1w[i].pUserName); + if (dwErrorCode != ERROR_SUCCESS) + { + goto Cleanup; + } + dwErrorCode = UnicodeToAnsiInPlace(pji1w[i].pDocument); + if (dwErrorCode != ERROR_SUCCESS) + { + goto Cleanup; + } + dwErrorCode = UnicodeToAnsiInPlace(pji1w[i].pDatatype); + if (dwErrorCode != ERROR_SUCCESS) + { + goto Cleanup; + } + dwErrorCode = UnicodeToAnsiInPlace(pji1w[i].pStatus); + if (dwErrorCode != ERROR_SUCCESS) + { + goto Cleanup; + } + } + } + break; + + case 2: + { + for ( i = 0; i < *pcReturned; i++ ) + { + dwErrorCode = UnicodeToAnsiInPlace(pji2w[i].pPrinterName); + if (dwErrorCode != ERROR_SUCCESS) + { + goto Cleanup; + } + dwErrorCode = UnicodeToAnsiInPlace(pji2w[i].pMachineName); + if (dwErrorCode != ERROR_SUCCESS) + { + goto Cleanup; + } + dwErrorCode = UnicodeToAnsiInPlace(pji2w[i].pUserName); + if (dwErrorCode != ERROR_SUCCESS) + { + goto Cleanup; + } + dwErrorCode = UnicodeToAnsiInPlace(pji2w[i].pDocument); + if (dwErrorCode != ERROR_SUCCESS) + { + goto Cleanup; + } + dwErrorCode = UnicodeToAnsiInPlace(pji2w[i].pNotifyName); + if (dwErrorCode != ERROR_SUCCESS) + { + goto Cleanup; + } + dwErrorCode = UnicodeToAnsiInPlace(pji2w[i].pDatatype); + if (dwErrorCode != ERROR_SUCCESS) + { + goto Cleanup; + } + dwErrorCode = UnicodeToAnsiInPlace(pji2w[i].pPrintProcessor); + if (dwErrorCode != ERROR_SUCCESS) + { + goto Cleanup; + } + dwErrorCode = UnicodeToAnsiInPlace(pji2w[i].pParameters); + if (dwErrorCode != ERROR_SUCCESS) + { + goto Cleanup; + } + dwErrorCode = UnicodeToAnsiInPlace(pji2w[i].pStatus); + if (dwErrorCode != ERROR_SUCCESS) + { + goto Cleanup; + } + if ( pji2w[i].pDevMode ) + { + RosConvertUnicodeDevModeToAnsiDevmode( pji2w[i].pDevMode, pji2a[i].pDevMode ); + } + } + } + break; + } + return TRUE; + } +Cleanup: return FALSE; } @@ -105,8 +238,108 @@ Cleanup: BOOL WINAPI GetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level, PBYTE pJob, DWORD cbBuf, PDWORD pcbNeeded) { - TRACE("GetJobA(%p, %lu, %lu, %p, %lu, %p)\n", hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded); - UNIMPLEMENTED; + DWORD dwErrorCode; + JOB_INFO_1W* pji1w = (JOB_INFO_1W*)pJob; + JOB_INFO_2A* pji2a = (JOB_INFO_2A*)pJob; + JOB_INFO_2W* pji2w = (JOB_INFO_2W*)pJob; + + FIXME("GetJobA(%p, %lu, %lu, %p, %lu, %p)\n", hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded); + + if ( Level == 3 ) + return GetJobW( hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded ); + + if ( GetJobW( hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded ) ) + { + switch ( Level ) + { + case 1: + dwErrorCode = UnicodeToAnsiInPlace(pji1w->pPrinterName); + if (dwErrorCode != ERROR_SUCCESS) + { + goto Cleanup; + } + dwErrorCode = UnicodeToAnsiInPlace(pji1w->pMachineName); + if (dwErrorCode != ERROR_SUCCESS) + { + goto Cleanup; + } + dwErrorCode = UnicodeToAnsiInPlace(pji1w->pUserName); + if (dwErrorCode != ERROR_SUCCESS) + { + goto Cleanup; + } + dwErrorCode = UnicodeToAnsiInPlace(pji1w->pDocument); + if (dwErrorCode != ERROR_SUCCESS) + { + goto Cleanup; + } + dwErrorCode = UnicodeToAnsiInPlace(pji1w->pDatatype); + if (dwErrorCode != ERROR_SUCCESS) + { + goto Cleanup; + } + dwErrorCode = UnicodeToAnsiInPlace(pji1w->pStatus); + if (dwErrorCode != ERROR_SUCCESS) + { + goto Cleanup; + } + break; + + case 2: + dwErrorCode = UnicodeToAnsiInPlace(pji2w->pPrinterName); + if (dwErrorCode != ERROR_SUCCESS) + { + goto Cleanup; + } + dwErrorCode = UnicodeToAnsiInPlace(pji2w->pMachineName); + if (dwErrorCode != ERROR_SUCCESS) + { + goto Cleanup; + } + dwErrorCode = UnicodeToAnsiInPlace(pji2w->pUserName); + if (dwErrorCode != ERROR_SUCCESS) + { + goto Cleanup; + } + dwErrorCode = UnicodeToAnsiInPlace(pji2w->pDocument); + if (dwErrorCode != ERROR_SUCCESS) + { + goto Cleanup; + } + dwErrorCode = UnicodeToAnsiInPlace(pji2w->pNotifyName); + if (dwErrorCode != ERROR_SUCCESS) + { + goto Cleanup; + } + dwErrorCode = UnicodeToAnsiInPlace(pji2w->pDatatype); + if (dwErrorCode != ERROR_SUCCESS) + { + goto Cleanup; + } + dwErrorCode = UnicodeToAnsiInPlace(pji2w->pPrintProcessor); + if (dwErrorCode != ERROR_SUCCESS) + { + goto Cleanup; + } + dwErrorCode = UnicodeToAnsiInPlace(pji2w->pParameters); + if (dwErrorCode != ERROR_SUCCESS) + { + goto Cleanup; + } + dwErrorCode = UnicodeToAnsiInPlace(pji2w->pStatus); + if (dwErrorCode != ERROR_SUCCESS) + { + goto Cleanup; + } + if ( pji2w->pDevMode ) + { + RosConvertUnicodeDevModeToAnsiDevmode( pji2w->pDevMode, pji2a->pDevMode ); + } + break; + } + return TRUE; + } +Cleanup: return FALSE; } @@ -116,7 +349,7 @@ GetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level, PBYTE pJob, DWORD cbBuf, PDWO DWORD dwErrorCode; PSPOOLER_HANDLE pHandle = (PSPOOLER_HANDLE)hPrinter; - TRACE("GetJobW(%p, %lu, %lu, %p, %lu, %p)\n", hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded); + FIXME("GetJobW(%p, %lu, %lu, %p, %lu, %p)\n", hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded); if (!pHandle) { @@ -174,6 +407,9 @@ ScheduleJob(HANDLE hPrinter, DWORD dwJobID) } RpcEndExcept; + if ( dwErrorCode == ERROR_SUCCESS ) + pHandle->bJob = FALSE; + Cleanup: SetLastError(dwErrorCode); return (dwErrorCode == ERROR_SUCCESS); @@ -182,9 +418,100 @@ Cleanup: BOOL WINAPI SetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level, PBYTE pJobInfo, DWORD Command) { + BOOL ret; + LPBYTE JobW; + UNICODE_STRING usBuffer; + TRACE("SetJobA(%p, %lu, %lu, %p, %lu)\n", hPrinter, JobId, Level, pJobInfo, Command); - UNIMPLEMENTED; - return FALSE; + + /* JobId, pPrinterName, pMachineName, pDriverName, Size, Submitted, Time and TotalPages + are all ignored by SetJob, so we don't bother copying them */ + switch(Level) + { + case 0: + JobW = NULL; + break; + case 1: + { + JOB_INFO_1W *info1W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info1W)); + ZeroMemory( info1W, sizeof(JOB_INFO_1W) ); + JOB_INFO_1A *info1A = (JOB_INFO_1A*)pJobInfo; + + JobW = (LPBYTE)info1W; + info1W->pUserName = AsciiToUnicode(&usBuffer, info1A->pUserName); + info1W->pDocument = AsciiToUnicode(&usBuffer, info1A->pDocument); + info1W->pDatatype = AsciiToUnicode(&usBuffer, info1A->pDatatype); + info1W->pStatus = AsciiToUnicode(&usBuffer, info1A->pStatus); + info1W->Status = info1A->Status; + info1W->Priority = info1A->Priority; + info1W->Position = info1A->Position; + info1W->PagesPrinted = info1A->PagesPrinted; + break; + } + case 2: + { + JOB_INFO_2W *info2W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info2W)); + ZeroMemory( info2W, sizeof(JOB_INFO_2W) ); + JOB_INFO_2A *info2A = (JOB_INFO_2A*)pJobInfo; + + JobW = (LPBYTE)info2W; + info2W->pUserName = AsciiToUnicode(&usBuffer, info2A->pUserName); + info2W->pDocument = AsciiToUnicode(&usBuffer, info2A->pDocument); + info2W->pNotifyName = AsciiToUnicode(&usBuffer, info2A->pNotifyName); + info2W->pDatatype = AsciiToUnicode(&usBuffer, info2A->pDatatype); + info2W->pPrintProcessor = AsciiToUnicode(&usBuffer, info2A->pPrintProcessor); + info2W->pParameters = AsciiToUnicode(&usBuffer, info2A->pParameters); + info2W->pDevMode = info2A->pDevMode ? GdiConvertToDevmodeW(info2A->pDevMode) : NULL; + info2W->pStatus = AsciiToUnicode(&usBuffer, info2A->pStatus); + info2W->pSecurityDescriptor = info2A->pSecurityDescriptor; + info2W->Status = info2A->Status; + info2W->Priority = info2A->Priority; + info2W->Position = info2A->Position; + info2W->StartTime = info2A->StartTime; + info2W->UntilTime = info2A->UntilTime; + info2W->PagesPrinted = info2A->PagesPrinted; + break; + } + case 3: + JobW = HeapAlloc(GetProcessHeap(), 0, sizeof(JOB_INFO_3)); + memcpy(JobW, pJobInfo, sizeof(JOB_INFO_3)); + break; + default: + ERR("Level = %d, unsupported!\n", Level); + SetLastError(ERROR_INVALID_LEVEL); + return FALSE; + } + + ret = SetJobW(hPrinter, JobId, Level, JobW, Command); + + switch(Level) + { + case 1: + { + JOB_INFO_1W *info1W = (JOB_INFO_1W*)JobW; + HeapFree(GetProcessHeap(), 0, info1W->pUserName); + HeapFree(GetProcessHeap(), 0, info1W->pDocument); + HeapFree(GetProcessHeap(), 0, info1W->pDatatype); + HeapFree(GetProcessHeap(), 0, info1W->pStatus); + break; + } + case 2: + { + JOB_INFO_2W *info2W = (JOB_INFO_2W*)JobW; + HeapFree(GetProcessHeap(), 0, info2W->pUserName); + HeapFree(GetProcessHeap(), 0, info2W->pDocument); + HeapFree(GetProcessHeap(), 0, info2W->pNotifyName); + HeapFree(GetProcessHeap(), 0, info2W->pDatatype); + HeapFree(GetProcessHeap(), 0, info2W->pPrintProcessor); + HeapFree(GetProcessHeap(), 0, info2W->pParameters); + HeapFree(GetProcessHeap(), 0, info2W->pDevMode); + HeapFree(GetProcessHeap(), 0, info2W->pStatus); + break; + } + } + HeapFree(GetProcessHeap(), 0, JobW); + + return ret; } BOOL WINAPI diff --git a/win32ss/printing/base/winspool/main.c b/win32ss/printing/base/winspool/main.c index c4f6f77ad1c..d9c66eb16d4 100644 --- a/win32ss/printing/base/winspool/main.c +++ b/win32ss/printing/base/winspool/main.c @@ -9,7 +9,8 @@ // Global Variables HANDLE hProcessHeap; - +HINSTANCE hinstWinSpool = NULL; +CRITICAL_SECTION rtlCritSec; handle_t __RPC_USER WINSPOOL_HANDLE_bind(WINSPOOL_HANDLE wszName) @@ -79,6 +80,12 @@ DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) case DLL_PROCESS_ATTACH: DisableThreadLibraryCalls(hinstDLL); hProcessHeap = GetProcessHeap(); + hinstWinSpool = hinstDLL; + InitializeCriticalSection(&rtlCritSec); + break; + + case DLL_PROCESS_DETACH: + DeleteCriticalSection(&rtlCritSec); break; } diff --git a/win32ss/printing/base/winspool/monitors.c b/win32ss/printing/base/winspool/monitors.c index 18c6fd1d697..720d3537334 100644 --- a/win32ss/printing/base/winspool/monitors.c +++ b/win32ss/printing/base/winspool/monitors.c @@ -11,41 +11,298 @@ BOOL WINAPI AddMonitorA(PSTR pName, DWORD Level, PBYTE pMonitors) { - TRACE("AddMonitorA(%s, %lu, %p)\n", pName, Level, pMonitors); - UNIMPLEMENTED; - return FALSE; + LPWSTR nameW = NULL; + INT len; + BOOL res; + LPMONITOR_INFO_2A mi2a; + MONITOR_INFO_2W mi2w; + + mi2a = (LPMONITOR_INFO_2A) pMonitors; + TRACE("AddMonitorA(%s, %d, %p) : %s %s %s\n", debugstr_a(pName), Level, pMonitors, + debugstr_a(mi2a ? mi2a->pName : NULL), + debugstr_a(mi2a ? mi2a->pEnvironment : NULL), + debugstr_a(mi2a ? mi2a->pDLLName : NULL)); + + if (Level != 2) + { + ERR("Level = %d, unsupported!\n", Level); + SetLastError(ERROR_INVALID_LEVEL); + return FALSE; + } + + /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */ + if (mi2a == NULL) + { + return FALSE; + } + + if (pName) + { + len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0); + nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); + MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len); + } + + memset(&mi2w, 0, sizeof(MONITOR_INFO_2W)); + if (mi2a->pName) + { + len = MultiByteToWideChar(CP_ACP, 0, mi2a->pName, -1, NULL, 0); + mi2w.pName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); + MultiByteToWideChar(CP_ACP, 0, mi2a->pName, -1, mi2w.pName, len); + } + if (mi2a->pEnvironment) + { + len = MultiByteToWideChar(CP_ACP, 0, mi2a->pEnvironment, -1, NULL, 0); + mi2w.pEnvironment = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); + MultiByteToWideChar(CP_ACP, 0, mi2a->pEnvironment, -1, mi2w.pEnvironment, len); + } + if (mi2a->pDLLName) + { + len = MultiByteToWideChar(CP_ACP, 0, mi2a->pDLLName, -1, NULL, 0); + mi2w.pDLLName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); + MultiByteToWideChar(CP_ACP, 0, mi2a->pDLLName, -1, mi2w.pDLLName, len); + } + + res = AddMonitorW(nameW, Level, (LPBYTE) &mi2w); + + HeapFree(GetProcessHeap(), 0, mi2w.pName); + HeapFree(GetProcessHeap(), 0, mi2w.pEnvironment); + HeapFree(GetProcessHeap(), 0, mi2w.pDLLName); + HeapFree(GetProcessHeap(), 0, nameW); + + return (res); } BOOL WINAPI AddMonitorW(PWSTR pName, DWORD Level, PBYTE pMonitors) { + DWORD dwErrorCode; + WINSPOOL_MONITOR_CONTAINER MonitorInfoContainer; TRACE("AddMonitorW(%S, %lu, %p)\n", pName, Level, pMonitors); - UNIMPLEMENTED; - return FALSE; + + if (Level != 2) + { + ERR("Level = %d, unsupported!\n", Level); + SetLastError(ERROR_INVALID_LEVEL); + return FALSE; + } + + MonitorInfoContainer.MonitorInfo.pMonitorInfo2 = (WINSPOOL_MONITOR_INFO_2*)pMonitors; + MonitorInfoContainer.Level = Level; + + // Do the RPC call + RpcTryExcept + { + dwErrorCode = _RpcAddMonitor(pName, &MonitorInfoContainer); + } + RpcExcept(EXCEPTION_EXECUTE_HANDLER) + { + dwErrorCode = RpcExceptionCode(); + ERR("_RpcAddMonitor failed with exception code %lu!\n", dwErrorCode); + } + RpcEndExcept; + + SetLastError(dwErrorCode); + return (dwErrorCode == ERROR_SUCCESS); } BOOL WINAPI DeleteMonitorA(PSTR pName, PSTR pEnvironment, PSTR pMonitorName) { + LPWSTR nameW = NULL; + LPWSTR EnvironmentW = NULL; + LPWSTR MonitorNameW = NULL; + BOOL res; + INT len; + TRACE("DeleteMonitorA(%s, %s, %s)\n", pName, pEnvironment, pMonitorName); - UNIMPLEMENTED; - return FALSE; + + if (pName) { + len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0); + nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); + MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len); + } + + if (pEnvironment) { + len = MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, NULL, 0); + EnvironmentW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); + MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, EnvironmentW, len); + } + if (pMonitorName) { + len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0); + MonitorNameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); + MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, MonitorNameW, len); + } + + res = DeleteMonitorW(nameW, EnvironmentW, MonitorNameW); + + HeapFree(GetProcessHeap(), 0, MonitorNameW); + HeapFree(GetProcessHeap(), 0, EnvironmentW); + HeapFree(GetProcessHeap(), 0, nameW); + + return (res); } BOOL WINAPI DeleteMonitorW(PWSTR pName, PWSTR pEnvironment, PWSTR pMonitorName) { + DWORD dwErrorCode; + TRACE("DeleteMonitorW(%S, %S, %S)\n", pName, pEnvironment, pMonitorName); - UNIMPLEMENTED; - return FALSE; + + // Do the RPC call + RpcTryExcept + { + dwErrorCode = _RpcDeleteMonitor(pName, pEnvironment, pMonitorName); + } + RpcExcept(EXCEPTION_EXECUTE_HANDLER) + { + dwErrorCode = RpcExceptionCode(); + ERR("_RpcDeleteMonitor failed with exception code %lu!\n", dwErrorCode); + } + RpcEndExcept; + + SetLastError(dwErrorCode); + return (dwErrorCode == ERROR_SUCCESS); + } BOOL WINAPI EnumMonitorsA(PSTR pName, DWORD Level, PBYTE pMonitors, DWORD cbBuf, PDWORD pcbNeeded, PDWORD pcReturned) { - TRACE("EnumMonitorsA(%s, %lu, %p, %lu, %p, %p)\n", pName, Level, pMonitors, cbBuf, pcbNeeded, pcReturned); - UNIMPLEMENTED; - return FALSE; + BOOL res; + LPBYTE bufferW = NULL; + LPWSTR nameW = NULL; + DWORD needed = 0; + DWORD numentries = 0; + INT len; + + FIXME("EnumMonitorsA(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), Level, pMonitors, cbBuf, pcbNeeded, pcReturned); + + if ( Level < 1 || Level > 2 ) + { + ERR("Level = %d, unsupported!\n", Level); + SetLastError( ERROR_INVALID_LEVEL ); + return FALSE; + } + + /* convert servername to unicode */ + if (pName) + { + len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0); + nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); + MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len); + } + /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */ + needed = cbBuf * sizeof(WCHAR); + if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed); + res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned); + + if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) + { + if (pcbNeeded) needed = *pcbNeeded; + /* HeapReAlloc return NULL, when bufferW was NULL */ + bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) : + HeapAlloc(GetProcessHeap(), 0, needed); + + /* Try again with the large Buffer */ + res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned); + } + numentries = pcReturned ? *pcReturned : 0; + needed = 0; + /* + W2k require the buffersize from EnumMonitorsW also for EnumMonitorsA. + We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps. + */ + if (res) + { + /* EnumMonitorsW collected all Data. Parse them to calculate ANSI-Size */ + DWORD entrysize = 0; + DWORD index; + LPSTR ptr; + LPMONITOR_INFO_2W mi2w; + LPMONITOR_INFO_2A mi2a; + + /* MONITOR_INFO_*W and MONITOR_INFO_*A have the same size */ + entrysize = (Level == 1) ? sizeof(MONITOR_INFO_1A) : sizeof(MONITOR_INFO_2A); + + /* First pass: calculate the size for all Entries */ + mi2w = (LPMONITOR_INFO_2W) bufferW; + mi2a = (LPMONITOR_INFO_2A) pMonitors; + index = 0; + while (index < numentries) + { + index++; + needed += entrysize; /* MONITOR_INFO_?A */ + TRACE("%p: parsing #%d (%s)\n", mi2w, index, debugstr_w(mi2w->pName)); + + needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1, + NULL, 0, NULL, NULL); + if (Level > 1) + { + needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1, + NULL, 0, NULL, NULL); + needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1, + NULL, 0, NULL, NULL); + } + /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */ + mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize); + mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize); + } + + /* check for errors and quit on failure */ + if (cbBuf < needed) + { + SetLastError(ERROR_INSUFFICIENT_BUFFER); + res = FALSE; + goto emA_cleanup; + } + len = entrysize * numentries; /* room for all MONITOR_INFO_?A */ + ptr = (LPSTR) &pMonitors[len]; /* room for strings */ + cbBuf -= len ; /* free Bytes in the user-Buffer */ + mi2w = (LPMONITOR_INFO_2W) bufferW; + mi2a = (LPMONITOR_INFO_2A) pMonitors; + index = 0; + /* Second Pass: Fill the User Buffer (if we have one) */ + while ((index < numentries) && pMonitors) + { + index++; + TRACE("%p: writing MONITOR_INFO_%dA #%d\n", mi2a, Level, index); + mi2a->pName = ptr; + len = WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1, + ptr, cbBuf , NULL, NULL); + ptr += len; + cbBuf -= len; + if (Level > 1) + { + mi2a->pEnvironment = ptr; + len = WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1, + ptr, cbBuf, NULL, NULL); + ptr += len; + cbBuf -= len; + + mi2a->pDLLName = ptr; + len = WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1, + ptr, cbBuf, NULL, NULL); + ptr += len; + cbBuf -= len; + } + /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */ + mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize); + mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize); + } + } +emA_cleanup: + if (pcbNeeded) *pcbNeeded = needed; + if (pcReturned) *pcReturned = (res) ? numentries : 0; + + HeapFree(GetProcessHeap(), 0, nameW); + HeapFree(GetProcessHeap(), 0, bufferW); + + FIXME("returning %d with %d (%d byte for %d entries)\n", (res), GetLastError(), needed, numentries); + + return (res); + } BOOL WINAPI @@ -53,7 +310,14 @@ EnumMonitorsW(PWSTR pName, DWORD Level, PBYTE pMonitors, DWORD cbBuf, PDWORD pcb { DWORD dwErrorCode; - TRACE("EnumMonitorsW(%S, %lu, %p, %lu, %p, %p)\n", pName, Level, pMonitors, cbBuf, pcbNeeded, pcReturned); + FIXME("EnumMonitorsW(%S, %lu, %p, %lu, %p, %p)\n", pName, Level, pMonitors, cbBuf, pcbNeeded, pcReturned); + + if ( Level < 1 || Level > 2 ) + { + ERR("Level = %d, unsupported!\n", Level); + SetLastError( ERROR_INVALID_LEVEL ); + return FALSE; + } // Do the RPC call RpcTryExcept @@ -63,7 +327,7 @@ EnumMonitorsW(PWSTR pName, DWORD Level, PBYTE pMonitors, DWORD cbBuf, PDWORD pcb RpcExcept(EXCEPTION_EXECUTE_HANDLER) { dwErrorCode = RpcExceptionCode(); - ERR("_RpcEnumPorts failed with exception code %lu!\n", dwErrorCode); + ERR("_RpcEnumMonitors failed with exception code %lu!\n", dwErrorCode); } RpcEndExcept; diff --git a/win32ss/printing/base/winspool/ports.c b/win32ss/printing/base/winspool/ports.c index f243567407e..80854ab23cf 100644 --- a/win32ss/printing/base/winspool/ports.c +++ b/win32ss/printing/base/winspool/ports.c @@ -8,76 +8,475 @@ #include "precomp.h" #include +typedef struct _PORTTHREADINFO +{ + LPWSTR pName; + HWND hWnd; + LPWSTR pPortName; + FARPROC fpFunction; + DWORD dwErrorCode; + HANDLE hEvent; +} PORTTHREADINFO, *PPORTTHREADINFO; + +VOID WINAPI +IntPortThread( PPORTTHREADINFO pPortThreadInfo ) +{ + // Do the RPC call + RpcTryExcept + { + pPortThreadInfo->dwErrorCode = (*pPortThreadInfo->fpFunction)( pPortThreadInfo->pName, pPortThreadInfo->hWnd, pPortThreadInfo->pPortName); + } + RpcExcept(EXCEPTION_EXECUTE_HANDLER) + { + pPortThreadInfo->dwErrorCode = RpcExceptionCode(); + } + RpcEndExcept; + + SetEvent( pPortThreadInfo->hEvent ); +} + +// +// Start a thread to wait on a printer port. +// +BOOL WINAPI +StartPortThread( LPWSTR pName, HWND hWnd, LPWSTR pPortName, FARPROC fpFunction ) +{ + PORTTHREADINFO PortThreadInfo; + HANDLE htHandle; + MSG Msg; + DWORD tid; + + if ( hWnd ) EnableWindow( hWnd, FALSE ); + + PortThreadInfo.pName = pName; + PortThreadInfo.hWnd = hWnd; + PortThreadInfo.pPortName = pPortName; + PortThreadInfo.fpFunction = fpFunction; + PortThreadInfo.dwErrorCode = ERROR_SUCCESS; + PortThreadInfo.hEvent = CreateEventW( NULL, TRUE, FALSE, NULL ); + + htHandle = CreateThread( NULL, + 32*1024, + (LPTHREAD_START_ROUTINE)IntPortThread, + &PortThreadInfo, + 0, + &tid ); + + CloseHandle( htHandle ); + + while ( MsgWaitForMultipleObjects( 1, &PortThreadInfo.hEvent, FALSE, INFINITE, QS_SENDMESSAGE|QS_ALLEVENTS ) == 1 ) + { + while ( PeekMessageW( &Msg, NULL, 0, 0, PM_REMOVE ) ) + { + TranslateMessage( &Msg ); + DispatchMessageW( &Msg ); + } + } + + CloseHandle( PortThreadInfo.hEvent ); + + if ( hWnd ) + { + EnableWindow(hWnd, TRUE); + SetForegroundWindow(hWnd); + SetFocus(hWnd); + } + + SetLastError(PortThreadInfo.dwErrorCode); + return (PortThreadInfo.dwErrorCode == ERROR_SUCCESS); +} + + BOOL WINAPI AddPortA(PSTR pName, HWND hWnd, PSTR pMonitorName) { - TRACE("AddPortA(%s, %p, %s)\n", pName, hWnd, pMonitorName); - UNIMPLEMENTED; - return FALSE; -} + LPWSTR nameW = NULL; + LPWSTR monitorW = NULL; + DWORD len; + BOOL res; -BOOL WINAPI -AddPortExA(PSTR pName, DWORD Level, PBYTE lpBuffer, PSTR lpMonitorName) -{ - TRACE("AddPortExA(%s, %lu, %p, %s)\n", pName, Level, lpBuffer, lpMonitorName); - UNIMPLEMENTED; - return FALSE; + TRACE("AddPortA(%s, %p, %s)\n",debugstr_a(pName), hWnd, debugstr_a(pMonitorName)); + + if (pName) + { + len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0); + nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); + MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len); + } + + if (pMonitorName) + { + len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0); + monitorW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); + MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, monitorW, len); + } + + res = AddPortW(nameW, hWnd, monitorW); + + HeapFree(GetProcessHeap(), 0, nameW); + HeapFree(GetProcessHeap(), 0, monitorW); + + return res; } BOOL WINAPI AddPortExW(PWSTR pName, DWORD Level, PBYTE lpBuffer, PWSTR lpMonitorName) { - TRACE("AddPortExA(%S, %lu, %p, %S)\n", pName, Level, lpBuffer, lpMonitorName); - UNIMPLEMENTED; - return FALSE; + DWORD dwErrorCode; + WINSPOOL_PORT_CONTAINER PortInfoContainer; + WINSPOOL_PORT_VAR_CONTAINER PortVarContainer; + WINSPOOL_PORT_INFO_FF *pPortInfoFF; + + TRACE("AddPortExW(%S, %lu, %p, %S)\n", pName, Level, lpBuffer, lpMonitorName); + + switch (Level) + { + case 1: + // FIXME!!!! Only Level 1 is supported? See note in wine winspool test info.c : line 575. + PortInfoContainer.PortInfo.pPortInfo1 = (WINSPOOL_PORT_INFO_1*)lpBuffer; + PortInfoContainer.Level = Level; + PortVarContainer.cbMonitorData = 0; + PortVarContainer.pMonitorData = NULL; + break; + + case 0xFFFFFFFF: + pPortInfoFF = (WINSPOOL_PORT_INFO_FF*)lpBuffer; + PortInfoContainer.PortInfo.pPortInfoFF = pPortInfoFF; + PortInfoContainer.Level = Level; + PortVarContainer.cbMonitorData = pPortInfoFF->cbMonitorData; + PortVarContainer.pMonitorData = pPortInfoFF->pMonitorData; + break; + + default: + ERR("Level = %d, unsupported!\n", Level); + SetLastError(ERROR_INVALID_LEVEL); + return FALSE; + } + + // Do the RPC call + RpcTryExcept + { + dwErrorCode = _RpcAddPortEx(pName, &PortInfoContainer, &PortVarContainer, lpMonitorName); + } + RpcExcept(EXCEPTION_EXECUTE_HANDLER) + { + dwErrorCode = RpcExceptionCode(); + } + RpcEndExcept; + + SetLastError(dwErrorCode); + return (dwErrorCode == ERROR_SUCCESS); +} + +BOOL WINAPI +AddPortExA(PSTR pName, DWORD Level, PBYTE lpBuffer, PSTR lpMonitorName) +{ + PORT_INFO_1W pi1W; + PORT_INFO_1A * pi1A; + LPWSTR nameW = NULL; + LPWSTR monitorW = NULL; + DWORD len; + BOOL res = FALSE; + WINSPOOL_PORT_INFO_FF *pPortInfoFF, PortInfoFF; + + pi1A = (PORT_INFO_1A *)lpBuffer; + pPortInfoFF = (WINSPOOL_PORT_INFO_FF*)lpBuffer; + + TRACE("AddPortExA(%s, %d, %p, %s): %s\n", debugstr_a(pName), Level, lpBuffer, debugstr_a(lpMonitorName), debugstr_a(pi1A ? pi1A->pName : NULL)); + + if ( !lpBuffer || !lpMonitorName ) + { + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + + if (pName) + { + len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0); + nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); + MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len); + } + + if (lpMonitorName) + { + len = MultiByteToWideChar(CP_ACP, 0, lpMonitorName, -1, NULL, 0); + monitorW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); + MultiByteToWideChar(CP_ACP, 0, lpMonitorName, -1, monitorW, len); + } + + pi1W.pName = NULL; + ZeroMemory( &PortInfoFF, sizeof(WINSPOOL_PORT_INFO_FF)); + + switch ( Level ) + { + case 1: + if ( pi1A->pName ) + { + len = MultiByteToWideChar(CP_ACP, 0, pi1A->pName, -1, NULL, 0); + pi1W.pName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); + MultiByteToWideChar(CP_ACP, 0, pi1A->pName, -1, pi1W.pName, len); + } + break; + + case 0xFFFFFFFF: + // + // Remember the calling parameter is Ansi. + // + if ( !pPortInfoFF->pPortName || !(PCHAR)pPortInfoFF->pPortName ) + { + SetLastError(ERROR_INVALID_PARAMETER); + goto Cleanup; + } + + len = MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pPortInfoFF->pPortName, -1, NULL, 0); + PortInfoFF.pPortName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); + MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pPortInfoFF->pPortName, -1, (LPWSTR)PortInfoFF.pPortName, len); + + PortInfoFF.cbMonitorData = pPortInfoFF->cbMonitorData; + PortInfoFF.pMonitorData = pPortInfoFF->pMonitorData; + break; + + default: + ERR("Level = %d, unsupported!\n", Level); + SetLastError(ERROR_INVALID_LEVEL); + goto Cleanup; + } + + res = AddPortExW( nameW, Level, Level == 1 ? (PBYTE)&pi1W : (PBYTE)&PortInfoFF, monitorW ); + +Cleanup: + if (nameW) HeapFree(GetProcessHeap(), 0, nameW); + if (monitorW) HeapFree(GetProcessHeap(), 0, monitorW); + if (pi1W.pName) HeapFree(GetProcessHeap(), 0, pi1W.pName); + if (PortInfoFF.pPortName) HeapFree(GetProcessHeap(), 0, PortInfoFF.pPortName); + + return res; } BOOL WINAPI AddPortW(PWSTR pName, HWND hWnd, PWSTR pMonitorName) { TRACE("AddPortW(%S, %p, %S)\n", pName, hWnd, pMonitorName); - UNIMPLEMENTED; - return FALSE; + return StartPortThread(pName, hWnd, pMonitorName, (FARPROC)_RpcAddPort); } BOOL WINAPI ConfigurePortA(PSTR pName, HWND hWnd, PSTR pPortName) { - TRACE("ConfigurePortA(%s, %p, %s)\n", pName, hWnd, pPortName); - UNIMPLEMENTED; - return FALSE; + LPWSTR nameW = NULL; + LPWSTR portW = NULL; + INT len; + DWORD res; + + TRACE("ConfigurePortA(%s, %p, %s)\n", debugstr_a(pName), hWnd, debugstr_a(pPortName)); + + /* convert servername to unicode */ + if (pName) + { + len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0); + nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); + MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len); + } + + /* convert portname to unicode */ + if (pPortName) + { + len = MultiByteToWideChar(CP_ACP, 0, pPortName, -1, NULL, 0); + portW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); + MultiByteToWideChar(CP_ACP, 0, pPortName, -1, portW, len); + } + + res = ConfigurePortW(nameW, hWnd, portW); + + HeapFree(GetProcessHeap(), 0, nameW); + HeapFree(GetProcessHeap(), 0, portW); + + return res; } BOOL WINAPI ConfigurePortW(PWSTR pName, HWND hWnd, PWSTR pPortName) { TRACE("ConfigurePortW(%S, %p, %S)\n", pName, hWnd, pPortName); - UNIMPLEMENTED; - return FALSE; + return StartPortThread(pName, hWnd, pPortName, (FARPROC)_RpcConfigurePort); } BOOL WINAPI DeletePortA(PSTR pName, HWND hWnd, PSTR pPortName) { - TRACE("DeletePortA(%s, %p, %s)\n", pName, hWnd, pPortName); - UNIMPLEMENTED; - return FALSE; + LPWSTR nameW = NULL; + LPWSTR portW = NULL; + INT len; + DWORD res; + + TRACE("DeletePortA(%s, %p, %s)\n", debugstr_a(pName), hWnd, debugstr_a(pPortName)); + + /* convert servername to unicode */ + if (pName) + { + len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0); + nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); + MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len); + } + + /* convert portname to unicode */ + if (pPortName) + { + len = MultiByteToWideChar(CP_ACP, 0, pPortName, -1, NULL, 0); + portW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); + MultiByteToWideChar(CP_ACP, 0, pPortName, -1, portW, len); + } + + res = DeletePortW(nameW, hWnd, portW); + + HeapFree(GetProcessHeap(), 0, nameW); + HeapFree(GetProcessHeap(), 0, portW); + + return res; } BOOL WINAPI DeletePortW(PWSTR pName, HWND hWnd, PWSTR pPortName) { TRACE("DeletePortW(%S, %p, %S)\n", pName, hWnd, pPortName); - UNIMPLEMENTED; - return FALSE; + return StartPortThread(pName, hWnd, pPortName, (FARPROC)_RpcDeletePort); } BOOL WINAPI EnumPortsA(PSTR pName, DWORD Level, PBYTE pPorts, DWORD cbBuf, PDWORD pcbNeeded, PDWORD pcReturned) { - TRACE("EnumPortsA(%s, %lu, %p, %lu, %p, %p)\n", pName, Level, pPorts, cbBuf, pcbNeeded, pcReturned); - UNIMPLEMENTED; - return FALSE; + BOOL res; + LPBYTE bufferW = NULL; + LPWSTR nameW = NULL; + DWORD needed = 0; + DWORD numentries = 0; + INT len; + + TRACE("EnumPortsA(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), Level, pPorts, cbBuf, pcbNeeded, pcReturned); + + /* convert servername to unicode */ + if (pName) + { + len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0); + nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); + MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len); + } + /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the Ports */ + needed = cbBuf * sizeof(WCHAR); + if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed); + res = EnumPortsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned); + + if (!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) + { + if (pcbNeeded) needed = *pcbNeeded; + /* HeapReAlloc return NULL, when bufferW was NULL */ + bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) : + HeapAlloc(GetProcessHeap(), 0, needed); + + /* Try again with the large Buffer */ + res = EnumPortsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned); + } + needed = pcbNeeded ? *pcbNeeded : 0; + numentries = pcReturned ? *pcReturned : 0; + + /* + W2k require the buffersize from EnumPortsW also for EnumPortsA. + We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps. + */ + if (res) + { + /* EnumPortsW collected all Data. Parse them to calculate ANSI-Size */ + DWORD entrysize = 0; + DWORD index; + LPSTR ptr; + LPPORT_INFO_2W pi2w; + LPPORT_INFO_2A pi2a; + + needed = 0; + entrysize = (Level == 1) ? sizeof(PORT_INFO_1A) : sizeof(PORT_INFO_2A); + + /* First pass: calculate the size for all Entries */ + pi2w = (LPPORT_INFO_2W) bufferW; + pi2a = (LPPORT_INFO_2A) pPorts; + index = 0; + while (index < numentries) + { + index++; + needed += entrysize; /* PORT_INFO_?A */ + TRACE("%p: parsing #%d (%s)\n", pi2w, index, debugstr_w(pi2w->pPortName)); + + needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pPortName, -1, + NULL, 0, NULL, NULL); + if (Level > 1) + { + needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pMonitorName, -1, + NULL, 0, NULL, NULL); + needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pDescription, -1, + NULL, 0, NULL, NULL); + } + /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */ + pi2w = (LPPORT_INFO_2W) (((LPBYTE)pi2w) + entrysize); + pi2a = (LPPORT_INFO_2A) (((LPBYTE)pi2a) + entrysize); + } + + /* check for errors and quit on failure */ + if (cbBuf < needed) + { + SetLastError(ERROR_INSUFFICIENT_BUFFER); + res = FALSE; + goto cleanup; + } + len = entrysize * numentries; /* room for all PORT_INFO_?A */ + ptr = (LPSTR) &pPorts[len]; /* room for strings */ + cbBuf -= len ; /* free Bytes in the user-Buffer */ + pi2w = (LPPORT_INFO_2W) bufferW; + pi2a = (LPPORT_INFO_2A) pPorts; + index = 0; + /* Second Pass: Fill the User Buffer (if we have one) */ + while ((index < numentries) && pPorts) + { + index++; + TRACE("%p: writing PORT_INFO_%dA #%d\n", pi2a, Level, index); + pi2a->pPortName = ptr; + len = WideCharToMultiByte(CP_ACP, 0, pi2w->pPortName, -1, + ptr, cbBuf , NULL, NULL); + ptr += len; + cbBuf -= len; + if (Level > 1) + { + pi2a->pMonitorName = ptr; + len = WideCharToMultiByte(CP_ACP, 0, pi2w->pMonitorName, -1, + ptr, cbBuf, NULL, NULL); + ptr += len; + cbBuf -= len; + + pi2a->pDescription = ptr; + len = WideCharToMultiByte(CP_ACP, 0, pi2w->pDescription, -1, + ptr, cbBuf, NULL, NULL); + ptr += len; + cbBuf -= len; + + pi2a->fPortType = pi2w->fPortType; + pi2a->Reserved = 0; /* documented: "must be zero" */ + + } + /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */ + pi2w = (LPPORT_INFO_2W) (((LPBYTE)pi2w) + entrysize); + pi2a = (LPPORT_INFO_2A) (((LPBYTE)pi2a) + entrysize); + } + } + +cleanup: + if (pcbNeeded) *pcbNeeded = needed; + if (pcReturned) *pcReturned = (res) ? numentries : 0; + + HeapFree(GetProcessHeap(), 0, nameW); + HeapFree(GetProcessHeap(), 0, bufferW); + + TRACE("returning %d with %d (%d byte for %d of %d entries)\n", + (res), GetLastError(), needed, (res)? numentries : 0, numentries); + + return (res); } BOOL WINAPI @@ -113,15 +512,84 @@ EnumPortsW(PWSTR pName, DWORD Level, PBYTE pPorts, DWORD cbBuf, PDWORD pcbNeeded BOOL WINAPI SetPortA(PSTR pName, PSTR pPortName, DWORD dwLevel, PBYTE pPortInfo) { + LPWSTR NameW = NULL; + LPWSTR PortNameW = NULL; + PORT_INFO_3W pi3W; + PORT_INFO_3A *pi3A; + DWORD len; + BOOL res; + TRACE("SetPortA(%s, %s, %lu, %p)\n", pName, pPortName, dwLevel, pPortInfo); - UNIMPLEMENTED; - return FALSE; + + if ( dwLevel != 3 ) + { + ERR("Level = %d, unsupported!\n", dwLevel); + SetLastError(ERROR_INVALID_LEVEL); + return FALSE; + } + + if (pName) + { + len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0); + NameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); + MultiByteToWideChar(CP_ACP, 0, pName, -1, NameW, len); + } + + if (pPortName) + { + len = MultiByteToWideChar(CP_ACP, 0, pPortName, -1, NULL, 0); + PortNameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); + MultiByteToWideChar(CP_ACP, 0, pPortName, -1, PortNameW, len); + } + + if (pi3A->pszStatus) + { + len = MultiByteToWideChar(CP_ACP, 0, pi3A->pszStatus, -1, NULL, 0); + pi3W.pszStatus = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); + MultiByteToWideChar(CP_ACP, 0, pi3A->pszStatus, -1, pi3W.pszStatus, len); + } + + pi3W.dwStatus = pi3A->dwStatus; + pi3W.dwSeverity = pi3A->dwSeverity; + + res = SetPortW( NameW, PortNameW, dwLevel, (PBYTE)&pi3W ); + + if (NameW) HeapFree(GetProcessHeap(), 0, NameW); + if (PortNameW) HeapFree(GetProcessHeap(), 0, PortNameW); + if (pi3W.pszStatus) HeapFree(GetProcessHeap(), 0, pi3W.pszStatus); + + return res; } BOOL WINAPI SetPortW(PWSTR pName, PWSTR pPortName, DWORD dwLevel, PBYTE pPortInfo) { + DWORD dwErrorCode; + WINSPOOL_PORT_CONTAINER PortInfoContainer; + TRACE("SetPortW(%S, %S, %lu, %p)\n", pName, pPortName, dwLevel, pPortInfo); - UNIMPLEMENTED; - return FALSE; + + if ( dwLevel != 3 ) + { + ERR("Level = %d, unsupported!\n", dwLevel); + SetLastError(ERROR_INVALID_LEVEL); + return FALSE; + } + + PortInfoContainer.PortInfo.pPortInfo3 = (WINSPOOL_PORT_INFO_3*)pPortInfo; + PortInfoContainer.Level = dwLevel; + + // Do the RPC call + RpcTryExcept + { + dwErrorCode = _RpcSetPort(pName, pPortName, &PortInfoContainer); + } + RpcExcept(EXCEPTION_EXECUTE_HANDLER) + { + dwErrorCode = RpcExceptionCode(); + } + RpcEndExcept; + + SetLastError(dwErrorCode); + return (dwErrorCode == ERROR_SUCCESS); } diff --git a/win32ss/printing/base/winspool/precomp.h b/win32ss/printing/base/winspool/precomp.h index e5a857b34e0..05eb85098b2 100644 --- a/win32ss/printing/base/winspool/precomp.h +++ b/win32ss/printing/base/winspool/precomp.h @@ -11,10 +11,12 @@ #define WIN32_NO_STATUS #include #include +#include #include #include #include #include +#include #include #include #include @@ -25,28 +27,79 @@ #include WINE_DEFAULT_DEBUG_CHANNEL(winspool); +#define SPOOLER_HANDLE_SIG 'gg' + // Structures /* - * Describes a handle returned by OpenPrinterW. + * Describes a handle returned by AddPrinterW or OpenPrinterW. */ typedef struct _SPOOLER_HANDLE { + DWORD_PTR Sig; BOOL bStartedDoc : 1; + BOOL bJob : 1; + BOOL bAnsi : 1; + BOOL bDocEvent : 1; + BOOL bTrayIcon : 1; + BOOL bNoColorProfile : 1; + BOOL bShared : 1; + BOOL bClosed : 1; DWORD dwJobID; HANDLE hPrinter; HANDLE hSPLFile; + DWORD cCount; + HANDLE hSpoolFileHandle; + DWORD dwOptions; } SPOOLER_HANDLE, *PSPOOLER_HANDLE; // main.c extern HANDLE hProcessHeap; +extern CRITICAL_SECTION rtlCritSec; // utils.c DWORD UnicodeToAnsiInPlace(PWSTR pwszField); +DWORD UnicodeToAnsiZZInPlace(PWSTR pwszzField); +SECURITY_DESCRIPTOR * get_sd( SECURITY_DESCRIPTOR *sd, DWORD *size ); +LONG WINAPI IntProtectHandle(HANDLE,BOOL); +BOOL WINAPI IntUnprotectHandle(HANDLE); // devmode.c -extern void RosConvertAnsiDevModeToUnicodeDevmode(PDEVMODEA pDevModeInput, PDEVMODEW pDevModeOutput); +extern void RosConvertAnsiDevModeToUnicodeDevmode(PDEVMODEA pDevModeInput, PDEVMODEW *pDevModeOutput); extern void RosConvertUnicodeDevModeToAnsiDevmode(PDEVMODEW pDevModeInput, PDEVMODEA pDevModeOutput); +// RC + +#define IDS_CAPTION 10 +#define IDS_FILE_EXISTS 11 +#define IDS_CANNOT_OPEN 12 +#define FILENAME_DIALOG 100 +#define EDITBOX 201 + +// +// [MS-EMF] 2.2.27 UniversalFontId Object +// +typedef struct _UNIVERSAL_FONT_ID +{ + ULONG CheckSum; + ULONG Index; +} UNIVERSAL_FONT_ID, *PUNIVERSAL_FONT_ID; + +BOOL WINAPI IsValidDevmodeNoSizeW(PDEVMODEW pDevmode); + +/* RtlCreateUnicodeStringFromAsciiz will return an empty string in the buffer + if passed a NULL string. This returns NULLs to the result. +*/ +static inline PWSTR AsciiToUnicode( UNICODE_STRING * usBufferPtr, LPCSTR src ) +{ + if ( (src) ) + { + RtlCreateUnicodeStringFromAsciiz(usBufferPtr, src); + return usBufferPtr->Buffer; + } + usBufferPtr->Buffer = NULL; /* so that RtlFreeUnicodeString won't barf */ + return NULL; +} + #endif diff --git a/win32ss/printing/base/winspool/printerdata.c b/win32ss/printing/base/winspool/printerdata.c index aefa944872f..7e574e95d9e 100644 --- a/win32ss/printing/base/winspool/printerdata.c +++ b/win32ss/printing/base/winspool/printerdata.c @@ -7,6 +7,22 @@ #include "precomp.h" +LONG WINAPI +AdvancedSetupDialog(HWND hWnd, INT Unknown, PDEVMODEA pDevModeInput, PDEVMODEA pDevModeOutput) +{ + HANDLE hPrinter; + LONG Ret = -1; + + TRACE("AdvancedSetupDialog(%p, %d, %p, %p)\n", hWnd, Unknown, pDevModeOutput, pDevModeInput); + + if ( OpenPrinterA( (LPSTR)pDevModeInput->dmDeviceName, &hPrinter, NULL ) ) + { + Ret = AdvancedDocumentPropertiesA( hWnd, hPrinter, (PSTR)pDevModeInput->dmDeviceName, pDevModeOutput, pDevModeInput ); + ClosePrinter(hPrinter); + } + return Ret; +} + LONG WINAPI AdvancedDocumentPropertiesA(HWND hWnd, HANDLE hPrinter, PSTR pDeviceName, PDEVMODEA pDevModeOutput, PDEVMODEA pDevModeInput) { @@ -26,17 +42,57 @@ AdvancedDocumentPropertiesW(HWND hWnd, HANDLE hPrinter, PWSTR pDeviceName, PDEVM DWORD WINAPI DeletePrinterDataA(HANDLE hPrinter, PSTR pValueName) { + LPWSTR valuenameW = NULL; + INT len; + DWORD res; + TRACE("DeletePrinterDataA(%p, %s)\n", hPrinter, pValueName); - UNIMPLEMENTED; - return ERROR_NOT_SUPPORTED; + + if (pValueName) + { + len = MultiByteToWideChar(CP_ACP, 0, pValueName, -1, NULL, 0); + valuenameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); + MultiByteToWideChar(CP_ACP, 0, pValueName, -1, valuenameW, len); + } + + res = DeletePrinterDataW( hPrinter, valuenameW ); + + HeapFree(GetProcessHeap(), 0, valuenameW); + + return res; + } DWORD WINAPI DeletePrinterDataExA(HANDLE hPrinter, PCSTR pKeyName, PCSTR pValueName) { + LPWSTR keynameW = NULL; + LPWSTR valuenameW = NULL; + INT len; + DWORD res; + TRACE("DeletePrinterDataExA(%p, %s, %s)\n", hPrinter, pKeyName, pValueName); - UNIMPLEMENTED; - return ERROR_NOT_SUPPORTED; + + if (pKeyName) + { + len = MultiByteToWideChar(CP_ACP, 0, pKeyName, -1, NULL, 0); + keynameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); + MultiByteToWideChar(CP_ACP, 0, pKeyName, -1, keynameW, len); + } + + if (pValueName) + { + len = MultiByteToWideChar(CP_ACP, 0, pValueName, -1, NULL, 0); + valuenameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); + MultiByteToWideChar(CP_ACP, 0, pValueName, -1, valuenameW, len); + } + + res = DeletePrinterDataExW( hPrinter, keynameW, valuenameW ); + + HeapFree(GetProcessHeap(), 0, keynameW); + HeapFree(GetProcessHeap(), 0, valuenameW); + + return res; } DWORD WINAPI @@ -58,9 +114,24 @@ DeletePrinterDataW(HANDLE hPrinter, PWSTR pValueName) DWORD WINAPI DeletePrinterKeyA(HANDLE hPrinter, PCSTR pKeyName) { + LPWSTR keynameW = NULL; + INT len; + DWORD res; + TRACE("DeletePrinterKeyA(%p, %s)\n", hPrinter, pKeyName); - UNIMPLEMENTED; - return ERROR_NOT_SUPPORTED; + + if (pKeyName) + { + len = MultiByteToWideChar(CP_ACP, 0, pKeyName, -1, NULL, 0); + keynameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); + MultiByteToWideChar(CP_ACP, 0, pKeyName, -1, keynameW, len); + } + + res = DeletePrinterKeyW( hPrinter, keynameW ); + + HeapFree(GetProcessHeap(), 0, keynameW); + + return res; } DWORD WINAPI @@ -82,9 +153,142 @@ EnumPrinterDataA(HANDLE hPrinter, DWORD dwIndex, PSTR pValueName, DWORD cbValueN DWORD WINAPI EnumPrinterDataExA(HANDLE hPrinter, PCSTR pKeyName, PBYTE pEnumValues, DWORD cbEnumValues, PDWORD pcbEnumValues, PDWORD pnEnumValues) { + INT len; + LPWSTR pKeyNameW; + DWORD ret, dwIndex, dwBufSize; + HANDLE hHeap; + LPSTR pBuffer; + TRACE("EnumPrinterDataExA(%p, %s, %p, %lu, %p, %p)\n", hPrinter, pKeyName, pEnumValues, cbEnumValues, pcbEnumValues, pnEnumValues); - UNIMPLEMENTED; - return ERROR_NOT_SUPPORTED; + + if (pKeyName == NULL || *pKeyName == 0) + return ERROR_INVALID_PARAMETER; + + len = MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, NULL, 0); + if (len == 0) + { + ret = GetLastError (); + ERR ("MultiByteToWideChar failed with code %i\n", ret); + return ret; + } + + hHeap = GetProcessHeap (); + if (hHeap == NULL) + { + ERR ("GetProcessHeap failed\n"); + return ERROR_OUTOFMEMORY; + } + + pKeyNameW = HeapAlloc (hHeap, 0, len * sizeof (WCHAR)); + if (pKeyNameW == NULL) + { + ERR ("Failed to allocate %i bytes from process heap\n", + (LONG)(len * sizeof (WCHAR))); + return ERROR_OUTOFMEMORY; + } + + if (MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, pKeyNameW, len) == 0) + { + ret = GetLastError (); + ERR ("MultiByteToWideChar failed with code %i\n", ret); + if (HeapFree (hHeap, 0, pKeyNameW) == 0) + WARN ("HeapFree failed with code %i\n", GetLastError ()); + return ret; + } + + ret = EnumPrinterDataExW (hPrinter, pKeyNameW, pEnumValues, cbEnumValues, pcbEnumValues, pnEnumValues); + + if (ret != ERROR_SUCCESS) + { + if (HeapFree (hHeap, 0, pKeyNameW) == 0) + WARN ("HeapFree failed with code %i\n", GetLastError ()); + TRACE ("EnumPrinterDataExW returned %i\n", ret); + return ret; + } + + if (HeapFree (hHeap, 0, pKeyNameW) == 0) + { + ret = GetLastError (); + ERR ("HeapFree failed with code %i\n", ret); + return ret; + } + + if (*pnEnumValues == 0) /* empty key */ + return ERROR_SUCCESS; + + dwBufSize = 0; + for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex) + { + PPRINTER_ENUM_VALUESW ppev = + &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex]; + + if (dwBufSize < ppev->cbValueName) + dwBufSize = ppev->cbValueName; + + if (dwBufSize < ppev->cbData && (ppev->dwType == REG_SZ || + ppev->dwType == REG_EXPAND_SZ || ppev->dwType == REG_MULTI_SZ)) + dwBufSize = ppev->cbData; + } + + TRACE ("Largest Unicode name or value is %i bytes\n", dwBufSize); + + pBuffer = HeapAlloc (hHeap, 0, dwBufSize); + if (pBuffer == NULL) + { + ERR ("Failed to allocate %i bytes from process heap\n", dwBufSize); + return ERROR_OUTOFMEMORY; + } + + for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex) + { + PPRINTER_ENUM_VALUESW ppev = + &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex]; + + len = WideCharToMultiByte (CP_ACP, 0, ppev->pValueName, + ppev->cbValueName / sizeof (WCHAR), pBuffer, dwBufSize, NULL, + NULL); + if (len == 0) + { + ret = GetLastError (); + ERR ("WideCharToMultiByte failed with code %i\n", ret); + if (HeapFree (hHeap, 0, pBuffer) == 0) + WARN ("HeapFree failed with code %i\n", GetLastError ()); + return ret; + } + + memcpy (ppev->pValueName, pBuffer, len); + + TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer); + + if (ppev->dwType != REG_SZ && ppev->dwType != REG_EXPAND_SZ && + ppev->dwType != REG_MULTI_SZ) + continue; + + len = WideCharToMultiByte (CP_ACP, 0, (LPWSTR) ppev->pData, + ppev->cbData / sizeof (WCHAR), pBuffer, dwBufSize, NULL, NULL); + if (len == 0) + { + ret = GetLastError (); + ERR ("WideCharToMultiByte failed with code %i\n", ret); + if (HeapFree (hHeap, 0, pBuffer) == 0) + WARN ("HeapFree failed with code %i\n", GetLastError ()); + return ret; + } + + memcpy (ppev->pData, pBuffer, len); + + TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer); + TRACE (" (only first string of REG_MULTI_SZ printed)\n"); + } + + if (HeapFree (hHeap, 0, pBuffer) == 0) + { + ret = GetLastError (); + ERR ("HeapFree failed with code %i\n", ret); + return ret; + } + + return ERROR_SUCCESS; } DWORD WINAPI diff --git a/win32ss/printing/base/winspool/printerdrivers.c b/win32ss/printing/base/winspool/printerdrivers.c index 07ba18c1311..a30b611820c 100644 --- a/win32ss/printing/base/winspool/printerdrivers.c +++ b/win32ss/printing/base/winspool/printerdrivers.c @@ -6,99 +6,994 @@ */ #include "precomp.h" +#include +extern const WCHAR wszCurrentEnvironment[]; + +static int multi_sz_lenA(const char *str) +{ + const char *ptr = str; + if(!str) return 0; + do + { + ptr += lstrlenA(ptr) + 1; + } while(*ptr); + + return ptr - str + 1; +} + +static int multi_sz_lenW(const WCHAR *str) +{ + const WCHAR *ptr = str; + if (!str) return 0; + do + { + ptr += lstrlenW(ptr) + 1; + } while (*ptr); + + return (ptr - str + 1); +} BOOL WINAPI AddPrinterDriverA(PSTR pName, DWORD Level, PBYTE pDriverInfo) { TRACE("AddPrinterDriverA(%s, %lu, %p)\n", pName, Level, pDriverInfo); - UNIMPLEMENTED; - return FALSE; + return AddPrinterDriverExA(pName, Level, pDriverInfo, APD_COPY_NEW_FILES); } BOOL WINAPI AddPrinterDriverExA(PSTR pName, DWORD Level, PBYTE pDriverInfo, DWORD dwFileCopyFlags) { - TRACE("AddPrinterDriverExA(%s, %lu, %p, %lu)\n", pName, Level, pDriverInfo, dwFileCopyFlags); - UNIMPLEMENTED; - return FALSE; + PDRIVER_INFO_8A pdiA; + DRIVER_INFO_8W diW; + LPWSTR nameW = NULL; + DWORD lenA; + DWORD len; + BOOL res = FALSE; + + TRACE("AddPrinterDriverExA(%s, %d, %p, 0x%x)\n", debugstr_a(pName), Level, pDriverInfo, dwFileCopyFlags); + + pdiA = (DRIVER_INFO_8A *) pDriverInfo; + ZeroMemory(&diW, sizeof(diW)); + + if (Level < 2 || Level == 5 || Level == 7 || Level > 8) + { + SetLastError(ERROR_INVALID_LEVEL); + return FALSE; + } + + if (pdiA == NULL) + { + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + + /* convert servername to unicode */ + if (pName) + { + len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0); + nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); + MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len); + } + + /* common fields */ + diW.cVersion = pdiA->cVersion; + + if (pdiA->pName) + { + len = MultiByteToWideChar(CP_ACP, 0, pdiA->pName, -1, NULL, 0); + diW.pName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); + MultiByteToWideChar(CP_ACP, 0, pdiA->pName, -1, diW.pName, len); + } + + if (pdiA->pEnvironment) + { + len = MultiByteToWideChar(CP_ACP, 0, pdiA->pEnvironment, -1, NULL, 0); + diW.pEnvironment = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); + MultiByteToWideChar(CP_ACP, 0, pdiA->pEnvironment, -1, diW.pEnvironment, len); + } + + if (pdiA->pDriverPath) + { + len = MultiByteToWideChar(CP_ACP, 0, pdiA->pDriverPath, -1, NULL, 0); + diW.pDriverPath = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); + MultiByteToWideChar(CP_ACP, 0, pdiA->pDriverPath, -1, diW.pDriverPath, len); + } + + if (pdiA->pDataFile) + { + len = MultiByteToWideChar(CP_ACP, 0, pdiA->pDataFile, -1, NULL, 0); + diW.pDataFile = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); + MultiByteToWideChar(CP_ACP, 0, pdiA->pDataFile, -1, diW.pDataFile, len); + } + + if (pdiA->pConfigFile) + { + len = MultiByteToWideChar(CP_ACP, 0, pdiA->pConfigFile, -1, NULL, 0); + diW.pConfigFile = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); + MultiByteToWideChar(CP_ACP, 0, pdiA->pConfigFile, -1, diW.pConfigFile, len); + } + + if ((Level > 2) && pdiA->pHelpFile) + { + len = MultiByteToWideChar(CP_ACP, 0, pdiA->pHelpFile, -1, NULL, 0); + diW.pHelpFile = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); + MultiByteToWideChar(CP_ACP, 0, pdiA->pHelpFile, -1, diW.pHelpFile, len); + } + + if ((Level > 2) && pdiA->pDependentFiles) + { + lenA = multi_sz_lenA(pdiA->pDependentFiles); + len = MultiByteToWideChar(CP_ACP, 0, pdiA->pDependentFiles, lenA, NULL, 0); + diW.pDependentFiles = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); + MultiByteToWideChar(CP_ACP, 0, pdiA->pDependentFiles, lenA, diW.pDependentFiles, len); + } + + if ((Level > 2) && pdiA->pMonitorName) + { + len = MultiByteToWideChar(CP_ACP, 0, pdiA->pMonitorName, -1, NULL, 0); + diW.pMonitorName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); + MultiByteToWideChar(CP_ACP, 0, pdiA->pMonitorName, -1, diW.pMonitorName, len); + } + + if ((Level > 2) && pdiA->pDefaultDataType) + { + len = MultiByteToWideChar(CP_ACP, 0, pdiA->pDefaultDataType, -1, NULL, 0); + diW.pDefaultDataType = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); + MultiByteToWideChar(CP_ACP, 0, pdiA->pDefaultDataType, -1, diW.pDefaultDataType, len); + } + + if ((Level > 3) && pdiA->pszzPreviousNames) + { + lenA = multi_sz_lenA(pdiA->pszzPreviousNames); + len = MultiByteToWideChar(CP_ACP, 0, pdiA->pszzPreviousNames, lenA, NULL, 0); + diW.pszzPreviousNames = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); + MultiByteToWideChar(CP_ACP, 0, pdiA->pszzPreviousNames, lenA, diW.pszzPreviousNames, len); + } + + if (Level > 5) + { + diW.ftDriverDate = pdiA->ftDriverDate; + diW.dwlDriverVersion = pdiA->dwlDriverVersion; + } + + if ((Level > 5) && pdiA->pszMfgName) + { + len = MultiByteToWideChar(CP_ACP, 0, pdiA->pszMfgName, -1, NULL, 0); + diW.pszMfgName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); + MultiByteToWideChar(CP_ACP, 0, pdiA->pszMfgName, -1, diW.pszMfgName, len); + } + + if ((Level > 5) && pdiA->pszOEMUrl) + { + len = MultiByteToWideChar(CP_ACP, 0, pdiA->pszOEMUrl, -1, NULL, 0); + diW.pszOEMUrl = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); + MultiByteToWideChar(CP_ACP, 0, pdiA->pszOEMUrl, -1, diW.pszOEMUrl, len); + } + + if ((Level > 5) && pdiA->pszHardwareID) + { + len = MultiByteToWideChar(CP_ACP, 0, pdiA->pszHardwareID, -1, NULL, 0); + diW.pszHardwareID = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); + MultiByteToWideChar(CP_ACP, 0, pdiA->pszHardwareID, -1, diW.pszHardwareID, len); + } + + if ((Level > 5) && pdiA->pszProvider) + { + len = MultiByteToWideChar(CP_ACP, 0, pdiA->pszProvider, -1, NULL, 0); + diW.pszProvider = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); + MultiByteToWideChar(CP_ACP, 0, pdiA->pszProvider, -1, diW.pszProvider, len); + } + + if ((Level > 7) && pdiA->pszPrintProcessor) + { + len = MultiByteToWideChar(CP_ACP, 0, pdiA->pszPrintProcessor, -1, NULL, 0); + diW.pszPrintProcessor = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); + MultiByteToWideChar(CP_ACP, 0, pdiA->pszPrintProcessor, -1, diW.pszPrintProcessor, len); + } + + if ((Level > 7) && pdiA->pszVendorSetup) + { + len = MultiByteToWideChar(CP_ACP, 0, pdiA->pszVendorSetup, -1, NULL, 0); + diW.pszVendorSetup = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); + MultiByteToWideChar(CP_ACP, 0, pdiA->pszVendorSetup, -1, diW.pszVendorSetup, len); + } + + if ((Level > 7) && pdiA->pszzColorProfiles) + { + lenA = multi_sz_lenA(pdiA->pszzColorProfiles); + len = MultiByteToWideChar(CP_ACP, 0, pdiA->pszzColorProfiles, lenA, NULL, 0); + diW.pszzColorProfiles = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); + MultiByteToWideChar(CP_ACP, 0, pdiA->pszzColorProfiles, lenA, diW.pszzColorProfiles, len); + } + + if ((Level > 7) && pdiA->pszInfPath) + { + len = MultiByteToWideChar(CP_ACP, 0, pdiA->pszInfPath, -1, NULL, 0); + diW.pszInfPath = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); + MultiByteToWideChar(CP_ACP, 0, pdiA->pszInfPath, -1, diW.pszInfPath, len); + } + + if ((Level > 7) && pdiA->pszzCoreDriverDependencies) + { + lenA = multi_sz_lenA(pdiA->pszzCoreDriverDependencies); + len = MultiByteToWideChar(CP_ACP, 0, pdiA->pszzCoreDriverDependencies, lenA, NULL, 0); + diW.pszzCoreDriverDependencies = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); + MultiByteToWideChar(CP_ACP, 0, pdiA->pszzCoreDriverDependencies, lenA, diW.pszzCoreDriverDependencies, len); + } + + if (Level > 7) + { + diW.dwPrinterDriverAttributes = pdiA->dwPrinterDriverAttributes; + diW.ftMinInboxDriverVerDate = pdiA->ftMinInboxDriverVerDate; + diW.dwlMinInboxDriverVerVersion = pdiA->dwlMinInboxDriverVerVersion; + } + + res = AddPrinterDriverExW(nameW, Level, (LPBYTE) &diW, dwFileCopyFlags); + + TRACE("got %u with %u\n", res, GetLastError()); + HeapFree(GetProcessHeap(), 0, nameW); + HeapFree(GetProcessHeap(), 0, diW.pName); + HeapFree(GetProcessHeap(), 0, diW.pEnvironment); + HeapFree(GetProcessHeap(), 0, diW.pDriverPath); + HeapFree(GetProcessHeap(), 0, diW.pDataFile); + HeapFree(GetProcessHeap(), 0, diW.pConfigFile); + HeapFree(GetProcessHeap(), 0, diW.pHelpFile); + HeapFree(GetProcessHeap(), 0, diW.pDependentFiles); + HeapFree(GetProcessHeap(), 0, diW.pMonitorName); + HeapFree(GetProcessHeap(), 0, diW.pDefaultDataType); + HeapFree(GetProcessHeap(), 0, diW.pszzPreviousNames); + HeapFree(GetProcessHeap(), 0, diW.pszMfgName); + HeapFree(GetProcessHeap(), 0, diW.pszOEMUrl); + HeapFree(GetProcessHeap(), 0, diW.pszHardwareID); + HeapFree(GetProcessHeap(), 0, diW.pszProvider); + HeapFree(GetProcessHeap(), 0, diW.pszPrintProcessor); + HeapFree(GetProcessHeap(), 0, diW.pszVendorSetup); + HeapFree(GetProcessHeap(), 0, diW.pszzColorProfiles); + HeapFree(GetProcessHeap(), 0, diW.pszInfPath); + HeapFree(GetProcessHeap(), 0, diW.pszzCoreDriverDependencies); + + TRACE("=> %u with %u\n", res, GetLastError()); + return res; } BOOL WINAPI AddPrinterDriverExW(PWSTR pName, DWORD Level, PBYTE pDriverInfo, DWORD dwFileCopyFlags) { + DWORD dwErrorCode; + WINSPOOL_DRIVER_INFO_8 * pdi = NULL; + WINSPOOL_DRIVER_CONTAINER pDriverContainer; + TRACE("AddPrinterDriverExW(%S, %lu, %p, %lu)\n", pName, Level, pDriverInfo, dwFileCopyFlags); - UNIMPLEMENTED; - return FALSE; + + pDriverContainer.Level = Level; + + switch (Level) + { + case 8: + { + PDRIVER_INFO_8W pdi8w = (PDRIVER_INFO_8W)pDriverInfo; + pdi = HeapAlloc(hProcessHeap, 0, sizeof(WINSPOOL_DRIVER_INFO_8)); + + pdi->pPrintProcessor = pdi8w->pszPrintProcessor; + pdi->pVendorSetup = pdi8w->pszVendorSetup; + + pdi->pszzColorProfiles = pdi8w->pszzColorProfiles; + pdi->cchColorProfiles = 0; + if ( pdi8w->pszzColorProfiles && *pdi8w->pszzColorProfiles ) + { + pdi->cchColorProfiles = multi_sz_lenW( pdi8w->pszzColorProfiles ); + } + + pdi->pInfPath = pdi8w->pszInfPath; + + pdi->pszzCoreDriverDependencies = pdi8w->pszzCoreDriverDependencies; + pdi->cchCoreDependencies = 0; + if ( pdi8w->pszzCoreDriverDependencies && *pdi8w->pszzCoreDriverDependencies ) + { + pdi->cchCoreDependencies = multi_sz_lenW( pdi8w->pszzCoreDriverDependencies ); + } + + pdi->ftMinInboxDriverVerDate = pdi8w->ftMinInboxDriverVerDate; + pdi->dwlMinInboxDriverVerVersion = pdi8w->dwlMinInboxDriverVerVersion; + } + case 6: + { + PDRIVER_INFO_6W pdi6w = (PDRIVER_INFO_6W)pDriverInfo; + if ( pdi == NULL ) pdi = HeapAlloc(hProcessHeap, 0, sizeof(WINSPOOL_DRIVER_INFO_6)); + + pdi->pMfgName = pdi6w->pszMfgName; + pdi->pOEMUrl = pdi6w->pszOEMUrl; + pdi->pHardwareID = pdi6w->pszHardwareID; + pdi->pProvider = pdi6w->pszProvider; + pdi->ftDriverDate = pdi6w->ftDriverDate; + pdi->dwlDriverVersion = pdi6w->dwlDriverVersion; + } + case 4: + { + + PDRIVER_INFO_4W pdi4w = (PDRIVER_INFO_4W)pDriverInfo; + if ( pdi == NULL ) pdi = HeapAlloc(hProcessHeap, 0, sizeof(WINSPOOL_DRIVER_INFO_4)); + + pdi->pszzPreviousNames = pdi4w->pszzPreviousNames; + pdi->cchPreviousNames = 0; + if ( pdi4w->pDependentFiles && *pdi4w->pDependentFiles ) + { + pdi->cchPreviousNames = multi_sz_lenW( pdi4w->pDependentFiles ); + } + } + case 3: + { + PDRIVER_INFO_3W pdi3w = (PDRIVER_INFO_3W)pDriverInfo; + if ( pdi == NULL ) pdi = HeapAlloc(hProcessHeap, 0, sizeof(WINSPOOL_DRIVER_INFO_3)); + + pdi->pHelpFile = pdi3w->pHelpFile; + pdi->pDependentFiles = pdi3w->pDependentFiles; + pdi->pMonitorName = pdi3w->pMonitorName; + pdi->pDefaultDataType = pdi3w->pDefaultDataType; + + pdi->pDependentFiles = pdi3w->pDependentFiles; + pdi->cchDependentFiles = 0; + if ( pdi3w->pDependentFiles && *pdi3w->pDependentFiles ) + { + pdi->cchDependentFiles = multi_sz_lenW( pdi3w->pDependentFiles ); + } + } + case 2: + { + PDRIVER_INFO_2W pdi2w = (PDRIVER_INFO_2W)pDriverInfo; + if ( pdi == NULL ) pdi = HeapAlloc(hProcessHeap, 0, sizeof(WINSPOOL_DRIVER_INFO_2)); + + pdi->pName = pdi2w->pName; + + pdi->pEnvironment = pdi2w->pEnvironment; + if ( !pdi2w->pEnvironment || !*pdi2w->pEnvironment ) + { + pdi2w->pEnvironment = (PWSTR)wszCurrentEnvironment; + } + + pdi->pDriverPath = pdi2w->pDriverPath; + pdi->pDataFile = pdi2w->pDataFile; + pdi->pConfigFile = pdi2w->pConfigFile; + } + break; + + default: + SetLastError(ERROR_INVALID_LEVEL); + return FALSE; + } + + pDriverContainer.DriverInfo.Level8 = pdi; + + RpcTryExcept + { + dwErrorCode = _RpcAddPrinterDriverEx( pName, &pDriverContainer, dwFileCopyFlags ); + } + RpcExcept(EXCEPTION_EXECUTE_HANDLER) + { + dwErrorCode = RpcExceptionCode(); + ERR("_RpcAddPrinterDriverEx failed with exception code %lu!\n", dwErrorCode); + } + RpcEndExcept; + + if ( pdi ) HeapFree( GetProcessHeap(), 0, pdi ); + + SetLastError(dwErrorCode); + return (dwErrorCode == ERROR_SUCCESS); } BOOL WINAPI AddPrinterDriverW(PWSTR pName, DWORD Level, PBYTE pDriverInfo) { TRACE("AddPrinterDriverW(%S, %lu, %p)\n", pName, Level, pDriverInfo); - UNIMPLEMENTED; - return FALSE; + return AddPrinterDriverExW(pName, Level, pDriverInfo, APD_COPY_NEW_FILES); } BOOL WINAPI DeletePrinterDriverA(PSTR pName, PSTR pEnvironment, PSTR pDriverName) { TRACE("DeletePrinterDriverA(%s, %s, %s)\n", pName, pEnvironment, pDriverName); - UNIMPLEMENTED; - return FALSE; + return DeletePrinterDriverExA(pName, pEnvironment, pDriverName, 0, 0); } BOOL WINAPI DeletePrinterDriverExA(PSTR pName, PSTR pEnvironment, PSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag) { + UNICODE_STRING NameW, EnvW, DriverW; + BOOL ret; + TRACE("DeletePrinterDriverExA(%s, %s, %s, %lu, %lu)\n", pName, pEnvironment, pDriverName, dwDeleteFlag, dwVersionFlag); - UNIMPLEMENTED; - return FALSE; + + AsciiToUnicode(&NameW, pName); + AsciiToUnicode(&EnvW, pEnvironment); + AsciiToUnicode(&DriverW, pDriverName); + + ret = DeletePrinterDriverExW(NameW.Buffer, EnvW.Buffer, DriverW.Buffer, dwDeleteFlag, dwVersionFlag); + + RtlFreeUnicodeString(&DriverW); + RtlFreeUnicodeString(&EnvW); + RtlFreeUnicodeString(&NameW); + + return ret; } BOOL WINAPI DeletePrinterDriverExW(PWSTR pName, PWSTR pEnvironment, PWSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag) { + DWORD dwErrorCode; + TRACE("DeletePrinterDriverExW(%S, %S, %S, %lu, %lu)\n", pName, pEnvironment, pDriverName, dwDeleteFlag, dwVersionFlag); - UNIMPLEMENTED; - return FALSE; + + if ( !pDriverName || !*pDriverName ) + { + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + + if ( !pEnvironment || !*pEnvironment ) + { + pEnvironment = (PWSTR)wszCurrentEnvironment; + } + + // Do the RPC call. + RpcTryExcept + { + dwErrorCode = _RpcDeletePrinterDriverEx(pName, pEnvironment, pDriverName, dwDeleteFlag, dwVersionFlag); + } + RpcExcept(EXCEPTION_EXECUTE_HANDLER) + { + dwErrorCode = RpcExceptionCode(); + ERR("_RpcDeletePrinterDriverEx failed with exception code %lu!\n", dwErrorCode); + } + RpcEndExcept; + + SetLastError(dwErrorCode); + return (dwErrorCode == ERROR_SUCCESS); + } BOOL WINAPI DeletePrinterDriverW(PWSTR pName, PWSTR pEnvironment, PWSTR pDriverName) { TRACE("DeletePrinterDriverW(%S, %S, %S)\n", pName, pEnvironment, pDriverName); - UNIMPLEMENTED; - return FALSE; + return DeletePrinterDriverExW(pName, pEnvironment, pDriverName, 0, 0); } BOOL WINAPI EnumPrinterDriversA(PSTR pName, PSTR pEnvironment, DWORD Level, PBYTE pDriverInfo, DWORD cbBuf, PDWORD pcbNeeded, PDWORD pcReturned) { + BOOL ret; + DWORD dwErrorCode, i; + UNICODE_STRING pNameW, pEnvironmentW; + PWSTR pwstrNameW, pwstrEnvironmentW; + PDRIVER_INFO_1W pdi1w = (PDRIVER_INFO_1W)pDriverInfo; + PDRIVER_INFO_8W pdi8w = (PDRIVER_INFO_8W)pDriverInfo; + TRACE("EnumPrinterDriversA(%s, %s, %lu, %p, %lu, %p, %p)\n", pName, pEnvironment, Level, pDriverInfo, cbBuf, pcbNeeded, pcReturned); - UNIMPLEMENTED; - return FALSE; + + pwstrNameW = AsciiToUnicode(&pNameW, pName); + pwstrEnvironmentW = AsciiToUnicode(&pEnvironmentW, pEnvironment); + + ret = EnumPrinterDriversW( pwstrNameW, pwstrEnvironmentW, Level, pDriverInfo, cbBuf, pcbNeeded, pcReturned ); + + if (ret) + { + for ( i = 0; i < *pcReturned; i++ ) + { + switch (Level) + { + case 1: + { + dwErrorCode = UnicodeToAnsiInPlace(pdi1w[i].pName); + if (dwErrorCode != ERROR_SUCCESS) + { + goto Cleanup; + } + break; + } + case 8: + { + dwErrorCode = UnicodeToAnsiInPlace(pdi8w[i].pszPrintProcessor); + if (dwErrorCode != ERROR_SUCCESS) + { + goto Cleanup; + } + dwErrorCode = UnicodeToAnsiInPlace(pdi8w[i].pszVendorSetup); + if (dwErrorCode != ERROR_SUCCESS) + { + goto Cleanup; + } + dwErrorCode = UnicodeToAnsiZZInPlace(pdi8w[i].pszzColorProfiles); + if (dwErrorCode != ERROR_SUCCESS) + { + goto Cleanup; + } + dwErrorCode = UnicodeToAnsiInPlace(pdi8w[i].pszInfPath); + if (dwErrorCode != ERROR_SUCCESS) + { + goto Cleanup; + } + dwErrorCode = UnicodeToAnsiZZInPlace(pdi8w[i].pszzCoreDriverDependencies); + if (dwErrorCode != ERROR_SUCCESS) + { + goto Cleanup; + } + } + case 6: + { + dwErrorCode = UnicodeToAnsiInPlace(pdi8w[i].pszMfgName); + if (dwErrorCode != ERROR_SUCCESS) + { + goto Cleanup; + } + + dwErrorCode = UnicodeToAnsiInPlace(pdi8w[i].pszOEMUrl); + if (dwErrorCode != ERROR_SUCCESS) + { + goto Cleanup; + } + + dwErrorCode = UnicodeToAnsiInPlace(pdi8w[i].pszHardwareID); + if (dwErrorCode != ERROR_SUCCESS) + { + goto Cleanup; + } + + dwErrorCode = UnicodeToAnsiInPlace(pdi8w[i].pszProvider); + if (dwErrorCode != ERROR_SUCCESS) + { + goto Cleanup; + } + } + case 4: + { + dwErrorCode = UnicodeToAnsiZZInPlace(pdi8w[i].pszzPreviousNames); + if (dwErrorCode != ERROR_SUCCESS) + { + goto Cleanup; + } + } + case 3: + { + dwErrorCode = UnicodeToAnsiInPlace(pdi8w[i].pHelpFile); + if (dwErrorCode != ERROR_SUCCESS) + { + goto Cleanup; + } + + dwErrorCode = UnicodeToAnsiZZInPlace(pdi8w[i].pDependentFiles); + if (dwErrorCode != ERROR_SUCCESS) + { + goto Cleanup; + } + + dwErrorCode = UnicodeToAnsiInPlace(pdi8w[i].pMonitorName); + if (dwErrorCode != ERROR_SUCCESS) + { + goto Cleanup; + } + + dwErrorCode = UnicodeToAnsiInPlace(pdi8w[i].pDefaultDataType); + if (dwErrorCode != ERROR_SUCCESS) + { + goto Cleanup; + } + } + case 2: + case 5: + { + dwErrorCode = UnicodeToAnsiInPlace(pdi8w[i].pName); + if (dwErrorCode != ERROR_SUCCESS) + { + goto Cleanup; + } + + dwErrorCode = UnicodeToAnsiInPlace(pdi8w[i].pEnvironment); + if (dwErrorCode != ERROR_SUCCESS) + { + goto Cleanup; + } + + dwErrorCode = UnicodeToAnsiInPlace(pdi8w[i].pDriverPath); + if (dwErrorCode != ERROR_SUCCESS) + { + goto Cleanup; + } + + dwErrorCode = UnicodeToAnsiInPlace(pdi8w[i].pDataFile); + if (dwErrorCode != ERROR_SUCCESS) + { + goto Cleanup; + } + + dwErrorCode = UnicodeToAnsiInPlace(pdi8w[i].pConfigFile); + if (dwErrorCode != ERROR_SUCCESS) + { + goto Cleanup; + } + } + } + } + } +Cleanup: + RtlFreeUnicodeString(&pNameW); + RtlFreeUnicodeString(&pEnvironmentW); + + return ret; } BOOL WINAPI EnumPrinterDriversW(PWSTR pName, PWSTR pEnvironment, DWORD Level, PBYTE pDriverInfo, DWORD cbBuf, PDWORD pcbNeeded, PDWORD pcReturned) { + DWORD dwErrorCode; + TRACE("EnumPrinterDriversW(%S, %S, %lu, %p, %lu, %p, %p)\n", pName, pEnvironment, Level, pDriverInfo, cbBuf, pcbNeeded, pcReturned); - UNIMPLEMENTED; - return FALSE; + + // Dismiss invalid levels already at this point. + if (Level > 8 || Level == 7 || Level < 1) + { + dwErrorCode = ERROR_INVALID_LEVEL; + goto Cleanup; + } + + if ( !pEnvironment || !*pEnvironment ) + { + pEnvironment = (PWSTR)wszCurrentEnvironment; + } + + if (cbBuf && pDriverInfo) + ZeroMemory(pDriverInfo, cbBuf); + + // Do the RPC call + RpcTryExcept + { + dwErrorCode = _RpcEnumPrinterDrivers( pName, pEnvironment, Level, pDriverInfo, cbBuf, pcbNeeded, pcReturned ); + } + RpcExcept(EXCEPTION_EXECUTE_HANDLER) + { + dwErrorCode = RpcExceptionCode(); + ERR("_RpcEnumPrinterDrivers failed with exception code %lu!\n", dwErrorCode); + } + RpcEndExcept; + + if (dwErrorCode == ERROR_SUCCESS) + { + // Replace relative offset addresses in the output by absolute pointers. + ASSERT(Level <= 6 || Level == 8); + MarshallUpStructuresArray(cbBuf, pDriverInfo, *pcReturned, pPrinterDriverMarshalling[Level]->pInfo, pPrinterDriverMarshalling[Level]->cbStructureSize, TRUE); + } + +Cleanup: + SetLastError(dwErrorCode); + return (dwErrorCode == ERROR_SUCCESS); + +} + +BOOL WINAPI +GetPrinterDriverA(HANDLE hPrinter, LPSTR pEnvironment, DWORD Level, LPBYTE pDriverInfo, DWORD cbBuf, LPDWORD pcbNeeded) +{ + DWORD dwErrorCode; + /* + * We are mapping multiple different pointers to the same pDriverInfo pointer here so that + * we can use the same incoming pointer for different Levels + */ + PDRIVER_INFO_1W pdi1w = (PDRIVER_INFO_1W)pDriverInfo; + PDRIVER_INFO_8W pdi8w = (PDRIVER_INFO_8W)pDriverInfo; + + DWORD cch; + PWSTR pwszEnvironment = NULL; + + TRACE("GetPrinterDriverA(%p, %s, %lu, %p, %lu, %p)\n", hPrinter, pEnvironment, Level, pDriverInfo, cbBuf, pcbNeeded); + + // Check for invalid levels here for early error return. Should be 1-6 & 8. + if (Level < 1 || Level == 7 || Level > 8) + { + dwErrorCode = ERROR_INVALID_LEVEL; + ERR("Invalid Level!\n"); + goto Cleanup; + } + + if (pEnvironment) + { + // Convert pEnvironment to a Unicode string pwszEnvironment. + cch = strlen(pEnvironment); + + pwszEnvironment = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(WCHAR)); + if (!pwszEnvironment) + { + dwErrorCode = ERROR_NOT_ENOUGH_MEMORY; + ERR("HeapAlloc failed!\n"); + goto Cleanup; + } + + MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, pwszEnvironment, cch + 1); + } + + if (!GetPrinterDriverW(hPrinter, pwszEnvironment, Level, pDriverInfo, cbBuf, pcbNeeded)) + { + dwErrorCode = GetLastError(); + goto Cleanup; + } + + // Do Unicode to ANSI conversions for strings based on Level + switch (Level) + { + case 1: + { + dwErrorCode = UnicodeToAnsiInPlace(pdi1w->pName); + if (dwErrorCode != ERROR_SUCCESS) + { + goto Cleanup; + } + break; + } + case 8: + { + dwErrorCode = UnicodeToAnsiInPlace(pdi8w->pszPrintProcessor); + if (dwErrorCode != ERROR_SUCCESS) + { + goto Cleanup; + } + dwErrorCode = UnicodeToAnsiInPlace(pdi8w->pszVendorSetup); + if (dwErrorCode != ERROR_SUCCESS) + { + goto Cleanup; + } + dwErrorCode = UnicodeToAnsiZZInPlace(pdi8w->pszzColorProfiles); + if (dwErrorCode != ERROR_SUCCESS) + { + goto Cleanup; + } + dwErrorCode = UnicodeToAnsiInPlace(pdi8w->pszInfPath); + if (dwErrorCode != ERROR_SUCCESS) + { + goto Cleanup; + } + dwErrorCode = UnicodeToAnsiZZInPlace(pdi8w->pszzCoreDriverDependencies); + if (dwErrorCode != ERROR_SUCCESS) + { + goto Cleanup; + } + } + case 6: + { + dwErrorCode = UnicodeToAnsiInPlace(pdi8w->pszMfgName); + if (dwErrorCode != ERROR_SUCCESS) + { + goto Cleanup; + } + + dwErrorCode = UnicodeToAnsiInPlace(pdi8w->pszOEMUrl); + if (dwErrorCode != ERROR_SUCCESS) + { + goto Cleanup; + } + + dwErrorCode = UnicodeToAnsiInPlace(pdi8w->pszHardwareID); + if (dwErrorCode != ERROR_SUCCESS) + { + goto Cleanup; + } + + dwErrorCode = UnicodeToAnsiInPlace(pdi8w->pszProvider); + if (dwErrorCode != ERROR_SUCCESS) + { + goto Cleanup; + } + } + case 4: + { + dwErrorCode = UnicodeToAnsiZZInPlace(pdi8w->pszzPreviousNames); + if (dwErrorCode != ERROR_SUCCESS) + { + goto Cleanup; + } + } + case 3: + { + dwErrorCode = UnicodeToAnsiInPlace(pdi8w->pHelpFile); + if (dwErrorCode != ERROR_SUCCESS) + { + goto Cleanup; + } + + dwErrorCode = UnicodeToAnsiZZInPlace(pdi8w->pDependentFiles); + if (dwErrorCode != ERROR_SUCCESS) + { + goto Cleanup; + } + + dwErrorCode = UnicodeToAnsiInPlace(pdi8w->pMonitorName); + if (dwErrorCode != ERROR_SUCCESS) + { + goto Cleanup; + } + + dwErrorCode = UnicodeToAnsiInPlace(pdi8w->pDefaultDataType); + if (dwErrorCode != ERROR_SUCCESS) + { + goto Cleanup; + } + } + case 2: + case 5: + { + dwErrorCode = UnicodeToAnsiInPlace(pdi8w->pName); + if (dwErrorCode != ERROR_SUCCESS) + { + goto Cleanup; + } + + dwErrorCode = UnicodeToAnsiInPlace(pdi8w->pEnvironment); + if (dwErrorCode != ERROR_SUCCESS) + { + goto Cleanup; + } + + dwErrorCode = UnicodeToAnsiInPlace(pdi8w->pDriverPath); + if (dwErrorCode != ERROR_SUCCESS) + { + goto Cleanup; + } + + dwErrorCode = UnicodeToAnsiInPlace(pdi8w->pDataFile); + if (dwErrorCode != ERROR_SUCCESS) + { + goto Cleanup; + } + + dwErrorCode = UnicodeToAnsiInPlace(pdi8w->pConfigFile); + if (dwErrorCode != ERROR_SUCCESS) + { + goto Cleanup; + } + } + } + + dwErrorCode = ERROR_SUCCESS; + +Cleanup: + if (pwszEnvironment) + { + HeapFree(hProcessHeap, 0, pwszEnvironment); + } + + SetLastError(dwErrorCode); + return (dwErrorCode == ERROR_SUCCESS); +} + +BOOL WINAPI +GetPrinterDriverW(HANDLE hPrinter, LPWSTR pEnvironment, DWORD Level, LPBYTE pDriverInfo, DWORD cbBuf, LPDWORD pcbNeeded) +{ + DWORD dwErrorCode; + PSPOOLER_HANDLE pHandle = (PSPOOLER_HANDLE)hPrinter; + + TRACE("GetPrinterDriverW(%p, %S, %lu, %p, %lu, %p)\n", hPrinter, pEnvironment, Level, pDriverInfo, cbBuf, pcbNeeded); + + // Sanity checks. + if (!pHandle) + { + dwErrorCode = ERROR_INVALID_HANDLE; + goto Cleanup; + } + + // Dismiss invalid levels already at this point. + if (Level > 8 || Level == 7 || Level < 1) + { + dwErrorCode = ERROR_INVALID_LEVEL; + goto Cleanup; + } + + if ( !pEnvironment || !*pEnvironment ) + { + pEnvironment = (PWSTR)wszCurrentEnvironment; + } + + if (cbBuf && pDriverInfo) + ZeroMemory(pDriverInfo, cbBuf); + + // Do the RPC call + RpcTryExcept + { + dwErrorCode = _RpcGetPrinterDriver(pHandle->hPrinter, pEnvironment, Level, pDriverInfo, cbBuf, pcbNeeded); + } + RpcExcept(EXCEPTION_EXECUTE_HANDLER) + { + dwErrorCode = RpcExceptionCode(); + ERR("_RpcGetPrinterDriver failed with exception code %lu!\n", dwErrorCode); + } + RpcEndExcept; + + if (dwErrorCode == ERROR_SUCCESS) + { + // Replace relative offset addresses in the output by absolute pointers. + ASSERT(Level <= 6 || Level == 8); + MarshallUpStructure(cbBuf, pDriverInfo, pPrinterDriverMarshalling[Level]->pInfo, pPrinterDriverMarshalling[Level]->cbStructureSize, TRUE); + } + +Cleanup: + SetLastError(dwErrorCode); + return (dwErrorCode == ERROR_SUCCESS); } BOOL WINAPI GetPrinterDriverDirectoryA(PSTR pName, PSTR pEnvironment, DWORD Level, PBYTE pDriverDirectory, DWORD cbBuf, PDWORD pcbNeeded) { - TRACE("GetPrinterDriverDirectoryA(%s, %s, %lu, %p, %lu, %p)\n", pName, pEnvironment, Level, pDriverDirectory, cbBuf, pcbNeeded); - UNIMPLEMENTED; - return FALSE; + UNICODE_STRING nameW, environmentW; + BOOL ret; + DWORD pcbNeededW; + INT len = cbBuf * sizeof(WCHAR)/sizeof(CHAR); + WCHAR *driverDirectoryW = NULL; + + TRACE("GetPrinterDriverDirectoryA(%s, %s, %d, %p, %d, %p)\n", debugstr_a(pName), debugstr_a(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded); + + if (len) driverDirectoryW = HeapAlloc( GetProcessHeap(), 0, len ); + + if (pName) + { + RtlCreateUnicodeStringFromAsciiz(&nameW, pName); + } + else + { + nameW.Buffer = NULL; + } + if (pEnvironment) + { + RtlCreateUnicodeStringFromAsciiz(&environmentW, pEnvironment); + } + else + { + environmentW.Buffer = NULL; + } + + ret = GetPrinterDriverDirectoryW( nameW.Buffer, environmentW.Buffer, Level, (LPBYTE)driverDirectoryW, len, &pcbNeededW ); + + if (ret) + { + DWORD needed = WideCharToMultiByte( CP_ACP, 0, driverDirectoryW, -1, (LPSTR)pDriverDirectory, cbBuf, NULL, NULL); + + if ( pcbNeeded ) + *pcbNeeded = needed; + + ret = needed <= cbBuf; + } + else + { + if (pcbNeeded) *pcbNeeded = pcbNeededW * sizeof(CHAR)/sizeof(WCHAR); + } + + TRACE("required: 0x%x/%d\n", pcbNeeded ? *pcbNeeded : 0, pcbNeeded ? *pcbNeeded : 0); + + HeapFree( GetProcessHeap(), 0, driverDirectoryW ); + RtlFreeUnicodeString(&environmentW); + RtlFreeUnicodeString(&nameW); + + return ret; } BOOL WINAPI GetPrinterDriverDirectoryW(PWSTR pName, PWSTR pEnvironment, DWORD Level, PBYTE pDriverDirectory, DWORD cbBuf, PDWORD pcbNeeded) { + DWORD dwErrorCode; + TRACE("GetPrinterDriverDirectoryW(%S, %S, %lu, %p, %lu, %p)\n", pName, pEnvironment, Level, pDriverDirectory, cbBuf, pcbNeeded); - UNIMPLEMENTED; - return FALSE; + + if ( !pEnvironment || !*pEnvironment ) + { + pEnvironment = (PWSTR)wszCurrentEnvironment; + } + + // Do the RPC call. + RpcTryExcept + { + dwErrorCode = _RpcGetPrinterDriverDirectory(pName, pEnvironment, Level, pDriverDirectory, cbBuf, pcbNeeded); + } + RpcExcept(EXCEPTION_EXECUTE_HANDLER) + { + dwErrorCode = RpcExceptionCode(); + ERR("_RpcGetPrinterDriverDirectory failed with exception code %lu!\n", dwErrorCode); + } + RpcEndExcept; + + SetLastError(dwErrorCode); + return (dwErrorCode == ERROR_SUCCESS); } diff --git a/win32ss/printing/base/winspool/printers.c b/win32ss/printing/base/winspool/printers.c index 249d41256bd..12c299ade01 100644 --- a/win32ss/printing/base/winspool/printers.c +++ b/win32ss/printing/base/winspool/printers.c @@ -7,9 +7,53 @@ #include "precomp.h" #include -#include +//#include #include +extern HINSTANCE hinstWinSpool; +// +// See winddiui.h, ReactOS version is limited. +// Loading from XyzUI.dll part of XyzDRV.dll set. example TTYUI.DLL or UniDrvUI.DLL. +// +typedef DWORD (WINAPI *DEVICECAPABILITIES) (HANDLE,PWSTR,WORD,PVOID,PDEVMODEW); +static DEVICECAPABILITIES fpDeviceCapabilities; + +typedef LONG (WINAPI *DEVICEPROPERTYSHEETS) (PPROPSHEETUI_INFO,LPARAM); +static DEVICEPROPERTYSHEETS fpDevicePropertySheets; +typedef LONG (WINAPI *DOCUMENTPROPERTYSHEETS) (PPROPSHEETUI_INFO,LPARAM); +static DOCUMENTPROPERTYSHEETS fpDocumentPropertySheets; + +typedef LONG (WINAPI *COMMONPROPERTYSHEETUIW) (HWND,PFNPROPSHEETUI,LPARAM,LPDWORD); +static COMMONPROPERTYSHEETUIW fpCommonPropertySheetUIW; + +typedef LONG (WINAPI *QUERYCOLORPROFILE) (HANDLE,PDEVMODEW,ULONG,PVOID,ULONG*,FLONG*); +static QUERYCOLORPROFILE fpQueryColorProfile; + +typedef BOOL (WINAPI *SPOOLERPRINTEREVENT) (LPWSTR,int,DWORD,LPARAM); +static SPOOLERPRINTEREVENT fpPrinterEvent; + +typedef BOOL (WINAPI *DEVQUERYPRINT) (HANDLE,LPDEVMODEW,DWORD*); +static DEVQUERYPRINT fpDevQueryPrint; + +typedef BOOL (WINAPI *DEVQUERYPRINTEX) (PDEVQUERYPRINT_INFO); +static DEVQUERYPRINTEX fpDevQueryPrintEx; + +// +// PrintUI.dll +// +LONG WINAPI ConstructPrinterFriendlyName( PWSTR, PVOID, LPDWORD Size ); +typedef LONG (WINAPI *CONSTRUCTPRINTERFRIENDLYNAME) (PWSTR,PVOID,LPDWORD); +static CONSTRUCTPRINTERFRIENDLYNAME fpConstructPrinterFriendlyName; + +// +// CompstUI User Data +// +typedef struct _COMPUI_USERDATA +{ + HMODULE hModule; + LPWSTR pszPrinterName; +} COMPUI_USERDATA, *PCOMPUI_USERDATA; + // Local Constants /** And the award for the most confusingly named setting goes to "Device", for storing the default printer of the current user. @@ -110,25 +154,257 @@ _StartDocPrinterWithRPC(PSPOOLER_HANDLE pHandle, PDOC_INFO_1W pDocInfo1) BOOL WINAPI AbortPrinter(HANDLE hPrinter) { + DWORD dwErrorCode; + PSPOOLER_HANDLE pHandle = (PSPOOLER_HANDLE)hPrinter; + TRACE("AbortPrinter(%p)\n", hPrinter); - UNIMPLEMENTED; - return FALSE; + + // Sanity checks. + if (!pHandle) + { + dwErrorCode = ERROR_INVALID_HANDLE; + goto Cleanup; + } + + pHandle->bTrayIcon = pHandle->bStartedDoc = FALSE; + + if ( pHandle->hSPLFile != INVALID_HANDLE_VALUE && pHandle->bJob ) + { + // Close any open file handle. + CloseHandle( pHandle->hSPLFile ); + pHandle->hSPLFile = INVALID_HANDLE_VALUE; + + SetJobW( hPrinter, pHandle->dwJobID, 0, NULL, JOB_CONTROL_DELETE ); + + return ScheduleJob( hPrinter, pHandle->dwJobID ); + } + + // Do the RPC call. + RpcTryExcept + { + dwErrorCode = _RpcAbortPrinter(&pHandle->hPrinter); + } + RpcExcept(EXCEPTION_EXECUTE_HANDLER) + { + dwErrorCode = RpcExceptionCode(); + ERR("_RpcAbortPrinter failed with exception code %lu!\n", dwErrorCode); + } + RpcEndExcept; + +Cleanup: + SetLastError(dwErrorCode); + return (dwErrorCode == ERROR_SUCCESS); } HANDLE WINAPI AddPrinterA(PSTR pName, DWORD Level, PBYTE pPrinter) { - TRACE("AddPrinterA(%s, %lu, %p)\n", pName, Level, pPrinter); - UNIMPLEMENTED; - return NULL; + UNICODE_STRING pNameW, usBuffer; + PWSTR pwstrNameW; + PRINTER_INFO_2W *ppi2w = (PRINTER_INFO_2W*)pPrinter; + PRINTER_INFO_2A *ppi2a = (PRINTER_INFO_2A*)pPrinter; + HANDLE ret = NULL; + PWSTR pwszPrinterName = NULL; + PWSTR pwszServerName = NULL; + PWSTR pwszShareName = NULL; + PWSTR pwszPortName = NULL; + PWSTR pwszDriverName = NULL; + PWSTR pwszComment = NULL; + PWSTR pwszLocation = NULL; + PWSTR pwszSepFile = NULL; + PWSTR pwszPrintProcessor = NULL; + PWSTR pwszDatatype = NULL; + PWSTR pwszParameters = NULL; + PDEVMODEW pdmw = NULL; + + TRACE("AddPrinterA(%s, %d, %p)\n", debugstr_a(pName), Level, pPrinter); + + if(Level != 2) + { + ERR("Level = %d, unsupported!\n", Level); + SetLastError(ERROR_INVALID_LEVEL); + return NULL; + } + + pwstrNameW = AsciiToUnicode(&pNameW,pName); + + if (ppi2a->pShareName) + { + pwszShareName = AsciiToUnicode(&usBuffer, ppi2a->pShareName); + if (!(ppi2w->pShareName = pwszShareName)) goto Cleanup; + } + if (ppi2a->pPortName) + { + pwszPortName = AsciiToUnicode(&usBuffer, ppi2a->pPortName); + if (!(ppi2w->pPortName = pwszPortName)) goto Cleanup; + } + if (ppi2a->pDriverName) + { + pwszDriverName = AsciiToUnicode(&usBuffer, ppi2a->pDriverName); + if (!(ppi2w->pDriverName = pwszDriverName)) goto Cleanup; + } + if (ppi2a->pComment) + { + pwszComment = AsciiToUnicode(&usBuffer, ppi2a->pComment); + if (!(ppi2w->pComment = pwszComment)) goto Cleanup; + } + if (ppi2a->pLocation) + { + pwszLocation = AsciiToUnicode(&usBuffer, ppi2a->pLocation); + if (!(ppi2w->pLocation = pwszLocation)) goto Cleanup; + } + if (ppi2a->pSepFile) + { + pwszSepFile = AsciiToUnicode(&usBuffer, ppi2a->pSepFile); + if (!(ppi2w->pSepFile = pwszSepFile)) goto Cleanup; + } + if (ppi2a->pServerName) + { + pwszPrintProcessor = AsciiToUnicode(&usBuffer, ppi2a->pPrintProcessor); + if (!(ppi2w->pPrintProcessor = pwszPrintProcessor)) goto Cleanup; + } + if (ppi2a->pDatatype) + { + pwszDatatype = AsciiToUnicode(&usBuffer, ppi2a->pDatatype); + if (!(ppi2w->pDatatype = pwszDatatype)) goto Cleanup; + } + if (ppi2a->pParameters) + { + pwszParameters = AsciiToUnicode(&usBuffer, ppi2a->pParameters); + if (!(ppi2w->pParameters = pwszParameters)) goto Cleanup; + } + if ( ppi2a->pDevMode ) + { + RosConvertAnsiDevModeToUnicodeDevmode( ppi2a->pDevMode, &pdmw ); + ppi2w->pDevMode = pdmw; + } + if (ppi2a->pServerName) + { + pwszServerName = AsciiToUnicode(&usBuffer, ppi2a->pServerName); + if (!(ppi2w->pPrinterName = pwszServerName)) goto Cleanup; + } + if (ppi2a->pPrinterName) + { + pwszPrinterName = AsciiToUnicode(&usBuffer, ppi2a->pPrinterName); + if (!(ppi2w->pPrinterName = pwszPrinterName)) goto Cleanup; + } + + ret = AddPrinterW(pwstrNameW, Level, (LPBYTE)ppi2w); + +Cleanup: + if (pdmw) HeapFree(hProcessHeap, 0, pdmw); + if (pwszPrinterName) HeapFree(hProcessHeap, 0, pwszPrinterName); + if (pwszServerName) HeapFree(hProcessHeap, 0, pwszServerName); + if (pwszShareName) HeapFree(hProcessHeap, 0, pwszShareName); + if (pwszPortName) HeapFree(hProcessHeap, 0, pwszPortName); + if (pwszDriverName) HeapFree(hProcessHeap, 0, pwszDriverName); + if (pwszComment) HeapFree(hProcessHeap, 0, pwszComment); + if (pwszLocation) HeapFree(hProcessHeap, 0, pwszLocation); + if (pwszSepFile) HeapFree(hProcessHeap, 0, pwszSepFile); + if (pwszPrintProcessor) HeapFree(hProcessHeap, 0, pwszPrintProcessor); + if (pwszDatatype) HeapFree(hProcessHeap, 0, pwszDatatype); + if (pwszParameters) HeapFree(hProcessHeap, 0, pwszParameters); + + RtlFreeUnicodeString(&pNameW); + return ret; } HANDLE WINAPI AddPrinterW(PWSTR pName, DWORD Level, PBYTE pPrinter) { + DWORD dwErrorCode; + WINSPOOL_PRINTER_CONTAINER PrinterContainer; + WINSPOOL_DEVMODE_CONTAINER DevModeContainer; + WINSPOOL_SECURITY_CONTAINER SecurityContainer; + SECURITY_DESCRIPTOR *sd = NULL; + DWORD size; + HANDLE hPrinter = NULL, hHandle = NULL; + PSPOOLER_HANDLE pHandle = NULL; + TRACE("AddPrinterW(%S, %lu, %p)\n", pName, Level, pPrinter); - UNIMPLEMENTED; - return NULL; + + DevModeContainer.cbBuf = 0; + DevModeContainer.pDevMode = NULL; + + SecurityContainer.cbBuf = 0; + SecurityContainer.pSecurity = NULL; + + if ( Level != 2 ) + { + FIXME( "Unsupported level %d\n", Level ); + SetLastError( ERROR_INVALID_LEVEL ); + return hHandle; + } + else + { + PPRINTER_INFO_2W pi2w = (PPRINTER_INFO_2W)pPrinter; + if ( pi2w ) + { + if ( pi2w->pDevMode ) + { + if ( IsValidDevmodeNoSizeW( pi2w->pDevMode ) ) + { + DevModeContainer.cbBuf = pi2w->pDevMode->dmSize + pi2w->pDevMode->dmDriverExtra; + DevModeContainer.pDevMode = (PBYTE)pi2w->pDevMode; + } + } + + if ( pi2w->pSecurityDescriptor ) + { + sd = get_sd( pi2w->pSecurityDescriptor, &size ); + if ( sd ) + { + SecurityContainer.cbBuf = size; + SecurityContainer.pSecurity = (PBYTE)sd; + } + } + } + else + { + SetLastError(ERROR_INVALID_PARAMETER); + return hHandle; + } + } + + PrinterContainer.PrinterInfo.pPrinterInfo1 = (WINSPOOL_PRINTER_INFO_1*)pPrinter; + PrinterContainer.Level = Level; + + // Do the RPC call + RpcTryExcept + { + dwErrorCode = _RpcAddPrinter( pName, &PrinterContainer, &DevModeContainer, &SecurityContainer, &hPrinter ); + } + RpcExcept(EXCEPTION_EXECUTE_HANDLER) + { + dwErrorCode = RpcExceptionCode(); + } + RpcEndExcept; + + if (hPrinter) + { + // Create a new SPOOLER_HANDLE structure. + pHandle = HeapAlloc(hProcessHeap, HEAP_ZERO_MEMORY, sizeof(SPOOLER_HANDLE)); + if (!pHandle) + { + dwErrorCode = ERROR_NOT_ENOUGH_MEMORY; + ERR("HeapAlloc failed!\n"); + _RpcDeletePrinter(hPrinter); + _RpcClosePrinter(hPrinter); + goto Cleanup; + } + + pHandle->Sig = SPOOLER_HANDLE_SIG; + pHandle->hPrinter = hPrinter; + pHandle->hSPLFile = INVALID_HANDLE_VALUE; + pHandle->hSpoolFileHandle = INVALID_HANDLE_VALUE; + hHandle = (HANDLE)pHandle; + } + +Cleanup: + if ( sd ) HeapFree( GetProcessHeap(), 0, sd ); + + SetLastError(dwErrorCode); + return hHandle; } BOOL WINAPI @@ -140,7 +416,7 @@ ClosePrinter(HANDLE hPrinter) TRACE("ClosePrinter(%p)\n", hPrinter); // Sanity checks. - if (!pHandle) + if ( IntProtectHandle( hPrinter, TRUE ) ) { dwErrorCode = ERROR_INVALID_HANDLE; goto Cleanup; @@ -162,6 +438,8 @@ ClosePrinter(HANDLE hPrinter) if (pHandle->hSPLFile != INVALID_HANDLE_VALUE) CloseHandle(pHandle->hSPLFile); + pHandle->Sig = -1; + // Free the memory for the handle. HeapFree(hProcessHeap, 0, pHandle); @@ -173,25 +451,207 @@ Cleanup: BOOL WINAPI DeletePrinter(HANDLE hPrinter) { + DWORD dwErrorCode; + PSPOOLER_HANDLE pHandle = (PSPOOLER_HANDLE)hPrinter; + TRACE("DeletePrinter(%p)\n", hPrinter); - UNIMPLEMENTED; - return FALSE; + + // Sanity checks. + if (!pHandle) + { + dwErrorCode = ERROR_INVALID_HANDLE; + goto Cleanup; + } + + // Do the RPC call. + RpcTryExcept + { + dwErrorCode = _RpcDeletePrinter(&pHandle->hPrinter); + } + RpcExcept(EXCEPTION_EXECUTE_HANDLER) + { + dwErrorCode = RpcExceptionCode(); + ERR("_RpcDeletePrinter failed with exception code %lu!\n", dwErrorCode); + } + RpcEndExcept; + +Cleanup: + SetLastError(dwErrorCode); + return (dwErrorCode == ERROR_SUCCESS); +} + +// +// Based on GDI32:printdrv.c:IntGetPrinterDriver. +// +HMODULE +WINAPI +LoadPrinterDriver( HANDLE hspool ) +{ + INT iTries = 0; + DWORD Size = (sizeof(WCHAR) * MAX_PATH) * 2; // DRIVER_INFO_5W + plus strings. + PDRIVER_INFO_5W pdi = NULL; + HMODULE hLibrary = NULL; + + do + { + ++iTries; + + pdi = RtlAllocateHeap( GetProcessHeap(), 0, Size); + + if ( !pdi ) + break; + + if ( GetPrinterDriverW(hspool, NULL, 5, (LPBYTE)pdi, Size, &Size) ) + { + TRACE("Level 5 Size %d\n",Size); + + // Name and load configure library (for example, C:\DRIVERS\Pscrptui.dll). Not printui.dll! + + hLibrary = LoadLibrary(pdi->pConfigFile); + + FIXME("IGPD : Get Printer Driver %S\n",pdi->pConfigFile); + + RtlFreeHeap( GetProcessHeap(), 0, pdi); + return hLibrary; + } + + if ( GetLastError() != ERROR_INSUFFICIENT_BUFFER ) + ++iTries; + + RtlFreeHeap( GetProcessHeap(), 0, pdi); + } + while ( iTries < 2 ); + ERR("No Printer Driver Error %d\n",GetLastError()); + return NULL; } DWORD WINAPI DeviceCapabilitiesA(LPCSTR pDevice, LPCSTR pPort, WORD fwCapability, LPSTR pOutput, const DEVMODEA* pDevMode) { - TRACE("DeviceCapabilitiesA(%s, %s, %hu, %p, %p)\n", pDevice, pPort, fwCapability, pOutput, pDevMode); - UNIMPLEMENTED; - return 0; + PWSTR pwszDeviceName = NULL; + PDEVMODEW pdmwInput = NULL; + BOOL bReturnValue = GDI_ERROR; + DWORD cch; + + FIXME("DeviceCapabilitiesA(%s, %s, %hu, %p, %p)\n", pDevice, pPort, fwCapability, pOutput, pDevMode); + + if (pDevice) + { + // Convert pName to a Unicode string pwszDeviceName. + cch = strlen(pDevice); + + pwszDeviceName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(WCHAR)); + if (!pwszDeviceName) + { + SetLastError(ERROR_NOT_ENOUGH_MEMORY); + ERR("HeapAlloc failed!\n"); + goto Cleanup; + } + + MultiByteToWideChar(CP_ACP, 0, pDevice, -1, pwszDeviceName, cch + 1); + } + + if (pDevMode) + { + RosConvertAnsiDevModeToUnicodeDevmode((PDEVMODEA)pDevMode, &pdmwInput); + } + + // pPort is ignored so no need to pass it. + bReturnValue = DeviceCapabilitiesW( pwszDeviceName, NULL, fwCapability, (LPWSTR)pOutput, (const DEVMODEW*) pdmwInput ); + +Cleanup: + if(pwszDeviceName) + HeapFree(hProcessHeap, 0, pwszDeviceName); + + if (pdmwInput) + HeapFree(hProcessHeap, 0, pdmwInput); + + return bReturnValue; } DWORD WINAPI DeviceCapabilitiesW(LPCWSTR pDevice, LPCWSTR pPort, WORD fwCapability, LPWSTR pOutput, const DEVMODEW* pDevMode) { - TRACE("DeviceCapabilitiesW(%S, %S, %hu, %p, %p)\n", pDevice, pPort, fwCapability, pOutput, pDevMode); - UNIMPLEMENTED; - return 0; + HANDLE hPrinter; + HMODULE hLibrary; + DWORD iDevCap = GDI_ERROR; + + FIXME("DeviceCapabilitiesW(%S, %S, %hu, %p, %p)\n", pDevice, pPort, fwCapability, pOutput, pDevMode); + + if ( pDevMode ) + { + if (!IsValidDevmodeNoSizeW( (PDEVMODEW)pDevMode ) ) + { + ERR("DeviceCapabilitiesW : Devode Invalid"); + return -1; + } + } + + if ( OpenPrinterW( (LPWSTR)pDevice, &hPrinter, NULL ) ) + { + hLibrary = LoadPrinterDriver( hPrinter ); + + if ( hLibrary ) + { + fpDeviceCapabilities = (PVOID)GetProcAddress( hLibrary, "DrvDeviceCapabilities" ); + + if ( fpDeviceCapabilities ) + { + iDevCap = fpDeviceCapabilities( hPrinter, (PWSTR)pDevice, fwCapability, pOutput, (PDEVMODE)pDevMode ); + } + + FreeLibrary(hLibrary); + } + + ClosePrinter( hPrinter ); + } + + return iDevCap; +} + +BOOL +WINAPI +DevQueryPrint( HANDLE hPrinter, LPDEVMODEW pDevMode, DWORD *pResID) +{ + HMODULE hLibrary; + BOOL Ret = FALSE; + + hLibrary = LoadPrinterDriver( hPrinter ); + + if ( hLibrary ) + { + fpDevQueryPrint = (PVOID)GetProcAddress( hLibrary, "DevQueryPrint" ); + + if ( fpDevQueryPrint ) + { + Ret = fpDevQueryPrint( hPrinter, pDevMode, pResID ); + } + + FreeLibrary(hLibrary); + } + return Ret; +} + +BOOL WINAPI +DevQueryPrintEx( PDEVQUERYPRINT_INFO pDQPInfo ) +{ + HMODULE hLibrary; + BOOL Ret = FALSE; + + hLibrary = LoadPrinterDriver( pDQPInfo->hPrinter ); + + if ( hLibrary ) + { + fpDevQueryPrintEx = (PVOID)GetProcAddress( hLibrary, "DevQueryPrintEx" ); + + if ( fpDevQueryPrintEx ) + { + Ret = fpDevQueryPrintEx( pDQPInfo ); + } + + FreeLibrary(hLibrary); + } + return Ret; } INT WINAPI @@ -211,7 +671,7 @@ DocumentPropertiesA(HWND hWnd, HANDLE hPrinter, LPSTR pDeviceName, PDEVMODEA pDe BOOL bReturnValue = -1; DWORD cch; - TRACE("DocumentPropertiesA(%p, %p, %s, %p, %p, %lu)\n", hWnd, hPrinter, pDeviceName, pDevModeOutput, pDevModeInput, fMode); + FIXME("DocumentPropertiesA(%p, %p, %s, %p, %p, %lu)\n", hWnd, hPrinter, pDeviceName, pDevModeOutput, pDevModeInput, fMode); if (pDeviceName) { @@ -232,20 +692,22 @@ DocumentPropertiesA(HWND hWnd, HANDLE hPrinter, LPSTR pDeviceName, PDEVMODEA pDe if (pDevModeInput) { // Create working buffer for input to DocumentPropertiesW. - pdmwInput = HeapAlloc(hProcessHeap, 0, sizeof(DEVMODEW)); - if (!pdmwInput) - { - SetLastError(ERROR_NOT_ENOUGH_MEMORY); - ERR("HeapAlloc failed!\n"); - goto Cleanup; - } - RosConvertAnsiDevModeToUnicodeDevmode(pDevModeInput, pdmwInput); + RosConvertAnsiDevModeToUnicodeDevmode(pDevModeInput, &pdmwInput); } if (pDevModeOutput) { // Create working buffer for output from DocumentPropertiesW. - pdmwOutput = HeapAlloc(hProcessHeap, 0, sizeof(DEVMODEW)); + + // Do it RIGHT! Get the F...ing Size! + LONG Size = DocumentPropertiesW( hWnd, hPrinter, pwszDeviceName, NULL, NULL, 0 ); + + if ( Size < 0 ) + { + goto Cleanup; + } + + pdmwOutput = HeapAlloc(hProcessHeap, 0, Size); if (!pdmwOutput) { SetLastError(ERROR_NOT_ENOUGH_MEMORY); @@ -255,7 +717,7 @@ DocumentPropertiesA(HWND hWnd, HANDLE hPrinter, LPSTR pDeviceName, PDEVMODEA pDe } bReturnValue = DocumentPropertiesW(hWnd, hPrinter, pwszDeviceName, pdmwOutput, pdmwInput, fMode); - TRACE("bReturnValue from DocumentPropertiesW is '%ld'.\n", bReturnValue); + FIXME("bReturnValue from DocumentPropertiesW is '%ld'.\n", bReturnValue); if (pwszDeviceName) { @@ -264,7 +726,7 @@ DocumentPropertiesA(HWND hWnd, HANDLE hPrinter, LPSTR pDeviceName, PDEVMODEA pDe if (bReturnValue < 0) { - TRACE("DocumentPropertiesW failed!\n"); + FIXME("DocumentPropertiesW failed!\n"); goto Cleanup; } @@ -286,7 +748,7 @@ Cleanup: return bReturnValue; } -static PRINTER_INFO_9W * get_devmodeW(HANDLE hprn) +PRINTER_INFO_9W * get_devmodeW(HANDLE hprn) { PRINTER_INFO_9W *pi9 = NULL; DWORD needed = 0; @@ -307,14 +769,398 @@ static PRINTER_INFO_9W * get_devmodeW(HANDLE hprn) return NULL; } +BOOL +FASTCALL +CreateUIUserData( ULONG_PTR *puserdata, HANDLE hPrinter ) +{ + PCOMPUI_USERDATA pcui_ud = DllAllocSplMem( sizeof(COMPUI_USERDATA) ); + + *puserdata = (ULONG_PTR)pcui_ud; + FIXME("CreateUIUserData\n"); + if ( pcui_ud ) + { + pcui_ud->hModule = LoadPrinterDriver( hPrinter ); + + if ( !pcui_ud->hModule ) + { + DllFreeSplMem( pcui_ud ); + *puserdata = 0; + } + } + return *puserdata != 0; +} + +VOID +FASTCALL +DestroyUIUserData( ULONG_PTR *puserdata ) +{ + PCOMPUI_USERDATA pcui_ud = (PCOMPUI_USERDATA)*puserdata; + FIXME("DestroyUIUserData\n"); + if ( pcui_ud ) + { + if ( pcui_ud->hModule ) + { + FreeLibrary( pcui_ud->hModule ); + pcui_ud->hModule = NULL; + } + + if ( pcui_ud->pszPrinterName ) + { + DllFreeSplMem( pcui_ud->pszPrinterName ); + pcui_ud->pszPrinterName = NULL; + } + + DllFreeSplMem( pcui_ud ); + *puserdata = 0; + } +} + +BOOL +FASTCALL +IntFixUpDevModeNames( PDOCUMENTPROPERTYHEADER pdphdr ) +{ + PRINTER_INFO_2W *pi2 = NULL; + DWORD needed = 0; + BOOL res; + + if (!(pdphdr->fMode & DM_OUT_BUFFER) || + pdphdr->fMode & DM_NOPERMISSION || // Do not allow the user to modify properties on the displayed property sheet pages. + !pdphdr->pdmOut ) + { + return FALSE; + } + + res = GetPrinterW( pdphdr->hPrinter, 2, NULL, 0, &needed); + if (!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) + { + pi2 = HeapAlloc(hProcessHeap, 0, needed); + res = GetPrinterW( pdphdr->hPrinter, 2, (LPBYTE)pi2, needed, &needed); + } + + if (res) + { + FIXME("IFUDMN : Get Printer Name %S\n",pi2->pPrinterName); + StringCchCopyW( pdphdr->pdmOut->dmDeviceName, CCHDEVICENAME-1, pi2->pPrinterName ); + pdphdr->pdmOut->dmDeviceName[CCHDEVICENAME-1] = 0; + } + else + { + ERR("IFUDMN : GetPrinterW failed with %u\n", GetLastError()); + } + HeapFree(hProcessHeap, 0, pi2); + return res; +} + +LONG +WINAPI +CreatePrinterFriendlyName( PCOMPUI_USERDATA pcui_ud, LPWSTR pszPrinterName ) +{ + LONG Result = 0; + DWORD Size = 0; + HMODULE hLibrary = NULL; + + hLibrary = LoadLibraryA( "printui.dll" ); + + if ( hLibrary ) + { + fpConstructPrinterFriendlyName = (PVOID)GetProcAddress( hLibrary, "ConstructPrinterFriendlyName" ); + + if ( fpConstructPrinterFriendlyName ) + { + if ( !fpConstructPrinterFriendlyName( pszPrinterName, NULL, &Size ) ) + { + if ( GetLastError() == ERROR_INSUFFICIENT_BUFFER ) + { + PWSTR pwstr = DllAllocSplMem( (Size + 1) * sizeof(WCHAR) ); + + pcui_ud->pszPrinterName = pwstr; + + if ( pwstr ) + Result = fpConstructPrinterFriendlyName( pszPrinterName, pwstr, &Size ); + } + } + } + FreeLibrary( hLibrary ); + } + + if ( !Result ) + { + DllFreeSplMem( pcui_ud->pszPrinterName ); + pcui_ud->pszPrinterName = AllocSplStr( pszPrinterName ); + } + + return Result; +} + +// +// Tested with XP CompstUI as a callback and works. Fails perfectly. +// +LONG +WINAPI +DocumentPropertySheets( PPROPSHEETUI_INFO pCPSUIInfo, LPARAM lparam ) +{ + LONG Result = -1; + PDOCUMENTPROPERTYHEADER pdphdr; + + FIXME("DocumentPropertySheets(%p, 0x%lx)\n", pCPSUIInfo, lparam); + + // If pPSUIInfo is NULL, and if either lParam -> fMode is zero or lParam -> pdmOut is NULL, + // this function should return the size, in bytes, of the printer's DEVMODEW structure. + if ( !pCPSUIInfo && lparam ) + { + pdphdr = (PDOCUMENTPROPERTYHEADER)lparam; + + if ( pdphdr->cbSize >= sizeof(PDOCUMENTPROPERTYHEADER) && + !(pdphdr->fMode & DM_PROMPT) ) + { + HMODULE hLibrary = LoadPrinterDriver( pdphdr->hPrinter ); + + if ( hLibrary ) + { + fpDocumentPropertySheets = (PVOID)GetProcAddress( hLibrary, "DrvDocumentPropertySheets" ); + + if ( fpDocumentPropertySheets ) + { + Result = fpDocumentPropertySheets( pCPSUIInfo, lparam ); + } + else + { + // + // ReactOS backup!!! Currently no supporting UI driver. + // + PRINTER_INFO_9W * pi9 = get_devmodeW( pdphdr->hPrinter ); + if ( pi9 ) + { + Result = pi9->pDevMode->dmSize + pi9->pDevMode->dmDriverExtra; + FIXME("IDPS : Using ReactOS backup!!! DevMode Size %d\n",Result); + HeapFree(hProcessHeap, 0, pi9); + } + } + + FreeLibrary(hLibrary); + + if ( Result > 0 ) + { + IntFixUpDevModeNames( pdphdr ); + } + + return Result; + } + else + { + SetLastError(ERROR_INVALID_HANDLE); + } + } + else + { + SetLastError(ERROR_INVALID_PARAMETER); + } + return Result; + } + + Result = 0; + + if ( pCPSUIInfo ) + { + PSETRESULT_INFO psri; + PPROPSHEETUI_INFO_HEADER ppsuiihdr; + PCOMPUI_USERDATA pcui_ud; + pdphdr = (PDOCUMENTPROPERTYHEADER)pCPSUIInfo->lParamInit; + + if ( pdphdr->cbSize < sizeof(PDOCUMENTPROPERTYHEADER) ) + { + SetLastError(ERROR_INVALID_PARAMETER); + return Result; + } + + switch ( pCPSUIInfo->Reason ) + { + case PROPSHEETUI_REASON_INIT: + { + FIXME("DocPS : PROPSHEETUI_REASON_INIT\n"); + if ( CreateUIUserData( &pCPSUIInfo->UserData, pdphdr->hPrinter ) ) + { + pcui_ud = (PCOMPUI_USERDATA)pCPSUIInfo->UserData; + + fpDocumentPropertySheets = (PVOID)GetProcAddress( pcui_ud->hModule, "DrvDocumentPropertySheets" ); + + if ( fpDocumentPropertySheets ) + { + pCPSUIInfo->pfnComPropSheet( pCPSUIInfo->hComPropSheet, + CPSFUNC_SET_FUSION_CONTEXT, + -3, // What type of handle is this? + 0 ); // Not used, must be zero. + + Result = pCPSUIInfo->pfnComPropSheet( pCPSUIInfo->hComPropSheet, + CPSFUNC_ADD_PFNPROPSHEETUIW, + (LPARAM)fpDocumentPropertySheets, + pCPSUIInfo->lParamInit ); + break; + } + FIXME("DocPS : PROPSHEETUI_REASON_INIT Fail\n"); + DestroyUIUserData( &pCPSUIInfo->UserData ); + } + } + break; + + case PROPSHEETUI_REASON_GET_INFO_HEADER: + FIXME("DocPS : PROPSHEETUI_REASON_GET_INFO_HEADER\n"); + + ppsuiihdr = (PPROPSHEETUI_INFO_HEADER)lparam; + + pcui_ud = (PCOMPUI_USERDATA)pCPSUIInfo->UserData; + + CreatePrinterFriendlyName( pcui_ud, pdphdr->pszPrinterName ); + + ppsuiihdr->Flags = PSUIHDRF_NOAPPLYNOW|PSUIHDRF_PROPTITLE; + ppsuiihdr->pTitle = pcui_ud->pszPrinterName; + ppsuiihdr->hInst = hinstWinSpool; + ppsuiihdr->IconID = IDI_CPSUI_DOCUMENT; + + Result = CPSUI_OK; + break; + + case PROPSHEETUI_REASON_DESTROY: + FIXME("DocPS : PROPSHEETUI_REASON_DESTROY\n"); + DestroyUIUserData( &pCPSUIInfo->UserData ); + Result = CPSUI_OK; + break; + + case PROPSHEETUI_REASON_SET_RESULT: + FIXME("DocPS : PROPSHEETUI_REASON_SET_RESULT\n"); + + psri = (PSETRESULT_INFO)lparam; + + pCPSUIInfo->Result = psri->Result; + if ( pCPSUIInfo->Result > 0 ) + { + IntFixUpDevModeNames( pdphdr ); + } + Result = CPSUI_OK; + break; + } + } + return Result; +} + +LONG +WINAPI +DevicePropertySheets( PPROPSHEETUI_INFO pCPSUIInfo, LPARAM lparam ) +{ + LONG Result = 0; + PDEVICEPROPERTYHEADER pdphdr; + + FIXME("DevicePropertySheets(%p, 0x%lx)\n", pCPSUIInfo, lparam); + + if ( pCPSUIInfo ) + { + PSETRESULT_INFO psri; + PPROPSHEETUI_INFO_HEADER ppsuiihdr; + PCOMPUI_USERDATA pcui_ud; + pdphdr = (PDEVICEPROPERTYHEADER)pCPSUIInfo->lParamInit; + + if ( pdphdr->cbSize < sizeof(DEVICEPROPERTYHEADER) ) + { + SetLastError(ERROR_INVALID_PARAMETER); + return Result; + } + + switch ( pCPSUIInfo->Reason ) + { + case PROPSHEETUI_REASON_INIT: + { + FIXME("DevPS : PROPSHEETUI_REASON_INIT\n"); + if ( CreateUIUserData( &pCPSUIInfo->UserData, pdphdr->hPrinter ) ) + { + pcui_ud = (PCOMPUI_USERDATA)pCPSUIInfo->UserData; + + fpDevicePropertySheets = (PVOID)GetProcAddress( pcui_ud->hModule, "DrvDevicePropertySheets" ); + + if ( fpDevicePropertySheets ) + { + pCPSUIInfo->pfnComPropSheet( pCPSUIInfo->hComPropSheet, + CPSFUNC_SET_FUSION_CONTEXT, + -3, // What type of handle is this? + 0 ); // Not used, must be zero. + + Result = pCPSUIInfo->pfnComPropSheet( pCPSUIInfo->hComPropSheet, + CPSFUNC_ADD_PFNPROPSHEETUIW, + (LPARAM)fpDevicePropertySheets, + pCPSUIInfo->lParamInit ); + break; + } + FIXME("DevPS : PROPSHEETUI_REASON_INIT Fail\n"); + DestroyUIUserData( &pCPSUIInfo->UserData ); + } + } + break; + + case PROPSHEETUI_REASON_GET_INFO_HEADER: + FIXME("DevPS : PROPSHEETUI_REASON_GET_INFO_HEADER\n"); + + ppsuiihdr = (PPROPSHEETUI_INFO_HEADER)lparam; + + pcui_ud = (PCOMPUI_USERDATA)pCPSUIInfo->UserData; + + CreatePrinterFriendlyName( pcui_ud, pdphdr->pszPrinterName ); + + ppsuiihdr->Flags = PSUIHDRF_NOAPPLYNOW|PSUIHDRF_PROPTITLE; + ppsuiihdr->pTitle = pcui_ud->pszPrinterName; + ppsuiihdr->hInst = hinstWinSpool; + ppsuiihdr->IconID = IDI_CPSUI_DOCUMENT; + + Result = CPSUI_OK; + break; + + case PROPSHEETUI_REASON_DESTROY: + FIXME("DevPS : PROPSHEETUI_REASON_DESTROY\n"); + DestroyUIUserData( &pCPSUIInfo->UserData ); + Result = CPSUI_OK; + break; + + case PROPSHEETUI_REASON_SET_RESULT: + FIXME("DevPS : PROPSHEETUI_REASON_SET_RESULT\n"); + psri = (PSETRESULT_INFO)lparam; + pCPSUIInfo->Result = psri->Result; + Result = CPSUI_OK; + break; + } + } + return Result; +} + +LONG +WINAPI +CallCommonPropertySheetUI(HWND hWnd, PFNPROPSHEETUI pfnPropSheetUI, LPARAM lparam, LPDWORD pResult) +{ + HMODULE hLibrary = NULL; + LONG Ret = ERR_CPSUI_GETLASTERROR; + + FIXME("CallCommonPropertySheetUI(%p, %p, 0x%lx, %p)\n", hWnd, pfnPropSheetUI, lparam, pResult); + + if ( ( hLibrary = LoadLibraryA( "compstui.dll" ) ) ) + { + fpCommonPropertySheetUIW = (PVOID) GetProcAddress(hLibrary, "CommonPropertySheetUIW"); + + if ( fpCommonPropertySheetUIW ) + { + Ret = fpCommonPropertySheetUIW( hWnd, pfnPropSheetUI, lparam, pResult ); + } + + FreeLibrary(hLibrary); + } + return Ret; +} + LONG WINAPI DocumentPropertiesW(HWND hWnd, HANDLE hPrinter, LPWSTR pDeviceName, PDEVMODEW pDevModeOutput, PDEVMODEW pDevModeInput, DWORD fMode) { HANDLE hUseHandle = NULL; - PRINTER_INFO_9W *pi9 = NULL; - LONG Result = -1, Length; + DOCUMENTPROPERTYHEADER docprophdr; + LONG Result = IDOK; + + FIXME("DocumentPropertiesW(%p, %p, %S, %p, %p, %lu)\n", hWnd, hPrinter, pDeviceName, pDevModeOutput, pDevModeInput, fMode); - TRACE("DocumentPropertiesW(%p, %p, %S, %p, %p, %lu)\n", hWnd, hPrinter, pDeviceName, pDevModeOutput, pDevModeInput, fMode); if (hPrinter) { hUseHandle = hPrinter; @@ -325,47 +1171,68 @@ DocumentPropertiesW(HWND hWnd, HANDLE hPrinter, LPWSTR pDeviceName, PDEVMODEW pD return -1; } - pi9 = get_devmodeW(hUseHandle); - - if (pi9) + if ( !(fMode & DM_IN_BUFFER ) || + ( ( pDevModeInput && !IsValidDevmodeNoSizeW( (PDEVMODEW)pDevModeInput ) ) ) ) { - Length = pi9->pDevMode->dmSize + pi9->pDevMode->dmDriverExtra; - // See wineps.drv PSDRV_ExtDeviceMode - if (fMode) + pDevModeInput = NULL; + fMode &= ~DM_IN_BUFFER; + } + + docprophdr.cbSize = sizeof(DOCUMENTPROPERTYHEADER); + docprophdr.Reserved = 0; + docprophdr.hPrinter = hUseHandle; + docprophdr.pszPrinterName = pDeviceName; + docprophdr.cbOut = 0; + + if ( pDevModeOutput ) + { + docprophdr.pdmIn = NULL; + docprophdr.pdmOut = NULL; + docprophdr.fMode = 0; + FIXME("DPW : Call DocumentPropertySheets with pDevModeOutput %p\n",pDevModeOutput); + docprophdr.cbOut = DocumentPropertySheets( NULL, (LPARAM)&docprophdr ); + } + + docprophdr.pdmIn = pDevModeInput; + docprophdr.pdmOut = pDevModeOutput; + docprophdr.fMode = fMode; + + if ( fMode & DM_IN_PROMPT ) + { + Result = CPSUI_CANCEL; + + // + // Now call the Property Sheet for Print > Properties. + // + if ( CallCommonPropertySheetUI( hWnd, (PFNPROPSHEETUI)DocumentPropertySheets, (LPARAM)&docprophdr, (LPDWORD)&Result ) < 0 ) { - Result = 1; /* IDOK */ + FIXME("CallCommonPropertySheetUI return error\n"); + Result = ERR_CPSUI_GETLASTERROR; + } + else + Result = (Result == CPSUI_OK) ? IDOK : IDCANCEL; + FIXME("CallCommonPropertySheetUI returned\n"); + } + else + { + FIXME("DPW : CallDocumentPropertySheets\n"); + Result = DocumentPropertySheets( NULL, (LPARAM)&docprophdr ); + } - if (fMode & DM_IN_BUFFER) + if ( Result != ERR_CPSUI_GETLASTERROR || Result != ERR_CPSUI_ALLOCMEM_FAILED ) + { + if ( pDevModeOutput ) + { + if ( !IsValidDevmodeNoSizeW( pDevModeOutput ) ) { - FIXME("Merge pDevModeInput with pi9, write back to driver!\n"); - // See wineps.drv PSDRV_MergeDevmodes - } - - if (fMode & DM_IN_PROMPT) - { - FIXME("Show property sheet!\n"); - Result = 2; /* IDCANCEL */ - } - - if (fMode & (DM_OUT_BUFFER | DM_OUT_DEFAULT)) - { - if (pDevModeOutput) - { - memcpy(pDevModeOutput, pi9->pDevMode, pi9->pDevMode->dmSize + pi9->pDevMode->dmDriverExtra); - } - else - { - ERR("No pDevModeOutput\n"); - Result = -1; - } + ERR("DPW : Improper pDevModeOutput size.\n"); + Result = -1; } } else { - Result = Length; + ERR("No pDevModeOutput\n"); } - - HeapFree(hProcessHeap, 0, pi9); } if (hUseHandle && !hPrinter) @@ -373,6 +1240,56 @@ DocumentPropertiesW(HWND hWnd, HANDLE hPrinter, LPWSTR pDeviceName, PDEVMODEW pD return Result; } +BOOL +WINAPI +PrinterProperties( HWND hWnd, HANDLE hPrinter ) +{ + PRINTER_INFO_2W *pi2 = NULL; + DWORD needed = 0; + LONG Ret, Result = 0; + BOOL res; + DEVICEPROPERTYHEADER devprophdr; + + FIXME("PrinterProperties(%p, %p)\n", hWnd, hPrinter); + + devprophdr.cbSize = sizeof(DEVICEPROPERTYHEADER); + devprophdr.Flags = DPS_NOPERMISSION; + devprophdr.hPrinter = hPrinter; + devprophdr.pszPrinterName = NULL; + + res = GetPrinterW( hPrinter, 2, NULL, 0, &needed); + if (!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) + { + pi2 = HeapAlloc(hProcessHeap, 0, needed); + res = GetPrinterW(hPrinter, 2, (LPBYTE)pi2, needed, &needed); + } + + // + // Above can fail, still process w/o printer name. + // + if ( res ) devprophdr.pszPrinterName = pi2->pPrinterName; + + needed = 1; + + if ( ( SetPrinterDataW( hPrinter, L"PrinterPropertiesPermission", REG_DWORD, (LPBYTE)&needed, sizeof(DWORD) ) == ERROR_SUCCESS ) ) + { + devprophdr.Flags &= ~DPS_NOPERMISSION; + } + + Ret = CallCommonPropertySheetUI( hWnd, (PFNPROPSHEETUI)DevicePropertySheets, (LPARAM)&devprophdr, (LPDWORD)&Result ); + + res = (Ret >= 0); + + if (!res) + { + FIXME("PrinterProperties fail ICPSUI\n"); + } + + if (pi2) HeapFree(hProcessHeap, 0, pi2); + + return res; +} + BOOL WINAPI EndDocPrinter(HANDLE hPrinter) { @@ -421,7 +1338,7 @@ EndDocPrinter(HANDLE hPrinter) } // A new document can now be started again. - pHandle->bStartedDoc = FALSE; + pHandle->bTrayIcon = pHandle->bJob = pHandle->bStartedDoc = FALSE; Cleanup: SetLastError(dwErrorCode); @@ -823,8 +1740,11 @@ EnumPrintersA(DWORD Flags, PSTR Name, DWORD Level, PBYTE pPrinterEnum, DWORD cbB HeapFree(hProcessHeap, 0, pszParameters); } + if ( ppi2w[i].pDevMode ) + { + RosConvertUnicodeDevModeToAnsiDevmode( ppi2w[i].pDevMode, ppi2a[i].pDevMode ); + } break; - } case 4: @@ -1089,7 +2009,7 @@ GetDefaultPrinterW(LPWSTR pszBuffer, LPDWORD pcchBuffer) *pcchBuffer = pwszComma - pwszDevice + 1; // Check if the supplied buffer is large enough. - if (cchInputBuffer < *pcchBuffer) + if ( !pszBuffer || cchInputBuffer < *pcchBuffer) { dwErrorCode = ERROR_INSUFFICIENT_BUFFER; goto Cleanup; @@ -1126,6 +2046,8 @@ GetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter, DWORD cbBuf, LPDWORD PPRINTER_INFO_5W ppi5w = (PPRINTER_INFO_5W)pPrinter; PPRINTER_INFO_7A ppi7a = (PPRINTER_INFO_7A)pPrinter; PPRINTER_INFO_7W ppi7w = (PPRINTER_INFO_7W)pPrinter; + PPRINTER_INFO_9A ppi9a = (PPRINTER_INFO_9A)pPrinter; + PPRINTER_INFO_9W ppi9w = (PPRINTER_INFO_9W)pPrinter; DWORD cch; TRACE("GetPrinterA(%p, %lu, %p, %lu, %p)\n", hPrinter, Level, pPrinter, cbBuf, pcbNeeded); @@ -1445,6 +2367,10 @@ GetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter, DWORD cbBuf, LPDWORD HeapFree(hProcessHeap, 0, pszParameters); } + if ( ppi2w->pDevMode ) + { + RosConvertUnicodeDevModeToAnsiDevmode( ppi2w->pDevMode, ppi2a->pDevMode ); + } break; } @@ -1562,8 +2488,12 @@ GetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter, DWORD cbBuf, LPDWORD HeapFree(hProcessHeap, 0, pszaObjectGUID); } - break; } + break; + case 8: + case 9: + RosConvertUnicodeDevModeToAnsiDevmode(ppi9w->pDevMode, ppi9a->pDevMode); + break; } // switch dwErrorCode = ERROR_SUCCESS; @@ -1573,413 +2503,6 @@ Cleanup: return (dwErrorCode == ERROR_SUCCESS); } -BOOL WINAPI -GetPrinterDriverA(HANDLE hPrinter, LPSTR pEnvironment, DWORD Level, LPBYTE pDriverInfo, DWORD cbBuf, LPDWORD pcbNeeded) -{ - DWORD dwErrorCode; - /* - * We are mapping multiple different pointers to the same pDriverInfo pointer here so that - * we can use the same incoming pointer for different Levels - */ - PDRIVER_INFO_1W pdi1w = (PDRIVER_INFO_1W)pDriverInfo; - PDRIVER_INFO_2W pdi2w = (PDRIVER_INFO_2W)pDriverInfo; - PDRIVER_INFO_3W pdi3w = (PDRIVER_INFO_3W)pDriverInfo; - PDRIVER_INFO_4W pdi4w = (PDRIVER_INFO_4W)pDriverInfo; - PDRIVER_INFO_5W pdi5w = (PDRIVER_INFO_5W)pDriverInfo; - PDRIVER_INFO_6W pdi6w = (PDRIVER_INFO_6W)pDriverInfo; - - DWORD cch; - PWSTR pwszEnvironment = NULL; - - TRACE("GetPrinterDriverA(%p, %s, %lu, %p, %lu, %p)\n", hPrinter, pEnvironment, Level, pDriverInfo, cbBuf, pcbNeeded); - - // Check for invalid levels here for early error return. Should be 1-6. - if (Level < 1 || Level > 6) - { - dwErrorCode = ERROR_INVALID_LEVEL; - ERR("Invalid Level!\n"); - goto Cleanup; - } - - if (pEnvironment) - { - // Convert pEnvironment to a Unicode string pwszEnvironment. - cch = strlen(pEnvironment); - - pwszEnvironment = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(WCHAR)); - if (!pwszEnvironment) - { - dwErrorCode = ERROR_NOT_ENOUGH_MEMORY; - ERR("HeapAlloc failed!\n"); - goto Cleanup; - } - - MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, pwszEnvironment, cch + 1); - } - - if (!GetPrinterDriverW(hPrinter, pwszEnvironment, Level, pDriverInfo, cbBuf, pcbNeeded)) - { - dwErrorCode = GetLastError(); - goto Cleanup; - } - - // Do Unicode to ANSI conversions for strings based on Level - switch (Level) - { - case 1: - { - dwErrorCode = UnicodeToAnsiInPlace(pdi1w->pName); - if (dwErrorCode != ERROR_SUCCESS) - { - goto Cleanup; - } - - break; - } - - case 2: - { - dwErrorCode = UnicodeToAnsiInPlace(pdi2w->pName); - if (dwErrorCode != ERROR_SUCCESS) - { - goto Cleanup; - } - - dwErrorCode = UnicodeToAnsiInPlace(pdi2w->pEnvironment); - if (dwErrorCode != ERROR_SUCCESS) - { - goto Cleanup; - } - - dwErrorCode = UnicodeToAnsiInPlace(pdi2w->pDriverPath); - if (dwErrorCode != ERROR_SUCCESS) - { - goto Cleanup; - } - - dwErrorCode = UnicodeToAnsiInPlace(pdi2w->pDataFile); - if (dwErrorCode != ERROR_SUCCESS) - { - goto Cleanup; - } - - dwErrorCode = UnicodeToAnsiInPlace(pdi2w->pConfigFile); - if (dwErrorCode != ERROR_SUCCESS) - { - goto Cleanup; - } - - break; - } - - case 3: - { - dwErrorCode = UnicodeToAnsiInPlace(pdi3w->pName); - if (dwErrorCode != ERROR_SUCCESS) - { - goto Cleanup; - } - - dwErrorCode = UnicodeToAnsiInPlace(pdi3w->pEnvironment); - if (dwErrorCode != ERROR_SUCCESS) - { - goto Cleanup; - } - - dwErrorCode = UnicodeToAnsiInPlace(pdi3w->pDriverPath); - if (dwErrorCode != ERROR_SUCCESS) - { - goto Cleanup; - } - - dwErrorCode = UnicodeToAnsiInPlace(pdi3w->pDataFile); - if (dwErrorCode != ERROR_SUCCESS) - { - goto Cleanup; - } - - dwErrorCode = UnicodeToAnsiInPlace(pdi3w->pConfigFile); - if (dwErrorCode != ERROR_SUCCESS) - { - goto Cleanup; - } - - dwErrorCode = UnicodeToAnsiInPlace(pdi3w->pHelpFile); - if (dwErrorCode != ERROR_SUCCESS) - { - goto Cleanup; - } - - dwErrorCode = UnicodeToAnsiInPlace(pdi3w->pDependentFiles); - if (dwErrorCode != ERROR_SUCCESS) - { - goto Cleanup; - } - - dwErrorCode = UnicodeToAnsiInPlace(pdi3w->pMonitorName); - if (dwErrorCode != ERROR_SUCCESS) - { - goto Cleanup; - } - - dwErrorCode = UnicodeToAnsiInPlace(pdi3w->pDefaultDataType); - if (dwErrorCode != ERROR_SUCCESS) - { - goto Cleanup; - } - - break; - } - - case 4: - { - dwErrorCode = UnicodeToAnsiInPlace(pdi4w->pName); - if (dwErrorCode != ERROR_SUCCESS) - { - goto Cleanup; - } - - dwErrorCode = UnicodeToAnsiInPlace(pdi4w->pEnvironment); - if (dwErrorCode != ERROR_SUCCESS) - { - goto Cleanup; - } - - dwErrorCode = UnicodeToAnsiInPlace(pdi4w->pDriverPath); - if (dwErrorCode != ERROR_SUCCESS) - { - goto Cleanup; - } - - dwErrorCode = UnicodeToAnsiInPlace(pdi4w->pDataFile); - if (dwErrorCode != ERROR_SUCCESS) - { - goto Cleanup; - } - - dwErrorCode = UnicodeToAnsiInPlace(pdi4w->pConfigFile); - if (dwErrorCode != ERROR_SUCCESS) - { - goto Cleanup; - } - - dwErrorCode = UnicodeToAnsiInPlace(pdi4w->pHelpFile); - if (dwErrorCode != ERROR_SUCCESS) - { - goto Cleanup; - } - - dwErrorCode = UnicodeToAnsiInPlace(pdi4w->pDependentFiles); - if (dwErrorCode != ERROR_SUCCESS) - { - goto Cleanup; - } - - dwErrorCode = UnicodeToAnsiInPlace(pdi4w->pMonitorName); - if (dwErrorCode != ERROR_SUCCESS) - { - goto Cleanup; - } - - dwErrorCode = UnicodeToAnsiInPlace(pdi4w->pDefaultDataType); - if (dwErrorCode != ERROR_SUCCESS) - { - goto Cleanup; - } - - dwErrorCode = UnicodeToAnsiInPlace(pdi4w->pszzPreviousNames); - if (dwErrorCode != ERROR_SUCCESS) - { - goto Cleanup; - } - - break; - } - - case 5: - { - dwErrorCode = UnicodeToAnsiInPlace(pdi5w->pName); - if (dwErrorCode != ERROR_SUCCESS) - { - goto Cleanup; - } - - dwErrorCode = UnicodeToAnsiInPlace(pdi5w->pEnvironment); - if (dwErrorCode != ERROR_SUCCESS) - { - goto Cleanup; - } - - dwErrorCode = UnicodeToAnsiInPlace(pdi5w->pDriverPath); - if (dwErrorCode != ERROR_SUCCESS) - { - goto Cleanup; - } - - dwErrorCode = UnicodeToAnsiInPlace(pdi5w->pDataFile); - if (dwErrorCode != ERROR_SUCCESS) - { - goto Cleanup; - } - - dwErrorCode = UnicodeToAnsiInPlace(pdi5w->pConfigFile); - if (dwErrorCode != ERROR_SUCCESS) - { - goto Cleanup; - } - - break; - } - - case 6: - { - dwErrorCode = UnicodeToAnsiInPlace(pdi6w->pName); - if (dwErrorCode != ERROR_SUCCESS) - { - goto Cleanup; - } - - dwErrorCode = UnicodeToAnsiInPlace(pdi6w->pEnvironment); - if (dwErrorCode != ERROR_SUCCESS) - { - goto Cleanup; - } - - dwErrorCode = UnicodeToAnsiInPlace(pdi6w->pDriverPath); - if (dwErrorCode != ERROR_SUCCESS) - { - goto Cleanup; - } - - dwErrorCode = UnicodeToAnsiInPlace(pdi6w->pDataFile); - if (dwErrorCode != ERROR_SUCCESS) - { - goto Cleanup; - } - - dwErrorCode = UnicodeToAnsiInPlace(pdi6w->pConfigFile); - if (dwErrorCode != ERROR_SUCCESS) - { - goto Cleanup; - } - - dwErrorCode = UnicodeToAnsiInPlace(pdi6w->pHelpFile); - if (dwErrorCode != ERROR_SUCCESS) - { - goto Cleanup; - } - - dwErrorCode = UnicodeToAnsiInPlace(pdi6w->pDependentFiles); - if (dwErrorCode != ERROR_SUCCESS) - { - goto Cleanup; - } - - dwErrorCode = UnicodeToAnsiInPlace(pdi6w->pMonitorName); - if (dwErrorCode != ERROR_SUCCESS) - { - goto Cleanup; - } - - dwErrorCode = UnicodeToAnsiInPlace(pdi6w->pDefaultDataType); - if (dwErrorCode != ERROR_SUCCESS) - { - goto Cleanup; - } - - dwErrorCode = UnicodeToAnsiInPlace(pdi6w->pszzPreviousNames); - if (dwErrorCode != ERROR_SUCCESS) - { - goto Cleanup; - } - - dwErrorCode = UnicodeToAnsiInPlace(pdi6w->pszMfgName); - if (dwErrorCode != ERROR_SUCCESS) - { - goto Cleanup; - } - - dwErrorCode = UnicodeToAnsiInPlace(pdi6w->pszOEMUrl); - if (dwErrorCode != ERROR_SUCCESS) - { - goto Cleanup; - } - - dwErrorCode = UnicodeToAnsiInPlace(pdi6w->pszHardwareID); - if (dwErrorCode != ERROR_SUCCESS) - { - goto Cleanup; - } - - dwErrorCode = UnicodeToAnsiInPlace(pdi6w->pszProvider); - if (dwErrorCode != ERROR_SUCCESS) - { - goto Cleanup; - } - } - } - - dwErrorCode = ERROR_SUCCESS; - -Cleanup: - if (pwszEnvironment) - { - HeapFree(hProcessHeap, 0, pwszEnvironment); - } - - SetLastError(dwErrorCode); - return (dwErrorCode == ERROR_SUCCESS); -} - -BOOL WINAPI -GetPrinterDriverW(HANDLE hPrinter, LPWSTR pEnvironment, DWORD Level, LPBYTE pDriverInfo, DWORD cbBuf, LPDWORD pcbNeeded) -{ - DWORD dwErrorCode; - PSPOOLER_HANDLE pHandle = (PSPOOLER_HANDLE)hPrinter; - - TRACE("GetPrinterDriverW(%p, %S, %lu, %p, %lu, %p)\n", hPrinter, pEnvironment, Level, pDriverInfo, cbBuf, pcbNeeded); - - // Sanity checks. - if (!pHandle) - { - dwErrorCode = ERROR_INVALID_HANDLE; - goto Cleanup; - } - - // Dismiss invalid levels already at this point. - if (Level > 8 || Level < 1) - { - dwErrorCode = ERROR_INVALID_LEVEL; - goto Cleanup; - } - - if (cbBuf && pDriverInfo) - ZeroMemory(pDriverInfo, cbBuf); - - // Do the RPC call - RpcTryExcept - { - dwErrorCode = _RpcGetPrinterDriver(pHandle->hPrinter, pEnvironment, Level, pDriverInfo, cbBuf, pcbNeeded); - } - RpcExcept(EXCEPTION_EXECUTE_HANDLER) - { - dwErrorCode = RpcExceptionCode(); - ERR("_RpcGetPrinterDriver failed with exception code %lu!\n", dwErrorCode); - } - RpcEndExcept; - - if (dwErrorCode == ERROR_SUCCESS) - { - // Replace relative offset addresses in the output by absolute pointers. - ASSERT(Level <= 5); - MarshallUpStructure(cbBuf, pDriverInfo, pPrinterDriverMarshalling[Level]->pInfo, pPrinterDriverMarshalling[Level]->cbStructureSize, TRUE); - } - -Cleanup: - SetLastError(dwErrorCode); - return (dwErrorCode == ERROR_SUCCESS); -} - BOOL WINAPI GetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter, DWORD cbBuf, LPDWORD pcbNeeded) { @@ -2081,6 +2604,12 @@ OpenPrinterA(LPSTR pPrinterName, LPHANDLE phPrinter, LPPRINTER_DEFAULTSA pDefaul bReturnValue = OpenPrinterW(pwszPrinterName, phPrinter, &wDefault); + if ( bReturnValue ) + { + PSPOOLER_HANDLE pHandle = (PSPOOLER_HANDLE)*phPrinter; + pHandle->bAnsi = TRUE; + } + Cleanup: if (wDefault.pDatatype) HeapFree(hProcessHeap, 0, wDefault.pDatatype); @@ -2145,8 +2674,10 @@ OpenPrinterW(LPWSTR pPrinterName, LPHANDLE phPrinter, LPPRINTER_DEFAULTSW pDefau goto Cleanup; } + pHandle->Sig = SPOOLER_HANDLE_SIG; pHandle->hPrinter = hPrinter; pHandle->hSPLFile = INVALID_HANDLE_VALUE; + pHandle->hSpoolFileHandle = INVALID_HANDLE_VALUE; // Return it as phPrinter. *phPrinter = (HANDLE)pHandle; @@ -2157,6 +2688,176 @@ Cleanup: return (dwErrorCode == ERROR_SUCCESS); } +// +// Dead API. +// +DWORD WINAPI +PrinterMessageBoxA(HANDLE hPrinter, DWORD Error, HWND hWnd, LPSTR pText, LPSTR pCaption, DWORD dwType) +{ + return 50; +} + +DWORD WINAPI +PrinterMessageBoxW(HANDLE hPrinter, DWORD Error, HWND hWnd, LPWSTR pText, LPWSTR pCaption, DWORD dwType) +{ + return 50; +} + +BOOL WINAPI +QueryColorProfile( + HANDLE hPrinter, + PDEVMODEW pdevmode, + ULONG ulQueryMode, + VOID *pvProfileData, + ULONG *pcbProfileData, + FLONG *pflProfileData ) +{ + PSPOOLER_HANDLE pHandle = (PSPOOLER_HANDLE)hPrinter; + BOOL Ret = FALSE; + HMODULE hLibrary; + + FIXME("QueryColorProfile(%p, %p, %l, %p, %p, %p)\n", hPrinter, pdevmode, ulQueryMode, pvProfileData, pcbProfileData, pflProfileData); + + if ( pHandle->bNoColorProfile ) + { + Ret = (BOOL)SP_ERROR; + } + else + { + + if ( pdevmode ) + { + if (!IsValidDevmodeNoSizeW( pdevmode ) ) + { + ERR("DeviceCapabilitiesW : Devode Invalid"); + return FALSE; + } + } + + hLibrary = LoadPrinterDriver( hPrinter ); + + if ( hLibrary ) + { + fpQueryColorProfile = (PVOID)GetProcAddress( hLibrary, "DrvQueryColorProfile" ); + + if ( fpQueryColorProfile ) + { + Ret = fpQueryColorProfile( hPrinter, pdevmode, ulQueryMode, pvProfileData, pcbProfileData, pflProfileData ); + } + else + { + pHandle->bNoColorProfile = TRUE; + Ret = (BOOL)SP_ERROR; + } + + FreeLibrary(hLibrary); + } + } + return Ret; +} + +// Note from GDI32:printdrv.c +// +// QuerySpoolMode : +// BOOL return TRUE if successful. +// dlFont 0x0001 for Downloading fonts. 0x0002 unknown XPS_PASS?. +// dwVersion is version of EMFSPOOL. Must be 0x00010000. See [MS-EMFSPOOL] page 18. +// + +#define QSM_DOWNLOADINGFONTS 0x0001 + +/* + Note from MSDN : "V4 print drivers using RAW mode to send PCL/Postscript have 0 byte spool file" + + Use XPS_PASS instead of RAW to pass information directly to the print filter pipeline in + v4 and v3 XPSDrv drivers. Here's how to proceed with Windows 8: + + Call GetPrinterDriver to retrieve the DRIVER_INFO_8 structure. + Check DRIVER_INFO_8::dwPrinterDriverAttributes for the PRINTER_DRIVER_XPS flag. + Choose your datatype based on the presence or absence of the flag: + If the flag is set, use XPS_PASS. + If the flag isn't set, use RAW. + */ + +#define QSM_XPS_PASS 0x0002 // Guessing. PRINTER_DRIVER_XPS? + +BOOL WINAPI +QuerySpoolMode( HANDLE hPrinter, PDWORD downloadFontsFlags, PDWORD dwVersion ) +{ + PRINTER_INFO_2W *pi2 = NULL; + DWORD needed = 0; + BOOL res; + + FIXME("QuerySpoolMode(%p, %p, %p)\n", hPrinter, downloadFontsFlags, dwVersion); + + res = GetPrinterW( hPrinter, 2, NULL, 0, &needed); + if (!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) + { + pi2 = HeapAlloc(hProcessHeap, 0, needed); + res = GetPrinterW(hPrinter, 2, (LPBYTE)pi2, needed, &needed); + } + + if ( res ) + { + *dwVersion = 0x10000; + *downloadFontsFlags = 0; + + if ( pi2->pServerName ) + { + *downloadFontsFlags |= QSM_DOWNLOADINGFONTS; + } + } +// +// Guessing,,, +// To do : Add GetPrinterDriver for DRIVER_INFO_8, test PRINTER_DRIVER_XPS flag, +// to set *downloadFontsFlags |= QSM_XPS_PASS; +// +// Vista+ looks for QSM_XPS_PASS to be set in GDI32. +// + HeapFree(hProcessHeap, 0, pi2); + return res; +} + +// +// This requires IC support. +// +DWORD WINAPI +QueryRemoteFonts( HANDLE hPrinter, PUNIVERSAL_FONT_ID pufi, ULONG NumberOfUFIs ) +{ + HANDLE hIC; + DWORD Result = -1, cOut, cIn = 0; + PBYTE pOut; + + FIXME("QueryRemoteFonts(%p, %p, %lu)\n", hPrinter, pufi, NumberOfUFIs); + + hIC = CreatePrinterIC( hPrinter, NULL ); + if ( hIC ) + { + cOut = (NumberOfUFIs * sizeof(UNIVERSAL_FONT_ID)) + sizeof(DWORD); // Include "DWORD" first part to return size. + + pOut = HeapAlloc( hProcessHeap, 0, cOut ); + if ( pOut ) + { + if ( PlayGdiScriptOnPrinterIC( hIC, (LPBYTE)&cIn, sizeof(DWORD), pOut, cOut, 0 ) ) + { + cIn = *((PDWORD)pOut); // Fisrt part is the size of the UFID object. + + Result = cIn; // Return the required size. + + if( NumberOfUFIs < cIn ) + { + cIn = NumberOfUFIs; + } + // Copy whole object back to GDI32, exclude first DWORD part. + memcpy( pufi, pOut + sizeof(DWORD), cIn * sizeof(UNIVERSAL_FONT_ID) ); + } + HeapFree( hProcessHeap, 0, pOut ); + } + DeletePrinterIC( hIC ); + } + return Result; +} + BOOL WINAPI ReadPrinter(HANDLE hPrinter, PVOID pBuf, DWORD cbBuf, PDWORD pNoBytesRead) { @@ -2192,9 +2893,41 @@ Cleanup: BOOL WINAPI ResetPrinterA(HANDLE hPrinter, PPRINTER_DEFAULTSA pDefault) { + BOOL ret; + UNICODE_STRING pNameW; + PDEVMODEW pdmw = NULL; + PPRINTER_DEFAULTSW pdw = (PPRINTER_DEFAULTSW)pDefault; + TRACE("ResetPrinterA(%p, %p)\n", hPrinter, pDefault); - UNIMPLEMENTED; - return FALSE; + + if ( pDefault->pDatatype == (LPSTR)-1 ) + { + pdw->pDatatype = (LPWSTR)-1; + } + else + { + pdw->pDatatype = AsciiToUnicode( &pNameW, pDefault->pDatatype ); + } + if ( pDefault->pDevMode == (LPDEVMODEA)-1) + { + pdw->pDevMode = (LPDEVMODEW)-1; + } + else + { + if ( pDefault->pDevMode )//&& IsValidDevmodeNoSizeW( pDefault->pDevMode ) ) + { + RosConvertAnsiDevModeToUnicodeDevmode( pDefault->pDevMode, &pdmw ); + pdw->pDevMode = pdmw; + } + } + + ret = ResetPrinterW( hPrinter, pdw ); + + if (pdmw) HeapFree(hProcessHeap, 0, pdmw); + + RtlFreeUnicodeString( &pNameW ); + + return ret; } BOOL WINAPI @@ -2354,17 +3087,323 @@ Cleanup: BOOL WINAPI SetPrinterA(HANDLE hPrinter, DWORD Level, PBYTE pPrinter, DWORD Command) { - TRACE("SetPrinterA(%p, %lu, %p, %lu)\n", hPrinter, Level, pPrinter, Command); - UNIMPLEMENTED; - return FALSE; + BOOL Ret = FALSE; + UNICODE_STRING usBuffer; + PPRINTER_INFO_STRESS ppisa = (PPRINTER_INFO_STRESS)pPrinter; + PPRINTER_INFO_STRESS ppisw = (PPRINTER_INFO_STRESS)pPrinter; + PPRINTER_INFO_2A ppi2a = (PPRINTER_INFO_2A)pPrinter; + PPRINTER_INFO_2W ppi2w = (PPRINTER_INFO_2W)pPrinter; + PPRINTER_INFO_7A ppi7a = (PPRINTER_INFO_7A)pPrinter; + PPRINTER_INFO_7W ppi7w = (PPRINTER_INFO_7W)pPrinter; + PPRINTER_INFO_9A ppi9a = (PPRINTER_INFO_9A)pPrinter; + PPRINTER_INFO_9W ppi9w = (PPRINTER_INFO_9W)pPrinter; + PWSTR pwszPrinterName = NULL; + PWSTR pwszServerName = NULL; + PWSTR pwszShareName = NULL; + PWSTR pwszPortName = NULL; + PWSTR pwszDriverName = NULL; + PWSTR pwszComment = NULL; + PWSTR pwszLocation = NULL; + PWSTR pwszSepFile = NULL; + PWSTR pwszPrintProcessor = NULL; + PWSTR pwszDatatype = NULL; + PWSTR pwszParameters = NULL; + PDEVMODEW pdmw = NULL; + + FIXME("SetPrinterA(%p, %lu, %p, %lu)\n", hPrinter, Level, pPrinter, Command); + + switch ( Level ) + { + case 0: + if ( Command == 0 ) + { + if (ppisa->pPrinterName) + { + pwszPrinterName = AsciiToUnicode(&usBuffer, (LPCSTR)ppisa->pPrinterName); + if (!(ppisw->pPrinterName = pwszPrinterName)) goto Cleanup; + } + if (ppisa->pServerName) + { + pwszServerName = AsciiToUnicode(&usBuffer, (LPCSTR)ppisa->pServerName); + if (!(ppisw->pPrinterName = pwszServerName)) goto Cleanup; + } + } + if ( Command == PRINTER_CONTROL_SET_STATUS ) + { + // Set the pPrinter parameter to a pointer to a DWORD value that specifies the new printer status. + PRINTER_INFO_6 pi6; + pi6.dwStatus = (DWORD)pPrinter; + pPrinter = (LPBYTE)&pi6; + Level = 6; + Command = 0; + } + break; + case 2: + { + if (ppi2a->pShareName) + { + pwszShareName = AsciiToUnicode(&usBuffer, ppi2a->pShareName); + if (!(ppi2w->pShareName = pwszShareName)) goto Cleanup; + } + if (ppi2a->pPortName) + { + pwszPortName = AsciiToUnicode(&usBuffer, ppi2a->pPortName); + if (!(ppi2w->pPortName = pwszPortName)) goto Cleanup; + } + if (ppi2a->pDriverName) + { + pwszDriverName = AsciiToUnicode(&usBuffer, ppi2a->pDriverName); + if (!(ppi2w->pDriverName = pwszDriverName)) goto Cleanup; + } + if (ppi2a->pComment) + { + pwszComment = AsciiToUnicode(&usBuffer, ppi2a->pComment); + if (!(ppi2w->pComment = pwszComment)) goto Cleanup; + } + if (ppi2a->pLocation) + { + pwszLocation = AsciiToUnicode(&usBuffer, ppi2a->pLocation); + if (!(ppi2w->pLocation = pwszLocation)) goto Cleanup; + } + if (ppi2a->pSepFile) + { + pwszSepFile = AsciiToUnicode(&usBuffer, ppi2a->pSepFile); + if (!(ppi2w->pSepFile = pwszSepFile)) goto Cleanup; + } + if (ppi2a->pServerName) + { + pwszPrintProcessor = AsciiToUnicode(&usBuffer, ppi2a->pPrintProcessor); + if (!(ppi2w->pPrintProcessor = pwszPrintProcessor)) goto Cleanup; + } + if (ppi2a->pDatatype) + { + pwszDatatype = AsciiToUnicode(&usBuffer, ppi2a->pDatatype); + if (!(ppi2w->pDatatype = pwszDatatype)) goto Cleanup; + } + if (ppi2a->pParameters) + { + pwszParameters = AsciiToUnicode(&usBuffer, ppi2a->pParameters); + if (!(ppi2w->pParameters = pwszParameters)) goto Cleanup; + } + + if ( ppi2a->pDevMode ) + { + RosConvertAnsiDevModeToUnicodeDevmode( ppi2a->pDevMode, &pdmw ); + ppi2w->pDevMode = pdmw; + } + } + // + // These two strings are relitive and common to these three Levels. + // Fall through... + // + case 4: + case 5: + { + if (ppi2a->pServerName) // 4 & 5 : pPrinterName. + { + pwszServerName = AsciiToUnicode(&usBuffer, ppi2a->pServerName); + if (!(ppi2w->pPrinterName = pwszServerName)) goto Cleanup; + } + if (ppi2a->pPrinterName) // 4 : pServerName, 5 : pPortName. + { + pwszPrinterName = AsciiToUnicode(&usBuffer, ppi2a->pPrinterName); + if (!(ppi2w->pPrinterName = pwszPrinterName)) goto Cleanup; + } + } + break; + case 3: + case 6: + break; + case 7: + { + if (ppi7a->pszObjectGUID) + { + pwszPrinterName = AsciiToUnicode(&usBuffer, ppi7a->pszObjectGUID); + if (!(ppi7w->pszObjectGUID = pwszPrinterName)) goto Cleanup; + } + } + break; + + case 8: + /* 8 is the global default printer info and 9 already sets it instead of the per-user one */ + /* still, PRINTER_INFO_8W is the same as PRINTER_INFO_9W */ + /* fall through */ + case 9: + { + RosConvertAnsiDevModeToUnicodeDevmode( ppi9a->pDevMode, &pdmw ); + ppi9w->pDevMode = pdmw; + } + break; + + default: + FIXME( "Unsupported level %d\n", Level); + SetLastError( ERROR_INVALID_LEVEL ); + } + + Ret = SetPrinterW( hPrinter, Level, pPrinter, Command ); + +Cleanup: + if (pdmw) HeapFree(hProcessHeap, 0, pdmw); + if (pwszPrinterName) HeapFree(hProcessHeap, 0, pwszPrinterName); + if (pwszServerName) HeapFree(hProcessHeap, 0, pwszServerName); + if (pwszShareName) HeapFree(hProcessHeap, 0, pwszShareName); + if (pwszPortName) HeapFree(hProcessHeap, 0, pwszPortName); + if (pwszDriverName) HeapFree(hProcessHeap, 0, pwszDriverName); + if (pwszComment) HeapFree(hProcessHeap, 0, pwszComment); + if (pwszLocation) HeapFree(hProcessHeap, 0, pwszLocation); + if (pwszSepFile) HeapFree(hProcessHeap, 0, pwszSepFile); + if (pwszPrintProcessor) HeapFree(hProcessHeap, 0, pwszPrintProcessor); + if (pwszDatatype) HeapFree(hProcessHeap, 0, pwszDatatype); + if (pwszParameters) HeapFree(hProcessHeap, 0, pwszParameters); + return Ret; } BOOL WINAPI SetPrinterW(HANDLE hPrinter, DWORD Level, PBYTE pPrinter, DWORD Command) { - TRACE("SetPrinterW(%p, %lu, %p, %lu)\n", hPrinter, Level, pPrinter, Command); - UNIMPLEMENTED; - return FALSE; + DWORD dwErrorCode; + WINSPOOL_PRINTER_CONTAINER PrinterContainer; + WINSPOOL_DEVMODE_CONTAINER DevModeContainer; + WINSPOOL_SECURITY_CONTAINER SecurityContainer; + SECURITY_DESCRIPTOR *sd = NULL; + DWORD size; + PSPOOLER_HANDLE pHandle = (PSPOOLER_HANDLE)hPrinter; + + FIXME("SetPrinterW(%p, %lu, %p, %lu)\n", hPrinter, Level, pPrinter, Command); + + // Sanity checks + if (!pHandle) + return ERROR_INVALID_HANDLE; + + DevModeContainer.cbBuf = 0; + DevModeContainer.pDevMode = NULL; + + SecurityContainer.cbBuf = 0; + SecurityContainer.pSecurity = NULL; + + switch ( Level ) + { + case 0: + if ( Command == PRINTER_CONTROL_SET_STATUS ) + { + // Set the pPrinter parameter to a pointer to a DWORD value that specifies the new printer status. + PRINTER_INFO_6 pi6; + pi6.dwStatus = (DWORD)pPrinter; + pPrinter = (LPBYTE)&pi6; + Level = 6; + Command = 0; + } + break; + case 2: + { + PPRINTER_INFO_2W pi2w = (PPRINTER_INFO_2W)pPrinter; + if ( pi2w ) + { + if ( pi2w->pDevMode ) + { + if ( IsValidDevmodeNoSizeW( pi2w->pDevMode ) ) + { + DevModeContainer.cbBuf = pi2w->pDevMode->dmSize + pi2w->pDevMode->dmDriverExtra; + DevModeContainer.pDevMode = (PBYTE)pi2w->pDevMode; + } + } + + if ( pi2w->pSecurityDescriptor ) + { + sd = get_sd( pi2w->pSecurityDescriptor, &size ); + if ( sd ) + { + SecurityContainer.cbBuf = size; + SecurityContainer.pSecurity = (PBYTE)sd; + } + } + } + else + { + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + } + break; + case 3: + { + PPRINTER_INFO_3 pi3 = (PPRINTER_INFO_3)pPrinter; + if ( pi3 ) + { + if ( pi3->pSecurityDescriptor ) + { + sd = get_sd( pi3->pSecurityDescriptor, &size ); + if ( sd ) + { + SecurityContainer.cbBuf = size; + SecurityContainer.pSecurity = (PBYTE)sd; + } + } + } + else + { + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + } + break; + + case 4: + case 5: + case 6: + case 7: + if ( pPrinter == NULL ) + { + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + break; + + case 8: + /* 8 is the global default printer info and 9 already sets it instead of the per-user one */ + /* still, PRINTER_INFO_8W is the same as PRINTER_INFO_9W */ + /* fall through */ + case 9: + { + PPRINTER_INFO_9W pi9w = (PPRINTER_INFO_9W)pPrinter; + if ( pi9w ) + { + if ( pi9w->pDevMode ) + { + if ( IsValidDevmodeNoSizeW( pi9w->pDevMode ) ) + { + DevModeContainer.cbBuf = pi9w->pDevMode->dmSize + pi9w->pDevMode->dmDriverExtra; + DevModeContainer.pDevMode = (LPBYTE)pi9w->pDevMode; + } + } + } + } + break; + + default: + FIXME( "Unsupported level %d\n", Level ); + SetLastError( ERROR_INVALID_LEVEL ); + return FALSE; + } + + PrinterContainer.PrinterInfo.pPrinterInfo1 = (WINSPOOL_PRINTER_INFO_1*)pPrinter; + PrinterContainer.Level = Level; + + // Do the RPC call + RpcTryExcept + { + dwErrorCode = _RpcSetPrinter(pHandle->hPrinter, &PrinterContainer, &DevModeContainer, &SecurityContainer, Command); + } + RpcExcept(EXCEPTION_EXECUTE_HANDLER) + { + dwErrorCode = RpcExceptionCode(); + } + RpcEndExcept; + + if ( sd ) HeapFree( GetProcessHeap(), 0, sd ); + + SetLastError(dwErrorCode); + return (dwErrorCode == ERROR_SUCCESS); } BOOL WINAPI @@ -2374,6 +3413,219 @@ SplDriverUnloadComplete(LPWSTR pDriverFile) UNIMPLEMENTED; return TRUE; // return true for now. } +BOOL WINAPI + +SpoolerPrinterEvent( LPWSTR pPrinterName, INT DriverEvent, DWORD Flags, LPARAM lParam ) +{ + HMODULE hLibrary; + HANDLE hPrinter; + BOOL Ret = FALSE; + + if ( OpenPrinterW( pPrinterName, &hPrinter, NULL ) ) + { + hLibrary = LoadPrinterDriver( hPrinter ); + + if ( hLibrary ) + { + fpPrinterEvent = (PVOID)GetProcAddress( hLibrary, "DrvPrinterEvent" ); + + if ( fpPrinterEvent ) + { + Ret = fpPrinterEvent( pPrinterName, DriverEvent, Flags, lParam ); + } + + FreeLibrary(hLibrary); + } + + ClosePrinter( hPrinter ); + } + + return Ret; +} + +INT_PTR CALLBACK file_dlg_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) +{ + LPWSTR filename; + + switch(msg) + { + case WM_INITDIALOG: + SetWindowLongPtrW(hwnd, DWLP_USER, lparam); + return TRUE; + + case WM_COMMAND: + if(HIWORD(wparam) == BN_CLICKED) + { + if(LOWORD(wparam) == IDOK) + { + HANDLE hf; + DWORD len = SendDlgItemMessageW(hwnd, EDITBOX, WM_GETTEXTLENGTH, 0, 0); + LPWSTR *output; + + filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR)); + GetDlgItemTextW(hwnd, EDITBOX, filename, len + 1); + + if(GetFileAttributesW(filename) != INVALID_FILE_ATTRIBUTES) + { + WCHAR caption[200], message[200]; + int mb_ret; + + LoadStringW(hinstWinSpool, IDS_CAPTION, caption, ARRAYSIZE(caption)); + LoadStringW(hinstWinSpool, IDS_FILE_EXISTS, message, ARRAYSIZE(message)); + mb_ret = MessageBoxW(hwnd, message, caption, MB_OKCANCEL | MB_ICONEXCLAMATION); + if(mb_ret == IDCANCEL) + { + HeapFree(GetProcessHeap(), 0, filename); + return TRUE; + } + } + hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); + if(hf == INVALID_HANDLE_VALUE) + { + WCHAR caption[200], message[200]; + + LoadStringW(hinstWinSpool, IDS_CAPTION, caption, ARRAYSIZE(caption)); + LoadStringW(hinstWinSpool, IDS_CANNOT_OPEN, message, ARRAYSIZE(message)); + MessageBoxW(hwnd, message, caption, MB_OK | MB_ICONEXCLAMATION); + HeapFree(GetProcessHeap(), 0, filename); + return TRUE; + } + CloseHandle(hf); + DeleteFileW(filename); + output = (LPWSTR *)GetWindowLongPtrW(hwnd, DWLP_USER); + *output = filename; + EndDialog(hwnd, IDOK); + return TRUE; + } + if(LOWORD(wparam) == IDCANCEL) + { + EndDialog(hwnd, IDCANCEL); + return TRUE; + } + } + return FALSE; + } + return FALSE; +} + +static const WCHAR FILE_Port[] = {'F','I','L','E',':',0}; + +LPWSTR WINAPI +StartDocDlgW( HANDLE hPrinter, DOCINFOW *doc ) +{ + LPWSTR ret = NULL; + DWORD len, attr, retDlg; + + FIXME("StartDocDlgW(%p, %p)\n", hPrinter, doc); + + if (doc->lpszOutput == NULL) /* Check whether default port is FILE: */ + { + PRINTER_INFO_5W *pi5; + GetPrinterW(hPrinter, 5, NULL, 0, &len); + if(GetLastError() != ERROR_INSUFFICIENT_BUFFER) + return NULL; + pi5 = HeapAlloc(GetProcessHeap(), 0, len); + GetPrinterW(hPrinter, 5, (LPBYTE)pi5, len, &len); + if (!pi5->pPortName || wcsicmp(pi5->pPortName, FILE_Port)) + { + HeapFree(GetProcessHeap(), 0, pi5); + return NULL; + } + HeapFree(GetProcessHeap(), 0, pi5); + } + + if (doc->lpszOutput == NULL || !wcsicmp(doc->lpszOutput, FILE_Port)) + { + LPWSTR name; + + retDlg = DialogBoxParamW( hinstWinSpool, + MAKEINTRESOURCEW(FILENAME_DIALOG), + GetForegroundWindow(), + file_dlg_proc, + (LPARAM)&name ); + + if ( retDlg == IDOK ) + { + if (!(len = GetFullPathNameW(name, 0, NULL, NULL))) + { + HeapFree(GetProcessHeap(), 0, name); + return NULL; + } + ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); + GetFullPathNameW(name, len, ret, NULL); + HeapFree(GetProcessHeap(), 0, name); + } + else if ( retDlg == 0 ) // FALSE, some type of error occurred. + { + ret = (LPWSTR)SP_ERROR; + } + else if ( retDlg == IDCANCEL ) + { + SetLastError( ERROR_CANCELLED ); + ret = (LPWSTR)SP_APPABORT; + } + return ret; + } + + if (!(len = GetFullPathNameW(doc->lpszOutput, 0, NULL, NULL))) + return NULL; + + ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); + GetFullPathNameW(doc->lpszOutput, len, ret, NULL); + + attr = GetFileAttributesW(ret); + if (attr != INVALID_FILE_ATTRIBUTES && (attr & FILE_ATTRIBUTE_DIRECTORY)) + { + HeapFree(GetProcessHeap(), 0, ret); + ret = NULL; + } + return ret; +} + +LPSTR WINAPI +StartDocDlgA( HANDLE hPrinter, DOCINFOA *doc ) +{ + UNICODE_STRING usBuffer; + DOCINFOW docW = { 0 }; + LPWSTR retW; + LPWSTR docnameW = NULL, outputW = NULL, datatypeW = NULL; + LPSTR ret = NULL; + + docW.cbSize = sizeof(docW); + if (doc->lpszDocName) + { + docnameW = AsciiToUnicode(&usBuffer, doc->lpszDocName); + if (!(docW.lpszDocName = docnameW)) goto failed; + } + if (doc->lpszOutput) + { + outputW = AsciiToUnicode(&usBuffer, doc->lpszOutput); + if (!(docW.lpszOutput = outputW)) goto failed; + } + if (doc->lpszDatatype) + { + datatypeW = AsciiToUnicode(&usBuffer, doc->lpszDatatype); + if (!(docW.lpszDatatype = datatypeW)) goto failed; + } + docW.fwType = doc->fwType; + + retW = StartDocDlgW(hPrinter, &docW); + + if (retW) + { + DWORD len = WideCharToMultiByte(CP_ACP, 0, retW, -1, NULL, 0, NULL, NULL); + ret = HeapAlloc(GetProcessHeap(), 0, len); + WideCharToMultiByte(CP_ACP, 0, retW, -1, ret, len, NULL, NULL); + HeapFree(GetProcessHeap(), 0, retW); + } + +failed: + if (datatypeW) HeapFree(GetProcessHeap(), 0, datatypeW); + if (outputW) HeapFree(GetProcessHeap(), 0, outputW); + if (docnameW) HeapFree(GetProcessHeap(), 0, docnameW); + + return ret; +} DWORD WINAPI StartDocPrinterA(HANDLE hPrinter, DWORD Level, PBYTE pDocInfo) @@ -2396,6 +3648,7 @@ StartDocPrinterA(HANDLE hPrinter, DWORD Level, PBYTE pDocInfo) if (Level != 1) { + ERR("Level = %d, unsupported!\n", Level); dwErrorCode = ERROR_INVALID_LEVEL; goto Cleanup; } @@ -2493,6 +3746,7 @@ StartDocPrinterW(HANDLE hPrinter, DWORD Level, PBYTE pDocInfo) if (Level != 1) { + ERR("Level = %d, unsupported!\n", Level); dwErrorCode = ERROR_INVALID_LEVEL; goto Cleanup; } @@ -2546,6 +3800,10 @@ StartDocPrinterW(HANDLE hPrinter, DWORD Level, PBYTE pDocInfo) { pHandle->bStartedDoc = TRUE; dwReturnValue = pHandle->dwJobID; + if ( !pHandle->bTrayIcon ) + { + FIXME("Notify Tray Icon\n"); + } } Cleanup: diff --git a/win32ss/printing/base/winspool/printprocessors.c b/win32ss/printing/base/winspool/printprocessors.c index 9283eeb788f..d40d81e4523 100644 --- a/win32ss/printing/base/winspool/printprocessors.c +++ b/win32ss/printing/base/winspool/printprocessors.c @@ -12,33 +12,89 @@ BOOL WINAPI AddPrintProcessorA(PSTR pName, PSTR pEnvironment, PSTR pPathName, PSTR pPrintProcessorName) { + UNICODE_STRING NameW, EnvW, PathW, ProcessorW; + BOOL Ret; + TRACE("AddPrintProcessorA(%s, %s, %s, %s)\n", pName, pEnvironment, pPathName, pPrintProcessorName); - UNIMPLEMENTED; - return FALSE; + + AsciiToUnicode(&NameW, pName); + AsciiToUnicode(&EnvW, pEnvironment); + AsciiToUnicode(&PathW, pPathName); + AsciiToUnicode(&ProcessorW, pPrintProcessorName); + + Ret = AddPrintProcessorW(NameW.Buffer, EnvW.Buffer, PathW.Buffer, ProcessorW.Buffer); + + RtlFreeUnicodeString(&ProcessorW); + RtlFreeUnicodeString(&PathW); + RtlFreeUnicodeString(&EnvW); + RtlFreeUnicodeString(&NameW); + + return Ret; } BOOL WINAPI AddPrintProcessorW(PWSTR pName, PWSTR pEnvironment, PWSTR pPathName, PWSTR pPrintProcessorName) { + DWORD dwErrorCode; + TRACE("AddPrintProcessorW(%S, %S, %S, %S)\n", pName, pEnvironment, pPathName, pPrintProcessorName); - UNIMPLEMENTED; - return FALSE; + + RpcTryExcept + { + dwErrorCode = _RpcAddPrintProcessor( pName, pEnvironment, pPathName, pPrintProcessorName ); + } + RpcExcept(EXCEPTION_EXECUTE_HANDLER) + { + dwErrorCode = RpcExceptionCode(); + ERR("_RpcPrintProcessor failed with exception code %lu!\n", dwErrorCode); + } + RpcEndExcept; + + SetLastError(dwErrorCode); + return (dwErrorCode == ERROR_SUCCESS); } BOOL WINAPI DeletePrintProcessorA(PSTR pName, PSTR pEnvironment, PSTR pPrintProcessorName) { + UNICODE_STRING NameW, EnvW, ProcessorW; + BOOL Ret; + TRACE("DeletePrintProcessorA(%s, %s, %s)\n", pName, pEnvironment, pPrintProcessorName); - UNIMPLEMENTED; - return FALSE; + + AsciiToUnicode(&NameW, pName); + AsciiToUnicode(&EnvW, pEnvironment); + AsciiToUnicode(&ProcessorW, pPrintProcessorName); + + Ret = DeletePrintProcessorW(NameW.Buffer, EnvW.Buffer, ProcessorW.Buffer); + + RtlFreeUnicodeString(&ProcessorW); + RtlFreeUnicodeString(&EnvW); + RtlFreeUnicodeString(&NameW); + + return Ret; } BOOL WINAPI DeletePrintProcessorW(PWSTR pName, PWSTR pEnvironment, PWSTR pPrintProcessorName) { + DWORD dwErrorCode; + TRACE("DeletePrintProcessorW(%S, %S, %S)\n", pName, pEnvironment, pPrintProcessorName); - UNIMPLEMENTED; - return FALSE; + + RpcTryExcept + { + dwErrorCode = _RpcDeletePrintProcessor( pName, pEnvironment, pPrintProcessorName ); + } + RpcExcept(EXCEPTION_EXECUTE_HANDLER) + { + dwErrorCode = RpcExceptionCode(); + ERR("_RpcDeletePrintProcessor failed with exception code %lu!\n", dwErrorCode); + } + RpcEndExcept; + + SetLastError(dwErrorCode); + return (dwErrorCode == ERROR_SUCCESS); } BOOL WINAPI @@ -89,9 +145,115 @@ Cleanup: BOOL WINAPI EnumPrintProcessorsA(PSTR pName, PSTR pEnvironment, DWORD Level, PBYTE pPrintProcessorInfo, DWORD cbBuf, PDWORD pcbNeeded, PDWORD pcReturned) { - TRACE("EnumPrintProcessorsA(%s, %s, %lu, %p, %lu, %p, %p)\n", pName, pEnvironment, Level, pPrintProcessorInfo, cbBuf, pcbNeeded, pcReturned); - UNIMPLEMENTED; - return FALSE; + BOOL res; + LPBYTE bufferW = NULL; + LPWSTR nameW = NULL; + LPWSTR envW = NULL; + DWORD needed = 0; + DWORD numentries = 0; + INT len; + + TRACE("EnumPrintProcessorsA(%s, %s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), debugstr_a(pEnvironment), Level, pPrintProcessorInfo, cbBuf, pcbNeeded, pcReturned); + + /* convert names to unicode */ + if (pName) + { + len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0); + nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); + MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len); + } + if (pEnvironment) + { + len = MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, NULL, 0); + envW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); + MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, envW, len); + } + + /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */ + needed = cbBuf * sizeof(WCHAR); + if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed); + res = EnumPrintProcessorsW(nameW, envW, Level, bufferW, needed, pcbNeeded, pcReturned); + + if (!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) + { + if (pcbNeeded) needed = *pcbNeeded; + /* HeapReAlloc return NULL, when bufferW was NULL */ + bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) : + HeapAlloc(GetProcessHeap(), 0, needed); + + /* Try again with the large Buffer */ + res = EnumPrintProcessorsW(nameW, envW, Level, bufferW, needed, pcbNeeded, pcReturned); + } + numentries = pcReturned ? *pcReturned : 0; + needed = 0; + + if (res) + { + /* EnumPrintProcessorsW collected all Data. Parse them to calculate ANSI-Size */ + DWORD index; + LPSTR ptr; + PPRINTPROCESSOR_INFO_1W ppiw; + PPRINTPROCESSOR_INFO_1A ppia; + + /* First pass: calculate the size for all Entries */ + ppiw = (PPRINTPROCESSOR_INFO_1W) bufferW; + ppia = (PPRINTPROCESSOR_INFO_1A) pPrintProcessorInfo; + index = 0; + while (index < numentries) + { + index++; + needed += sizeof(PRINTPROCESSOR_INFO_1A); + TRACE("%p: parsing #%d (%s)\n", ppiw, index, debugstr_w(ppiw->pName)); + + needed += WideCharToMultiByte(CP_ACP, 0, ppiw->pName, -1, + NULL, 0, NULL, NULL); + + ppiw = (PPRINTPROCESSOR_INFO_1W) (((LPBYTE)ppiw) + sizeof(PRINTPROCESSOR_INFO_1W)); + ppia = (PPRINTPROCESSOR_INFO_1A) (((LPBYTE)ppia) + sizeof(PRINTPROCESSOR_INFO_1A)); + } + + /* check for errors and quit on failure */ + if (cbBuf < needed) + { + SetLastError(ERROR_INSUFFICIENT_BUFFER); + res = FALSE; + goto epp_cleanup; + } + + len = numentries * sizeof(PRINTPROCESSOR_INFO_1A); /* room for structs */ + ptr = (LPSTR) &pPrintProcessorInfo[len]; /* start of strings */ + cbBuf -= len ; /* free Bytes in the user-Buffer */ + ppiw = (PPRINTPROCESSOR_INFO_1W) bufferW; + ppia = (PPRINTPROCESSOR_INFO_1A) pPrintProcessorInfo; + index = 0; + /* Second Pass: Fill the User Buffer (if we have one) */ + while ((index < numentries) && pPrintProcessorInfo) + { + index++; + TRACE("%p: writing PRINTPROCESSOR_INFO_1A #%d\n", ppia, index); + ppia->pName = ptr; + len = WideCharToMultiByte(CP_ACP, 0, ppiw->pName, -1, + ptr, cbBuf , NULL, NULL); + ptr += len; + cbBuf -= len; + + ppiw = (PPRINTPROCESSOR_INFO_1W) (((LPBYTE)ppiw) + sizeof(PRINTPROCESSOR_INFO_1W)); + ppia = (PPRINTPROCESSOR_INFO_1A) (((LPBYTE)ppia) + sizeof(PRINTPROCESSOR_INFO_1A)); + + } + } +epp_cleanup: + if (pcbNeeded) *pcbNeeded = needed; + if (pcReturned) *pcReturned = (res) ? numentries : 0; + + HeapFree(GetProcessHeap(), 0, nameW); + HeapFree(GetProcessHeap(), 0, envW); + HeapFree(GetProcessHeap(), 0, bufferW); + + TRACE("returning %d with %d (%d byte for %d entries)\n", (res), GetLastError(), needed, numentries); + + return (res); + } BOOL WINAPI diff --git a/win32ss/printing/base/winspool/printproviders.c b/win32ss/printing/base/winspool/printproviders.c index 58efb89f202..ffeb5339e19 100644 --- a/win32ss/printing/base/winspool/printproviders.c +++ b/win32ss/printing/base/winspool/printproviders.c @@ -10,31 +10,152 @@ BOOL WINAPI AddPrintProvidorA(PSTR pName, DWORD Level, PBYTE pProviderInfo) { + LPWSTR nameW = NULL; + PROVIDOR_INFO_1W pi1W; + PROVIDOR_INFO_2W pi2W; + DWORD len; + BOOL res; + PBYTE pPI = NULL; + TRACE("AddPrintProvidorA(%s, %lu, %p)\n", pName, Level, pProviderInfo); - UNIMPLEMENTED; - return FALSE; + + ZeroMemory(&pi1W, sizeof(PROVIDOR_INFO_1W)); + pi2W.pOrder = NULL; + + switch (Level) + { + case 1: + { + PROVIDOR_INFO_1A *pi1A = (PROVIDOR_INFO_1A*)pProviderInfo; + if (pi1A->pName) + { + len = MultiByteToWideChar(CP_ACP, 0, pi1A->pName, -1, NULL, 0); + pi1W.pName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); + MultiByteToWideChar(CP_ACP, 0, pi1A->pName, -1, pi1W.pName, len); + } + if (pi1A->pEnvironment) + { + len = MultiByteToWideChar(CP_ACP, 0, pi1A->pEnvironment, -1, NULL, 0); + pi1W.pEnvironment = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); + MultiByteToWideChar(CP_ACP, 0, pi1A->pEnvironment, -1, pi1W.pEnvironment, len); + } + if (pi1A->pDLLName) + { + len = MultiByteToWideChar(CP_ACP, 0, pi1A->pDLLName, -1, NULL, 0); + pi1W.pDLLName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); + MultiByteToWideChar(CP_ACP, 0, pi1A->pDLLName, -1, pi1W.pDLLName, len); + } + pPI = (PBYTE)&pi1W; + } + break; + + case 2: + { + PROVIDOR_INFO_2A *pi2A = (PROVIDOR_INFO_2A*)pProviderInfo; + if (pi2A->pOrder) + { + len = MultiByteToWideChar(CP_ACP, 0, pi2A->pOrder, -1, NULL, 0); + pi2W.pOrder = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); + MultiByteToWideChar(CP_ACP, 0, pi2A->pOrder, -1, pi2W.pOrder, len); + } + pPI = (PBYTE)&pi2W; + } + break; + + default: + SetLastError(ERROR_INVALID_LEVEL); + return FALSE; + } + + if (pName) + { + len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0); + nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); + MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len); + } + + res = AddPrintProvidorW( nameW, Level, pPI ); + + if (pName) HeapFree(GetProcessHeap(), 0, nameW); + if (pi1W.pName) HeapFree(GetProcessHeap(), 0, pi1W.pName); + if (pi1W.pEnvironment) HeapFree(GetProcessHeap(), 0, pi1W.pEnvironment); + if (pi1W.pDLLName) HeapFree(GetProcessHeap(), 0, pi1W.pDLLName); + if (pi2W.pOrder) HeapFree(GetProcessHeap(), 0, pi2W.pOrder); + + return res; } BOOL WINAPI AddPrintProvidorW(PWSTR pName, DWORD Level, PBYTE pProviderInfo) { + DWORD dwErrorCode; + WINSPOOL_PROVIDOR_CONTAINER ProvidorContainer; + TRACE("AddPrintProvidorW(%S, %lu, %p)\n", pName, Level, pProviderInfo); - UNIMPLEMENTED; - return FALSE; + + if ((Level < 1) || (Level > 2)) + { + SetLastError(ERROR_INVALID_LEVEL); + return FALSE; + } + + ProvidorContainer.ProvidorInfo.pProvidorInfo1 = (WINSPOOL_PROVIDOR_INFO_1*)pProviderInfo; + ProvidorContainer.Level = Level; + + RpcTryExcept + { + dwErrorCode = _RpcAddPrintProvidor( pName, &ProvidorContainer ); + } + RpcExcept(EXCEPTION_EXECUTE_HANDLER) + { + dwErrorCode = RpcExceptionCode(); + ERR("_RpcEnumPorts failed with exception code %lu!\n", dwErrorCode); + } + RpcEndExcept; + + SetLastError(dwErrorCode); + return (dwErrorCode == ERROR_SUCCESS); } BOOL WINAPI DeletePrintProvidorA(PSTR pName, PSTR pEnvironment, PSTR pPrintProviderName) { + UNICODE_STRING NameW, EnvW, ProviderW; + BOOL Ret; + TRACE("DeletePrintProvidorW(%s, %s, %s)\n", pName, pEnvironment, pPrintProviderName); - UNIMPLEMENTED; - return FALSE; + + AsciiToUnicode(&NameW, pName); + AsciiToUnicode(&EnvW, pEnvironment); + AsciiToUnicode(&ProviderW, pPrintProviderName); + + Ret = DeletePrintProvidorW(NameW.Buffer, EnvW.Buffer, ProviderW.Buffer); + + RtlFreeUnicodeString(&ProviderW); + RtlFreeUnicodeString(&EnvW); + RtlFreeUnicodeString(&NameW); + + return Ret; } BOOL WINAPI DeletePrintProvidorW(PWSTR pName, PWSTR pEnvironment, PWSTR pPrintProviderName) { + DWORD dwErrorCode; + TRACE("DeletePrintProvidorW(%S, %S, %S)\n", pName, pEnvironment, pPrintProviderName); - UNIMPLEMENTED; - return FALSE; + + RpcTryExcept + { + dwErrorCode = _RpcDeletePrintProvidor( pName, pEnvironment, pPrintProviderName ); + } + RpcExcept(EXCEPTION_EXECUTE_HANDLER) + { + dwErrorCode = RpcExceptionCode(); + ERR("_RpcEnumPorts failed with exception code %lu!\n", dwErrorCode); + } + RpcEndExcept; + + SetLastError(dwErrorCode); + return (dwErrorCode == ERROR_SUCCESS); } diff --git a/win32ss/printing/base/winspool/spoolfile.c b/win32ss/printing/base/winspool/spoolfile.c new file mode 100644 index 00000000000..d40e090bccf --- /dev/null +++ b/win32ss/printing/base/winspool/spoolfile.c @@ -0,0 +1,154 @@ +/* + * PROJECT: ReactOS Spooler API + * LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+) + * PURPOSE: Functions related to Spool Files and printing + * COPYRIGHT: Copyright 1998-2020 ReactOS + */ + +#include "precomp.h" + + +HANDLE WINAPI +GetSpoolFileHandle( HANDLE hPrinter ) +{ + DWORD dwErrorCode, cpid; + WINSPOOL_FILE_INFO_CONTAINER FileInfoContainer; + WINSPOOL_FILE_INFO_1 wsplfi; + PSPOOLER_HANDLE pHandle = (PSPOOLER_HANDLE)hPrinter; + HANDLE hHandle = NULL; + + FIXME("GetSpoolFileHandle(%p)\n", hPrinter); + + if ( IntProtectHandle( hPrinter, FALSE ) ) + { + dwErrorCode = ERROR_INVALID_HANDLE; + } + else + { + if ( pHandle->hSpoolFileHandle != INVALID_HANDLE_VALUE ) + { + hHandle = pHandle->hSpoolFileHandle; + } + else + { + cpid = GetCurrentProcessId(); + + FileInfoContainer.Level = 1; + FileInfoContainer.FileInfo.pFileInfo1 = &wsplfi; + + // Do the RPC call. + RpcTryExcept + { + dwErrorCode = _RpcGetSpoolFileInfo2( &pHandle->hPrinter, cpid, 1, &FileInfoContainer ); + } + RpcExcept(EXCEPTION_EXECUTE_HANDLER) + { + dwErrorCode = RpcExceptionCode(); + ERR("_RpcGetSpoolFileInfo failed with exception code %lu!\n", dwErrorCode); + } + RpcEndExcept; + + if (dwErrorCode == ERROR_SUCCESS) + { + pHandle->hSpoolFileHandle = wsplfi.hSpoolFileHandle; + pHandle->dwOptions = wsplfi.dwOptions; + hHandle = pHandle->hSpoolFileHandle; + } + } + IntUnprotectHandle(pHandle); + } + SetLastError(dwErrorCode); + return hHandle; +} + +HANDLE WINAPI +CommitSpoolData( HANDLE hPrinter, HANDLE hSpoolFile, DWORD cbCommit ) +{ + DWORD dwErrorCode, cpid; + WINSPOOL_FILE_INFO_CONTAINER FileInfoContainer; + WINSPOOL_FILE_INFO_1 wsplfi; + PSPOOLER_HANDLE pHandle = (PSPOOLER_HANDLE)hPrinter; + HANDLE hHandle = INVALID_HANDLE_VALUE; + + FIXME("CommitSpoolData(%p, %p, %d)\n", hPrinter,hSpoolFile,cbCommit); + + if ( IntProtectHandle( hPrinter, FALSE ) ) + { + return hHandle; + } + + if ( pHandle->hSpoolFileHandle == INVALID_HANDLE_VALUE || pHandle->hSpoolFileHandle != hSpoolFile ) + { + dwErrorCode = ERROR_INVALID_HANDLE; + } + else + { + cpid = GetCurrentProcessId(); + + FileInfoContainer.Level = 1; + FileInfoContainer.FileInfo.pFileInfo1 = &wsplfi; + + // Do the RPC call. + RpcTryExcept + { + dwErrorCode = _RpcCommitSpoolData2( &pHandle->hPrinter, cpid, cbCommit, 1, &FileInfoContainer ); + } + RpcExcept(EXCEPTION_EXECUTE_HANDLER) + { + dwErrorCode = RpcExceptionCode(); + ERR("_RpcCommitSpoolData failed with exception code %lu!\n", dwErrorCode); + } + RpcEndExcept; + + if (dwErrorCode == ERROR_SUCCESS) + { + if ( wsplfi.hSpoolFileHandle != INVALID_HANDLE_VALUE ) + { + CloseHandle( pHandle->hSpoolFileHandle ); + pHandle->hSpoolFileHandle = wsplfi.hSpoolFileHandle; + } + hHandle = pHandle->hSpoolFileHandle; + } + IntUnprotectHandle(pHandle); + } + SetLastError(dwErrorCode); + return hHandle; +} + +BOOL WINAPI +CloseSpoolFileHandle( HANDLE hPrinter, HANDLE hSpoolFile ) +{ + DWORD dwErrorCode; + PSPOOLER_HANDLE pHandle = (PSPOOLER_HANDLE)hPrinter; + + FIXME("CloseSpoolFileHandle(%p, %p)\n", hPrinter,hSpoolFile); + + if ( IntProtectHandle( hPrinter, FALSE ) ) + { + return FALSE; + } + if ( pHandle->hSpoolFileHandle == hSpoolFile ) + { + CloseHandle( pHandle->hSpoolFileHandle ); + pHandle->hSpoolFileHandle = INVALID_HANDLE_VALUE; + + // Do the RPC call. + RpcTryExcept + { + dwErrorCode = _RpcCloseSpoolFileHandle( &pHandle->hPrinter ); + } + RpcExcept(EXCEPTION_EXECUTE_HANDLER) + { + dwErrorCode = RpcExceptionCode(); + ERR("_RpcloseSpoolFileHandle failed with exception code %lu!\n", dwErrorCode); + } + RpcEndExcept; + } + else + { + dwErrorCode = ERROR_INVALID_HANDLE; + } + IntUnprotectHandle(pHandle); + SetLastError(dwErrorCode); + return (dwErrorCode == ERROR_SUCCESS); +} diff --git a/win32ss/printing/base/winspool/utils.c b/win32ss/printing/base/winspool/utils.c index f16cd95d014..8dae057601b 100644 --- a/win32ss/printing/base/winspool/utils.c +++ b/win32ss/printing/base/winspool/utils.c @@ -52,3 +52,281 @@ DWORD UnicodeToAnsiInPlace(PWSTR pwszField) return ERROR_SUCCESS; } + +static int multi_sz_lenW(const WCHAR *str) +{ + const WCHAR *ptr = str; + if (!str) return 0; + do + { + ptr += lstrlenW(ptr) + 1; + } while (*ptr); + + return (ptr - str + 1);// * sizeof(WCHAR); wine does this. +} + +DWORD UnicodeToAnsiZZInPlace(PWSTR pwszzField) +{ + PSTR pszTemp; + INT len, lenW; + PSTR pszField = (PSTR)pwszzField; + + lenW = multi_sz_lenW(pwszzField); + if (lenW == 0) + { + return ERROR_SUCCESS; + } + + len = WideCharToMultiByte(CP_ACP, 0, pwszzField, lenW, NULL, 0, NULL, NULL); + + pszTemp = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); + + WideCharToMultiByte(CP_ACP, 0, pwszzField, lenW, pszTemp, len, NULL, NULL); + + StringCchCopyA(pszField, len, pszTemp); + + HeapFree(hProcessHeap, 0, pszTemp); + + return ERROR_SUCCESS; +} + +// +// Implement and simplify later. +// +LONG WINAPI +IntProtectHandle( HANDLE hSpooler, BOOL Close ) +{ + BOOL Bad = TRUE; + LONG Ret; + PSPOOLER_HANDLE pHandle; + + EnterCriticalSection(&rtlCritSec); + + _SEH2_TRY + { + pHandle = (PSPOOLER_HANDLE)hSpooler; + if ( pHandle && pHandle->Sig == SPOOLER_HANDLE_SIG ) + { + Bad = FALSE; // Not bad. + } + } + _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) + { + } + _SEH2_END; + + Ret = Bad; // Set return Level to 1 if we are BAD. + + if ( Bad ) + { + SetLastError(ERROR_INVALID_HANDLE); + ERR("IPH : Printer Handle failed!\n"); + } + else + { + if ( Close ) + { + if ( pHandle->bShared || pHandle->cCount != 0 ) + { + pHandle->bShared = TRUE; + Ret = 2; // Return a high level and we are shared. + FIXME("IPH Close : We are shared\n"); + } + else + { + pHandle->bClosed = TRUE; + FIXME("IPH Close : closing.\n"); + } + } + } + + if ( !Ret ) // Need to be Level 0. + { + pHandle->cCount++; + FIXME("IPH : Count %d\n",pHandle->cCount); + } + + LeaveCriticalSection(&rtlCritSec); + + // Return Level: + // 2 : Close and/or shared + // 1 : Failed Handle + // 0 : In use. + return Ret; +} +// +// This one too. +// +BOOL WINAPI +IntUnprotectHandle( HANDLE hSpooler ) +{ + BOOL Ret = FALSE; + PSPOOLER_HANDLE pHandle = (PSPOOLER_HANDLE)hSpooler; + EnterCriticalSection(&rtlCritSec); + if ( pHandle->bShared && --pHandle->cCount == 0 ) + { + pHandle->bClosed = TRUE; + pHandle->bShared = FALSE; + Ret = TRUE; + } + LeaveCriticalSection(&rtlCritSec); + FIXME("IUH : Count %d\n",pHandle->cCount); + if ( Ret ) + { +// ClosePrinterWorker( pHandle ); + } + return Ret; +} + +/** + * @name AllocSplStr + * + * Allocates memory for a Unicode string and copies the input string into it. + * Equivalent of wcsdup, but the returned buffer is allocated from the spooler heap and must be freed with DllFreeSplStr. + * + * @param pwszInput + * The input string to copy + * + * @return + * Pointer to the copied string or NULL if no memory could be allocated. + */ +PWSTR WINAPI +AllocSplStr(PCWSTR pwszInput) +{ + DWORD cbInput; + PWSTR pwszOutput; + + // Sanity check + if (!pwszInput) + return NULL; + + // Get the length of the input string. + cbInput = (wcslen(pwszInput) + 1) * sizeof(WCHAR); + + // Allocate it. We don't use DllAllocSplMem here, because it unnecessarily zeroes the memory. + pwszOutput = HeapAlloc(hProcessHeap, 0, cbInput); + if (!pwszOutput) + { + ERR("HeapAlloc failed!\n"); + return NULL; + } + + // Copy the string and return it. + CopyMemory(pwszOutput, pwszInput, cbInput); + return pwszOutput; +} + +/** + * @name DllAllocSplMem + * + * Allocate a block of zeroed memory. + * Windows allocates from a separate spooler heap here while we just use the process heap. + * + * @param dwBytes + * Number of bytes to allocate. + * + * @return + * A pointer to the allocated memory or NULL in case of an error. + * You have to free this memory using DllFreeSplMem. + */ +PVOID WINAPI +DllAllocSplMem(DWORD dwBytes) +{ + return HeapAlloc(hProcessHeap, HEAP_ZERO_MEMORY, dwBytes); +} + +/** + * @name DllFreeSplMem + * + * Frees the memory allocated with DllAllocSplMem. + * + * @param pMem + * Pointer to the allocated memory. + * + * @return + * TRUE in case of success, FALSE otherwise. + */ +BOOL WINAPI +DllFreeSplMem(PVOID pMem) +{ + if ( !pMem ) return TRUE; + return HeapFree(hProcessHeap, 0, pMem); +} + +/** + * @name DllFreeSplStr + * + * Frees the string allocated with AllocSplStr. + * + * @param pwszString + * Pointer to the allocated string. + * + * @return + * TRUE in case of success, FALSE otherwise. + */ +BOOL WINAPI +DllFreeSplStr(PWSTR pwszString) +{ + if ( pwszString ) + return HeapFree(hProcessHeap, 0, pwszString); + return FALSE; +} + +SECURITY_DESCRIPTOR * get_sd( SECURITY_DESCRIPTOR *sd, DWORD *size ) +{ + PSID sid_group, sid_owner; + ACL *sacl, *dacl; + BOOL bSet = FALSE, bSetd = FALSE, bSets = FALSE; + PSECURITY_DESCRIPTOR absolute_sd, retsd; + + if ( !IsValidSecurityDescriptor( sd ) ) + { + return NULL; + } + + InitializeSecurityDescriptor( &absolute_sd, SECURITY_DESCRIPTOR_REVISION ); + + if ( !GetSecurityDescriptorOwner( sd, &sid_owner, &bSet ) ) + { + return NULL; + } + + SetSecurityDescriptorOwner( &absolute_sd, sid_owner, bSet ); + + if ( !GetSecurityDescriptorGroup( sd, &sid_group, &bSet ) ) + { + return NULL; + } + + SetSecurityDescriptorGroup( &absolute_sd, sid_group, bSet ); + + if ( !GetSecurityDescriptorDacl( sd, &bSetd, &dacl, &bSet ) ) + { + return NULL; + } + + SetSecurityDescriptorDacl( &absolute_sd, bSetd, dacl, bSet ); + + if ( !GetSecurityDescriptorSacl( sd, &bSets, &sacl, &bSet ) ) + { + return(NULL); + } + + SetSecurityDescriptorSacl( &absolute_sd, bSets, sacl, bSet ); + + *size = GetSecurityDescriptorLength( &absolute_sd ); + + retsd = HeapAlloc( GetProcessHeap(), 0, *size ); + + if ( retsd ) + { + if ( !MakeSelfRelativeSD( &absolute_sd, retsd, size ) ) + { + HeapFree( GetProcessHeap(), 0, retsd ); + retsd = NULL; + } + } + + return retsd; +} + diff --git a/win32ss/printing/base/winspool/winspool.rc b/win32ss/printing/base/winspool/winspool.rc index c7b2a807239..e7db2a13c44 100644 --- a/win32ss/printing/base/winspool/winspool.rc +++ b/win32ss/printing/base/winspool/winspool.rc @@ -1,5 +1,35 @@ + +#include "precomp.h" + #define REACTOS_VERSION_DLL #define REACTOS_STR_FILE_DESCRIPTION "ReactOS Spooler API" #define REACTOS_STR_INTERNAL_NAME "winspool" #define REACTOS_STR_ORIGINAL_FILENAME "winspool.drv" #include + +#pragma makedep po + +LANGUAGE LANG_ENGLISH, SUBLANG_DEFAULT + +STRINGTABLE +{ + IDS_CAPTION "Local Port" + IDS_FILE_EXISTS "The output file already exists. Click OK to overwrite." + IDS_CANNOT_OPEN "Unable to create the output file." +} + +FILENAME_DIALOG DIALOG 6, 18, 245, 47 +STYLE DS_CONTEXTHELP | DS_MODALFRAME | DS_SETFONT | DS_SETFOREGROUND | WS_POPUPWINDOW | WS_VISIBLE | WS_CAPTION +CAPTION "Print to File" +FONT 8, "MS Shell Dlg" +BEGIN + LTEXT "&Output File Name:", -1, 7, 13, 194, 13, WS_VISIBLE + EDITTEXT EDITBOX, 6, 28, 174, 12, WS_VISIBLE | ES_AUTOHSCROLL + DEFPUSHBUTTON "OK", IDOK, 199, 10, 40, 14, WS_VISIBLE + PUSHBUTTON "Cancel", IDCANCEL, 199, 27, 40, 14, WS_VISIBLE +END + +LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL + +/* @makedep: generic.ppd */ +/*1 PPDFILE generic.ppd*/ diff --git a/win32ss/printing/base/winspool/winspool.spec b/win32ss/printing/base/winspool/winspool.spec index 419354dfc32..e459f5adbe4 100644 --- a/win32ss/printing/base/winspool/winspool.spec +++ b/win32ss/printing/base/winspool/winspool.spec @@ -5,7 +5,7 @@ 104 stub PerfClose 105 stub PerfCollect 106 stub PerfOpen -107 stub ADVANCEDSETUPDIALOG +107 stdcall ADVANCEDSETUPDIALOG(ptr long ptr ptr) AdvancedSetupDialog 108 stdcall AbortPrinter(ptr) 109 stdcall AddFormA(ptr long ptr) 110 stdcall AddFormW(ptr long ptr) @@ -31,18 +31,18 @@ 130 stdcall AddPrinterW(wstr long ptr) 131 stdcall AdvancedDocumentPropertiesA(ptr ptr str ptr ptr) 132 stdcall AdvancedDocumentPropertiesW(ptr ptr wstr ptr ptr) -133 stub AdvancedSetupDialog +133 stdcall AdvancedSetupDialog(ptr long ptr ptr) 134 stdcall ClosePrinter(ptr) -135 stub CloseSpoolFileHandle -136 stub CommitSpoolData +135 stdcall CloseSpoolFileHandle(ptr ptr) +136 stdcall CommitSpoolData(ptr ptr long) 137 stdcall ConfigurePortA(str ptr str) 138 stdcall ConfigurePortW(wstr ptr wstr) 139 stub ConnectToPrinterDlg 140 stub ConvertAnsiDevModeToUnicodeDevmode 141 stub ConvertUnicodeDevModeToAnsiDevmode -142 stub CreatePrinterIC -143 stub DEVICECAPABILITIES -144 stub DEVICEMODE +142 stdcall -stub CreatePrinterIC(ptr ptr) +143 stdcall DEVICECAPABILITIES(str str long ptr ptr) DeviceCapabilitiesA +144 stdcall DEVICEMODE(ptr ptr str ptr) DeviceMode 145 stdcall DeleteFormA(ptr str) 146 stdcall DeleteFormW(ptr wstr) 147 stdcall DeleteMonitorA(str str str) @@ -64,21 +64,21 @@ 163 stdcall DeletePrinterDriverExA(str str str long long) 164 stdcall DeletePrinterDriverExW(wstr wstr wstr long long) 165 stdcall DeletePrinterDriverW(wstr wstr wstr) -166 stub DeletePrinterIC +166 stdcall -stub DeletePrinterIC(ptr) 167 stdcall DeletePrinterKeyA(ptr str) 168 stdcall DeletePrinterKeyW(ptr wstr) -169 stub DevQueryPrint -170 stub DevQueryPrintEx -171 stub DeviceCapabilities +169 stdcall DevQueryPrint(ptr ptr ptr) +170 stdcall DevQueryPrintEx(ptr) +171 stdcall DeviceCapabilities(str str long ptr ptr) DeviceCapabilitiesA 172 stdcall DeviceCapabilitiesA(str str long ptr ptr) 173 stdcall DeviceCapabilitiesW(wstr wstr long ptr ptr) -174 stub DeviceMode -175 stub DevicePropertySheets +174 stdcall -stub DeviceMode(ptr ptr str ptr) +175 stdcall DevicePropertySheets(ptr long) 176 stdcall DocumentEvent(ptr ptr long long ptr long ptr) -177 stdcall DocumentPropertiesA(ptr ptr ptr ptr ptr long) -178 stdcall DocumentPropertiesW(ptr ptr ptr ptr ptr long) -179 stub DocumentPropertySheets -180 stub EXTDEVICEMODE +177 stdcall DocumentPropertiesA(ptr ptr str ptr ptr long) +178 stdcall DocumentPropertiesW(ptr ptr wstr ptr ptr long) +179 stdcall DocumentPropertySheets(ptr long) +180 stdcall EXTDEVICEMODE(ptr ptr ptr str str ptr str long) ExtDeviceMode 181 stdcall EndDocPrinter(ptr) 182 stdcall EndPagePrinter(ptr) 183 stdcall EnumFormsA(ptr long ptr long ptr ptr) @@ -110,13 +110,13 @@ 209 stub -noname DeletePerMachineConnectionW 210 stub -noname EnumPerMachineConnectionsA 211 stub -noname EnumPerMachineConnectionsW -212 stub -noname LoadPrinterDriver +212 stdcall -noname LoadPrinterDriver(ptr) 213 stub -noname RefCntLoadDriver 214 stub -noname RefCntUnloadDriver 215 stub -noname ForceUnloadDriver 216 stub -noname PublishPrinterA 217 stub -noname PublishPrinterW -218 stub -noname CallCommonPropertySheetUI +218 stdcall -noname CallCommonPropertySheetUI(ptr ptr long ptr) 219 stub -noname PrintUIQueueCreate 220 stub -noname PrintUIPrinterPropPages 221 stub -noname PrintUIDocumentDefaults @@ -134,7 +134,7 @@ 233 stdcall EnumPrinterKeyW(ptr wstr wstr long ptr) 234 stdcall EnumPrintersA(long ptr long ptr long ptr ptr) 235 stdcall EnumPrintersW(long ptr long ptr long ptr ptr) -236 stub ExtDeviceMode +236 stdcall -stub ExtDeviceMode(ptr ptr ptr str str ptr str long) 237 stub FindClosePrinterChangeNotification 238 stub FindFirstPrinterChangeNotification 239 stub FindNextPrinterChangeNotification @@ -156,18 +156,18 @@ 255 stdcall GetPrinterDriverDirectoryW(wstr wstr long ptr long ptr) 256 stdcall GetPrinterDriverW(ptr wstr long ptr long ptr) 257 stdcall GetPrinterW(ptr long ptr long ptr) -258 stub GetSpoolFileHandle +258 stdcall GetSpoolFileHandle(ptr) 259 stdcall IsValidDevmodeA(ptr long) 260 stdcall IsValidDevmodeW(ptr long) 261 stdcall OpenPrinterA(str ptr ptr) 262 stdcall OpenPrinterW(wstr ptr ptr) -263 stub PlayGdiScriptOnPrinterIC -264 stub PrinterMessageBoxA -265 stub PrinterMessageBoxW -266 stub PrinterProperties -267 stub QueryColorProfile -268 stub QueryRemoteFonts -269 stub QuerySpoolMode +263 stdcall -stub PlayGdiScriptOnPrinterIC(ptr ptr long ptr long long) +264 stdcall PrinterMessageBoxA(ptr long ptr str str long) +265 stdcall PrinterMessageBoxW(ptr long ptr wstr wstr long) +266 stdcall PrinterProperties(ptr ptr) +267 stdcall QueryColorProfile(ptr ptr long ptr ptr ptr) +268 stdcall QueryRemoteFonts(ptr ptr long) +269 stdcall QuerySpoolMode(ptr ptr ptr) 270 stdcall ReadPrinter(ptr ptr long ptr) 271 stdcall ResetPrinterA(ptr ptr) 272 stdcall ResetPrinterW(ptr ptr) @@ -189,9 +189,9 @@ 288 stdcall SplDriverUnloadComplete(ptr) 289 stub SpoolerDevQueryPrintW 290 stdcall SpoolerInit() -291 stub SpoolerPrinterEvent -292 stub StartDocDlgA -293 stub StartDocDlgW +291 stdcall SpoolerPrinterEvent(wstr long long long) +292 stdcall StartDocDlgA(ptr ptr) +293 stdcall StartDocDlgW(ptr ptr) 294 stdcall StartDocPrinterA(ptr long ptr) 295 stdcall StartDocPrinterW(ptr long ptr) 296 stdcall StartPagePrinter(ptr) diff --git a/win32ss/printing/include/marshalling/forms.h b/win32ss/printing/include/marshalling/forms.h new file mode 100644 index 00000000000..90af25969da --- /dev/null +++ b/win32ss/printing/include/marshalling/forms.h @@ -0,0 +1,31 @@ +/* + * PROJECT: ReactOS Printing Stack Marshalling Functions + * LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+) + * PURPOSE: Marshalling definitions for FORM_INFO_* + * COPYRIGHT: Copyright 1998-2020 ReactOS + */ + +static const MARSHALLING FormInfo1Marshalling = { + sizeof(FORM_INFO_1W), + { + { FIELD_OFFSET(FORM_INFO_1W, pName), RTL_FIELD_SIZE(FORM_INFO_1W, pName), RTL_FIELD_SIZE(FORM_INFO_1W, pName), TRUE }, + { MAXDWORD, 0, 0, FALSE } + } +}; + +static const MARSHALLING FormInfo2Marshalling = { + sizeof(FORM_INFO_2W), + { + { FIELD_OFFSET(FORM_INFO_2W, pName), RTL_FIELD_SIZE(FORM_INFO_2W, pName), RTL_FIELD_SIZE(FORM_INFO_2W, pName), TRUE }, + { FIELD_OFFSET(FORM_INFO_2W, pKeyword), RTL_FIELD_SIZE(FORM_INFO_2W, pKeyword), RTL_FIELD_SIZE(FORM_INFO_2W, pKeyword), TRUE }, + { FIELD_OFFSET(FORM_INFO_2W, pMuiDll), RTL_FIELD_SIZE(FORM_INFO_2W, pMuiDll), RTL_FIELD_SIZE(FORM_INFO_2W, pMuiDll), TRUE }, + { FIELD_OFFSET(FORM_INFO_2W, pDisplayName), RTL_FIELD_SIZE(FORM_INFO_2W, pDisplayName), RTL_FIELD_SIZE(FORM_INFO_2W, pDisplayName), FALSE }, + { MAXDWORD, 0, 0, FALSE } + } +}; + +static const MARSHALLING* pFormInfoMarshalling[] = { + NULL, + &FormInfo1Marshalling, + &FormInfo2Marshalling +}; diff --git a/win32ss/printing/include/marshalling/printerdrivers.h b/win32ss/printing/include/marshalling/printerdrivers.h index ffaf50fa21c..d46c77454c3 100644 --- a/win32ss/printing/include/marshalling/printerdrivers.h +++ b/win32ss/printing/include/marshalling/printerdrivers.h @@ -53,7 +53,7 @@ static const MARSHALLING PrinterDriver4Marshalling = { { FIELD_OFFSET(DRIVER_INFO_4W, pDependentFiles), RTL_FIELD_SIZE(DRIVER_INFO_4W, pDependentFiles), RTL_FIELD_SIZE(DRIVER_INFO_4W, pDependentFiles), TRUE }, { FIELD_OFFSET(DRIVER_INFO_4W, pMonitorName), RTL_FIELD_SIZE(DRIVER_INFO_4W, pMonitorName), RTL_FIELD_SIZE(DRIVER_INFO_4W, pMonitorName), TRUE }, { FIELD_OFFSET(DRIVER_INFO_4W, pDefaultDataType), RTL_FIELD_SIZE(DRIVER_INFO_4W, pDefaultDataType), RTL_FIELD_SIZE(DRIVER_INFO_4W, pDefaultDataType), TRUE }, - { FIELD_OFFSET(DRIVER_INFO_4W, pszzPreviousNames), RTL_FIELD_SIZE(DRIVER_INFO_4W, pszzPreviousNames), RTL_FIELD_SIZE(DRIVER_INFO_4W, pDefaultDataType), TRUE }, + { FIELD_OFFSET(DRIVER_INFO_4W, pszzPreviousNames), RTL_FIELD_SIZE(DRIVER_INFO_4W, pszzPreviousNames), RTL_FIELD_SIZE(DRIVER_INFO_4W, pszzPreviousNames), TRUE }, { MAXDWORD, 0, 0, FALSE } } }; @@ -70,6 +70,52 @@ static const MARSHALLING PrinterDriver5Marshalling = { } }; +static const MARSHALLING PrinterDriver6Marshalling = { + sizeof(DRIVER_INFO_6W), + { + { FIELD_OFFSET(DRIVER_INFO_6W, pName), RTL_FIELD_SIZE(DRIVER_INFO_6W, pName), RTL_FIELD_SIZE(DRIVER_INFO_6W, pName), TRUE }, + { FIELD_OFFSET(DRIVER_INFO_6W, pEnvironment), RTL_FIELD_SIZE(DRIVER_INFO_6W, pEnvironment), RTL_FIELD_SIZE(DRIVER_INFO_6W, pEnvironment), TRUE }, + { FIELD_OFFSET(DRIVER_INFO_6W, pDriverPath), RTL_FIELD_SIZE(DRIVER_INFO_6W, pDriverPath), RTL_FIELD_SIZE(DRIVER_INFO_6W, pDriverPath), TRUE }, + { FIELD_OFFSET(DRIVER_INFO_6W, pDataFile), RTL_FIELD_SIZE(DRIVER_INFO_6W, pDataFile), RTL_FIELD_SIZE(DRIVER_INFO_6W, pDataFile), TRUE }, + { FIELD_OFFSET(DRIVER_INFO_6W, pConfigFile), RTL_FIELD_SIZE(DRIVER_INFO_6W, pConfigFile), RTL_FIELD_SIZE(DRIVER_INFO_6W, pConfigFile), TRUE }, + { FIELD_OFFSET(DRIVER_INFO_6W, pHelpFile), RTL_FIELD_SIZE(DRIVER_INFO_6W, pHelpFile), RTL_FIELD_SIZE(DRIVER_INFO_6W, pHelpFile), TRUE }, + { FIELD_OFFSET(DRIVER_INFO_6W, pDependentFiles), RTL_FIELD_SIZE(DRIVER_INFO_6W, pDependentFiles), RTL_FIELD_SIZE(DRIVER_INFO_6W, pDependentFiles), TRUE }, + { FIELD_OFFSET(DRIVER_INFO_6W, pMonitorName), RTL_FIELD_SIZE(DRIVER_INFO_6W, pMonitorName), RTL_FIELD_SIZE(DRIVER_INFO_6W, pMonitorName), TRUE }, + { FIELD_OFFSET(DRIVER_INFO_6W, pDefaultDataType), RTL_FIELD_SIZE(DRIVER_INFO_6W, pDefaultDataType), RTL_FIELD_SIZE(DRIVER_INFO_6W, pDefaultDataType), TRUE }, + { FIELD_OFFSET(DRIVER_INFO_6W, pszzPreviousNames), RTL_FIELD_SIZE(DRIVER_INFO_6W, pszzPreviousNames), RTL_FIELD_SIZE(DRIVER_INFO_6W, pszzPreviousNames), TRUE }, + { FIELD_OFFSET(DRIVER_INFO_6W, pszMfgName), RTL_FIELD_SIZE(DRIVER_INFO_6W, pszMfgName), RTL_FIELD_SIZE(DRIVER_INFO_6W, pszMfgName), TRUE }, + { FIELD_OFFSET(DRIVER_INFO_6W, pszOEMUrl), RTL_FIELD_SIZE(DRIVER_INFO_6W, pszOEMUrl), RTL_FIELD_SIZE(DRIVER_INFO_6W, pszOEMUrl), TRUE }, + { FIELD_OFFSET(DRIVER_INFO_6W, pszHardwareID), RTL_FIELD_SIZE(DRIVER_INFO_6W, pszHardwareID), RTL_FIELD_SIZE(DRIVER_INFO_6W, pszHardwareID), TRUE }, + { FIELD_OFFSET(DRIVER_INFO_6W, pszProvider), RTL_FIELD_SIZE(DRIVER_INFO_6W, pszProvider), RTL_FIELD_SIZE(DRIVER_INFO_6W, pszProvider), TRUE }, + { MAXDWORD, 0, 0, FALSE } + } +}; + +static const MARSHALLING PrinterDriver8Marshalling = { + sizeof(DRIVER_INFO_8W), + { + { FIELD_OFFSET(DRIVER_INFO_8W, pName), RTL_FIELD_SIZE(DRIVER_INFO_8W, pName), RTL_FIELD_SIZE(DRIVER_INFO_8W, pName), TRUE }, + { FIELD_OFFSET(DRIVER_INFO_8W, pEnvironment), RTL_FIELD_SIZE(DRIVER_INFO_8W, pEnvironment), RTL_FIELD_SIZE(DRIVER_INFO_8W, pEnvironment), TRUE }, + { FIELD_OFFSET(DRIVER_INFO_8W, pDriverPath), RTL_FIELD_SIZE(DRIVER_INFO_8W, pDriverPath), RTL_FIELD_SIZE(DRIVER_INFO_8W, pDriverPath), TRUE }, + { FIELD_OFFSET(DRIVER_INFO_8W, pDataFile), RTL_FIELD_SIZE(DRIVER_INFO_8W, pDataFile), RTL_FIELD_SIZE(DRIVER_INFO_8W, pDataFile), TRUE }, + { FIELD_OFFSET(DRIVER_INFO_8W, pConfigFile), RTL_FIELD_SIZE(DRIVER_INFO_8W, pConfigFile), RTL_FIELD_SIZE(DRIVER_INFO_8W, pConfigFile), TRUE }, + { FIELD_OFFSET(DRIVER_INFO_8W, pHelpFile), RTL_FIELD_SIZE(DRIVER_INFO_8W, pHelpFile), RTL_FIELD_SIZE(DRIVER_INFO_8W, pHelpFile), TRUE }, + { FIELD_OFFSET(DRIVER_INFO_8W, pDependentFiles), RTL_FIELD_SIZE(DRIVER_INFO_8W, pDependentFiles), RTL_FIELD_SIZE(DRIVER_INFO_8W, pDependentFiles), TRUE }, + { FIELD_OFFSET(DRIVER_INFO_8W, pMonitorName), RTL_FIELD_SIZE(DRIVER_INFO_8W, pMonitorName), RTL_FIELD_SIZE(DRIVER_INFO_8W, pMonitorName), TRUE }, + { FIELD_OFFSET(DRIVER_INFO_8W, pDefaultDataType), RTL_FIELD_SIZE(DRIVER_INFO_8W, pDefaultDataType), RTL_FIELD_SIZE(DRIVER_INFO_8W, pDefaultDataType), TRUE }, + { FIELD_OFFSET(DRIVER_INFO_8W, pszzPreviousNames), RTL_FIELD_SIZE(DRIVER_INFO_8W, pszzPreviousNames), RTL_FIELD_SIZE(DRIVER_INFO_8W, pszzPreviousNames), TRUE }, + { FIELD_OFFSET(DRIVER_INFO_8W, pszMfgName), RTL_FIELD_SIZE(DRIVER_INFO_8W, pszMfgName), RTL_FIELD_SIZE(DRIVER_INFO_8W, pszMfgName), TRUE }, + { FIELD_OFFSET(DRIVER_INFO_8W, pszOEMUrl), RTL_FIELD_SIZE(DRIVER_INFO_8W, pszOEMUrl), RTL_FIELD_SIZE(DRIVER_INFO_8W, pszOEMUrl), TRUE }, + { FIELD_OFFSET(DRIVER_INFO_8W, pszHardwareID), RTL_FIELD_SIZE(DRIVER_INFO_8W, pszHardwareID), RTL_FIELD_SIZE(DRIVER_INFO_8W, pszHardwareID), TRUE }, + { FIELD_OFFSET(DRIVER_INFO_8W, pszProvider), RTL_FIELD_SIZE(DRIVER_INFO_8W, pszProvider), RTL_FIELD_SIZE(DRIVER_INFO_8W, pszProvider), TRUE }, + { FIELD_OFFSET(DRIVER_INFO_8W, pszPrintProcessor), RTL_FIELD_SIZE(DRIVER_INFO_8W, pszPrintProcessor), RTL_FIELD_SIZE(DRIVER_INFO_8W, pszPrintProcessor), TRUE }, + { FIELD_OFFSET(DRIVER_INFO_8W, pszVendorSetup), RTL_FIELD_SIZE(DRIVER_INFO_8W, pszVendorSetup), RTL_FIELD_SIZE(DRIVER_INFO_8W, pszVendorSetup), TRUE }, + { FIELD_OFFSET(DRIVER_INFO_8W, pszzColorProfiles), RTL_FIELD_SIZE(DRIVER_INFO_8W, pszzColorProfiles), RTL_FIELD_SIZE(DRIVER_INFO_8W, pszzColorProfiles), TRUE }, + { FIELD_OFFSET(DRIVER_INFO_8W, pszInfPath), RTL_FIELD_SIZE(DRIVER_INFO_8W, pszInfPath), RTL_FIELD_SIZE(DRIVER_INFO_8W, pszInfPath), TRUE }, + { FIELD_OFFSET(DRIVER_INFO_8W, pszzCoreDriverDependencies), RTL_FIELD_SIZE(DRIVER_INFO_8W, pszzCoreDriverDependencies), RTL_FIELD_SIZE(DRIVER_INFO_8W, pszzCoreDriverDependencies), TRUE }, + { MAXDWORD, 0, 0, FALSE } + } +}; static const MARSHALLING* pPrinterDriverMarshalling[] = { NULL, @@ -78,4 +124,6 @@ static const MARSHALLING* pPrinterDriverMarshalling[] = { &PrinterDriver3Marshalling, &PrinterDriver4Marshalling, &PrinterDriver5Marshalling, + &PrinterDriver6Marshalling, + &PrinterDriver8Marshalling, }; diff --git a/win32ss/printing/include/spoolss.h b/win32ss/printing/include/spoolss.h index a16cca49ae8..51de84082f7 100644 --- a/win32ss/printing/include/spoolss.h +++ b/win32ss/printing/include/spoolss.h @@ -57,6 +57,13 @@ typedef struct _PRINTER_INFO_STRESS } PRINTER_INFO_STRESS, *PPRINTER_INFO_STRESS; +typedef struct _FILE_INFO_1 +{ + BOOL bInheritHandle; + HANDLE hSpoolFileHandle; + DWORD dwOptions; +} FILE_INFO_1, *PFILE_INFO_1; + PVOID WINAPI AlignRpcPtr(PVOID pBuffer, PDWORD pcbBuffer); PWSTR WINAPI AllocSplStr(PCWSTR pwszInput); PVOID WINAPI DllAllocSplMem(DWORD dwBytes); @@ -69,5 +76,8 @@ BOOL WINAPI ReallocSplStr(PWSTR* ppwszString, PCWSTR pwszInput); BOOL WINAPI SplInitializeWinSpoolDrv(PVOID* pTable); BOOL WINAPI SpoolerInit(VOID); PDWORD WINAPI UndoAlignRpcPtr(PVOID pDestinationBuffer, PVOID pSourceBuffer, DWORD cbBuffer, PDWORD pcbNeeded); +BOOL WINAPI SplGetSpoolFileInfo(HANDLE hPrinter,HANDLE hProcessHandle,DWORD Level,FILE_INFO_1 *pFileInfo,DWORD dwSize,DWORD* dwNeeded ); +BOOL WINAPI SplCommitSpoolData(HANDLE hPrinter,HANDLE hProcessHandle,DWORD cbCommit,DWORD Level,FILE_INFO_1 *pFileInfo,DWORD dwSize,DWORD* dwNeeded); +BOOL WINAPI SplCloseSpoolFileHandle( HANDLE hPrinter ); #endif diff --git a/win32ss/printing/providers/localspl/spoolfile.c b/win32ss/printing/providers/localspl/spoolfile.c index c919aead2d4..e6981b07966 100644 --- a/win32ss/printing/providers/localspl/spoolfile.c +++ b/win32ss/printing/providers/localspl/spoolfile.c @@ -2,7 +2,7 @@ * PROJECT: ReactOS Local Spooler * LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+) * PURPOSE: Functions related to Spool Files and printing - * COPYRIGHT: Copyright 1998-2020 ReactOS) + * COPYRIGHT: Copyright 1998-2020 ReactOS */ #include "precomp.h"