|
|
@@ -21,6 +21,39 @@ const DEVPROPKEY PKEY_Device_BusReportedDeviceDesc_local =
|
|
|
4
|
|
|
};
|
|
|
|
|
|
+//把配置里存的串口名统一成裸名(形如 COM3),只用于比较(R53)。
|
|
|
+//允许配置里带 \\.\ 前缀(手工改过配置文件的情况),避免比较时对不上。
|
|
|
+static std::wstring ToBareComName(const std::wstring& com_path)
|
|
|
+{
|
|
|
+ std::wstring s = com_path;
|
|
|
+
|
|
|
+ if (s.length() >= 4 && s.compare(0, 4, L"\\\\.\\") == 0)
|
|
|
+ {
|
|
|
+ s = s.substr(4);
|
|
|
+ }
|
|
|
+ else if (s.length() >= 4 && s.compare(0, 4, L"\\\\?\\") == 0)
|
|
|
+ {
|
|
|
+ s = s.substr(4);
|
|
|
+ }
|
|
|
+
|
|
|
+ return s;
|
|
|
+}
|
|
|
+
|
|
|
+//串口必须用 \\.\COMx 的形式打开(R53):裸口名 "COM3" 能打开只是 DOS 设备名的历史兼容,
|
|
|
+//而 "COM10" 及以上不走设备名解析,会被当成普通文件名 ⇒ CreateFile 直接失败。
|
|
|
+//CSerialPort(电子秤那边)一直用的是 \\.\ 前缀,打印机这里漏了。
|
|
|
+static std::wstring ToComDevicePath(const std::wstring& com_path)
|
|
|
+{
|
|
|
+ std::wstring bare = ToBareComName(com_path);
|
|
|
+
|
|
|
+ if (bare.empty())
|
|
|
+ {
|
|
|
+ return com_path;
|
|
|
+ }
|
|
|
+
|
|
|
+ return L"\\\\.\\" + bare;
|
|
|
+}
|
|
|
+
|
|
|
CPosPrinterWorker::CPosPrinterWorker()
|
|
|
{
|
|
|
}
|
|
|
@@ -73,6 +106,16 @@ void CPosPrinterWorker::StartShouyinChannels()
|
|
|
//收集本次要打开的端口路径及其类型
|
|
|
std::vector<std::pair<std::wstring, PrinterPortKind>> ports;
|
|
|
|
|
|
+ //电子秤占用的串口:打印机在**任何**模式下都不能去碰(R52 / R53)。
|
|
|
+ //串口是独占打开的(OpenComPort 用 share=0 的 CreateFile),两边都去连同一个口就会互相抢 ——
|
|
|
+ //谁先打开谁赢,输的那个一直打不开,秤那边表现成称重读数恒为 0。
|
|
|
+ //另外 OpenComPort 打开成功后会顺手把波特率改成 19200,抢到秤的口还会踩坏秤的波特率。
|
|
|
+ std::wstring ws_dianzicheng_com;
|
|
|
+ if (CSetting::GetInstance()->GetParam("setting_dianzicheng_is_lianjie") == "1")
|
|
|
+ {
|
|
|
+ ws_dianzicheng_com = ToBareComName(CLewaimaiString::UTF8ToUnicode(CSetting::GetInstance()->GetParam("setting_dianzicheng_com")));
|
|
|
+ }
|
|
|
+
|
|
|
if (printer_leixing == "auto")
|
|
|
{
|
|
|
//自动模式:同时检测usb、并口、串口
|
|
|
@@ -101,8 +144,15 @@ void CPosPrinterWorker::StartShouyinChannels()
|
|
|
|
|
|
CComHelper helper;
|
|
|
std::vector<std::wstring> comVector = helper.getComPort();
|
|
|
+
|
|
|
for (std::vector<std::wstring>::iterator it = comVector.begin(); it != comVector.end(); it++)
|
|
|
{
|
|
|
+ if (ws_dianzicheng_com.empty() == false && _wcsicmp(ToBareComName(*it).c_str(), ws_dianzicheng_com.c_str()) == 0)
|
|
|
+ {
|
|
|
+ //这是电子秤的串口,打印机不要去碰
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
ports.push_back(std::make_pair(*it, PrinterPortKind::Com));
|
|
|
}
|
|
|
}
|
|
|
@@ -125,7 +175,14 @@ void CPosPrinterWorker::StartShouyinChannels()
|
|
|
std::wstring ws_printer_com = CLewaimaiString::UTF8ToUnicode(printer_com);
|
|
|
if (!ws_printer_com.empty())
|
|
|
{
|
|
|
- ports.push_back(std::make_pair(ws_printer_com, PrinterPortKind::Com));
|
|
|
+ //显式串口模式同样可能选中电子秤的口(R53):也跳过。
|
|
|
+ //宁可这台打印机不出票,也不能让它把秤的口抢掉 —— 抢掉之后称重恒 0,界面上还看不出来。
|
|
|
+ //设置里给打印机换一个别的串口即可。
|
|
|
+ if (ws_dianzicheng_com.empty() == true
|
|
|
+ || _wcsicmp(ToBareComName(ws_printer_com).c_str(), ws_dianzicheng_com.c_str()) != 0)
|
|
|
+ {
|
|
|
+ ports.push_back(std::make_pair(ws_printer_com, PrinterPortKind::Com));
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@@ -370,8 +427,12 @@ bool CPosPrinterWorker::OpenChannelHandle(std::shared_ptr<CPortSendChannel> ch)
|
|
|
|
|
|
HANDLE CPosPrinterWorker::OpenComPort(const std::wstring& com_path)
|
|
|
{
|
|
|
+ //统一补 \\.\ 前缀(R53):裸口名在 COM1~COM9 上能碰巧打开(DOS 设备名兼容),
|
|
|
+ //但 COM10 及以上会被当成普通文件名,CreateFile 直接失败。
|
|
|
+ std::wstring real_path = ToComDevicePath(com_path);
|
|
|
+
|
|
|
//同步句柄(不带 FILE_FLAG_OVERLAPPED),WriteFile 写进驱动缓冲即返回,无需超时等待
|
|
|
- HANDLE hPort = CreateFile(com_path.c_str(), GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
|
|
|
+ HANDLE hPort = CreateFile(real_path.c_str(), GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
|
|
|
|
|
|
if (hPort == INVALID_HANDLE_VALUE)
|
|
|
{
|
|
|
@@ -749,68 +810,6 @@ void CPosPrinterWorker::SendDataToChufangPirnter(ChufangPrinterContent chufang_d
|
|
|
m_socket.close();
|
|
|
}
|
|
|
|
|
|
-//自动识别用于收银小票的USB打印机列表
|
|
|
-void CPosPrinterWorker::InitUsb()
|
|
|
-{
|
|
|
- //设置中文字符
|
|
|
- setlocale(LC_CTYPE, "chs");
|
|
|
-
|
|
|
- //取设备路径
|
|
|
- m_usb_devices.clear();
|
|
|
- int nDevice = GetDevicePath((LPGUID)&USB_GUID, m_usb_devices);
|
|
|
- //LOG_INFO("可用的USB打印机数量:" << nDevice);
|
|
|
-
|
|
|
- //添加usb端口
|
|
|
- int i = 0;
|
|
|
-
|
|
|
- while (i < nDevice)
|
|
|
- {
|
|
|
- std::string setting_biaoqian_printer_usb = CSetting::GetInstance()->GetParam("setting_biaoqian_printer_usb");
|
|
|
- std::wstring ws_setting_biaoqian_printer_usb = CLewaimaiString::UTF8ToUnicode(setting_biaoqian_printer_usb);
|
|
|
-
|
|
|
- if (CSetting::GetInstance()->GetParam("setting_is_new_waimai_biaoqian_printer") == "1" && ws_setting_biaoqian_printer_usb == m_usb_devices[i])
|
|
|
- {
|
|
|
- //碰到了一个在设置中心明确设置的标签打印机,过滤掉
|
|
|
- i++;
|
|
|
- continue;
|
|
|
- }
|
|
|
-
|
|
|
- //LOG_INFO("准备打开端口 Port = " << m_usb_devices[i].c_str());
|
|
|
-
|
|
|
- HANDLE hPort = CreateFile(m_usb_devices[i].c_str(), GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, NULL);
|
|
|
-
|
|
|
- if (hPort == INVALID_HANDLE_VALUE)
|
|
|
- {
|
|
|
- //LOG_INFO("打开USB端口失败, Port = " << m_usb_devices[i].c_str());
|
|
|
-
|
|
|
- // 打开端口失败
|
|
|
- DWORD error = GetLastError();
|
|
|
-
|
|
|
- if (error == 2)
|
|
|
- {
|
|
|
- //没有指定的文件
|
|
|
- //LOG_INFO("没有找对对应的usb端口");
|
|
|
- }
|
|
|
- else if (error == 5)
|
|
|
- {
|
|
|
- //LOG_INFO("usb端口被占用!");
|
|
|
- }
|
|
|
-
|
|
|
- i++;
|
|
|
- continue;
|
|
|
- }
|
|
|
-
|
|
|
- //LOG_INFO("打开usb端口成功,准备进行打印机检测! hPort:" << hPort);
|
|
|
-
|
|
|
- m_hShouyinPorts.push_back(hPort);
|
|
|
-
|
|
|
- i++;
|
|
|
- }
|
|
|
-
|
|
|
- //清空usb集合,下一次调用这个函数的时候会重新设置
|
|
|
- m_usb_devices.clear();
|
|
|
-}
|
|
|
-
|
|
|
bool CPosPrinterWorker::InitOneUsb(std::wstring usb_path, int nType)
|
|
|
{
|
|
|
if (usb_path == L"")
|
|
|
@@ -854,61 +853,6 @@ bool CPosPrinterWorker::InitOneUsb(std::wstring usb_path, int nType)
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
-bool CPosPrinterWorker::InitBingkou()
|
|
|
-{
|
|
|
- std::wstring LptStr = L"lpt1";
|
|
|
-
|
|
|
- HANDLE hPort = CreateFile(LptStr.c_str(), GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, NULL);
|
|
|
-
|
|
|
- if (hPort == INVALID_HANDLE_VALUE)
|
|
|
- {
|
|
|
- //LOG_INFO("打开并口失败, Port = " << LptStr.c_str());
|
|
|
-
|
|
|
- DWORD error = GetLastError();
|
|
|
-
|
|
|
- if (error == 2)
|
|
|
- {
|
|
|
- //没有指定的文件
|
|
|
- //LOG_INFO("本机器没有并口!");
|
|
|
- }
|
|
|
- else if (error == 5)
|
|
|
- {
|
|
|
- //LOG_INFO("并口被占用!");
|
|
|
- }
|
|
|
-
|
|
|
- return false;
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- //这个表示并口可以使用
|
|
|
- //LOG_INFO("找到并口,准备进行打印机检测! hPort:" << hPort);
|
|
|
-
|
|
|
- m_hShouyinPorts.push_back(hPort);
|
|
|
- }
|
|
|
-
|
|
|
- return true;
|
|
|
-}
|
|
|
-
|
|
|
-void CPosPrinterWorker::InitCom()
|
|
|
-{
|
|
|
- CComHelper helper;
|
|
|
- std::vector<std::wstring> comVector = helper.getComPort();
|
|
|
-
|
|
|
- for (std::vector<std::wstring>::iterator it = comVector.begin(); it != comVector.end(); it++)
|
|
|
- {
|
|
|
- std::wstring com2Str = *it;
|
|
|
-
|
|
|
- HANDLE hPort = OpenComPort(com2Str);
|
|
|
-
|
|
|
- if (hPort == NULL)
|
|
|
- {
|
|
|
- continue;
|
|
|
- }
|
|
|
-
|
|
|
- m_hShouyinPorts.push_back(hPort);
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
/*
|
|
|
*获取CreateFile的USB端口号
|
|
|
**/
|