用代码实现标签打印的三种方式

news2024/11/24 6:08:16

最近项目中要实现标签打印的功能,有几个条件

  • 标签模板可以事先生成,用的是CodeSoft软件
  • 标签模板里面有二维码
  • 标签模板里面有一些变量,要求打印的时候自动填充
  • 产线电脑上没有安装CodeSoft,即便安装也不能使用,因为没有License

从开始计划做标签打印开始,做了三套解决方案,难度和依赖条件各不相同

  1. 利用Excel
  2. CodeSoft API
  3. ZPL+Win32 API
  • 利用Excel

这是一个半自动化的方案,主要想法是在Excel里面做好模板,变量的部分通过编写VBA脚本,读取SQL Server数据库里面的内容进行填充,填充好了之后,手动打印。缺点是没有办法生成二维码。 --- Pass

代码

Public Sub SynTableConfig()
Dim cnn As New ADODB.Connection, sh As Worksheet
Dim rs As New ADODB.Recordset
Dim cnnStr As String, SQL As String
   
'建立与SQL Server数据库服务器的连接
cnnStr = "Provider=SQLOLEDB;Initial Catalog=" & myDataBase & ";User ID=" & myname & ";Password=" & mypassword & ";Data Source=" & serverip
cnn.ConnectionString = cnnStr
cnn.Open
SQL = "select  * from sys_table where id='123' order by 表名称"
Set rs = cnn.Execute(SQL)
While Not rs.EOF
.............
rs.MoveNext
Wend
rs.Close
Set rs = Nothing
cnn.Close
Set cnn = Nothing
End Sub

  • CodeSoft API

CodeSoft企业版提供了ActiveX控件,可以在C#中添加对Lppx2.tlb的引用,调用相关API对CodeSoft编辑好的Label文件进行变量替换等操作,然后打印。编程难度不大,但是有个致命限制,要安装CodeSoft软件并插入usbkey。公司虽然买了license,但是仅限于工程师编辑Label模板文件,产线电脑上没有安装软件,更不可能插入usbkey,因为很贵。--- Pass

代码如下

class CodeSoft
    {

        string _printerName = "";
        

        public CodeSoft(string printerName)
        {

            _printerName = printerName;

        }

        public void Print(string labelFileName, Dictionary<string,string> parameters)
        {

            LabelManager2.Application labApp = null;

            LabelManager2.Document doc = null;

            string labFileName = System.Windows.Forms.Application.StartupPath + @"\" + labelFileName;

            try
            {

                if (!File.Exists(labFileName))
                {
                    throw new FileNotFoundException("File not exsit", labFileName);
                }

                labApp = new LabelManager2.Application();

                labApp.Documents.Open(labFileName, false);

                doc = labApp.ActiveDocument;

                doc.Printer.SwitchTo(_printerName);

                string printerName = labApp.ActivePrinterName;

                foreach (string parameterName in parameters.Keys)
                {

                    doc.Variables.FormVariables.Item(parameterName).Value = parameters[parameterName];

                }

                doc.PrintDocument(1);

            }
            catch (Exception ex)
            {
                throw ex;
            }
            finally
            {
                labApp.Documents.CloseAll(true);
                //doc.Quit();
                doc = null;
                doc = null;
                GC.Collect(0);
            }

        }

    }

  • ZPL+Win32 API

ZPL是Zebra公司的标签标记语言,描述了标签上有哪些内容,何种字体,何种颜色等等。大部分标签打印机应该都支持,最起码我们的430t是可以支持的。具体打印的思路是利用CodeSoft软件,生成一个PRN文件(具体怎么生成不知道)。PRN文件里面的内容就是用ZPL描述的标签。我用程序读入这个PRN文件,将里面的变量替换掉,生成一个新文件,然后调用系统Native的打印功能,进行打印。

代码如下

class PrinterHelper
    {

        // Structure and API declarions:
        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
        public class DOCINFOA
        {
            [MarshalAs(UnmanagedType.LPStr)]
            public string pDocName;
            [MarshalAs(UnmanagedType.LPStr)]
            public string pOutputFile;
            [MarshalAs(UnmanagedType.LPStr)]
            public string pDataType;
        }
        [DllImport("winspool.Drv", EntryPoint = "OpenPrinterA", SetLastError = true, CharSet = CharSet.Ansi, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
        public static extern bool OpenPrinter([MarshalAs(UnmanagedType.LPStr)] string szPrinter, out IntPtr hPrinter, IntPtr pd);

        [DllImport("winspool.Drv", EntryPoint = "ClosePrinter", SetLastError = true, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
        public static extern bool ClosePrinter(IntPtr hPrinter);

        [DllImport("winspool.Drv", EntryPoint = "StartDocPrinterA", SetLastError = true, CharSet = CharSet.Ansi, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
        public static extern bool StartDocPrinter(IntPtr hPrinter, Int32 level, [In, MarshalAs(UnmanagedType.LPStruct)] DOCINFOA di);

        [DllImport("winspool.Drv", EntryPoint = "EndDocPrinter", SetLastError = true, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
        public static extern bool EndDocPrinter(IntPtr hPrinter);

        [DllImport("winspool.Drv", EntryPoint = "StartPagePrinter", SetLastError = true, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
        public static extern bool StartPagePrinter(IntPtr hPrinter);

        [DllImport("winspool.Drv", EntryPoint = "EndPagePrinter", SetLastError = true, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
        public static extern bool EndPagePrinter(IntPtr hPrinter);

        [DllImport("winspool.Drv", EntryPoint = "WritePrinter", SetLastError = true, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
        public static extern bool WritePrinter(IntPtr hPrinter, IntPtr pBytes, Int32 dwCount, out Int32 dwWritten);

        // SendBytesToPrinter()
        // When the function is given a printer name and an unmanaged array
        // of bytes, the function sends those bytes to the print queue.
        // Returns true on success, false on failure.
        public static bool SendBytesToPrinter(string szPrinterName, IntPtr pBytes, Int32 dwCount)
        {
            Int32 dwError = 0, dwWritten = 0;
            IntPtr hPrinter = new IntPtr(0);
            DOCINFOA di = new DOCINFOA();
            bool bSuccess = false; // Assume failure unless you specifically succeed.

            di.pDocName = "My C#.NET RAW Document";
            di.pDataType = "RAW";

            // Open the printer.
            if (OpenPrinter(szPrinterName.Normalize(), out hPrinter, IntPtr.Zero))
            {
                // Start a document.
                if (StartDocPrinter(hPrinter, 1, di))
                {
                    // Start a page.
                    if (StartPagePrinter(hPrinter))
                    {
                        // Write your bytes.
                        bSuccess = WritePrinter(hPrinter, pBytes, dwCount, out dwWritten);
                        EndPagePrinter(hPrinter);
                    }
                    EndDocPrinter(hPrinter);
                }
                ClosePrinter(hPrinter);
            }
            // If you did not succeed, GetLastError may give more information
            // about why not.
            if (bSuccess == false)
            {
                dwError = Marshal.GetLastWin32Error();
            }
            return bSuccess;
        }


        public static bool SendFileToPrinter(string szPrinterName, string szFileName, Dictionary<string, string> parameters)
        {


            string fileName = AssignValueToVariables(szFileName, parameters);

            return SendFileToPrinter(szPrinterName, fileName);

        }
        public static bool SendFileToPrinter(string szPrinterName, string szFileName)
        {
            // Open the file.
            FileStream fs = new FileStream(szFileName, FileMode.Open);
            // Create a BinaryReader on the file.
            BinaryReader br = new BinaryReader(fs);
            // Dim an array of bytes big enough to hold the file's contents.
            Byte[] bytes = new Byte[fs.Length];
            bool bSuccess = false;
            // Your unmanaged pointer.
            IntPtr pUnmanagedBytes = new IntPtr(0);
            int nLength;

            nLength = Convert.ToInt32(fs.Length);
            // Read the contents of the file into the array.
            bytes = br.ReadBytes(nLength);
            // Allocate some unmanaged memory for those bytes.
            pUnmanagedBytes = Marshal.AllocCoTaskMem(nLength);
            // Copy the managed byte array into the unmanaged array.
            Marshal.Copy(bytes, 0, pUnmanagedBytes, nLength);
            // Send the unmanaged bytes to the printer.
            bSuccess = SendBytesToPrinter(szPrinterName, pUnmanagedBytes, nLength);
            // Free the unmanaged memory that you allocated earlier.
            Marshal.FreeCoTaskMem(pUnmanagedBytes);
            return bSuccess;
        }

        private static string AssignValueToVariables(string szFileName, Dictionary<string, string> parameters)
        {

            StreamReader sr = new StreamReader(szFileName, Encoding.Default);

            string line;

            StringBuilder sb = new StringBuilder();

            while ((line = sr.ReadLine()) != null)
            {

                sb.AppendLine(line);

            }

            string newContent = UpdateVariable(sb.ToString(), parameters);

            return WriteToFile(szFileName, newContent);

        }

        private static string WriteToFile(string szFileName, string newContent)
        {

            string fullFileName = szFileName + ".new.PRN";

            if (File.Exists(fullFileName))
            {

                File.Delete(fullFileName);

            }

            using (FileStream fs = new FileStream(fullFileName, FileMode.Create))
            {

                using (StreamWriter sw = new StreamWriter(fs))
                {

                    sw.Write(newContent);

                    sw.Flush();
                }

            }

            return fullFileName;

        }

        private static string UpdateVariable(string content, Dictionary<string, string> parameters)
        {

            string newContent = content;

            foreach (string parameterName in parameters.Keys)
            {

                string parameterValue = parameters[parameterName];

                newContent = newContent.Replace(string.Format("_tag${0}$tag_", parameterName), parameterValue);

            }

            return newContent;

        }

        public static bool SendStringToPrinter(string szPrinterName, string szString)
        {
            IntPtr pBytes;
            Int32 dwCount;
            // How many characters are in the string?
            dwCount = szString.Length;
            // Assume that the printer is expecting ANSI text, and then convert
            // the string to ANSI text.
            pBytes = Marshal.StringToCoTaskMemAnsi(szString);
            // Send the converted ANSI string to the printer.
            SendBytesToPrinter(szPrinterName, pBytes, dwCount);
            Marshal.FreeCoTaskMem(pBytes);
            return true;
        }

    }

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/461746.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Java线程池及拒绝策略详解

前文提到线程的使用以及线程间通信方式&#xff0c;通常情况下我们通过new Thread或者new Runnable创建线程&#xff0c;这种情况下&#xff0c;需要开发者手动管理线程的创建和回收&#xff0c;线程对象没有复用&#xff0c;大量的线程对象创建与销毁会引起频繁GC&#xff0c;…

Unity入门(一)

Unity Unity是一套完善体系与编辑器的跨平台游戏开发工具&#xff0c;也可以称之为游戏引擎。游戏引擎是指一些编写好的可以重复利用的代码与开发游戏所用的各功能编辑器。 基于C#编程&#xff0c;易上手&#xff0c;高安全性独特的面向组件游戏开发思想让游戏开发更加简单易…

Maven 如何下载依赖包的源码包

使用Maven下载依赖包的时候&#xff0c; 默认是不会下载源码包的&#xff0c;但是有时候&#xff0c; 需要Debug代码&#xff0c;或是看看依赖项的源码的写法&#xff0c; 就需要下载源码包了。 这里以 Apache 的 commons-text 为例&#xff0c; 在Maven中添加如下依赖配置&am…

pwlink用作USB转TTL,进入HC-05的AT模式

不说废话的文章概括&#xff1a; 直接连接PWLINK与HC-05&#xff0c;无法进入AT模式&#xff0c;因为蓝牙模块的VCC只能接5V&#xff0c;不能接3.3V&#xff0c;而且PWLINK有两个VDD引脚&#xff0c;且两个VDD引脚初始默认输出电压都是3.3V&#xff0c;所以需要将3.3V改为5V的…

【JavaEE】网络通信中的一些基本概念及协议分层

博主简介&#xff1a;想进大厂的打工人博主主页&#xff1a;xyk:所属专栏: JavaEE初阶 互联网是怎么来的&#xff1f;很多先进技术&#xff0c;都是先军用&#xff0c;用了之后太香了才逐渐民用~~ 互联网也是如此&#xff0c;互联网之前&#xff0c;可以通过有线/无线&#xf…

单链表——“数据结构与算法”

各位CSDN的uu们你们好呀&#xff0c;今天&#xff0c;小雅兰的内容终于是我们心心念念的单链表啦&#xff0c;这一块呢&#xff0c;是一个很重要的部分&#xff0c;也是一个对目前的我来说&#xff0c;比较困难的部分&#xff0c;下面&#xff0c;就让我们进入单链表的世界吧 之…

【unity项目实战】3DRPG游戏开发04——导航、人物移动和鼠标指针图片替换

AI导航烘培 还不清楚怎么用的可以看我另一篇文章 零基础带你从小白到超神29——导航系统 将地形调成静态导航的 选中地形,设置为可行区域 点击烘培 可爬坡改为30度,就会发现坑就变为不可行区域了 选择所有的树,为不可行区域,点击烘培 给主角人物添加导航组件

Kafka3.0.0版本——生产者数据可靠性

目录 一、ACK应答原理1.1、应答级别1.1.1、acks 01.1.2、acks 11.1.3、acks -1&#xff08;all&#xff09; 1.2、问题思考 二、数据可靠性2.1、数据可靠性分析2.2、 数据完全可靠条件2.3、ACK应答级别可靠性总结 三、数据可靠性代码示例 一、ACK应答原理 1.1、应答级别 1…

一日一题:第十二题---模拟散列表(三种方法!!)

​作者&#xff1a;小妮无语 专栏&#xff1a;一日一题 &#x1f6b6;‍♀️✌️道阻且长&#xff0c;不要放弃✌️&#x1f3c3;‍♀️ 今天来给大家介绍的是简单的Hash表的应用 目录 关于哈希的知识点 题目描述&#xff08;模拟散列表&#xff09; 代码 1&#xff08;拉链…

基于GPT-4的神仙插件Bito,亲测好用

基于GPT-4的神仙插件&#xff0c;无需魔法,目前免费 一、Bito 简介 最近发现一个可以有效提升coding效率的插件神器&#xff0c;截止当前(20230425)已有65k的下载量了&#xff01; 类似与Cursor一样&#xff0c;可以使用AI辅助写代码&#xff0c;但是又解决Cursor没有语法提…

力扣刷题day35|416分割等和子集

416. 分割等和子集 力扣题目链接 给你一个 只包含正整数 的 非空 数组 nums 。请你判断是否可以将这个数组分割成两个子集&#xff0c;使得两个子集的元素和相等。 示例 1&#xff1a; 输入&#xff1a;nums [1,5,11,5] 输出&#xff1a;true 解释&#xff1a;数组可以分割…

keil设置程序起始地址及生成bin文件的方法

一.keil设置程序起始地址 1.1FLASH APP 的起始地址设置 随便打开一个之前的实例工程&#xff0c;点击 Options for Target→Target 选项卡 默认的条件下&#xff0c;图中 IROM1 的起始地址&#xff08;Start&#xff09;一般为 0X08000000&#xff0c;大小&#xff08;Size&a…

通用el-table 修改样式

通用el-table 修改样式 el-table实现下图效果: <template><div class"contentbox"><el-table:data"tableData"height"310"style"width: 40%"highlight-current-rowcurrent-change"handleCurrentChange"&g…

利用Floodlight进行DDOS攻击防御实验笔记

Floodlight Floodlight是Apache授权并基于JAVA开发的企业级OpenFlow控制器&#xff0c;当前最新版本是1.2。 Floodlight OpenFlow Controller -ProjectFloodlight&#xff1a;http://www.projectfloodlight.org/floodlight/ 流表 把同一时间&#xff0c;经过同一网络中具有某种…

线程同步方式之二条件变量

Linux线程同步方法之二 条件变量 饥饿状态&#xff1a;由于线程A频繁地申请/释放锁&#xff0c;而导致其他线程无法访问临界资源的情况。 同步synchronized&#xff1a;在保证数据安全的前提下&#xff0c;让线程能够按照某种特定的顺序访问临界资源&#xff0c;从而有效避免…

Spring Security实战(九)—— 使用Spring Security OAuth实现OAuth对接

一、OAuth2.0介绍 OAuth2.0是一种授权协议&#xff0c;允许用户授权第三方应用程序代表他们获取受保护的资源&#xff0c;如个人信息或照片等。它允许用户授权访问他们存储在另一个服务提供商上的资源&#xff0c;而无需将其凭据共享给第三方应用程序。OAuth2.0协议建立在OAuth…

直升机空气动力学基础--004翼型的阻力

来源 1. 空气的粘性 2.阻力的产生 3.形成因素 4.阻力系数曲线

LeetCode-242. 有效的字母异位词

题目链接 LeetCode-242. 有效的字母异位词 题目描述 题解 题解一&#xff08;Java&#xff09; 作者&#xff1a;仲景 首先&#xff0c;满足条件的情况下&#xff0c;两个字符串的长度一定是相等的&#xff0c;不相等一定不满足条件 使用Hash表来存储字符串s中各个字符出现的…

回溯算法——我欲修仙(功法篇)

个人主页&#xff1a;【&#x1f60a;个人主页】 系列专栏&#xff1a;【❤️我欲修仙】 系列文章目录 第一章 ❤️ 学习前的必知知识 第二章 ❤️ 二分查找 文章目录 系列文章目录回溯算法&#x1f914;&#x1f914;&#x1f914;回溯算法一般可以解决的问题回溯算法的实现回…

Python语言简介

B站讲解视频&#xff1a;https://www.bilibili.com/video/BV1Mv4y1n7n8/?vd_source515e6808c21c69114a4fae34589dfb0e Python是什么 Python是一个高层次的结合了解释性、编译性、互动性和面向对象的脚本语言。具有很强的可读性&#xff0c;相比其他语言经常使用英文关键字&a…