begincsdn .NET 趴趴窝
[天行健,君子以自强不息]
[天道酬勤思]
    解决打印时,程序中动态添加纸型的问题是C#中常见的难题,为了避免大家也走我一样的弯路,特将我的解决过程分享出来

    在写过大量C#代码后,大家都有一种同感,C#类库功能极其强大,但总有部分不足。
在前不久,为了满足众多客户对打印格式和纸型要求并不完全一致的需求,花了N个夜晚做了个的自定义套打的工具集,主要功能包括:定制数据源(由朋友http://blog.csdn.net/windcsn/完成),根据数据源定制打印模板,根据打印模板和数据源参数进行打印。
    当然这里的重点不是说明该程序的功能。这里是说明如何在C#中更有效的方法增加自定义纸型。
    刚开始我所想到的方法应当是大家都能想到的方法:就是使用DllImport.
    经过多次寻找,我找到了一个专门提供系统API在VB/VB.net/C#中使用的网址:
    http://www.webtropy.com/articles/art9-1.asp
    在这里提供了AddForm,DeleteForm等打印专用的API的DllImport方法,
    同时参考在微软网站上的打印纸型增加的方法:
    如何在 Windows NT 和 Windows 2000 中使用自定义页面大小打印
    
    文章内代码全是VB写的,无法在C#中直接使用,怎么办呢?改造成C#吧。
    接下来就是改造过程,有一大堆的结构体要转换,还有一大堆的API要定义。苦啊,也罢问题能解决不就得了。
    等等。这里有这么两段:

   Call CopyMemory(aFI1(0), Temp(0), BytesNeeded)
   Call CopyMemory(aDevMode(1), pDevMode, Len(pDevMode))

    晕,如何转CopyMemory呢?在C++中使用指针对我来说,并没有什么困难,但在C#中,想使用指针还真费手脚。继续还是放弃?
    暂时放弃吧,原因是VB也可以写COM的。而COM在C#中使用比较简单,说干就干,开始使用MS的代码用VB写ATL控件,忙了半天,终于出来了,呵呵,主要是删截代码。
   在C#中成功引用,并写出使用的代码,结果提示说类型不匹配?什么地方类型不匹配呢?无法跟踪,痛苦。再次放弃。
    重新回到C#的DllImport上,研究IntPtr等,结果还是有种很难受的感觉。怎么办呢?郁闷了两天,那两天可是周末的两天啊。
    经过两天痛苦之后,周一时重新理了下思路,还是从COM的路。不过换方向,使用VC++吧。
    先定义了三个方法:
    Add,Remove,Update,对我来说这三个方法已经足够了
    Add用于增加纸型,Remove用于删除纸型,Update当然是更新纸型大小了。
    用C++写起来就是爽啊。很快几个方法就写好了。
    放在C#代码中一试,增加纸型成功。
    在打印机的纸型列表中一看,没有?真是奇怪了。这是怎么回事呢?
    查询MSDN中关于FORM_INFO_1的说明,
   
pName
Pointer to a null-terminated string that specifies the name of the form.
Size
Specifies the width and height, in thousandths of millimeters, of the form.
ImageableArea
Specifies the width and height, in thousandths of millimeters, of the form.

      原来如此,我使用的代码中定义的自以为是1/100英寸为单位的,因为C#类中说明PageSize的大小是以1/100吋为单位的。这里尽然是1/1000毫米,真是气坏我了。
到此,问题全部解决,纸型定义成功。
     部分代码:
     
  1// Paper.cpp : CPaper 的实现
  2
  3#include "stdafx.h"
  4#include "Paper.h"
  5#include ".\paper.h"
  6#include <comutil.h>
  7#include <Windows.h>
  8#include <iostream>
  9#pragma comment(lib, "comsupp.lib")
 10
 11#ifndef CNW_DEBUG
 12#define CNW_DEBUG
 13#endif
 14
 15// CPaper
 16namespace CNetware
 17{
 18
 19STDMETHODIMP CPaper::Add(IN BSTR  printerName,IN BSTR  paperName, IN LONG width,IN LONG height,LONG* ret)
 20{
 21    char * strPrinterName = _com_util::ConvertBSTRToString(printerName);
 22    char * strPaperName = _com_util::ConvertBSTRToString(paperName);
 23    HANDLE pPrinter;
 24    *ret =OpenPrinter(strPrinterName,&pPrinter,NULL);
 25
 26    if(*ret == FALSE) goto END_ADD;
 27    if(GetIndex(pPrinter,strPaperName)!=-1)
 28    {
 29        ClosePrinter(pPrinter);
 30        *ret = FALSE;
 31        goto END_ADD;
 32    }

 33
 34    FORM_INFO_1 aFI1;
 35    aFI1.Flags = 0;
 36    aFI1.pName = strPaperName;
 37    aFI1.Size.cx = width;
 38    aFI1.Size.cy = height;
 39    aFI1.ImageableArea.left = 0;
 40    aFI1.ImageableArea.top = 0;
 41    aFI1.ImageableArea.right = width;
 42    aFI1.ImageableArea.bottom = height;
 43
 44    *ret = AddForm(pPrinter, 1, (LPBYTE)&aFI1);
 45    ClosePrinter(pPrinter);
 46
 47END_ADD:
 48    if(*ret == FALSE) return S_FALSE;
 49    return S_OK;
 50}

 51int CPaper::GetIndex(HANDLE hPrinter,LPSTR paperName)
 52{
 53    DWORD dwNeeded, dwReturned ;
 54    FORM_INFO_1 * aFI1;
 55    BOOL bret;
 56    BYTE * TEMP;
 57    int index = -1;
 58
 59    aFI1 = (FORM_INFO_1 *)new BYTE[sizeof(FORM_INFO_1)];
 60    bret = EnumForms (hPrinter, 1,(LPBYTE)&aFI1[0], 0&dwNeeded, &dwReturned) ;
 61    delete [] (BYTE *)aFI1;
 62    TEMP = new BYTE[dwNeeded];
 63    aFI1 = (FORM_INFO_1 *)new BYTE[dwNeeded];
 64    bret = EnumForms(hPrinter, 1, TEMP,dwNeeded, &dwNeeded, &dwReturned);
 65
 66    CopyMemory(aFI1,TEMP,dwNeeded);
 67
 68    for(int i = 0; i < (int)dwReturned;i++)
 69    {
 70        if(strcmp(aFI1[i].pName,paperName)==0)
 71        {
 72            index = i;
 73            break;
 74        }

 75    }

 76    delete [] (BYTE *)TEMP;
 77    delete [] (BYTE *)aFI1;
 78
 79    return index;
 80}

 81STDMETHODIMP CPaper::Remove(BSTR  printerName,BSTR  paperName,LONG* ret)
 82{
 83    HANDLE pPrinter=NULL;
 84
 85    char * strPrinterName = _com_util::ConvertBSTRToString(printerName);
 86    char * strPaperName = _com_util::ConvertBSTRToString(paperName);
 87    *ret =OpenPrinter(strPrinterName,&pPrinter,NULL);
 88    if(*ret == FALSE || pPrinter == NULL) 
 89    {
 90        goto END_REMOVE;
 91    }

 92    if(GetIndex(pPrinter,strPaperName)==-1)
 93    {
 94        ClosePrinter(pPrinter);
 95        *ret = TRUE;
 96        goto END_REMOVE;
 97    }

 98
 99    *ret = DeleteForm(pPrinter,strPaperName);
100    ClosePrinter(pPrinter);
101END_REMOVE:
102    if(*ret == FALSE) return S_FALSE;
103    return S_OK;
104}

105
106STDMETHODIMP CPaper::Update(BSTR  printerName,BSTR  paperName, LONG width, LONG height,LONG* ret)
107{
108    // TODO: 在此添加实现代码
109    Remove(printerName,paperName,ret);
110    if(*ret == FALSE) return S_FALSE;
111    Add(printerName,paperName,width,height,ret);
112    if(*ret == FALSE) return S_FALSE;
113    return S_OK;
114}

115
116}

117
    
    

 1// Paper.h : CPaper 的声明
 2
 3#pragma once
 4#include "resource.h"       // 主符号
 5#include "Winuser.h"
 6
 7namespace CNetware
 8{
 9
10
11
12// IPaper
13[
14    object,
15    uuid("4BCEEB5C-F384-4424-B961-FB7B1214D871"),
16    dual,    helpstring("IPaper 接口"),
17    pointer_default(unique)
18]
19__interface IPaper : IDispatch
20{
21    [id(1), helpstring("方法AddPaper")] HRESULT Add([in] BSTR  printerName,[in] BSTR  paperName,[in]  LONG width,[in]  LONG height,[out,retval] LONG* ret);
22    [id(2), helpstring("方法Remove")] HRESULT Remove([in] BSTR  printerName,[in] BSTR  paperName,[out,retval] LONG* ret);
23    [id(3), helpstring("方法Update")] HRESULT Update([in] BSTR  printerName,[in] BSTR  paperName, [in] LONG width, [in] LONG height,[out,retval] LONG* ret);
24}
;
25
26
27
28// CPaper
29
30[
31    coclass,
32    threading("apartment"),
33    vi_progid("PrintCOM.Paper"),
34    progid("PrintCOM.Paper.1"),
35    version(1.0),
36    uuid("4C53CAB7-AD89-4A6A-8114-90E6A6554573"),
37    helpstring("Paper Class")
38]
39class ATL_NO_VTABLE CPaper : 
40    public IPaper
41{
42public:
43    CPaper()
44    {
45    }

46
47
48    DECLARE_PROTECT_FINAL_CONSTRUCT()
49
50    HRESULT FinalConstruct()
51    {
52        return S_OK;
53    }

54    
55    void FinalRelease() 
56    {
57    }

58
59public:
60
61    STDMETHOD(Add)(IN BSTR   printerName,IN BSTR  paperName,IN LONG width, IN LONG height,OUT LONG* ret);
62    STDMETHOD(Remove)(IN BSTR  printerName,IN BSTR  paperName,OUT LONG* ret);
63    STDMETHOD(Update)(IN BSTR  printerName,IN BSTR  paperName, IN LONG width, IN LONG height,OUT LONG* ret);
64
65private:
66    // 查询纸型的索引号
67    int GetIndex(HANDLE hPrinter,LPSTR paperName);
68}
;
69
70}
;
71

   
 1using System;
 2using System.Drawing.Printing;
 3using System.Windows.Forms;
 4
 5namespace CNetware.Print.Design
 6{
 7    /// <summary>
 8    /// PaperForm 的摘要说明。
 9    /// </summary>

10    public class PaperForm
11    {
12        private static PrintCOM.CPaperClass cp = new PrintCOM.CPaperClass();
13
14        private PaperForm()
15        {
16            //
17            // TODO: 在此处添加构造函数逻辑
18            //
19        }

20        //如果存在则更新,不存在则增加
21        /// <summary>
22        /// 向指定的打印机增加纸型
23        /// </summary>
24        /// <param name="printerName">打印机名称</param>
25        /// <param name="formName">纸型名称</param>
26        /// <param name="width">单位1/1000毫米</param>
27        /// <param name="height">单位1/1000毫米</param>
28        /// <param name="paperSizes">检查纸型是否存在于当前纸型集合中。</param>

29        public static bool Add(string printerName,string formName,int width,int height,PrinterSettings.PaperSizeCollection paperSizes)
30        {
31            foreach(PaperSize ps in paperSizes)
32            {
33                if(ps.PaperName == formName)
34                {
35                    throw new Exception(formName+"已经存在,请使用Update更新。");
36                }

37            }

38            if(cp.Add(null,formName,width,height)==1)
39            {
40                return true;
41            }

42            else
43            {
44                return false;
45            }

46        }

47
48        /// <summary>
49        /// 移除纸型。
50        /// </summary>
51        /// <param name="printerName">打印机名称</param>
52        /// <param name="formName">纸型名称</param>
53        /// <param name="paperSizes">检查纸型是否存在于当前纸型集合中。</param>

54        public static bool Remove(string printerName,string formName,PrinterSettings.PaperSizeCollection paperSizes)
55        {
56            if(cp.Remove(null,formName)==1)
57            {
58                return true;
59            }

60            else
61            {
62                return false;
63            }

64        }

65
66        /// <summary>
67        /// 修改指定打印中的纸型大小。
68        /// </summary>
69        /// <param name="printerName">打印机名称</param>
70        /// <param name="formName">纸型名称</param>
71        /// <param name="width">单位1/1000毫米</param>
72        /// <param name="height">单位1/1000毫米</param>
73        /// <param name="paperSizes">检查纸型是否存在于当前纸型集合中。</param>

74        public static bool Update(string printerName,string formName,int width,int height,PrinterSettings.PaperSizeCollection paperSizes)
75        {
76//            foreach(PaperSize ps in paperSizes)
77//            {
78//                if(ps.PaperName == formName)
79//                {
80//                    int inchH = height*100/25400; 
81//                    int inchW = width*100/25400; 
82//                    if((Math.Abs(inchH-ps.Height) < 2)&&(Math.Abs(inchW-ps.Width) < 2))
83//                        return true;
84//                    break;
85//                }
86//            }
87            if(cp.Update(null,formName,width,height)==1)
88            {
89                return true;
90            }

91            else
92            {
93                return false;
94            }

95        }

96    }

97}

98

posted on 2005-07-12 12:12  begincsdn  阅读(1292)  评论(2编辑  收藏  举报