首页
> 计算机技术
> 后端开发
> C/C++
B/S架构POS客户端开发之一-POS小票打印机动态链接库的实现
原创 lihf8515于2025年02月13日 14:52发表
来源:本站 阅读:96
本篇是 B/S架构POS客户端开发之一-POS小票打印机动态链接库的实现 篇
您有没有想过自己从零开始实现一个Windows系统中的POS小票打印机动态链接库,这次我将带领您一步步实现它!
随着技术的更新,如今的POS机打印控制已经不再是简单的本地调用打印机打印小票这种情况了,我们经常可以看到网络打印小票。那么它是如何实现的呢?
这次,笔者将带领您从最基本的原理讲起。
首先,我们创建一个动态的链接库文件,它负责接收相关命令,调用本地打印机输出内容。需要考虑到两种情况:
1、不需要驱动程序的LPT1接口的小票打印机。
2、需要安装驱动程序的USB接口的小票打印机。
接着,再于本地起一个Web服务作为本地打印代理(当然,也可以不使用Web打印代理服务,而是通过js和原生程序的代码注入直接用js调用打印程序),它时刻准备接收客户端的打印命令,当此打印代理服务接收到正确的命令,它将调用我们开发的打印程序,打印程序的实现则是调用上一步的动态链接库的相关函数实现打印输出。
这里,我们先讲解如何从零开始开发Windows下的打印动态链接库。
1、编写实现代码,我们这里将该动态库起名为 winprint.dll
下面是实现代码,使用的是 C 语言
// USB驱动程序的打印机调用此函数
int winPrint(char str[]) {
//获取默认打印机
char szPrinterName[255] = {0};
DWORD size = 0;
GetDefaultPrinter(NULL, &size);
if(size) {
GetDefaultPrinter(szPrinterName, &size);
}else{
return 1;
}
//打开打印机
HANDLE hPrinter = NULL;
if(!OpenPrinter(szPrinterName, &hPrinter, NULL)) {
return 1;
}
//开始打印
DOC_INFO_1 docInfo = {0};
docInfo.pDocName = "hfsoft.top";
if(StartDocPrinter(hPrinter, 1, (LPBYTE)&docInfo) == FALSE) {
ClosePrinter(hPrinter);
return 1;
}
//开始一页
if(StartPagePrinter(hPrinter) == FALSE) {
EndDocPrinter(hPrinter);
ClosePrinter(hPrinter);
return 1;
}
//写入打印内容
DWORD dwWritten = 0;
if(WritePrinter(hPrinter, str, strlen(str), &dwWritten) == FALSE) {
EndPagePrinter(hPrinter);
EndDocPrinter(hPrinter);
ClosePrinter(hPrinter);
return 1;
}
//结束一页
if(EndPagePrinter(hPrinter) == FALSE) {
EndDocPrinter(hPrinter);
ClosePrinter(hPrinter);
return 1;
}
//结束打印
if(EndDocPrinter(hPrinter) == FALSE) {
ClosePrinter(hPrinter);
return 1;
}
//关闭打印机
if(ClosePrinter(hPrinter) == FALSE) {
return 1;
}
return 0;
}
// LPT等不需要驱动的打印机调用此函数
int winWriteFile(char filename[], char buffer[], int length) {
// 指定文件名和访问模式
HANDLE hFile = NULL;
hFile = CreateFile(filename,
GENERIC_WRITE,
0, // 不共享
NULL, // 默认安全描述符
CREATE_ALWAYS, // 如果文件存在,则覆盖
FILE_ATTRIBUTE_NORMAL, // 文件属性
NULL); // 没有模板文件
if (hFile == INVALID_HANDLE_VALUE) {
return 1;
}
// 定义写入的字节数
DWORD bytesWritten = 0;
// 向文件中写入数据
if (!WriteFile(hFile, buffer, length, &bytesWritten, NULL)) {
CloseHandle(hFile);
return 1;
}else{
// 关闭文件句柄
CloseHandle(hFile);
return 0;
}
}
2、编译成Dll文件
怎么样?是不是很简单,这里实现了两个函数,先将其编译为动态库文件,这里使用的是gcc编译需要使用到 libwinspool.a,而strip命令则会压缩文件大小。
gcc -fPIC -shared winprint.c -o ../../winprint.dll libwinspool.a
strip ../../winprint.dll
3、在具体编程语言中导入
我们以Nim语言为例将其导入,然后就可以在Nim语言中像正常的本地函数一样调用打印了。
# 导入有驱动程序的打印动态库
proc winPrint*(printString: cstring): cint {.stdcall dynlib: "winprint.dll" importc: "winPrint".}
# 导入winapi的写文件,支持写lpt端口
proc winWriteFile*(filename, printString: cstring, len: cint): cint {.stdcall dynlib: "winprint.dll" importc: "winWriteFile".}
下一篇将讲解 B/S架构POS客户端开发之二-本地Web打印代理服务的实现。
阅读排行榜