特别注意:
1)Note that a call to ResetDC resets all device context attributes back to default values.
2)The system disables the ResetDC function between calls to the StartPage and EndPage functions. This means that you cannot change the device mode except at page boundaries.
这时可以和下面的另外一种方法配合使用:用下面的另外一种方法修改打印机的默认值,再用ResetDC
Using a DEVMODE structure to modify printer settings is more difficult than just changing the fields of the structure. Specifically, a valid DEVMODE structure for a device contains private data that can only be modified by the DocumentProperties() function.
Details
LPDEVMODE GetLandscapeDevMode(HWND hWnd, const CString& strPrinterName, SHORT dmOrientation)
{
HANDLE hPrinter = NULL;
LPDEVMODE pDevMode = NULL;
DWORD dwNeeded = 0, dwRet = 0;
CString strName(strPrinterName);
/* Start by opening the printer */
if (!OpenPrinter((LPTSTR)(LPCTSTR)(strName), &hPrinter, NULL))
return NULL;
/*
* Step 1:
* Allocate a buffer of the correct size.
*/
dwNeeded = DocumentProperties(hWnd,
hPrinter, /* Handle to our printer. */
(LPTSTR)(LPCTSTR)(strName),/* Name of the printer. */
NULL, /* Asking for size, so */
NULL, /* these are not used. */
0); /* Zero returns buffer size. */
pDevMode = (LPDEVMODE)malloc(dwNeeded);
/*
* Step 2:
* Get the default DevMode for the printer and
* modify it for your needs.
*/
dwRet = DocumentProperties(hWnd,
hPrinter,
(LPTSTR)(LPCTSTR)(strName),
pDevMode, /* The address of the buffer to fill. */
NULL, /* Not using the input buffer. */
DM_OUT_BUFFER); /* Have the output buffer filled. */
if (dwRet != IDOK)
{
/* If failure, cleanup and return failure. */
free(pDevMode);
ClosePrinter(hPrinter);
return NULL;
}
/*
* Make changes to the DevMode which are supported.
*/
if (pDevMode->dmFields & DM_ORIENTATION)
{
/* If the printer supports paper orientation, set it.*/
pDevMode->dmOrientation = dmOrientation;//DMORIENT_PORTRAIT or DMORIENT_LANDSCAPE;
}
//if (pDevMode->dmFields & DM_DUPLEX)
//{
// /* If it supports duplex printing, use it. */
// pDevMode->dmDuplex = DMDUP_HORIZONTAL;
//}
/*
* Step 3:
* Merge the new settings with the old.
* This gives the driver an opportunity to update any private
* portions of the DevMode structure.
*/
dwRet = DocumentProperties(hWnd,
hPrinter,
(LPTSTR)(LPCTSTR)(strName),
pDevMode, /* Reuse our buffer for output. */
pDevMode, /* Pass the driver our changes. */
DM_IN_BUFFER | /* Commands to Merge our changes and */
DM_OUT_BUFFER); /* write the result. */
/* Finished with the printer */
ClosePrinter(hPrinter);
if (dwRet != IDOK)
{
/* If failure, cleanup and return failure. */
free(pDevMode);
return NULL;
}
/* Return the modified DevMode structure. */
return pDevMode;
}
LPDEVMODE pDevMode = GetLandscapeDevMode(hWnd, strPrinterName, DMORIENT_LANDSCAPE);
if(NULL != pDevMode)
{//Step4: apply to new DEVMODE
BOOL bRet = pDC->ResetDC(pDevMode);
free(pDevMode);//release memory
}
//usage example:
StartDoc();
foreach(page in pages)
{
//调用上面的方法为每一页修改页面方向
StartPage();
OnPrint();//do print
EndPage();
}
EndDoc();
//after printing, recover original orientation
if(bChanged)
ChangePrinterOrientation(szPrinterName, originalOrientation, shPreOrientation);
直接传入pOriDevMode,只修改orientation,这里的关键是对pOriDevMode->dmDriverExtra的处理。
BOOL ChangePageOrient(IN OUT CDC* pDC, IN SHORT shOrient, LPDEVMODE pOriDevMode)
{
if (NULL == pDC)
return FALSE;
if(NULL == pOriDevMode)
return FALSE;
DWORD dwNeeded = pOriDevMode->dmSize + pOriDevMode->dmDriverExtra;
LPDEVMODE pDevMode = (LPDEVMODE)malloc(dwNeeded);
if(NULL == pDevMode)
return FALSE;
memcpy(pDevMode, pOriDevMode, pOriDevMode->dmSize + pOriDevMode->dmDriverExtra);
//Make changes to the DevMode which are supported.
if (pDevMode->dmFields & DM_ORIENTATION)
{
pDevMode->dmOrientation = shOrient;
}
else
{
free(pDevMode);
return FALSE;
}
BOOL bRet = pDC->ResetDC(pDevMode);
free(pDevMode);
return bRet;
}
使用举例
CPrintDialog oDlg(FALSE, PD_COLLATE | PD_PAGENUMS | PD_HIDEPRINTTOFILE, this);
oDlg.m_pd.nCopies = 1;
oDlg.m_pd.nMinPage = oDlg.m_pd.nFromPage =1;
oDlg.m_pd.nMaxPage = oDlg.m_pd.nToPage = 1;
if( IDOK == oDlg.DoModal() )
{
DOCINFO sDocInfo;
memset(&sDocInfo, 0, sizeof(DOCINFO));
sDocInfo.cbSize = sizeof(DOCINFO);
sDocInfo.lpszOutput = NULL;
HDC hdc = oDlg.CreatePrinterDC();
CDC* pDC = CDC::FromHandle(hdc);
LPDEVMODE pMode = oDlg.GetDevMode();
{
strDocName += _T("GDIPlus");
sDocInfo.lpszDocName = strDocName;
::StartDoc(pDC->m_hDC, &sDocInfo);
ChangePageOrient(pDC, DMORIENT_PORTRAIT, pMode);
::StartPage(pDC->m_hDC);
{
//draw on pDC
}
::EndPage(pDC->m_hDC);
::EndDoc(pDC->m_hDC);
}
::GlobalUnlock(pMode);
::DeleteDC(hdc);
}
//return if the orientation be changed
BOOL ChangePrinterOrientation(const CString& strPrinterName,
short dmNewVal,
short& dmOrigOrientation)
{
CString strName(strPrinterName);
// Open printer handle
PRINTER_DEFAULTS pd;
ZeroMemory(&pd, sizeof(pd));
pd.DesiredAccess = PRINTER_ALL_ACCESS;
HANDLE hPrinter = NULL;
LPTSTR pPrinterName = (LPTSTR)(LPCTSTR)(strName);
BOOL bFlag = OpenPrinter(pPrinterName, &hPrinter, &pd);
if (!bFlag || (hPrinter == NULL))
{
return FALSE;
}
SetLastError(0);
DWORD dwNeeded = 0;
bFlag = GetPrinter(hPrinter, 2, 0, 0, &dwNeeded);
if ((!bFlag) && (GetLastError() != ERROR_INSUFFICIENT_BUFFER) || (dwNeeded == 0))
{
ClosePrinter(hPrinter);
return FALSE;
}
// Allocate enough space for PRINTER_INFO_2...
PRINTER_INFO_2* pi2 = (PRINTER_INFO_2 *)GlobalAlloc(GPTR, dwNeeded);
if (pi2 == NULL)
{
ClosePrinter(hPrinter);
return FALSE;
}
// The second GetPrinter fills in all the current settings, so all you
// need to do is modify what you're interested in...
bFlag = GetPrinter(hPrinter, 2, (LPBYTE)pi2, dwNeeded, &dwNeeded);
if (!bFlag)
{
GlobalFree(pi2);
ClosePrinter(hPrinter);
return FALSE;
}
// If GetPrinter didn't fill in the DEVMODE,
// try to get it by calling DocumentProperties...
LONG lFlag;
DEVMODE *pDevMode = NULL;
if (pi2->pDevMode == NULL)
{
dwNeeded = DocumentProperties(NULL, hPrinter,
pPrinterName, NULL, NULL, 0);
if (dwNeeded <= 0)
{
GlobalFree(pi2);
ClosePrinter(hPrinter);
return FALSE;
}
pDevMode = (DEVMODE *)GlobalAlloc(GPTR, dwNeeded);
if (pDevMode == NULL)
{
GlobalFree(pi2);
ClosePrinter(hPrinter);
return FALSE;
}
lFlag = DocumentProperties(NULL, hPrinter,
pPrinterName, pDevMode, NULL, DM_OUT_BUFFER);
if (lFlag != IDOK || pDevMode == NULL)
{
GlobalFree(pDevMode);
GlobalFree(pi2);
ClosePrinter(hPrinter);
return FALSE;
}
pi2->pDevMode = pDevMode;
}
// Driver is reporting that it doesn't support this change...
if (!(pi2->pDevMode->dmFields & DM_ORIENTATION))
{
GlobalFree(pi2);
ClosePrinter(hPrinter);
if (pDevMode)
GlobalFree(pDevMode);
return FALSE;
}
if (pi2->pDevMode->dmOrientation == dmNewVal)
{
GlobalFree(pi2);
ClosePrinter(hPrinter);
if (pDevMode)
GlobalFree(pDevMode);
dmOrigOrientation = dmNewVal;
return FALSE;
}
// Specify exactly what we are attempting to change...
pi2->pDevMode->dmFields = DM_ORIENTATION;
short OriginalOrientation = pi2->pDevMode->dmOrientation;
// Now, change it to whatever was requested by the calling application
pi2->pDevMode->dmOrientation = dmNewVal;
// Do not attempt to set security descriptor...
pi2->pSecurityDescriptor = NULL;
// Make sure the driver-dependent part of devmode is updated...
lFlag = DocumentProperties(NULL,
hPrinter,
pPrinterName,
pi2->pDevMode,
pi2->pDevMode,
DM_IN_BUFFER |
DM_OUT_BUFFER);
if (lFlag != IDOK)
{
GlobalFree(pi2);
ClosePrinter(hPrinter);
if (pDevMode)
GlobalFree(pDevMode);
return FALSE;
}
// Update printer information...
bFlag = SetPrinter(hPrinter, 2, (LPBYTE)pi2, 0);
if (!bFlag)
{// The driver doesn't support, or it is unable to make the change...
GlobalFree(pi2);
ClosePrinter(hPrinter);
if (pDevMode)
GlobalFree(pDevMode);
return FALSE;
}
//notify other apps
SendMessageTimeout(HWND_BROADCAST, WM_DEVMODECHANGE, 0L, (LPARAM)(LPCSTR)pPrinterName, SMTO_NORMAL, 1000, NULL);
// Clean up...
if (pi2)
GlobalFree(pi2);
if (hPrinter)
ClosePrinter(hPrinter);
if (pDevMode)
GlobalFree(pDevMode);
//bring back the origianl value
dmOrigOrientation = OriginalOrientation;
return TRUE;
}
//usage example:
BOOL bChanged = FALSE;
SHORT shPreOrientation = 0;
//change orientation for all pages
bChanged = ChangePrinterOrientation(szPrinterName, page.shPageOrientation, shPreOrientation);
StartDoc();
foreach(page in pages)
{
StartPage();
OnPrint();//do print
EndPage();
}
EndDoc();
//after printing, recover original orientation
if(bChanged)
ChangePrinterOrientation(szPrinterName, originalOrientation, shPreOrientation);