csn_dll.go 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227
  1. package service
  2. import (
  3. "fmt"
  4. "os"
  5. "path/filepath"
  6. "syscall"
  7. "unsafe"
  8. )
  9. // CSN Printer SDK — Go wrapper for CsnPrinterLibs.dll (x64)
  10. // FindCsnDllPath 按优先级探测 CsnPrinterLibs.dll 位置:
  11. // 1. exe 同目录(生产环境:build/bin/ 与 smart-parking.exe 一起分发)
  12. // 2. 当前工作目录
  13. // 3. 项目相对路径(wails dev 时 cwd 为 lc_garage/)
  14. // 4. 开发机原始绝对路径(兜底)
  15. func FindCsnDllPath() string {
  16. exePath, _ := os.Executable()
  17. candidates := []string{
  18. filepath.Join(filepath.Dir(exePath), "CsnPrinterLibs.dll"),
  19. "CsnPrinterLibs.dll",
  20. "build/bin/CsnPrinterLibs.dll",
  21. `D:\lq\资料\停车场 道闸 车牌识别 收费机\票机自制\打印机\EMD807嵌入式热敏票据打印模组\5、SDK指令集\Win_SDK_Demo_2023_08_14\Win_SDK_Demo_2023_08_14\lib\x64\CsnPrinterLibs.dll`,
  22. }
  23. for _, p := range candidates {
  24. if _, err := os.Stat(p); err == nil {
  25. return p
  26. }
  27. }
  28. return candidates[0]
  29. }
  30. var csnDll *syscall.LazyDLL
  31. // parseCSNPortNames parses the SDK's double-NUL-terminated port list.
  32. // Port_EnumUSB and Port_EnumPRN return the number of entries, not the byte length.
  33. func parseCSNPortNames(buffer []byte) []string {
  34. var names []string
  35. for start := 0; start < len(buffer); {
  36. end := start
  37. for end < len(buffer) && buffer[end] != 0 {
  38. end++
  39. }
  40. if end == start {
  41. break
  42. }
  43. names = append(names, string(buffer[start:end]))
  44. start = end + 1
  45. }
  46. return names
  47. }
  48. func csnEnumPortNames(procName string) []string {
  49. if csnDll == nil {
  50. return nil
  51. }
  52. buf := make([]byte, 256)
  53. ret, _, _ := csnDll.NewProc(procName).Call(uintptr(unsafe.Pointer(&buf[0])), uintptr(len(buf)))
  54. if ret == 0 {
  55. return nil
  56. }
  57. return parseCSNPortNames(buf)
  58. }
  59. func InitCSN(dllPath string) error {
  60. csnDll = syscall.NewLazyDLL(dllPath)
  61. // Test load
  62. if err := csnDll.Load(); err != nil {
  63. return fmt.Errorf("加载 CsnPrinterLibs.dll 失败: %w", err)
  64. }
  65. return nil
  66. }
  67. // === Port functions ===
  68. func Csn_EnumUSB() string {
  69. names := csnEnumPortNames("Port_EnumUSB")
  70. if len(names) == 0 {
  71. return ""
  72. }
  73. return names[0]
  74. }
  75. func Csn_EnumPRN() string {
  76. names := csnEnumPortNames("Port_EnumPRN")
  77. if len(names) == 0 {
  78. return ""
  79. }
  80. return names[0]
  81. }
  82. func Csn_EnumUSBNames() []string {
  83. return csnEnumPortNames("Port_EnumUSB")
  84. }
  85. func Csn_EnumPRNNames() []string {
  86. return csnEnumPortNames("Port_EnumPRN")
  87. }
  88. func Csn_OpenUSB(name string) (uintptr, error) {
  89. if csnDll == nil {
  90. return 0, fmt.Errorf("DLL 未加载")
  91. }
  92. nameBytes := append([]byte(name), 0)
  93. ret, _, _ := csnDll.NewProc("Port_OpenUSBIO").Call(
  94. uintptr(unsafe.Pointer(&nameBytes[0])))
  95. if ret == 0 {
  96. return 0, fmt.Errorf("打开 USB 打印机失败: %s", name)
  97. }
  98. return ret, nil
  99. }
  100. func Csn_OpenPRN(name string) (uintptr, error) {
  101. if csnDll == nil {
  102. return 0, fmt.Errorf("DLL 未加载")
  103. }
  104. nameBytes := append([]byte(name), 0)
  105. ret, _, _ := csnDll.NewProc("Port_OpenPRNIO").Call(
  106. uintptr(unsafe.Pointer(&nameBytes[0])))
  107. if ret == 0 {
  108. return 0, fmt.Errorf("打开 Windows 打印机失败: %s", name)
  109. }
  110. return ret, nil
  111. }
  112. func Csn_SetPort(handle uintptr) {
  113. if csnDll != nil && handle != 0 {
  114. csnDll.NewProc("Port_SetPort").Call(handle)
  115. }
  116. }
  117. func csn_Close(handle uintptr) {
  118. if csnDll != nil && handle != 0 {
  119. csnDll.NewProc("Port_ClosePort").Call(handle)
  120. }
  121. }
  122. // Csn_Close 关闭调试接口或外部适配层打开的 CSN 端口。
  123. func Csn_Close(handle uintptr) {
  124. csn_Close(handle)
  125. }
  126. // === Print functions ===
  127. func csn_Reset() {
  128. if csnDll != nil {
  129. csnDll.NewProc("Pos_Reset").Call()
  130. }
  131. }
  132. func csn_FeedLine() {
  133. if csnDll != nil {
  134. csnDll.NewProc("Pos_FeedLine").Call()
  135. }
  136. }
  137. func csn_FeedLines(n int) {
  138. if csnDll != nil {
  139. csnDll.NewProc("Pos_Feed_N_Line").Call(uintptr(n))
  140. }
  141. }
  142. func csn_Align(value int) { // 0=左, 1=中, 2=右
  143. if csnDll != nil {
  144. csnDll.NewProc("Pos_Align").Call(uintptr(value))
  145. }
  146. }
  147. func csn_FullCut() {
  148. if csnDll != nil {
  149. csnDll.NewProc("Pos_FullCutPaper").Call()
  150. }
  151. }
  152. // WriteData 直接发送 RAW 字节到当前激活的打印机端口
  153. func Csn_WriteData(data []byte) int {
  154. if csnDll == nil {
  155. return 0
  156. }
  157. ret, _, _ := csnDll.NewProc("WriteData").Call(
  158. uintptr(unsafe.Pointer(&data[0])),
  159. uintptr(len(data)),
  160. 3000) // timeout 3s
  161. return int(ret)
  162. }
  163. // csn_Text 打印一行文字
  164. // nOrgx: -1=左对齐, -2=居中, -3=右对齐
  165. func csn_Text(text string, widthTimes, heightTimes, fontType, fontStyle, nOrgx int) {
  166. if csnDll == nil {
  167. return
  168. }
  169. // Pos_Text(const wchar_t *prnText, int nLan, int nOrgx, int nWidthTimes, int nHeightTimes, int FontType, int nFontStyle)
  170. wstr, _ := syscall.UTF16FromString(text)
  171. csnDll.NewProc("Pos_Text").Call(
  172. uintptr(unsafe.Pointer(&wstr[0])),
  173. 0, // nLan: 0=GBK
  174. uintptr(nOrgx),
  175. uintptr(widthTimes),
  176. uintptr(heightTimes),
  177. uintptr(fontType),
  178. uintptr(fontStyle))
  179. csn_FeedLine()
  180. }
  181. func csn_QRCode(data string, width int) bool {
  182. if csnDll == nil {
  183. return false
  184. }
  185. wstr, _ := syscall.UTF16FromString(data)
  186. ret, _, _ := csnDll.NewProc("Pos_EscQrcode").Call(
  187. uintptr(unsafe.Pointer(&wstr[0])),
  188. uintptr(width), 4) // nWidth, nErrLevel=4
  189. return ret != 0
  190. }
  191. func csn_Barcode(data string, barcodeType int, unitWidth, unitHeight, fontStyle, fontPos int) {
  192. if csnDll == nil {
  193. return
  194. }
  195. dataBytes := append([]byte(data), 0)
  196. csnDll.NewProc("Pos_Barcode").Call(
  197. uintptr(unsafe.Pointer(&dataBytes[0])),
  198. uintptr(barcodeType), 0, uintptr(unitWidth), uintptr(unitHeight),
  199. uintptr(fontStyle), uintptr(fontPos))
  200. }