虽然说使在IE上直接调用打印插件打印已经不常用,但是有时候还是会用到,这里就记录一下。

首先我们列出来我们的打印类

     public class PrintService
{
//打印机名称
private static readonly string _printerName = "";
//业务名称
private static string _printStr = ""; /// <summary>
/// 打印
/// </summary>
/// <param name="printStr"></param>
/// <returns>0:success;1:未找到打印机;2:fail</returns>
public static int PrintNo(string printStr)
{
try
{
_printStr = printStr;
PrintDocument pd = new PrintDocument();
//取消打印弹窗(PrintDocment默认的PrintController 是PrintControllerWithStatusDialog)
pd.PrintController = new StandardPrintController();
//pd.PrinterSettings.PrinterName = "打印机的名字";
//打印机名称可以不配置,取默认打印机
pd.DocumentName = string.Format("取号{0:yyyyMMddHHmmss}", DateTime.Now);
pd.OriginAtMargins = true;
pd.DefaultPageSettings.Margins = new Margins(, , , );
//打印开始前
pd.BeginPrint += new PrintEventHandler(pd_BeginPrint);
//打印输出(过程)
pd.PrintPage += new PrintPageEventHandler(pd_PrintPage);
//打印结束
pd.EndPrint += new PrintEventHandler(pd_EndPrint);
pd.Print(); return ;
}
catch (Exception ex)
{
NLog.Error(ex.ToString());
return ;
}
} private static void pd_EndPrint(object sender, PrintEventArgs e)
{
//打印结束后相关操作
} private static void pd_PrintPage(object sender, PrintPageEventArgs e)
{
try
{
int pagewidth = e.MarginBounds.Width;
float y = ;
_title = _title ?? string.Empty;
int titlerowspan = (_title.Length / ) + ;
y = CreateRectangleF(, y, pagewidth, e.Graphics.MeasureString("-", new Font("微软雅黑", , FontStyle.Bold)).Height, "------------------------------------", new Font("微软雅黑", , FontStyle.Bold), e);
y = CreateRectangleF(, y, pagewidth, e.Graphics.MeasureString("中A1", new Font("宋体", , FontStyle.Bold)).Height, _printStr, new Font("宋体", , FontStyle.Bold), e);
}
catch (InvalidPrinterException ex)
{
return;
}
} private static void pd_BeginPrint(object sender, PrintEventArgs e)
{
//也可以把一些打印的参数放在此处设置;
} /// <summary>
/// 绘制一个矩形区域文本文字
/// </summary>
private static float CreateRectangleF(float x, float y, float width, float height, string str, Font font, PrintPageEventArgs e)
{
StringFormat sf = new StringFormat { LineAlignment = StringAlignment.Center, Alignment = StringAlignment.Center };
//RectangleF rect = new RectangleF(x, y, width, height);
var size = MeasureStringExtend(e.Graphics, str, font, (int)width);
RectangleF rect = new RectangleF(x,y,size.Width, size.Height);
e.Graphics.DrawString(str, font, System.Drawing.Brushes.Black, rect, sf);
return rect.Bottom;
}
//多行文本自动换行
public static SizeF MeasureStringExtend(Graphics g, string text, Font font, int desWidth)
{
string tempString = text;
string workString = "";//当前打印的文本
int npos = ;//文字个数
int sp_pos = ;//
int line = ;//所在行数
int nWidth = ; //获取文字的Size对象
SizeF size = g.MeasureString(text, font);
//多行文本:文本的宽度大于纸张的宽度
if (size.Width > desWidth)
{
while (tempString.Length > )
{
//判断最后一行
if (npos > tempString.Length)
{
line++;
break;
}
//截取npos个文字,用于检测是否超出纸张宽度
workString = tempString.Substring(, npos);
//获取当前文本的宽度
nWidth = (int)g.MeasureString(workString, font).Width;
//仍然大于纸张宽度
if (nWidth > desWidth)
{
//最后一个空格的位置
sp_pos = workString.LastIndexOf(" ");
if (sp_pos > )
{
//从空格后一个字符作为起点,继续循环,可用于去除空格。这里并没有这么做。
tempString = tempString.Substring((sp_pos + ), tempString.Length - (sp_pos + ));
line++;
npos = ;
}
else //没有空格
{
tempString = tempString.Substring(npos, tempString.Length - npos);
line++;
npos = ;
}
}
npos++;
}
return new SizeF(desWidth, (line * size.Height));
}
else
return size; }
}

调用的时候

PrintSrivce.PrintNo(“这里是打印的文字内容,可以写很多,它会自动换行哦”);

为了做成Acivex插件,所以这里我们这么做:

     [Guid("F83174A0-087D-4634-B6AE-0094CD392FD1")]//IE浏览器通过这个GUID可以查到打印方法,调用打印方法,打印。
public class PrinterHelper:ActiveXControl
{
public int Printing(string printStr)
{
return PrintService.PrintNo(printStr);
}
}

下面是打印的HTML页面

<object id="printer-ActiveX" classid="clsid:F83174A0-087D-4634-B6AE-0094CD392FD1" codebase="Printer.CAB#version=1,0,0" style="display: none;"></object>
 var printerActiveX = document.getElementById('printer-ActiveX');
printerActiveX.Printing('这里是打印的文字内容,可以写很多,它会自动换行哦');

为什么这样就可以打印了呢?

其实之前省略了如何制作Acivex的步骤,下面介绍一下:

一、IObjectSafety接口

为了让ActiveX控件获得客户端的信任,控件类还需要实现一个名为“IObjectSafety”的接口。先创建该接口(注意,不能修改该接口的GUID值),接口内容如下:

     ComImport, Guid("CB5BDC81-93C1-11CF-8F20-00805F2CD064")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IObjectSafety
{
[PreserveSig]
int GetInterfaceSafetyOptions(ref Guid riid, [MarshalAs(UnmanagedType.U4)] ref int pdwSupportedOptions, [MarshalAs(UnmanagedType.U4)] ref int pdwEnabledOptions); [PreserveSig()]
int SetInterfaceSafetyOptions(ref Guid riid, [MarshalAs(UnmanagedType.U4)] int dwOptionSetMask, [MarshalAs(UnmanagedType.U4)] int dwEnabledOptions);
}

二、ActiveXControl控件基类

     public abstract class ActiveXControl : IObjectSafety
{
#region IObjectSafety 成员 private const string _IID_IDispatch = "{00020400-0000-0000-C000-000000000046}";
private const string _IID_IDispatchEx = "{a6ef9860-c720-11d0-9337-00a0c90dcaa9}";
private const string _IID_IPersistStorage = "{0000010A-0000-0000-C000-000000000046}";
private const string _IID_IPersistStream = "{00000109-0000-0000-C000-000000000046}";
private const string _IID_IPersistPropertyBag = "{37D84F60-42CB-11CE-8135-00AA004BB851}"; private const int INTERFACESAFE_FOR_UNTRUSTED_CALLER = 0x00000001;
private const int INTERFACESAFE_FOR_UNTRUSTED_DATA = 0x00000002;
private const int S_OK = 0;
private const int E_FAIL = unchecked((int)0x80004005);
private const int E_NOINTERFACE = unchecked((int)0x80004002); private bool _fSafeForScripting = true;
private bool _fSafeForInitializing = true; public int GetInterfaceSafetyOptions(ref Guid riid, ref int pdwSupportedOptions, ref int pdwEnabledOptions)
{
int Rslt = E_FAIL; string strGUID = riid.ToString("B");
pdwSupportedOptions = INTERFACESAFE_FOR_UNTRUSTED_CALLER | INTERFACESAFE_FOR_UNTRUSTED_DATA;
switch (strGUID)
{
case _IID_IDispatch:
case _IID_IDispatchEx:
Rslt = S_OK;
pdwEnabledOptions = 0;
if (_fSafeForScripting == true)
pdwEnabledOptions = INTERFACESAFE_FOR_UNTRUSTED_CALLER;
break;
case _IID_IPersistStorage:
case _IID_IPersistStream:
case _IID_IPersistPropertyBag:
Rslt = S_OK;
pdwEnabledOptions = 0;
if (_fSafeForInitializing == true)
pdwEnabledOptions = INTERFACESAFE_FOR_UNTRUSTED_DATA;
break;
default:
Rslt = E_NOINTERFACE;
break;
} return Rslt;
} public int SetInterfaceSafetyOptions(ref Guid riid, int dwOptionSetMask, int dwEnabledOptions)
{
int Rslt = E_FAIL; string strGUID = riid.ToString("B");
switch (strGUID)
{
case _IID_IDispatch:
case _IID_IDispatchEx:
if (((dwEnabledOptions & dwOptionSetMask) == INTERFACESAFE_FOR_UNTRUSTED_CALLER) &&
(_fSafeForScripting == true))
Rslt = S_OK;
break;
case _IID_IPersistStorage:
case _IID_IPersistStream:
case _IID_IPersistPropertyBag:
if (((dwEnabledOptions & dwOptionSetMask) == INTERFACESAFE_FOR_UNTRUSTED_DATA) &&
(_fSafeForInitializing == true))
Rslt = S_OK;
break;
default:
Rslt = E_NOINTERFACE;
break;
} return Rslt;
} #endregion
}

三、就是我们上面写的PrinterHelper类,并在这个类库的属性里设置“使程序集COM可见”。

四、使用VS2012发布

具体步骤如下:

1、

2、

3、

1)设置为简体中文,否则安装路径有中文的话就会出问题
2)设置默认安装路径
3)修改默认字体
4)每次升级,重新打包,只需要点击这一行右侧的“...”按钮,就会重新生成Code,安装时就会自动覆盖老版本
5)我们把INSTALLDIR里面改写为[ProgramFilesFolder],方便后面我们使用CAB打包
4、

5、这一步很重要,在主输出上点右键属性

6、点击“6 Prepare for Release”下方的Release

注意点:该解决方案需要以管理员身份运行。

生成两个文件:

PrinterActiveX.MSI和Data1.cab

剩下一步就是签名了。

makecab.exe   /f   "cab.ddf"
signtool sign -f mantishell.pfx -p mantishell PrinterActiveX.CAB
.OPTION   EXPLICIT
.Set Cabinet=on
.Set Compress=on
.Set MaxDiskSize=CDROM
.Set ReservePerCabinetSize=
.Set DiskDirectoryTemplate="."
.Set CompressionType=MSZIP
.Set CompressionLevel=
.Set CompressionMemory=
.Set CabinetNameTemplate="PrinterActiveX.CAB"
"installer.inf"
"PrinterActiveX.MSI"
"Data1.cab"

1、生成公钥文件
makecert -# 01 -r -n "CN=xxxx公司,O=xxxx,OU=xxxx,C=China,S=NanJing" -e 08/07/2019 -sky signature -sv mantishell.pvk d:\mantishell.cer
-e表示截至时间:如果去掉截至时间到2039年
私钥密码设置为:mantishell
2、生成证书
pvk2pfx.exe /pvk mantishell.pvk /pi mantishell /spc mantishell.cer /pfx mantishell.pfx /f

makecert -# 01 -r -n "CN=xxxx公司,O=xxxx公司,OU=xxxx公司,C=China,S=Nanjing" -sky signature -sv d:\ActiveX\CAB\mantishell.pvk d:\ActiveX\PrinterActiveX\CAB\mantishell.cer

使用PrintDocument定制打印格式的更多相关文章

  1. C# 利用PrintDocument定制打印单据

    本文是利用PrintDocument定制打印单据的小例子,仅供学习分享使用,如果不足之处,还请指正. 涉及知识点: PrintDocument :从 Windows 窗体应用程序打印时,定义一种可重用 ...

  2. 使用PrintDocument进行打印

    背景: 1.在winform中,需要直接调用打印机,进行打印处理 2.找了很多实现方法是web的处理,然后查了下度娘,发现可以使用自带类PrintDocument进行处理,所以就有了这篇文章 说明: ...

  3. 在sap系统设置纸张打印格式(针式打印机)

    在sap做一个打印报表,要先设置一个纸张打印格式,下面以工厂中常用来打印的针孔纸为例,在sap设置该纸张的打印格式,以用于报表: 1.运行事务代码SPAD:选择工具栏上的[完全管理]按钮——>选 ...

  4. Android打印机--小票打印格式及模板设置

    小票打印就是向打印设备发送控制打印格式的指令集,而这些打印格式须要去查询相应打印机的API文档,这里我把经常使用的api给封装了一下 文字对齐方式 打印字体大小 字体是否加粗 打印二维码 打印条形码 ...

  5. Smartforms 设置纸张打印格式

    在sap做一个打印报表,要先设置一个纸张打印格式,下面以工厂中常用来打印的针孔纸为例,在sap设置该纸张的打印格式,以用于报表: 1.运行事务代码SPAD:选择工具栏上的[完全管理]按钮——>选 ...

  6. print,cat打印格式及字符串引号格式,去掉字符串空格 in R

    print 函数的打印格式: ##no quote print out > x <- letters[1:5] > print(x,quote=F,);print(x,quote=T ...

  7. 【ABAP系列】SAP Smartforms 设置纸张打印格式

    公众号:SAP Technical 本文作者:matinal 原文出处:http://www.cnblogs.com/SAPmatinal/ 原文链接:[ABAP系列]SAP Smartforms 设 ...

  8. 关于str的打印格式

    实际上一般的打印格式应该是这样的: %[(keyname)][flags][width][.precision]typecode (1) keyname: 用于打印Dict类型时做索引; (2) fl ...

  9. rbac介绍、自动生成接口文档、jwt介绍与快速签发认证、jwt定制返回格式

    今日内容概要 RBAC 自动生成接口文档 jwt介绍与快速使用 jwt定制返回格式 jwt源码分析 内容详细 1.RBAC(重要) # RBAC 是基于角色的访问控制(Role-Based Acces ...

随机推荐

  1. 【洛谷】P4198 楼房重建(线段树)

    传送门 分析 被线段树按在地上摩擦  先把左边转化成斜率,那么这个题就转化成每次修改一个点的值,输出前缀最大值的个数 看到标签是线段树,所以还是想想线段树的做法吧 既然是线段树,那么就要将区间分成两半 ...

  2. 第10组alpha冲刺(2/4)

    队名:凹凸曼 组长博客 作业博客 组员实践情况 童景霖 过去两天完成了哪些任务 文字/口头描述 继续学习Android studio和Java 完善项目APP原型 展示GitHub当日代码/文档签入记 ...

  3. MySQL 自动插入、更新时间戳

    在 MySql 中,要做到自动出入当前时间戳,只要在定义表格时将字段的默认值设置为 CURRENT_TIMESTAMP 即可. 如: create table if not exists my_tab ...

  4. 2015-2016-2《Java程序设计》团队博客3

    项目进展 这周就是对上周所列出的类进行具体实现.但是到目前为止还没有遇到一些实质性的问题.虽然感觉没有问题就是最大的问题,但是还是希望能够尽早发现bug并及时改掉. 目前已经完成前几个文件之间的架构, ...

  5. 如何在IDEA上配置Maven

    IDEA 全称 IntelliJ IDEA,是java语言开发的集成环境,IntelliJ在业界被公认为最好的Java开发工具之一, IDEA是JetBrains公司的产品,现在有逐步取代老牌Java ...

  6. TICK/TIGK运维栈安装运行【上】

    TICK/TIGK运运维metrics栈包括 InfuluxDB:为时间序列数据专门定制的高性能数据存储.TSM引擎允许高速接收和数据压缩.完全go语言编写.编译成一个单一的二进制,没有外部依赖.简单 ...

  7. 爬虫中BeautifulSoup4解析器

    CSS 选择器:BeautifulSoup4 和 lxml 一样,Beautiful Soup 也是一个HTML/XML的解析器,主要的功能也是如何解析和提取 HTML/XML 数据. lxml 只会 ...

  8. 必须要注意的 C++ 动态内存资源管理(一)——视资源为对象

    必须要注意的 C++ 动态内存资源管理(一)——视资源为对象 一.前言         所谓资源就是,一旦你用了它,将来必须还给系统.如果不这样,糟糕的事情就会发生.C++ 程序中最常见使用的资源就是 ...

  9. (转载)Universal Correspondence Network

    转载自:Chris Choy's blog Universal Correspondence Network In this post, we will give a very high-level ...

  10. linux信号--阻塞与未决

    执行信号的处理动作称为信号递达(Delivery),信号从产生到递达之间的状态,称为信号未决(Pending). 进程可以选择阻塞(Block)某个信号.被阻塞的信号产生时将保持在未决状态,直到进程解 ...