1. 程式人生 > >C++ 印表機設定

C++ 印表機設定

我在網上已不斷看到一些網友關於自定義紙張列印的問題,基本上還沒有較完美的解決方案,我在這裡提供一個WindowsNT/2000/XP下的解決辦法,供廣大同仁參考。Windows9x/Me下也有解決辦法,有興趣者可共同探討。
  該方法的主要思想是在程式開始時新增自定義紙張並設為預設紙張,程式結束前刪除該自定義紙張並恢復原來的預設紙張型別。這種方法的通用性是顯而易見的,如果你正在用Document/View框架,那麼你就不必為了自定義紙張而去挖空心思過載其中的一些函數了。
  以下是我的程式片斷,請朋友們多提寶貴意見。如果我的程式碼能為您所用,那是我極大的榮幸。
  注:我在論壇中回覆的帖子中個別GlobalAlloc和GlobalFree打錯成了Alloc和Free,予以糾正並發表在此。


 

#i nclude
typedef TCHAR PAPERNAME[64]; //印表機紙張名稱型別
//檢測系統是否為Windows NT/2000/XP
BOOL CPrinter::IsWindowsNT()
{
OSVERSIONINFO vi;
vi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
GetVersionEx(&vi);
return (vi.dwPlatformId == VER_PLATFORM_WIN32_NT);
}
//獲得預設印表機名稱和預設的紙張
BOOL GetDefaultPrinterAndPaper(LPTSTR szPrinterName, int nPrintNameBufferLen, LPTSTR szPaperName)
{
*szPrinterName = 0;
*szPaperName = 0;
CPrintDialog pd(FALSE);
if (pd.GetDefaults())
{
if (pd.m_pd.hDC) DeleteDC(pd.m_pd.hDC);
if (pd.m_pd.hDevMode)
{
LPDEVMODE pdm = (LPDEVMODE)GlobalLock(pd.m_pd.hDevMode);
*(szPaperName + 63) = 0;
_tcsncpy(szPaperName, (LPCTSTR)pdm->dmFormName, 63); //列印紙張名稱
GlobalUnlock(pd.m_pd.hDevMode);
GlobalFree(pd.m_pd.hDevMode);
}
if (pd.m_pd.hDevNames)
{
LPDEVNAMES pdn = (LPDEVNAMES)GlobalLock(pd.m_pd.hDevNames);
nPrintNameBufferLen--;
*(szPrinterName + nPrintNameBufferLen) = 0;
_tcsncpy(szPrinterName, (LPTSTR)pdn + pdn->wDeviceOffset, nPrintNameBufferLen); //印表機名稱
GlobalUnlock(pd.m_pd.hDevNames);
GlobalFree(pd.m_pd.hDevNames);
}
}
return (*szPrinterName && *szPaperName);
}
//增加規格自定義紙張
//szPaperName: 自定義紙張名稱
//PaperSize: 紙張的大小,以0.1mm為單位
//rcPrintableMargin: 印表機的最小可列印邊界,以0.1mm為單位。
// 可參見GetDeviceCaps函式說明中的PHYSICALOFFSETX及PHYSICALOFFSETY
BOOL AddCustomPaper(LPCTSTR szPrinterName, PAPERNAME szPaperName, SIZE PaperSize, RECT rcPrintableMargin)
{
BOOL bOk = FALSE;
if (IsWindowsNT()) //Windows NT4/2000/XP才支援
{
FORM_INFO_1 fi1;
fi1.Flags = FORM_USER;
fi1.pName = (LPTSTR)szPaperName;
fi1.Size.cx = PaperSize.cx * 100;
fi1.Size.cy = PaperSize.cy * 100;
fi1.ImageableArea.left = rcPrintableMargin.left * 100;
fi1.ImageableArea.top = rcPrintableMargin.top * 100;
fi1.ImageableArea.right = fi1.Size.cx - rcPrintableMargin.right * 100;
fi1.ImageableArea.bottom = fi1.Size.cy - rcPrintableMargin.bottom * 100;
HANDLE hPrinter = GetPrinterHandle(szPrinterName);
if (hPrinter)
{
bOk = (SetForm(hPrinter, (LPSTR)szPaperName, 1, (LPBYTE)&fi1) || //已存在該型別紙張則更改
AddForm(hPrinter, 1, (LPBYTE)&fi1)); //否則新增此自定義紙張
ClosePrinter(hPrinter);
}
}
return bOk;
}
//刪除自定義規格紙張
BOOL DeleteCustomPaper(LPCTSTR szPrinterName, LPCTSTR szPaperName)
{
BOOL bOk = FALSE;
if (IsWindowsNT()) //Windows NT4/2000/XP才支援
{
HANDLE hPrinter = GetPrinterHandle(szPrinterName);
if (hPrinter)
{
bOk = DeleteForm(hPrinter, (LPSTR)szPaperName);
ClosePrinter(hPrinter);
}
}
return bOk;
}
//獲取印表機控制代碼
HANDLE GetPrinterHandle(LPCTSTR szPrinterName)
{
PRINTER_DEFAULTS pds;
HANDLE hPrinter = NULL;
ZeroMemory(&pds, sizeof(PRINTER_DEFAULTS));
pds.DesiredAccess = PRINTER_ALL_ACCESS;
OpenPrinter(szPrinterName, &hPrinter, &pds);
return hPrinter;
}
//由紙張名稱得到對應的DEVMODE中的那個dmPaperSize值,返回-1表示有錯誤
short GetPaperSize(LPCTSTR szPrinterName, LPCTSTR szPortName, PAPERNAME szPaperName)
{
short nPaperSize = -1;
//獲得可用印表機紙張型別數目
int nNeeded = DeviceCapabilities(szPrinterName, szPortName, DC_PAPERNAMES, NULL, NULL);
if (nNeeded)
{
PAPERNAME *pszPaperNames = new PAPERNAME[nNeeded]; //分配紙張名稱陣列
//獲得可用印表機紙張名稱陣列
if (DeviceCapabilities(szPrinterName, szPortName, DC_PAPERNAMES, (LPTSTR)pszPaperNames, NULL) != -1)
{
int i;
//查詢紙張型別szPaperName在陣列中的索引
for (i = 0; i < nNeeded && _tcscmp(pszPaperNames[i], szPaperName); i++);
if (i < nNeeded)
{
//獲得可用印表機紙張尺寸號數目(應該等於印表機紙張型別數目)
nNeeded = DeviceCapabilities(szPrinterName, szPortName, DC_PAPERS, NULL, NULL);
if (nNeeded)
{
LPWORD pPapers = new WORD[nNeeded]; //分配紙張尺寸號陣列
//獲得可用印表機紙張尺寸號陣列
if (DeviceCapabilities(szPrinterName, szPortName, DC_PAPERS, (LPSTR)pPapers, NULL) != -1)
nPaperSize = pPapers[i]; //獲得紙張型別szPaperName對應的尺寸號
delete []pPapers;
}
}
}
delete []pszPaperNames;
}
return nPaperSize;
}
//設定印表機的預設紙張和方向
BOOL SetPaper(LPCTSTR szPrinterName, PAPERNAME szPaperName, short nOrientation)
{
BOOL bOk = FALSE;
PRINTER_INFO_2 *ppi2 = GetInfo2(szPrinterName);
if (ppi2)
{
short nPaperSize = GetPaperSize(szPrinterName, ppi2->pPortName, szPaperName);
if (nPaperSize != -1)
{
ppi2->pDevMode->dmFields = DM_PAPERSIZE|DM_PAPERWIDTH|DM_PAPERLENGTH|DM_ORIENTATION;
ppi2->pDevMode->dmPaperSize = nPaperSize;
ppi2->pDevMode->dmPaperWidth = 0;
ppi2->pDevMode->dmPaperLength = 0;
ppi2->pDevMode->dmOrientation = nOrientation;
bOk = SetInfo2(ppi2);
}
GlobalFree((HGLOBAL)ppi2);
}
return bOk;
}
//獲取印表機詳細資訊,返回的指標用後必須以GlobalFree釋放
PRINTER_INFO_2 *GetInfo2(LPCTSTR szPrinterName)
{
HANDLE hPrinter = GetPrinterHandle(szPrinterName);
PRINTER_INFO_2 *ppi2 = NULL;
DWORD cbNeeded = 0;
if (hPrinter)
{
GetPrinter(hPrinter, 2, 0, 0, &cbNeeded);
if (cbNeeded)
{
ppi2 = (PRINTER_INFO_2 *)GlobalAlloc(GPTR, cbNeeded);
if (ppi2)
{
if (!GetPrinter(hPrinter, 2, (LPBYTE)ppi2, cbNeeded, &cbNeeded))
{
GlobalFree((HGLOBAL)ppi2);
ppi2 = NULL;
}
}
}
ClosePrinter(hPrinter);
}
return ppi2;
}
//印表機設定
BOOL SetInfo2(PRINTER_INFO_2 *ppi2)
{
HANDLE hPrinter = GetPrinterHandle(ppi2->pPrinterName);
BOOL bOk = FALSE;
DWORD fMode;
if (hPrinter)
{
fMode = DM_IN_BUFFER | DM_OUT_BUFFER;
bOk = (DocumentProperties(NULL, hPrinter,
ppi2->pPrinterName,
ppi2->pDevMode,
ppi2->pDevMode,
fMode) == IDOK &&
::SetPrinter(hPrinter, 2, (LPBYTE)ppi2, 0));
ClosePrinter(hPrinter);
}
return bOk;
}

TCHAR szPrinterName[32];
PAPERNAME szPaperName, szOldPaperName;
//在您的程式開始時,獲取預設印表機名和紙張名
GetDefaultPrinterAndPaper(szPrinterName, 32, szOldPaperName);
_tcscpy(szPaperName, _T("我的自定義紙張"));
//增加自定義紙張
AddCustomPaper(szPrinterName, szPaperName, CSize(1480, 2000), CRect(70, 70, 70, 70));
//並設自定義紙張為預設紙張
SetPaper(szPrinterName, szPaperName, DMORIENT_PORTRAIT);

//在您的程式結束前
//刪除自定義紙張
DeleteCustomPaper(szPrinterName, szPaperName);
//並恢復初始預設紙張
SetPaper(szPrinterName, szOldPaperName);
---------------------
作者:laowang2
來源:CSDN
原文:https://blog.csdn.net/wewaa/article/details/5992011
版權宣告:本文為博主原創文章,轉載請附上博文連結!