/*++ Copyright (C) Microsoft Corporation, 1995 - 1999 All rights reserved. Module Name: docprop.cxx Abstract: Job Properties Author: Steve Kiraly (SteveKi) 10/19/95 Revision History: Lazar Ivanov (LazarI) - added DocumentPropertiesWrap (Nov-03-2000) --*/ #include "precomp.hxx" #pragma hdrstop #include "time.hxx" #include "docdata.hxx" #include "propmgr.hxx" #include "docprop.hxx" /*++ Routine Name: vDocPropSelections Routine Description: Displays Document property sheets for multiple selections. Arguments: TSelection - pointer to a list of document selections. Return Value: Nothing. --*/ VOID vDocumentPropSelections( IN HWND hWnd, IN LPCTSTR pszPrinterName, IN TSelection *pSelection ) { // // Get the selection information. We are in a loop to // handle the selection of multiple jobs. // for( UINT i = 0; i < pSelection->_cSelected; ++i ){ // // Display the document property pages. // vDocumentPropPages( hWnd, pszPrinterName, pSelection->_pid[i], SW_SHOWNORMAL, 0 ); } } /*++ Routine Description: This function opens the property sheet of specified document. We can't guarentee that this propset will perform all lengthy operations in a worker thread (we synchronously call things like ConfigurePort). Therefore, we spawn off a separate thread to handle document properties. Arguments: hWnd - Specifies the parent window (optional). pszPrinter - Specifies the printer name nCmdShow - Initial show state lParam - May spcify a sheet specifc index to directly open. Return Value: --*/ VOID vDocumentPropPages( IN HWND hWnd, IN LPCTSTR pszPrinterName, IN IDENT JobId, IN INT iCmdShow, IN LPARAM lParam ) { HANDLE hThread; // // Create the document specific data // TDocumentData* pDocumentData = new TDocumentData( pszPrinterName, JobId, iCmdShow, lParam ); // // If errors were encountered creating document data. // if( !VALID_PTR( pDocumentData )){ goto Fail; } // // Create the thread which handles the UI. vPrinterPropPages adopts // pPrinterData, therefore only on thread creation failure do we // releae the document data back to the heap. // DWORD dwIgnore; hThread = TSafeThread::Create( NULL, 0, (LPTHREAD_START_ROUTINE)iDocumentPropPagesProc, pDocumentData, 0, &dwIgnore ); // // Check thread creation. // if( !hThread ){ // // Display error message, and release document data. // vShowResourceError( hWnd ); delete pDocumentData; } else { CloseHandle( hThread ); } return; Fail: // // Display the error message. // iMessage( hWnd, IDS_ERR_DOC_JOB_PROPERTY_TITLE, IDS_ERR_DOC_JOB_PROPERTY_JOB_NA, MB_OK|MB_ICONSTOP, kMsgGetLastError, NULL ); delete pDocumentData; } /*++ Routine Name: iDocumentPropPagesProc Routine Description: This is the routine called by the create thread call to display the document property sheets. Arguments: pDocumentData - Pointer to the document data needed for all property sheets. Return Value: TRUE - if the property sheets were displayed. FALSE - error creating and displaying property sheets. --*/ INT iDocumentPropPagesProc( IN TDocumentData *pDocumentData ADOPT ) { DBGMSG( DBG_TRACE, ( "iDocumentPropPagesProc\n") ); BOOL bStatus; bStatus = pDocumentData->bRegisterWindow( PRINTER_PIDL_TYPE_JOBID | pDocumentData->JobId( )); if( bStatus ){ // // Check if the window is already present. If it is, then // exit immediately. // if( !pDocumentData->hwnd( )){ delete pDocumentData; return 0; } bStatus = pDocumentData->bLoad(); } if( !bStatus ){ iMessage( pDocumentData->hwnd(), IDS_ERR_DOC_JOB_PROPERTY_TITLE, IDS_ERR_DOC_JOB_PROPERTY_JOB_NA, MB_OK|MB_ICONSTOP|MB_SETFOREGROUND, kMsgGetLastError, NULL ); delete pDocumentData; return 0; } // // Create the ducument property sheet windows. // TDocumentWindows DocumentWindows( pDocumentData ); // // Were the document windows create // if( !VALID_OBJ( DocumentWindows ) ){ vShowResourceError( pDocumentData->hwnd() ); bStatus = FALSE; } // // Display the property pages. // if( bStatus ){ if( !DocumentWindows.bDisplayPages( pDocumentData->hwnd() ) ){ vShowResourceError( pDocumentData->hwnd() ); bStatus = FALSE; } } // // Ensure we release the document data. // We have adopted pPrinterData, so we must free it. // delete pDocumentData; return bStatus; } /******************************************************************** Document Prop Base Class ********************************************************************/ /*++ Routine Name: TDocumentProp Routine Description: Initialized the document property sheet base class Arguments: pDocumentData - Pointer to the document data needed for all property sheets. Return Value: None. --*/ TDocumentProp:: TDocumentProp( TDocumentData* pDocumentData ) : _pDocumentData( pDocumentData ), _bApplyData( FALSE ) { } /*++ Routine Name: ~TDocumentProp Routine Description: Base class desctuctor. Arguments: None. Return Value: Nothing. --*/ TDocumentProp:: ~TDocumentProp( ) { } /*++ Routine Name: bHandleMessage Routine Description: Base class message handler. This routine is called by derived classes who do not want to handle the message. Arguments: uMsg - Windows message wParam - Word parameter lParam - Long parameter Return Value: TRUE if message was handled, FALSE if message not handled. --*/ BOOL TDocumentProp:: bHandleMessage( IN UINT uMsg, IN WPARAM wParam, IN LPARAM lParam ) { BOOL bStatus = TRUE; switch( uMsg ){ // // Set the values on the UI. // case WM_INITDIALOG: bStatus = bSetUI(); break; // // Handle help and context help. // case WM_HELP: case WM_CONTEXTMENU: bStatus = PrintUIHelp( uMsg, _hDlg, wParam, lParam ); break; case WM_NOTIFY: switch( ((LPNMHDR)lParam)->code ) { // // User switched to the next page. // case PSN_KILLACTIVE: bStatus = bReadUI(); vSetDlgMsgResult( !bStatus ? TRUE : FALSE ); break; // // User chiose the apply button. // case PSN_APPLY: _bApplyData = TRUE; bStatus = ( _bApplyData ) ? bSaveUI() : FALSE; if( !bStatus ) { // // Switch to page with the error. // PropSheet_SetCurSelByID( GetParent( _hDlg ), DLG_DOC_JOB_GENERAL ); } vSetDlgMsgResult( !bStatus ? PSNRET_INVALID_NOCHANGEPAGE : PSNRET_NOERROR ); break; // // Indicate the use canceled the dialog. // case PSN_QUERYCANCEL: _bApplyData = FALSE; break; default: bStatus = FALSE; break; } break; default: bStatus = FALSE; break; } if( !bStatus ) { // // Allow the derived classes to handle the message. // bStatus = _bHandleMessage( uMsg, wParam, lParam ); } // // If the message was handled check if the // apply button should be enabled. // if( bStatus ) { if( _pDocumentData->bCheckForChange() ) { PropSheet_Changed( GetParent( _hDlg ), _hDlg ); } else { PropSheet_UnChanged( GetParent( _hDlg), _hDlg ); } } return bStatus; } /******************************************************************** General Document Property Sheet. ********************************************************************/ /*++ Routine Name: TDocumentGeneral Routine Description: Document property sheet derived class. Arguments: None. Return Value: Nothing. --*/ TDocumentGeneral:: TDocumentGeneral( IN TDocumentData* pDocumentData ) : TDocumentProp( pDocumentData ), _bSetUIDone( FALSE ) { } /*++ Routine Name: ~TDocumentGeneral Routine Description: Document derived class destructor. Arguments: None. Return Value: Nothing. --*/ TDocumentGeneral:: ~TDocumentGeneral( ) { } /*++ Routine Name: bValid Routine Description: Document property sheet derived class valid object indicator. Arguments: None. Return Value: Returns the status of the base class. --*/ BOOL TDocumentGeneral:: bValid( VOID ) { return TDocumentProp::bValid(); } /*++ Routine Name: bSetStartAndUntilTime Routine Description: Initialized the start and until time. Arguments: None. Return Value: TRUE time controls initialized, FALSE error occured. --*/ BOOL TDocumentGeneral:: bSetStartAndUntilTime( VOID ) { TString strFormatString; TStatusB bStatus; // // Get the time format string without seconds. // bStatus DBGCHK = bGetTimeFormatString( strFormatString ); // // If we have retrived a valid time format string then use it, // else use the default format string implemented by common control. // if( bStatus ) { DateTime_SetFormat(GetDlgItem( _hDlg, IDC_DOC_JOB_START_TIME ), static_cast( strFormatString ) ); DateTime_SetFormat(GetDlgItem( _hDlg, IDC_DOC_JOB_UNTIL_TIME ), static_cast( strFormatString ) ); } // // If the printer is always available. // BOOL bAlways = ( _pDocumentData->pJobInfo()->StartTime == _pDocumentData->pJobInfo()->UntilTime ); // // Set the start time. // SYSTEMTIME StartTime = { 0 }; DWORD dwLocalStartTime = 0; GetLocalTime( &StartTime ); dwLocalStartTime = ( !bAlways ) ? SystemTimeToLocalTime( _pDocumentData->pJobInfo()->StartTime ) : 0; StartTime.wHour = static_cast( dwLocalStartTime / 60 ); StartTime.wMinute = static_cast( dwLocalStartTime % 60 ); DateTime_SetSystemtime(GetDlgItem( _hDlg, IDC_DOC_JOB_START_TIME ), GDT_VALID, &StartTime ); // // Set the until time. // SYSTEMTIME UntilTime = { 0 }; DWORD dwLocalUntilTime = 0; GetLocalTime( &UntilTime ); dwLocalUntilTime = ( !bAlways ) ? SystemTimeToLocalTime( _pDocumentData->pJobInfo()->UntilTime ) : 0; UntilTime.wHour = static_cast( dwLocalUntilTime / 60 ); UntilTime.wMinute = static_cast( dwLocalUntilTime % 60 ); DateTime_SetSystemtime(GetDlgItem( _hDlg, IDC_DOC_JOB_UNTIL_TIME ), GDT_VALID, &UntilTime ); return TRUE; } /*++ Routine Name: bSetUI Routine Description: Loads the property sheet dialog with the document data information. Arguments: None. Return Value: TRUE if data loaded successfully, FALSE if error occurred. --*/ BOOL TDocumentGeneral:: bSetUI( VOID ) { // // Get the flag if always availble. // BOOL bAlways = ( _pDocumentData->pJobInfo()->StartTime == _pDocumentData->pJobInfo()->UntilTime ); // // Initialize the stat and until time controls. // if( !bSetStartAndUntilTime() ) { DBGMSG( DBG_TRACE, ( "TDocumentGeneral::bSetStartAndUntilTime failed %d\n", GetLastError( ))); } // // Read the job size format string. // TString strFormat; if( strFormat.bLoadString( ghInst, IDS_JOB_SIZE ) ){ // // Set the size in byes of the job. // bSetEditTextFormat( _hDlg, IDC_DOC_JOB_SIZE, strFormat, _pDocumentData->pJobInfo()->Size ); } // // Set the Number of pages in the job. // bSetEditTextFormat( _hDlg, IDC_DOC_JOB_PAGES, TEXT( "%d" ), _pDocumentData->pJobInfo()->TotalPages ); // // Set the document text. // bSetEditText( _hDlg, IDC_DOC_JOB_TITLE, _pDocumentData->pJobInfo()->pDocument ); bSetEditText( _hDlg, IDC_DOC_JOB_DATATYPE, _pDocumentData->pJobInfo()->pDatatype ); bSetEditText( _hDlg, IDC_DOC_JOB_PROCCESSOR, _pDocumentData->pJobInfo()->pPrintProcessor ); bSetEditText( _hDlg, IDC_DOC_JOB_OWNER, _pDocumentData->pJobInfo()->pUserName ); bSetEditText( _hDlg, IDC_DOC_JOB_NOTIFY, _pDocumentData->pJobInfo()->pNotifyName ); // // Set the Priority indicator. // bSetEditTextFormat( _hDlg, IDC_DOC_JOB_PRIORITY, TEXT( "%d" ), _pDocumentData->pJobInfo()->Priority ); SendDlgItemMessage( _hDlg, IDC_DOC_JOB_PRIORITY_CONTROL, TBM_SETRANGE, FALSE, MAKELONG( TDocumentData::kPriorityLowerBound, TDocumentData::kPriorityUpperBound )); SendDlgItemMessage( _hDlg, IDC_DOC_JOB_PRIORITY_CONTROL, TBM_SETPOS, TRUE, _pDocumentData->pJobInfo()->Priority ); // // Format the submitted time field. // TStatusB bStatus = FALSE; TCHAR szBuff[kStrMax] = {0}; SYSTEMTIME LocalTime; // // Convert to local time. // bStatus DBGCHK = SystemTimeToTzSpecificLocalTime( NULL, &_pDocumentData->pJobInfo()->Submitted, &LocalTime ); if( !bStatus ){ DBGMSG( DBG_MIN, ( "SysTimeToTzSpecLocalTime failed %d\n", GetLastError( ))); } if( bStatus ){ // // Convert using local format information. // bStatus DBGCHK = GetTimeFormat( LOCALE_USER_DEFAULT, 0, &LocalTime, NULL, szBuff, COUNTOF( szBuff )); if( !bStatus ){ DBGMSG( DBG_MIN, ( "No Time %d, ", GetLastError( ))); } } if( bStatus ){ // // Tack on space between time and date. // StringCchCat( szBuff, ARRAYSIZE(szBuff), TEXT(" ") ); // // Get data format. // bStatus DBGCHK = GetDateFormat( LOCALE_USER_DEFAULT, 0, &LocalTime, NULL, szBuff + lstrlen( szBuff ), COUNTOF( szBuff ) - lstrlen( szBuff ) ); if( !bStatus ){ DBGMSG( DBG_MIN, ( "No Date %d\n", GetLastError( ))); } } // // Set the submitted field // bStatus DBGCHK = bSetEditText( _hDlg, IDC_DOC_JOB_AT, szBuff ); // // Set schedule radio buttons. // CheckRadioButton( _hDlg, IDC_DOC_JOB_START, IDC_DOC_JOB_ALWAYS, bAlways ? IDC_DOC_JOB_ALWAYS : IDC_DOC_JOB_START ); vEnableAvailable( !bAlways ); // // Disable all the controls if not an administrator. // if( !_pDocumentData->bAdministrator( )){ // // Disable the time controls. // vEnableAvailable( FALSE ); // // Disable things if not administrator. // static UINT auAvailable[] = { IDC_DOC_JOB_NOTIFY, IDC_DOC_JOB_PRIORITY_CONTROL, IDC_DOC_JOB_ALWAYS, IDC_DOC_JOB_START, }; COUNT i; for( i = 0; i < COUNTOF( auAvailable ); ++i ){ vEnableCtl( _hDlg, auAvailable[i], FALSE ); } } _bSetUIDone = TRUE; return TRUE; } /*++ Routine Name: bReadUI Routine Description: Stores the property information to the print server. Arguments: Nothing data is contained with in the class. Return Value: TRUE if data is stores successfully, FALSE if error occurred. --*/ BOOL TDocumentGeneral:: bReadUI( VOID ) { DBGMSG( DBG_TRACE, ( "TDocumentGeneral::bReadUI\n") ); // // Attempt to validate any UI changeable data. // Currently not much can be validated, since all the // controls have set constraints. // // // Extract the UI and save it into the Document Data. // _pDocumentData->pJobInfo()->Priority = (DWORD)SendDlgItemMessage( _hDlg, IDC_DOC_JOB_PRIORITY_CONTROL, TBM_GETPOS, 0, 0 ); // // Get the notify name. // bGetEditText( _hDlg, IDC_DOC_JOB_NOTIFY, _pDocumentData->strNotifyName() ); _pDocumentData->pJobInfo()->pNotifyName = (LPTSTR)(LPCTSTR)_pDocumentData->strNotifyName(); // // If the Job always is set then indicate // not time restriction in the start time and until time. // if( bGetCheck( _hDlg, IDC_DOC_JOB_ALWAYS ) ){ _pDocumentData->pJobInfo()->StartTime = 0; _pDocumentData->pJobInfo()->UntilTime = 0; } else { // // Get the Start time. // SYSTEMTIME StartTime; DateTime_GetSystemtime( GetDlgItem( _hDlg, IDC_DOC_JOB_START_TIME ), &StartTime ); _pDocumentData->pJobInfo()->StartTime = LocalTimeToSystemTime( StartTime.wHour * 60 + StartTime.wMinute ); // // Get the Until time. // SYSTEMTIME UntilTime; DateTime_GetSystemtime( GetDlgItem( _hDlg, IDC_DOC_JOB_UNTIL_TIME ), &UntilTime ); _pDocumentData->pJobInfo()->UntilTime = LocalTimeToSystemTime( UntilTime.wHour * 60 + UntilTime.wMinute ); // // If the printer start and until time are the same this is // exactly the same as always available. // if( _pDocumentData->pJobInfo()->StartTime == _pDocumentData->pJobInfo()->UntilTime ) { _pDocumentData->pJobInfo()->StartTime = 0; _pDocumentData->pJobInfo()->UntilTime = 0; } } // // Set the job position to unspecified it may // have changed while this dialog was up. // _pDocumentData->pJobInfo()->Position = JOB_POSITION_UNSPECIFIED; return TRUE; } /*++ Routine Name: bSaveUI Routine Description: Saves the UI data to some API call or print server. Arguments: Nothing data is contained with in the class. Return Value: TRUE if data is stores successfully, FALSE if error occurred. --*/ BOOL TDocumentGeneral:: bSaveUI( VOID ) { DBGMSG( DBG_TRACE, ( "TDocumentGeneral::bSaveUI\n") ); // // Clear the error saving flag. // _pDocumentData->bErrorSaving() = TRUE; // // Save the document data. // if( !_pDocumentData->bStore() ){ DWORD dwLastError = GetLastError (); if( dwLastError == ERROR_INVALID_TIME ){ _pDocumentData->iErrorMsgId() = IDS_ERR_DOC_JOB_PROPERTY_TIME; } else { _pDocumentData->iErrorMsgId() = IDS_ERR_DOC_JOB_PROPERTY_MODIFY; } _pDocumentData->bErrorSaving() = FALSE; } // // If there was an error saving the document data. // if( !_pDocumentData->bErrorSaving() ){ // // Display the error message. // iMessage( _hDlg, IDS_ERR_DOC_JOB_PROPERTY_TITLE, _pDocumentData->iErrorMsgId(), MB_OK|MB_ICONSTOP|MB_SETFOREGROUND, kMsgNone, NULL ); return FALSE; } return TRUE; } /*++ Routine Name: vEanbleAvailablity Routine Description: Enables the time availabilty of the job Arguments: TRUE enable the availablity, FALSE disable time availablity. Return Value: Nothing. --*/ VOID TDocumentGeneral:: vEnableAvailable( IN BOOL bEnable ) { vEnableCtl( _hDlg, IDC_DOC_JOB_START_TIME, bEnable ); vEnableCtl( _hDlg, IDC_DOC_JOB_UNTIL_TIME, bEnable ); } /*++ Routine Name: bReadUI Routine Description: Stores the property information to the print server. Arguments: Nothing data is contained with in the class. Return Value: TRUE if data is stores successfully, FALSE if error occurred. --*/ VOID TDocumentGeneral:: vSetActive( VOID ) { DBGMSG( DBG_TRACE, ( "TDocumentGeneral::vSetActive\n") ); (VOID)bSetStartAndUntilTime(); } /*++ Routine Name: bHandleMessage Routine Description: Document property sheet message handler. This handler only handles events it wants and the base class handle will do the standard message handling. Arguments: uMsg - Windows message wParam - Word parameter lParam - Long parameter Return Value: TRUE if message was handled, FALSE if message not handled. --*/ BOOL TDocumentGeneral:: _bHandleMessage( IN UINT uMsg, IN WPARAM wParam, IN LPARAM lParam ) { BOOL bStatus = TRUE; switch( uMsg ) { case WM_HSCROLL: // // Check for slider notification. // if( GET_WM_HSCROLL_HWND( wParam, lParam ) == GetDlgItem(_hDlg, IDC_DOC_JOB_PRIORITY_CONTROL ) ){ bSetEditTextFormat( _hDlg, IDC_DOC_JOB_PRIORITY, TEXT("%d"), SendDlgItemMessage( _hDlg, IDC_DOC_JOB_PRIORITY_CONTROL, TBM_GETPOS, 0, 0 ) ); } break; case WM_COMMAND: switch( GET_WM_COMMAND_ID( wParam, lParam )) { case IDC_DOC_JOB_ALWAYS: vEnableAvailable( FALSE ); PropSheet_Changed( GetParent( _hDlg ), _hDlg ); break; case IDC_DOC_JOB_START: vEnableAvailable( TRUE ); PropSheet_Changed( GetParent( _hDlg ), _hDlg ); break; case IDC_DOC_JOB_NOTIFY: bStatus = GET_WM_COMMAND_CMD(wParam, lParam) == EN_CHANGE; break; default: bStatus = FALSE; break; } break; case WM_WININICHANGE: vSetActive(); break; case WM_NOTIFY: { LPNMHDR pnmh = (LPNMHDR)lParam; switch( wParam ) { case 0: { switch( pnmh->code ) { case PSN_SETACTIVE: vSetActive(); break; default: bStatus = FALSE; break; } } break; case IDC_DOC_JOB_START_TIME: case IDC_DOC_JOB_UNTIL_TIME: { switch( pnmh->code ) { case DTN_DATETIMECHANGE: break; default: bStatus = FALSE; break; } } break; default: bStatus = FALSE; break; } } break; default: bStatus = FALSE; break; } // // If message handled look for change. // if( bStatus && _bSetUIDone ) { (VOID)bReadUI(); } return bStatus; } /******************************************************************** Document property windows. ********************************************************************/ /*++ Routine Description: Document property windows. Arguments: pDocumentData - Document data to display. Return Value: TRUE - Success, FALSE - failure. --*/ TDocumentWindows:: TDocumentWindows( TDocumentData* pDocumentData ) : _pDocumentData( pDocumentData ), _General( pDocumentData ) { DBGMSG( DBG_TRACE, ( "TDocumentWindows ctor\n") ); } TDocumentWindows:: ~TDocumentWindows( ) { DBGMSG( DBG_TRACE, ( "TDocumentWindows dtor\n") ); } /*++ Routine Name: bBuildPages Routine Description: Builds the document property windows. Arguments: None - class specific. Return Value: TRUE pages built ok, FALSE failure building pages. --*/ BOOL TDocumentWindows:: bBuildPages( IN PPROPSHEETUI_INFO pCPSUIInfo ) { TStatusB bStatus; DBGMSG( DBG_TRACE, ( "TDocumentWindows bBuildPages\n") ); // // Set the default activation context to be V6 prior calling into // compstui to create the pages. This will force V6 context unless // the callbacks which create the compstui pages specify otherwise // on a per page basis. // bStatus DBGCHK = (BOOL)pCPSUIInfo->pfnComPropSheet( pCPSUIInfo->hComPropSheet, CPSFUNC_SET_FUSION_CONTEXT, reinterpret_cast(g_hActCtx), static_cast(0)); if (bStatus) { PROPSHEETPAGE psp; ZeroMemory( &psp, sizeof( psp ) ); psp.dwSize = sizeof( psp ); psp.dwFlags = PSP_DEFAULT; psp.hInstance = ghInst; psp.pfnDlgProc = MGenericProp::SetupDlgProc; psp.pszTemplate = MAKEINTRESOURCE( DLG_DOC_JOB_GENERAL ); psp.lParam = (LPARAM)(MGenericProp*)&_General; if( pCPSUIInfo->pfnComPropSheet( pCPSUIInfo->hComPropSheet, CPSFUNC_ADD_PROPSHEETPAGE, (LPARAM)&psp, NULL ) <= 0 ) { DBGMSG( DBG_TRACE, ( "CPSFUNC_ADD_PROPSHEETPAGE failed.\n") ); bStatus DBGCHK = FALSE; } if (bStatus) { // // If the dev mode is null don't display the // device property sheets. // if( _pDocumentData->pJobInfo()->pDevMode ) { ZeroMemory( &_dph, sizeof( _dph ) ); _dph.cbSize = sizeof( _dph ); _dph.hPrinter = _pDocumentData->hPrinter(); _dph.pszPrinterName = (LPTSTR)(LPCTSTR)_pDocumentData->strPrinterName(); _dph.pdmOut = _pDocumentData->pJobInfo()->pDevMode; _dph.pdmIn = _pDocumentData->pJobInfo()->pDevMode; _dph.fMode = DM_IN_BUFFER | DM_PROMPT | DM_NOPERMISSION; if( pCPSUIInfo->pfnComPropSheet( pCPSUIInfo->hComPropSheet, CPSFUNC_ADD_PFNPROPSHEETUI, (LPARAM)DocumentPropertySheets, (LPARAM)&_dph ) <= 0 ) { DBGMSG( DBG_TRACE, ( "CPSFUNC_ADD_PFNPROPSHEETUI failed.\n") ); bStatus DBGCHK = FALSE; } } } } return bStatus; } BOOL TDocumentWindows:: bSetHeader( IN PPROPSHEETUI_INFO pCPSUIInfo, IN PPROPSHEETUI_INFO_HEADER pPSUIInfoHdr ) { DBGMSG( DBG_TRACE, ( "TDocumentWindows bSetHeader\n") ); UNREFERENCED_PARAMETER( pCPSUIInfo ); pPSUIInfoHdr->pTitle = _pDocumentData->pJobInfo()->pDocument; pPSUIInfoHdr->Flags = PSUIHDRF_PROPTITLE; pPSUIInfoHdr->hWndParent = _pDocumentData->hwnd(); pPSUIInfoHdr->hInst = ghInst; pPSUIInfoHdr->IconID = IDI_DOCUMENT; return TRUE; } BOOL TDocumentWindows:: bValid( VOID ) { return _General.bValid(); } /******************************************************************** Document properties UI (driver UI) ********************************************************************/ TDocumentProperties:: TDocumentProperties( IN HWND hwnd, IN HANDLE hPrinter, IN LPCTSTR pszPrinter, IN PDEVMODE pDevModeIn, OUT PDEVMODE pDevModeOut, IN DWORD dwHideBits, IN DWORD dwFlags ): _hwnd(hwnd), _hPrinter(hPrinter), _pszPrinter(pszPrinter), _pDevModeIn(pDevModeIn), _pDevModeOut(pDevModeOut), _dwHideBits(dwHideBits), _dwFlags(dwFlags), _lResult(-1) { // nothing } LONG TDocumentProperties:: lGetResult( VOID ) const { return _lResult; } BOOL TDocumentProperties:: bBuildPages( IN PPROPSHEETUI_INFO pCPSUIInfo ) { BOOL bRet = FALSE; if( bValid() ) { // // Set the default activation context to be V6 prior calling into // compstui to create the pages. This will force V6 context unless // the callbacks which create the compstui pages specify otherwise // on a per page basis. // bRet = (BOOL)pCPSUIInfo->pfnComPropSheet( pCPSUIInfo->hComPropSheet, CPSFUNC_SET_FUSION_CONTEXT, reinterpret_cast(g_hActCtx), static_cast(0)); if( bRet ) { ZeroMemory(&_dph, sizeof(_dph)); _dph.cbSize = sizeof(_dph); _dph.hPrinter = _hPrinter; _dph.pszPrinterName = const_cast(_pszPrinter); _dph.pdmIn = _pDevModeIn; _dph.pdmOut = _pDevModeOut; _dph.fMode = _dwFlags; if( _dwHideBits ) { _lResult = pCPSUIInfo->pfnComPropSheet(pCPSUIInfo->hComPropSheet, CPSFUNC_SET_DMPUB_HIDEBITS, static_cast(_dwHideBits), 0); } else { // // If no bit is hided, The result value should be valid. // _lResult = 1; } if( _lResult > 0 ) { _lResult = pCPSUIInfo->pfnComPropSheet(pCPSUIInfo->hComPropSheet, CPSFUNC_ADD_PFNPROPSHEETUI, reinterpret_cast(DocumentPropertySheets), reinterpret_cast(&_dph)); } } } return (_lResult > 0); } BOOL TDocumentProperties:: bSetHeader( IN PPROPSHEETUI_INFO pCPSUIInfo, IN PPROPSHEETUI_INFO_HEADER pPSUInfoHeader ) { // construct the title & setup the header UNREFERENCED_PARAMETER(pCPSUIInfo); if( 0 == _strTitle.uLen() ) { _strTitle.bLoadString(ghInst, IDS_PRINTER_PREFERENCES); } pPSUInfoHeader->pTitle = const_cast(static_cast(_strTitle)); pPSUInfoHeader->Flags = PSUIHDRF_EXACT_PTITLE | PSUIHDRF_NOAPPLYNOW; pPSUInfoHeader->hWndParent = _hwnd; pPSUInfoHeader->hInst = ghInst; pPSUInfoHeader->IconID = IDI_PRINTER; return TRUE; } // table to remap the devmode field selections to DMPUB_* ids. static DWORD arrDmFlagMap[] = { DM_ORIENTATION, MAKE_DMPUB_HIDEBIT( DMPUB_ORIENTATION ), DM_PAPERSIZE , MAKE_DMPUB_HIDEBIT( 0 ), DM_PAPERLENGTH, MAKE_DMPUB_HIDEBIT( 0 ), DM_PAPERWIDTH , MAKE_DMPUB_HIDEBIT( 0 ), DM_SCALE , MAKE_DMPUB_HIDEBIT( DMPUB_SCALE ), DM_COPIES , MAKE_DMPUB_HIDEBIT( DMPUB_COPIES_COLLATE ), DM_DEFAULTSOURCE, MAKE_DMPUB_HIDEBIT( DMPUB_DEFSOURCE ), DM_PRINTQUALITY, MAKE_DMPUB_HIDEBIT( DMPUB_PRINTQUALITY ), DM_COLOR , MAKE_DMPUB_HIDEBIT( DMPUB_COLOR ), DM_DUPLEX , MAKE_DMPUB_HIDEBIT( DMPUB_DUPLEX ), DM_YRESOLUTION, MAKE_DMPUB_HIDEBIT( 0 ), DM_TTOPTION , MAKE_DMPUB_HIDEBIT( DMPUB_TTOPTION ), DM_COLLATE , MAKE_DMPUB_HIDEBIT( DMPUB_COPIES_COLLATE ), DM_FORMNAME , MAKE_DMPUB_HIDEBIT( DMPUB_FORMNAME ), DM_LOGPIXELS , MAKE_DMPUB_HIDEBIT( 0 ), DM_BITSPERPEL , MAKE_DMPUB_HIDEBIT( 0 ), DM_PELSWIDTH , MAKE_DMPUB_HIDEBIT( 0 ), DM_PELSHEIGHT , MAKE_DMPUB_HIDEBIT( 0 ), DM_DISPLAYFLAGS, MAKE_DMPUB_HIDEBIT( 0 ), DM_DISPLAYFREQUENCY, MAKE_DMPUB_HIDEBIT( 0 ), DM_ICMMETHOD , MAKE_DMPUB_HIDEBIT( DMPUB_ICMMETHOD ), DM_ICMINTENT , MAKE_DMPUB_HIDEBIT( DMPUB_ICMINTENT ), DM_MEDIATYPE , MAKE_DMPUB_HIDEBIT( DMPUB_MEDIATYPE ), DM_DITHERTYPE , MAKE_DMPUB_HIDEBIT( DMPUB_DITHERTYPE ), DM_PANNINGWIDTH, MAKE_DMPUB_HIDEBIT( 0 ), DM_PANNINGHEIGHT, MAKE_DMPUB_HIDEBIT( 0 ) }; static DWORD RemapExclusionFlags(DWORD fExclusionFlags) { // walk through to collect the exclusion bits from the table above. DWORD dwFlags = 0; for( UINT i = 0; i < ARRAYSIZE(arrDmFlagMap); i += 2 ) { if( fExclusionFlags & arrDmFlagMap[i] ) { dwFlags |= arrDmFlagMap[i+1]; } } return dwFlags; } LONG DocumentPropertiesWrapNative( HWND hwnd, // handle to parent window HANDLE hPrinter, // handle to printer object LPTSTR pDeviceName, // device name PDEVMODE pDevModeOutput, // modified device mode PDEVMODE pDevModeInput, // original device mode DWORD fMode, // mode options DWORD fExclusionFlags // exclusion flags ) { // lResult <= 0 means error, for more information see // the description of DocumentProperties in SDK. LONG lResult = (-1); if( hPrinter && pDeviceName && pDevModeOutput && pDevModeInput ) { if (fMode & DM_PROMPT) { // invoke compstui to show up the driver UI TDocumentProperties props(hwnd, hPrinter, pDeviceName, pDevModeInput, pDevModeOutput, RemapExclusionFlags(fExclusionFlags), fMode); if( props.bDisplayPages(hwnd, &lResult) ) { // convert the result to IDOK/IDCANCEL lResult = (lResult == CPSUI_OK) ? IDOK : IDCANCEL; } else { // error occured. lResult = (-1); } } else { // this is no UI call - just invoke DocumentProperties. lResult = DocumentProperties(hwnd, hPrinter, pDeviceName, pDevModeOutput, pDevModeInput, fMode); } } return lResult; } LONG DocumentPropertiesWrapWOW64( HWND hwnd, // handle to parent window HANDLE hPrinter, // handle to printer object LPTSTR pDeviceName, // device name PDEVMODE pDevModeOutput, // modified device mode PDEVMODE pDevModeInput, // original device mode DWORD fMode, // mode options DWORD fExclusionFlags // exclusion flags ) { CDllLoader dll(TEXT("winspool.drv")); ptr_PrintUIDocumentPropertiesWrap pfnPrintUIDocumentPropertiesWrap = (ptr_PrintUIDocumentPropertiesWrap )dll.GetProcAddress(ord_PrintUIDocumentPropertiesWrap); LONG lResult = (-1); if( pfnPrintUIDocumentPropertiesWrap ) { lResult = pfnPrintUIDocumentPropertiesWrap(hwnd, hPrinter, pDeviceName, pDevModeOutput, pDevModeInput, fMode, fExclusionFlags); } return lResult; } LONG DocumentPropertiesWrap( HWND hwnd, // handle to parent window HANDLE hPrinter, // handle to printer object LPTSTR pDeviceName, // device name PDEVMODE pDevModeOutput, // modified device mode PDEVMODE pDevModeInput, // original device mode DWORD fMode, // mode options DWORD fExclusionFlags // exclusion flags ) { // if running in WOW64 environment we need to call winspool.drv to remote the // call into the surrogate 64bit process where the driver UI can be displayed. LONG lResult = IsRunningWOW64() ? DocumentPropertiesWrapWOW64(hwnd, hPrinter, pDeviceName, pDevModeOutput, pDevModeInput, fMode, fExclusionFlags) : DocumentPropertiesWrapNative(hwnd, hPrinter, pDeviceName, pDevModeOutput, pDevModeInput, fMode, fExclusionFlags); return lResult; }