ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

C#调用BarTender实现批量条码自动打印:从COM接入到项目实战

C#调用BarTender实现批量条码自动打印:从COM接入到项目实战 车间库房里最磨人的一件事就是每天几百上千张条码要打。以前的老办法是打开BarTender设计器手动填数据、手动点打印一张张来。员工手指点抽筋不说数据填错一张整批标签报废后面贴标、扫码、入库全跟着乱。后来我接到这个项目用VS2012 C#写了一个调用BarTender自动打印条形码的小工具把整个流程彻底改了程序从数据库里把待打印的数据拉出来批量塞进BarTender模板自动选择打印机自动出纸。这篇文章就把整个开发过程、核心代码、踩过的坑完整记录下来给正在做类似上位机、MES打印模块的朋友一个参考。这套方案的好处一句话就能说清模板归模板代码归代码。条码格式要改去BarTender设计器里改版面程序一行不用动打印逻辑要改改C#代码就行模板不用碰。说白了就是用BarTender的设计能力和SDK的自动化能力把人工操作换成程序驱动适合生产线标签、资产标签、物流面单、产品包装码这些批量打印场景。1. 为什么用C#调BarTender而不是别的方案接到自动打印条码需求第一反应不一定非得上BarTender。市面上至少有三种做法我挨个分析过最后才定下C# BarTender SDK这条路。1.1 几种常见自动化打印方案的对比第一种是直接给打印机发ZPL指令。条码打印机比如TSC、Zebra底层都支持ZPL或EPL指令程序把条码内容、尺寸、位置拼成一段指令文本通过网络或驱动发给打印机。好处是不依赖任何第三方软件单台打印机的成本最低打印速度也快。缺点是标签版式稍微复杂一点代码就非常难维护中文内容、LOGO、表格框线的排版基本要靠人肉算坐标改一次样式等于重写一次拼装逻辑。这个方案适合标签内容特别固定、短期项目、打印内容就是“一行条码一行文字”的场合。第二种是用条码控件生成图片再用.NET自带的PrintDocument去打印。这种做法的可控性最强条码图片的尺寸、颜色、位置全部代码控制界面里还能实时预览。但它本质上相当于把标签设计器的活全揽到自己身上数据源、模板、打印三层完全混在一起。客户说“标签右上角要加个公司LOGO”你就得改代码重新发布程序客户说“条码密度再调高一点”你还得去查条码控件的参数文档。后期维护成本不低。第三种就是C#调用BarTender的SDK。BarTender本身提供了一套ActiveX/COM接口C#通过引用它的类型库可以直接操作它的Application对象、打开模板、给模板里的命名数据源赋值、设置打印机、触发打印。这套方案的最大价值在于“模板与代码分离”模板文件.btw由BarTender设计器负责维护所有版面调整都在设计器里完成程序里的代码只关心“往哪个变量塞什么数据、打几份、用哪台打印机”。代码结构稳定客户的频繁改版需求也不会把你拖垮。1.2 什么场景适合用SDK方案根据我这几个项目的经验以下场景优先考虑C#调BarTender标签格式经常变。今天加个字段明天换个LOGO后天把条码从左侧挪到右侧。模板方式改版只要几分钟代码方式改版要改代码重新编译。打印量比较大数据来自数据库、Excel或扫码枪。程序批量从数据源拉记录循环赋值打印比人手在BarTender界面里录入快得多也杜绝了人为录错。要和现有上位机或MES系统集成。比如生产工位上的工控机已经跑着C#写的上位机程序在这个程序里直接调BarTender打印模块管理上更统一。需要打印后校验或要留打印日志。程序里可以在PrintOut之后把记录写入日志表方便追溯。反过来如果只是偶尔打几张小标签、项目周期只有一两周、现场还不允许安装BarTender软件那ZPL方案可能更实际。选型这事没有绝对的对错关键是搞清楚自己的约束条件。2. 环境准备VS2012项目如何接入BarTender项目既然限定在VS2012说明要么是公司的老项目遗留要么是现场工控机性能有限、环境已经锁定。这个没关系BarTender的SDK本身就是COM接口.NET Framework 4.0完全能调VS2012开发环境没有任何障碍。2.1 版本兼容性与选型首先要确认现场装的是BarTender哪个版本。不同版本的SDK接口名称有差异但核心的几个对象是一致的BarTender.Application代表BarTender应用主程序。BarTender.LabelFormatDocument代表一个打开的标签模板文档。LabelFormatDocument.PrintOut触发打印的方法。LabelFormatDocument.SetNamedDataValue给模板里的命名数据源赋值。我用过的BarTender 2016、2019在VS2012里用COM方式调用代码写法基本兼容。如果你的环境还是BarTender 9.x、10.x这种老版本方法名和枚举值可能会有差别比如结束文档时的保存选项枚举可能是btDoNotSaveChanges也可能是别的写法。碰上老版本最快的办法是装完SDK后在VS的对象浏览器里翻一遍确认实际的方法签名和枚举值别照着新版本代码硬抄。另外要注意版本的一个坑BarTender模板文件.btw是向下兼容性不太好的。高版本BarTender保存的模板低版本可能打不开。所以团队里一旦定了用哪个版本全流程最好都统一常规做法是冻结模板版本不要今天用2016明天换2019否则模板迁移会折腾死人。2.2 添加COM引用的完整步骤在VS2012里接BarTender常规做法是添加COM引用步骤如下打开项目在解决方案资源管理器里右键“引用”选择“添加引用”。在弹出的对话框里切到“COM”选项卡。在列表里找到BarTender相关的类型库。不同版本显示名称略有差异常见的是“BarTender 类型库”或“Seagull BarTender ...”。如果列表里找不到点“浏览”按钮到BarTender安装目录找BarTender.exe或相关的DLL文件选中后确认。添加成功后项目里会自动生成Interop程序集代码里直接用using BarTender;就能访问。这里我踩过一个坑如果目标机器上没装完整版BarTender或者是用精简方式部署的COM组件没有注册到系统里VS里就找不到类型库程序运行时创建Application对象也会直接报错。所以现场部署时安装BarTender完成之后建议先在命令行里检查一下COM组件是否注册成功或者直接跑一遍测试程序去new一个BarTender.Application试试省得程序布到现场再抓瞎。除了显式的COM引用也可以用dynamic类型动态调用省去添加引用的步骤。但对VS2012这种老项目来说我不推荐dynamic。一是不方便智能提示变量名和方法名敲错了编译期不报错运行期才炸二是每次调用都有反射开销批量打印时性能略受影响。老老实实添加COM引用写代码时能有代码提示少踩很多坑。2.3 32位/64位问题的处理这是整个项目里最容易踩、也最隐蔽的坑。BarTender的主程序是32位的它的COM组件也注册在32位环境里。如果你的C#程序项目平台是AnyCPU或x64在64位操作系统上运行时会以64位进程身份去找32位COM组件结果就是“检索 COM 类工厂中 CLSID 为……的组件时失败”0x80131515这种异常。解决方法很简单在VS2012里右键项目选“属性”切到“生成”选项卡把“平台目标”从“AnyCPU”改成“x86”。改完之后重新编译部署程序就会以32位进程运行调用BarTender的COM组件就没有问题了。这个改动还会连累一个问题如果你的程序里同时要调用其他64位专用组件就会冲突。一般条码打印上位机没有这种需求但我在做过的项目里确实遇到过程序里既有BarTender又要调用某厂家的64位视觉SDK最后只能把打印模块单独拆成一个32位进程通过进程间通信和主程序交互绕开位数不匹配的问题。这个思路你也可以记一下真遇上了不至于卡死。3. 核心代码连接模板、传值、打印这一部分是整个功能的核心代码量其实不大但每一步都有讲究尤其是COM对象的释放处理不好会有大麻烦。3.1 创建应用对象并打开模板用C#调用BarTender第一步是创建Application对象并打开模板文件using BarTender; // 创建BarTender应用对象 BarTender.Application btApp new BarTender.Application(); // 打开模板文件 // 参数1模板路径.btw文件 // 参数2打开密码没有就传空字符串 // 参数3是否只读打开 BarTender.LabelFormatDocument btFormat btApp.Documents.Open(D:\\Templates\\ProductLabel.btw, , false);这里有两个细节值得说。Documents.Open的第二个参数是模板密码这个密码是在BarTender设计器里给模板设置的权限密码不是数据库密码。如果模板没有加密传空字符串就行别画蛇添足。第三个参数是否只读建议传false因为打印完如果需要回写模板内容只读模式会报错而日常打印流程根本不需要考虑回写但保留读写权限更稳妥。另外一个容易被忽略的点模板路径是现场机器上的物理路径。部署程序时模板文件要跟着程序一起分发路径最好通过配置文件读取不要硬编码。有些项目里模板路径用相对路径程序工作目录一换就找不到了。经验做法是在App.config里配一个LabelTemplatePath键程序启动时检查文件是否存在不存在就在界面里提示防止打印时才报错打断生产节奏。3.2 给模板里的变量赋值BarTender模板里通常会有“命名数据源”简单理解就是模板里定义的变量比如产品编号、批次号、生产日期、流水号等。打印前要把实际数据塞进这些变量// 给模板里的命名数据源赋值 // 参数1变量名必须和模板里定义的名称完全一致 // 参数2要写入的值 btFormat.SetNamedDataValue(ProductCode, PRD-20250101-001); btFormat.SetNamedDataValue(BatchNo, BATCH-0715); btFormat.SetNamedDataValue(PrintDate, DateTime.Now.ToString(yyyy-MM-dd HH:mm));这里最大的坑就是变量名不匹配。SetNamedDataValue的变量名必须和模板设计器里“数据源属性”中定义的名称一模一样区分大小写前后不能有空格。一旦名字对不上BarTender会直接抛异常或者静默不替换最后打出来的是模板里的测试数据。我建议在模板设计阶段就统一变量命名规范比如全部用驼峰命名C#代码里用一个静态类把变量名集中定义成常量避免字符串满天飞。变量名确认的方法也分享给大家在BarTender设计器里选中文本对象右键属性找到“数据源”页面看到的“命名”就是SetNamedDataValue要用的变量名。很多新手把文本对象本身的文本内容当变量名赋值怎么都不生效原因就在这。3.3 指定打印机与触发打印打印前建议显式指定打印机名称别依赖模板里保存的默认打印机// 指定打印机名称要和Windows打印机列表里的完全一致 btFormat.PrinterName TSC TTP-244 Pro; // 触发打印 // 参数1打印份数 // 参数2打印任务名称一般传空字符串或简单描述 btFormat.PrintOut(1, );打印机名称这块我也踩过坑Windows系统里打印机名称可能是“TSC TTP-244 Pro (副本 1)”这种带后缀的从界面下拉框里复制过来最可靠不要凭印象手敲。如果要动态获取打印机列表可以用System.Drawing.Printing.PrinterSettings.InstalledPrinters枚举把结果填充到界面的ComboBox里用户选哪个就用哪个。代码会在后面实操示例里给出。PrintOut方法不同版本有不同重载。有的版本支持直接传份数和任务名有的版本第一个参数是是否显示打印对话框如果不小心调用了带对话框的重载打印时就会弹窗卡住生产流程。建议先在VS对象浏览器里看一下当前SDK的PrintOut方法签名确认参数顺序再写代码。一般生产环境要的就是“无界面直接打印”千万不要调出那个对话框。3.4 收尾正确释放COM资源BarTender的COM对象不释放后果非常直接内存暴涨、程序越跑越卡、进程里挂着一堆BarTender进程最后打印速度越来越慢。正确的收尾顺序是先关闭文档再退出应用最后释放COM引用if (btFormat ! null) { btFormat.Close(BarTender.BtSaveOptions.btDoNotSaveChanges); Marshal.ReleaseComObject(btFormat); } btApp.Quit(BarTender.BtSaveOptions.btDoNotSaveChanges); Marshal.ReleaseComObject(btApp);整个调用过程我建议放在try-catch-finally里finally里做释放操作保证无论打印成功还是失败COM对象都能被清掉。这里要提醒一个使用心得如果打印频率很高比如每几秒就打一张创建和销毁Application对象的开销其实不小更合理的做法是把Application对象作为程序里的单例长期持有模板Document也可以复用一个实例每次打印只更新数据源内容打印完不关闭文档这样性能会好很多。只有当程序退出时才去销毁这些COM对象。4. 实操示例做一个批量打印小工具光讲原理不够我直接给一套可抄作业的实操示例。这个示例是一个WinForm小工具功能是从一个DataGridView表格里读取要打印的数据批量循环打印。4.1 界面设计与功能划分界面参考布局模板文件选择一个TextBox加“浏览”按钮用OpenFileDialog选择.btw文件。打印机选择一个ComboBox加载系统已安装的打印机。数据区一个DataGridView用来展示待打印的数据至少包含“产品编号”“批次号”“生产日期”三列旁边一个“导入数据”按钮可以手工填行也可以后续扩展成从数据库导入。操作区一个“开始打印”按钮一个ProgressBar进度条一个多行TextBox用来显示打印日志。这个工具的规模不大但麻雀虽小五脏俱全涵盖了模板选择、打印机枚举、数据循环、进度反馈、日志记录这些核心环节。你完全可以在这个框架上扩展成数据库查询、扫码枪输入、生产队列管理等功能。4.2 核心代码逻辑先看打印机枚举这个简单直接using System.Drawing.Printing; foreach (string printerName in PrinterSettings.InstalledPrinters) { cmbPrinter.Items.Add(printerName); } if (cmbPrinter.Items.Count 0) { cmbPrinter.SelectedIndex 0; }然后是批量打印的核心方法。这里我用了一个关键设计Application对象和TemplateDocument对象都只创建一次在循环里复用循环结束后统一释放。这样连续打印几百张标签也不会因为反复创建COM对象而卡顿private void btnPrint_Click(object sender, EventArgs e) { string templatePath txtTemplatePath.Text.Trim(); if (!File.Exists(templatePath)) { MessageBox.Show(模板文件不存在请重新选择。); return; } if (dataGridView1.Rows.Count 0) { MessageBox.Show(没有待打印的数据。); return; } string printerName cmbPrinter.SelectedItem?.ToString() ?? ; if (printerName.Length 0) { MessageBox.Show(请选择打印机。); return; } BarTender.Application btApp new BarTender.Application(); BarTender.LabelFormatDocument btFormat null; try { btFormat btApp.Documents.Open(templatePath, , false); btFormat.PrinterName printerName; progressBar1.Maximum dataGridView1.Rows.Count; progressBar1.Value 0; for (int i 0; i dataGridView1.Rows.Count; i) { // 从表格行取数据注意去掉行末的空行 string productCode dataGridView1.Rows[i].Cells[ProductCode].Value?.ToString() ?? ; string batchNo dataGridView1.Rows[i].Cells[BatchNo].Value?.ToString() ?? ; string printDate dataGridView1.Rows[i].Cells[PrintDate].Value?.ToString() ?? ; if (productCode.Length 0 batchNo.Length 0) { continue; } btFormat.SetNamedDataValue(ProductCode, productCode); btFormat.SetNamedDataValue(BatchNo, batchNo); btFormat.SetNamedDataValue(PrintDate, printDate); btFormat.PrintOut(1, ); progressBar1.Value i 1; txtLog.AppendText($第{i 1}张打印成功{productCode} {batchNo}\r\n); } MessageBox.Show(批量打印完成。); } catch (Exception ex) { txtLog.AppendText($打印异常{ex.Message}\r\n); MessageBox.Show(打印过程中出现异常请查看日志。); } finally { // 释放COM资源顺序不能反 if (btFormat ! null) { btFormat.Close(BarTender.BtSaveOptions.btDoNotSaveChanges); Marshal.ReleaseComObject(btFormat); } btApp.Quit(BarTender.BtSaveOptions.btDoNotSaveChanges); Marshal.ReleaseComObject(btApp); } }这段代码在实际生产环境里已经够用。有两点需要根据你的SDK版本微调一是BtSaveOptions枚举的完整写法老版本可能是btDoNotSaveChanges新版本也可能是别的枚举值按对象浏览器里的实际名称来二是PrintOut方法的重载如果当前版本要求传更多参数就按签名调整。4.3 从数据库读取数据的扩展方式DataGridView手工填数据只适合测试场景。实际项目里数据大概率来自数据库。扩展起来很简单用ADO.NET把数据库里的待打印记录查到DataTable里再绑定到DataGridViewusing System.Data; using System.Data.SqlClient; private void btnLoadData_Click(object sender, EventArgs e) { string connStr Data Source.;Initial CatalogMesDb;Integrated SecurityTrue;; string sql SELECT ProductCode, BatchNo, CONVERT(varchar(20), PrintDate, 120) AS PrintDate FROM PrintQueue WHERE IsPrinted 0 ORDER BY Id; DataTable dt new DataTable(); using (SqlConnection conn new SqlConnection(connStr)) { using (SqlCommand cmd new SqlCommand(sql, conn)) { SqlDataAdapter adapter new SqlDataAdapter(cmd); adapter.Fill(dt); } } dataGridView1.DataSource dt; }选定记录后在循环打印内部适当位置调用数据库更新语句把已打印记录的IsPrinted字段置为1这样即使打印到一半程序崩了下次启动还能接着打剩下的具备了生产系统的容错能力。这里提醒一句更新状态和触发打印之间考虑好先后顺序。实际项目里出现过先更新状态后打印结果打印失败导致标签“丢失”的情况也出现过先打印后更新状态打印成功但没来得及更新下次重复打印的情况。稳妥做法是打印成功后更新状态同时把记录内容写进日志表保证可追溯。5. 常见问题与排查实录这块是整篇文章的干货部分我把这几年做BarTender自动化打印遇到的高频问题、排查思路都列出来按场景整理成速查表你现场遇到问题可以直接照着排查。5.1 常见错误与排查速查表现象主要原因排查方向创建Application对象就报“检索 COM 类工厂中 CLSID 为……的组件失败”没装BarTender、COM组件未注册、程序位数不对检查BarTender安装确认项目平台目标为x86用命令确认COM注册SetNamedDataValue赋值没反应或抛异常变量名不对、模板当前选中的不是命名数据源在BarTender设计器里核对数据源命名检查大小写和空格PrintOut没反应任务不进打印队列PrinterName设置错误、模板绑定的打印机不存在枚举本机打印机名称并逐一核对代码里显式指定打印机打印出来的条码扫枪扫不出来标签尺寸不对、条码密度过低、条码内容过长留足条码左右静区调整条码密度简化打印内容程序内存不断上涨打印几百次后卡死COM对象未释放或者每次都重复new Application复用Application实例finally里Close、Quit、ReleaseComObject程序在Windows服务里调用打印没反应BarTender需要交互式桌面会话服务运行在Session 0不要放在服务里调用改用用户会话常驻的小程序或任务计划程序模板打开时提示版本不兼容.btw模板是低版本保存的或已被高版本改过用当前BarTender版本重新保存模板或统一团队BarTender版本中文内容打印出来变方块或乱码模板里的字体不支持中文、变量类型没选文本模板里换中文字体检查数据源类型是否为文本5.2 条码扫不出来先检查这三个参数条码打印出来扫不出来的问题在产线现场特别常见。我排查的顺序很固定你照着来基本不会漏先看静区。条码两侧必须留出足够空白区域这个区域叫静区扫码枪全靠它来“感知”条码的起点和终点。模板里条码离标签边缘太近或者旁边有其他文字图形静区被侵占扫枪就会识别失败。条码离标签左右边缘至少留出3mm以上这是最低底线。再看密度和尺寸。条码整体太小或者组成条码的线条太密打印机的分辨率跟不上扫枪就更读不出来。比如在200dpi的热敏打印机上打特别密集的Code 128线条糊成一团什么都扫不出。解决办法是把条码做宽一点或者把打印机分辨率换到300dpi以上。批量打印前先打一张样张测扫别等到全部打完再发现整批报废。最后看内容本身。如果条码内容包含中文或其他非ASCII字符要确认打印机驱动、条码字体、BarTender的条码对象是否支持对应的编码规则。有些条码类型如Code 39本身只能支持有限的字符集内容太复杂时应该换Code 128或QR Code。5.3 内存飙升与COM泄漏的根治办法这个问题的根源就一句话COM对象没有释放。BarTender的COM对象是非托管资源不像普通.NET对象那样自动回收。批量打印场景里每循环一次new一个Application打印完不释放几百次之后就挂了。根治办法有三个层次第一写代码时务必保证释放逻辑利用try-catch-finally或者using模式确保任何异常路径下都能执行释放。try { // 打印逻辑 } finally { // 释放逻辑 }第二如果打印频率很高Application对象不要每次重新创建把它设计成单例或者类级字段整个程序生命周期内只创建一次退出时才释放。文档对象也可以复用循环里不Close只更新数据源和打印。第三程序里增加一个“打印机状态自检”按钮手动触发一次完整的打开模板、赋值、打印、释放流程观察任务管理器中BarTender进程数量。如果每次自检后进程数都增长说明释放逻辑有问题立刻排查。5.4 服务器上打印没反应别走弯路这是一个扩展场景但很重要。很多人想写一个Windows服务做打印队列服务结果发现服务启动后调用BarTender打印没任何反应。原因是BarTender的COM组件依赖交互式桌面会话。Windows服务运行在Session 0和用户的桌面会话隔离它创建的COM对象无法弹出打印交互界面打印任务也无法正确提交。我的建议是别在服务里死磕换个思路用任务计划程序在用户登录后自动启动一个常驻的WinForm打印代理程序这个程序负责监听打印请求比如定时查数据库发现待打印数据就执行打印。这样既能实现“后台自动打印”又避开了Session 0的坑。工控机上一般都有固定用户保持登录状态这个方案在产线环境非常实用。5.5 授权与部署的注意事项BarTender是商业软件上线之前一定要确认授权情况。很多项目在开发阶段用试用版没问题部署到现场后发现打印数量受限或者某些功能不可用。检查授权状态可以通过BarTender的License Manager工具确认授权类型和可用功能。批量自动打印属于Automation功能部分基础授权版本可能不支持编程调用这是采购阶段就要确认的点别等开发完再发现选错版本。部署时还应注意目标机器至少要安装能够调用SDK的BarTender组件。有些安装选项可以只装Runtime或Automation组件不一定需要完整的设计器但COM注册必须要带上。我在一个项目里遇到过现场机器上有人装了精简版绿色版程序跑不起来最后重新用完整安装包修复才解决。6. 扩展思路打印模块还能怎么玩把基础打印功能跑通之后这个模块的想象空间其实很大。我做一些项目时往往不只是做一个打印按钮而是把它编进整个生产流程里下面三个扩展方向都是亲测好用、能在实际项目中直接落地的。6.1 服务化封装让其他程序都能调用打印模块不要只和WinForm界面耦合。把打印逻辑抽成一个独立的类库比如PrintService类提供PrintOneLabel、PrintBatch、PrintFromDataTable这些方法任何上位机模块都能调用。更进一步可以把这个类库包在一个独立的打印服务进程里对外提供HTTP接口其他系统通过C#的HttpClient或者普通的HTTP请求就能触发打印实现跨语言、跨系统的打印能力。注意前面说的Session 0问题这个打印服务进程必须运行在用户会话中不能挂在Windows服务里。对外暴露接口的代码示意[HttpPost(api/print)] public IActionResult Print(PrintRequest req) { try { _printService.PrintOneLabel(req.TemplatePath, req.PrinterName, req.Data); return Ok(); } catch (Exception ex) { return BadRequest(ex.Message); } }6.2 打印校验闭环防止贴错标签光打印出来不算完产线最怕的是标签内容和产品对不上。常见做法是打印后增加一道扫码校验工序标签打印出来工人用扫码枪扫一下系统根据条码内容去数据库比对产品信息一致才能放行不一致立刻报警。C#这边做这个功能很简单扫码枪本质是个USB键盘设备扫到的内容就像键盘输入一样进入焦点控件你在TextBox的KeyPress或者扫描完成事件里截获内容触发校验逻辑就行。我做过一个项目扫码枪触发打印也很常见扫一个产品条码系统自动查找对应规格的标签数据并打印实现“扫到什么打什么”最大化减少人工操作。6.3 条码数据与数据库的直接关联BarTender模板本身可以直接配置数据库连接它自己能从SQL Server读取数据源。这种方式的好处是模板数据和打印逻辑都由BarTender统一管C#代码只需要打开模板并触发PrintOut连逐条赋值都省了。两种方案怎么选如果标签内容和数据库查询逻辑经常变化让BarTender直接管数据更方便如果数据在内存里经过复杂计算后才得到比如多张表关联、实时运算那还是C#端赋值更灵活。实际情况里两种方案都有人用我倾向于C#端赋值因为调试时可以在代码里看到具体数据排查问题更直观。6.4 导出PDF和图片不只是打印BarTender的SDK还支持把标签导出成PDF或图片这可太实用了。很多场景不一定需要立刻打印比如仓库按需打印先批量生成一批PDF标签放在共享文件夹里哪个订单要发货就打印对应文件再比如MES系统需要留存标签快照打一张存一张图片后续追溯质量问题时有据可查。实现方式是调用LabelFormatDocument的Export方法具体的参数和重载在SDK文档里有详细说明这里提个方向用的时候去翻对应版本的接口文档就好。做这个项目给我最大的体会是自动打印条形码这件事难点从来不在“调用SDK”本身而在于对整个流程的把握。模板怎么设计、变量怎么命名、COM资源怎么释放、异常怎么恢复、部署现场要注意什么这些细节才是真正决定项目能不能稳定跑起来的关键。尤其是COM对象的生命周期管理和32位/64位匹配问题开发时不容易暴露等程序部署到现场、长时间批量运行时才显现到那时候再改就狼狈了。如果你正在做类似的上位机打印模块我建议你先把模板设计规范定下来变量命名统一格式然后代码里把释放逻辑写死再做一次连续几百甚至上千次的压力测试。这套动作做完打印模块基本上就能稳如老狗了。希望这篇文章能帮你少走弯路。
返回列表