PrinterSettings.cpp
上传用户:jubilation
上传日期:2007-01-03
资源大小:18k
文件大小:12k
源码类别:

打印编程

开发平台:

Visual C++

  1. // PrinterSettings.cpp: Implementierung der Klasse CPrinterSettings.
  2. //
  3. //////////////////////////////////////////////////////////////////////
  4. #include "stdafx.h"
  5. #include "PrinterSettings.h"
  6. #ifdef _DEBUG
  7. #undef THIS_FILE
  8. static char THIS_FILE[]=__FILE__;
  9. #define new DEBUG_NEW
  10. #endif
  11. //////////////////////////////////////////////////////////////////////
  12. // Konstruktion/Destruktion
  13. //////////////////////////////////////////////////////////////////////
  14. CPrinterSettings::CPrinterSettings()
  15. {
  16. m_hDevMode = m_hDevNames = NULL;
  17. m_hSaveDevMode = NULL;
  18. m_hSaveDevNames = NULL;
  19. m_strPrinterName = PRINTERNAME_UNDEFINED;
  20. m_strdirname = PRINTERSETTINGS_DIRECTORYNAME;
  21. }
  22. CPrinterSettings::CPrinterSettings(const CString dirname)
  23. {
  24. CPrinterSettings();
  25. m_strdirname = dirname;
  26. }
  27. CPrinterSettings::~CPrinterSettings()
  28. {
  29. if (m_hDevMode)  GlobalFree(m_hDevMode);
  30. if (m_hDevNames) GlobalFree(m_hDevNames);
  31. // if possible MFC-Printer will go back to m_hSaveDevMode
  32. RestorePrinter();
  33. }
  34. void CPrinterSettings::operator=(const CPrinterSettings* src)
  35. {
  36. VERIFY(src != NULL);
  37. m_hDevMode = CopyHandle(src->m_hDevMode);
  38. m_hDevNames = CopyHandle(src->m_hDevNames);
  39. m_strPrinterName = src->m_strPrinterName;
  40. m_strdirname = src->m_strdirname;
  41. m_strfilename = src->m_strfilename;
  42. }
  43. void CPrinterSettings::operator=(const CPrinterSettings& src)
  44. {
  45. *this = &src;
  46. }
  47. //
  48. // check to see if our printer (e.g. m_strprintername)
  49. // is still available
  50. //
  51. BOOL CPrinterSettings::IsPrinterAvailable(LPCTSTR pszDeviceName)
  52. {
  53. HANDLE hPrinter;
  54. if (OpenPrinter((char *) pszDeviceName, &hPrinter, NULL) == FALSE)
  55. return FALSE;
  56. ClosePrinter(hPrinter);
  57. return TRUE;
  58. }
  59. //
  60. // change settings for global printer
  61. //
  62. // pszDeviceName is the name of your
  63. // printer e.g. "Epson Stylus Color 750"
  64. //
  65. BOOL CPrinterSettings::SetPrinterDevice(LPCTSTR pszDeviceName) const
  66. {
  67. HANDLE hPrinter;
  68. int ret = 0;
  69. PRINTER_DEFAULTS pd;
  70. ZeroMemory(&pd, sizeof(pd)); 
  71. // because of SetPrinter we need all access
  72. pd.DesiredAccess = PRINTER_ALL_ACCESS;
  73. if (OpenPrinter((char *) pszDeviceName, &hPrinter, &pd) == FALSE)
  74. return FALSE;
  75. DWORD dwBytesReturned, dwBytesNeeded;
  76. GetPrinter(hPrinter, 2, NULL, 0, &dwBytesNeeded);
  77. PRINTER_INFO_2* p2 = (PRINTER_INFO_2*)GlobalAlloc(GPTR,dwBytesNeeded);
  78. if (GetPrinter(hPrinter, 2, (LPBYTE)p2, dwBytesNeeded,&dwBytesReturned) == 0) {
  79. GlobalFree(p2);
  80. ClosePrinter(hPrinter);
  81. return FALSE;
  82. }
  83. // Lock handle for DEVMODE and copy DEVMODE data to PRINTER_INFO_2.
  84. // (Instead you can change DEVMODE-fields at p2->pDevMode directly)
  85. DEVMODE* pDevMode = (DEVMODE*) GlobalLock(m_hDevMode);
  86. int dwsize = sizeof(*p2->pDevMode);
  87. //CopyMemory(p2->pDevMode,pDevMode, sizeof(*p2->pDevMode));
  88. CopyDevmode(p2->pDevMode,pDevMode);
  89. // same for DEVNAMES.
  90. DEVNAMES* lpDevNames = (LPDEVNAMES)GlobalLock(m_hDevNames);
  91.     LPTSTR lpszDeviceName = (LPTSTR )lpDevNames + lpDevNames->wDeviceOffset;
  92. // check to see if our settings are valid
  93. ret = DocumentProperties(NULL,hPrinter,lpszDeviceName,NULL,pDevMode,DM_IN_BUFFER);
  94. p2->pSecurityDescriptor = NULL;
  95. // p2->Attributes = 0;
  96. p2->Priority = 0;
  97. // change settings
  98. if(IDOK == ret)
  99. ret = SetPrinter(hPrinter,2,(LPBYTE)p2,0);
  100. GlobalFree(p2);             // free PRINTER_INFO_2.
  101. GlobalUnlock(m_hDevMode);
  102. GlobalUnlock(m_hDevNames);
  103. ClosePrinter(hPrinter);
  104. // Notification: settings changed
  105. SendMessage(HWND_BROADCAST, WM_DEVMODECHANGE, 0L,
  106.                (LPARAM)pszDeviceName);
  107. return ret;
  108. }
  109. //
  110. // Show the printer common dialog
  111. // Accept and store all settings
  112. //
  113. // This code is predominantly from a microsoft sample:
  114. // HOWTO: Implementing an Application-Defined Default Printer 
  115. // Article ID: Q193103 
  116. //
  117. CString CPrinterSettings::PrinterSetup( CWnd* pWnd)
  118. {
  119. // Ask the user which printer to use.
  120. ASSERT(pWnd);
  121. CPrintDialog pd(
  122.   FALSE,PD_ALLPAGES | PD_USEDEVMODECOPIES | PD_NOPAGENUMS | PD_HIDEPRINTTOFILE | PD_NOSELECTION,pWnd);
  123. // Make sure we don't accidentally create a device context
  124. pd.m_pd.Flags &= ~PD_RETURNDC;   // Reset flag set by constructor.
  125. // Force the CPrintDialog to use our device mode & name.
  126. if(m_hDevMode)
  127. pd.m_pd.hDevMode  = CopyHandle(m_hDevMode);
  128. if(m_hDevNames)
  129. pd.m_pd.hDevNames = CopyHandle(m_hDevNames);
  130. // Display the dialog box and let the user make their selection.
  131. if (pd.DoModal() == IDOK) {
  132. // The user clicked OK
  133. // (and POSSIBLY changed printers).
  134. // In any case, the CPrintDialog logic made a copy of the original
  135. // DEVMODE/DEVNAMES that we passed it and applied the user's
  136. // changes to that copy and discarded the original copy we passed
  137. // it. (NOTE: If the user had clicked CANCEL instead, the original
  138. // values we passed would have been returned unchanged).
  139. if(m_hDevMode)
  140. GlobalFree(m_hDevMode);                      // Free old copies.
  141. if(m_hDevNames)
  142. GlobalFree(m_hDevNames);                     // Free old copies.
  143. if(pd.m_pd.hDevMode)
  144. m_hDevMode  = CopyHandle(pd.m_pd.hDevMode);  // Save new copies.
  145. if(pd.m_pd.hDevNames)
  146. m_hDevNames = CopyHandle(pd.m_pd.hDevNames); // Save new copies.
  147. }
  148. // Regardless of whether the user clicked OK or CANCEL,
  149. // we need to ALWAYS do a GlobalFree of CPrintDialog's
  150. // m_pd.hDevMode and m_pd.hDevNames upon return from
  151. // DoModal in order to prevent a resource leak.
  152. GlobalFree(pd.m_pd.hDevMode);   // Because DoModal was called,
  153. GlobalFree(pd.m_pd.hDevNames);  // we need to free these.
  154. return DevmodePrinterName();
  155. }
  156. //
  157. // This code is from a microsoft sample:
  158. // HOWTO: Implementing an Application-Defined Default Printer 
  159. // Article ID: Q193103 
  160. //
  161. HANDLE CPrinterSettings::CopyHandle(HANDLE h)
  162. {
  163. // Return a handle to a copy of the data
  164. // that the passed handle was for.
  165. if (!h) return NULL;
  166. DWORD   dwLen = GlobalSize(h);
  167. HANDLE hCopy = GlobalAlloc(GHND, dwLen);
  168. if(hCopy) {
  169. BYTE* lpCopy = (BYTE*)GlobalLock(hCopy);
  170. BYTE* lp     = (BYTE*)GlobalLock(h);
  171. CopyMemory(lpCopy,lp,dwLen);
  172. GlobalUnlock(hCopy);
  173. GlobalUnlock(h);
  174. }
  175. return hCopy;
  176. }
  177. //
  178. // retrieve our printername
  179. //
  180. CString CPrinterSettings::DevmodePrinterName()
  181. {
  182. if(!m_hDevMode) {
  183. m_strPrinterName = PRINTERNAME_UNDEFINED;
  184. } else {
  185. DEVMODE* pDevMode = (DEVMODE*)GlobalLock(m_hDevMode);
  186. m_strPrinterName = (LPCTSTR) (pDevMode->dmDeviceName);
  187. GlobalUnlock(m_hDevMode);
  188. }
  189. return m_strPrinterName;
  190. }
  191. void CPrinterSettings::CopyDefaultMfcPrinter()
  192. {
  193. PRINTDLG pd;
  194. // Get MFC's printer
  195. if(AfxGetApp()->GetPrinterDeviceDefaults(&pd) ) {
  196. // Make a copy
  197. m_hDevNames = CopyHandle(pd.hDevNames);
  198. m_hDevMode = CopyHandle(pd.hDevMode);
  199. DevmodePrinterName();
  200. }
  201. }
  202. void CPrinterSettings::SetThisPrinter()
  203. {
  204. PRINTDLG pd;
  205. // Save MFC's printer and select ours instead.
  206. AfxGetApp()->GetPrinterDeviceDefaults(&pd);
  207. m_hSaveDevNames = pd.hDevNames;
  208. m_hSaveDevMode = pd.hDevMode;
  209.     AfxGetApp()->SelectPrinter(m_hDevNames,m_hDevMode,FALSE);
  210. }
  211. void CPrinterSettings::RestorePrinter()
  212. {
  213. // Restore previous MFC printer if possible
  214. if(m_hSaveDevNames && m_hSaveDevMode)
  215. AfxGetApp()->SelectPrinter(m_hSaveDevNames,m_hSaveDevMode,FALSE);
  216. m_hSaveDevNames = NULL;
  217. m_hSaveDevMode = NULL;
  218. }
  219. //
  220. // Save our settings to file
  221. //
  222. int CPrinterSettings::Save(LPCTSTR strFileName)
  223. {
  224. SetFileName(strFileName);
  225. ASSERT( !m_strfilename.IsEmpty());
  226. ASSERT( !m_strdirname.IsEmpty());
  227. ASSERT(m_hDevMode);
  228. ASSERT(m_hDevNames);
  229. DWORD dret = NO_ERROR;
  230. // create special dir for printer settings
  231. BOOL ret = CreateDirectory(m_strdirname,NULL);
  232. if(!ret) {
  233. dret = GetLastError();
  234. if(dret != ERROR_ALREADY_EXISTS) {
  235. TRACE("error at CreateDirectory: %dn",dret);
  236. return dret;
  237. }
  238. }
  239. // ask for the length of current directoryname 
  240. // (e.g. "f:code gurusample" )
  241. dret = GetCurrentDirectory(0,NULL);
  242. if(dret > 0 ) {
  243. CString od;
  244. // just big enough
  245. LPTSTR pst = od.GetBuffer(dret);
  246. // to hold the string
  247. dret = GetCurrentDirectory(dret,pst);
  248. // change to our directory
  249. SetCurrentDirectory(m_strdirname);
  250. // create a new empty file
  251. HANDLE hDatei = 
  252. CreateFile(
  253. m_strfilename,
  254. GENERIC_READ | GENERIC_WRITE,
  255. 0,
  256. NULL,
  257. CREATE_ALWAYS,
  258. FILE_ATTRIBUTE_NORMAL,
  259. NULL);
  260. if(NULL == hDatei) {
  261. TRACE("error at CreateFile: %dn",GetLastError());
  262. return GetLastError();
  263. }
  264. //
  265. // Devmode
  266. //
  267. DWORD   dwLen = GlobalSize(m_hDevMode);
  268. BYTE* lp     = (BYTE*)GlobalLock(m_hDevMode);
  269. // leading length
  270. VERIFY(WriteFile(hDatei,&dwLen,sizeof(dwLen),&dret,NULL));
  271. // structure data
  272. VERIFY(WriteFile(hDatei,lp,dwLen,&dret,NULL));
  273. if(dret != dwLen) {
  274. TRACE("printersettings: problem writing DevMode %d <-> %dn",dwLen,dret);
  275. }
  276. GlobalUnlock(m_hDevMode);
  277. //
  278. // Devnames
  279. //
  280. dwLen = GlobalSize(m_hDevNames);
  281. lp     = (BYTE*)GlobalLock(m_hDevNames);
  282. // leading length
  283. VERIFY(WriteFile(hDatei,&dwLen,sizeof(dwLen),&dret,NULL));
  284. // structure data
  285. VERIFY(WriteFile(hDatei,lp,dwLen,&dret,NULL));
  286. if(dret != dwLen) {
  287. TRACE("printersettings: problem writing DevNames %d <-> %dn",dwLen,dret);
  288. }
  289. GlobalUnlock(m_hDevNames);
  290. CloseHandle(hDatei);
  291. // restore to previous directory
  292. SetCurrentDirectory(pst);
  293. od.ReleaseBuffer();
  294. }
  295. return NO_ERROR;
  296. }
  297. //
  298. // load our settings from file
  299. //
  300. int CPrinterSettings::Load(LPCTSTR strFileName)
  301. {
  302. SetFileName(strFileName);
  303. ASSERT( !m_strfilename.IsEmpty());
  304. ASSERT( !m_strdirname.IsEmpty());
  305. if(m_hDevMode) GlobalFree(m_hDevMode);
  306. if(m_hDevNames) GlobalFree(m_hDevNames);
  307. m_hDevMode = m_hDevNames = NULL;
  308. DWORD dret = NO_ERROR;
  309. // use a special directory for our printer settings
  310. BOOL ret = CreateDirectory(m_strdirname,NULL);
  311. if(!ret) {
  312. dret = GetLastError();
  313. if(dret != ERROR_ALREADY_EXISTS) {
  314. TRACE("error at CreateDirectory: %dn",dret);
  315. return dret;
  316. }
  317. }
  318. // where are we
  319. dret = GetCurrentDirectory(0,NULL);
  320. if(dret > 0 ) {
  321. CString od;
  322. od.~od();
  323. LPTSTR pst = od.GetBuffer(dret + 1);
  324. dret = GetCurrentDirectory(dret,pst);
  325. // and where will we go
  326. SetCurrentDirectory(m_strdirname);
  327. // open file, ensure it is present
  328. HANDLE hDatei = 
  329. CreateFile(
  330. m_strfilename,
  331. GENERIC_READ,
  332. 0,
  333. NULL,
  334. OPEN_EXISTING,
  335. FILE_ATTRIBUTE_NORMAL,
  336. NULL);
  337. // if the file could not be found
  338. // use MFC's fefault printer
  339. if(INVALID_HANDLE_VALUE == hDatei) {
  340. dret = GetLastError();
  341. CopyDefaultMfcPrinter();
  342. SetCurrentDirectory(pst);
  343. DevmodePrinterName();
  344. return dret;
  345. }
  346. //
  347. // DEVMODE
  348. //
  349. // 
  350. DWORD   dwLen = 0;
  351. // read leading length
  352. VERIFY(ReadFile(hDatei,&dwLen,sizeof(dwLen),&dret,NULL));
  353. // if desired do more testing for proper size here
  354. ASSERT(dwLen < 0xFFFF);
  355. ASSERT(dwLen > 0);
  356. m_hDevMode = GlobalAlloc(GHND, dwLen);
  357. if(NULL == m_hDevMode) {
  358. dret = GetLastError();
  359. TRACE("error at GlobalAlloc m_hDevMode: %dn",dret);
  360. CloseHandle(hDatei);
  361. return dret;
  362. }
  363. BYTE* lpCopy = (BYTE*)GlobalLock(m_hDevMode);
  364. // read the whole caboodle
  365. VERIFY(ReadFile(hDatei,lpCopy,dwLen,&dret,NULL));
  366. GlobalUnlock(m_hDevMode);
  367. //
  368. // DEVNAMES
  369. //
  370. // read leading length
  371. VERIFY(ReadFile(hDatei,&dwLen,sizeof(dwLen),&dret,NULL));
  372. // is it believable
  373. ASSERT(dwLen < 0xFFFF);
  374. ASSERT(dwLen > 0);
  375. m_hDevNames = GlobalAlloc(GHND, dwLen);
  376. if(NULL == m_hDevNames) {
  377. dret = GetLastError();
  378. TRACE("error at GlobalAlloc m_hDevNames: %dn",dret);
  379. CloseHandle(hDatei);
  380. return dret;
  381. }
  382. lpCopy = (BYTE*)GlobalLock(m_hDevNames);
  383. // read DevNames structure
  384. VERIFY(ReadFile(hDatei,lpCopy,dwLen,&dret,NULL));
  385. GlobalUnlock(m_hDevNames);
  386. CloseHandle(hDatei);
  387. // restore former dir
  388. SetCurrentDirectory(pst);
  389. }
  390. DevmodePrinterName();
  391. return NO_ERROR;
  392. }
  393. int CPrinterSettings::CopyDevmode(DEVMODE *pDest,const DEVMODE *pSrc) const
  394. {
  395. int nBytes = min( pDest->dmSize + pDest->dmDriverExtra, pSrc->dmSize + pSrc->dmDriverExtra);
  396. CopyMemory(pDest,pSrc,nBytes);
  397. return nBytes;
  398. }