张洋 1 month ago
parent
commit
ad7cbb0eca

+ 361 - 228
zhipuzi_pos_windows/worker/CPosPrinterWorker.cpp

@@ -3,13 +3,255 @@
 
 #include "../helper/CComHelper.h"
 
-namespace
+// 在文件顶部(现有 include 之后)添加
+#include <devpkey.h>
+#include <devpropdef.h>
+
+#pragma comment(lib, "setupapi.lib")
+#pragma comment(lib, "winspool.lib")
+
+// 本地定义 DEVPROPKEY,等价于 DEVPKEY_Device_BusReportedDeviceDesc (fmtid + pid=4)
+const DEVPROPKEY PKEY_Device_BusReportedDeviceDesc_local =
+{
+	{ 0x540b947e, 0x8b40, 0x45bc, { 0xa8, 0xa2, 0x6a, 0x0b, 0x89, 0x4c, 0xbd, 0xa2 } },
+	4
+};
+
+// Helper: case-insensitive find
+static bool ci_find_substr(const std::wstring& hay, const std::wstring& needle)
 {
-	// ESC/POS:DLE EOT 4,查询纸状态
-	const unsigned char ESC_POS_QUERY_PAPER_STATUS[] = { 0x10, 0x04, 0x04 };
+	if (needle.empty()) return false;
+	std::wstring h = hay, n = needle;
+	for (auto& c : h) c = towlower(c);
+	for (auto& c : n) c = towlower(c);
+	return h.find(n) != std::wstring::npos;
+}
+
+// 读取系统已安装打印机(PRINTER_INFO_2),返回 vector of printer names and port names
+static std::vector<std::pair<std::wstring, std::wstring>> EnumerateInstalledPrinters()
+{
+	std::vector<std::pair<std::wstring, std::wstring>> res;
+
+	DWORD needed = 0, returned = 0;
+	EnumPrinters(PRINTER_ENUM_LOCAL | PRINTER_ENUM_CONNECTIONS, NULL, 2, NULL, 0, &needed, &returned);
+	if (needed == 0) return res;
+
+	std::vector<BYTE> buffer(needed);
+	if (!EnumPrinters(PRINTER_ENUM_LOCAL | PRINTER_ENUM_CONNECTIONS, NULL, 2, buffer.data(), needed, &needed, &returned))
+	{
+		LOG_INFO("EnumerateInstalledPrinters: EnumPrinters failed err=" << GetLastError());
+		return res;
+	}
+
+	PRINTER_INFO_2W* p = reinterpret_cast<PRINTER_INFO_2W*>(buffer.data());
+	for (DWORD i = 0; i < returned; ++i)
+	{
+		std::wstring name = p[i].pPrinterName ? p[i].pPrinterName : L"";
+		std::wstring port = p[i].pPortName ? p[i].pPortName : L"";
+		res.emplace_back(name, port);
+		LOG_INFO(L"InstalledPrinter: Name=" << name << L", Port=" << port);
+	}
+
+	return res;
+}
+
+// 从 DevicePath 提取 vid/pid
+static void ExtractVidPidFromDevicePath(const std::wstring& devicePath, std::wstring& outVid, std::wstring& outPid)
+{
+	outVid.clear(); outPid.clear();
+	size_t posVid = devicePath.find(L"vid_");
+	size_t posPid = devicePath.find(L"pid_");
+	if (posVid != std::wstring::npos && posVid + 4 + 4 <= devicePath.length())
+		outVid = devicePath.substr(posVid + 4, 4);
+	if (posPid != std::wstring::npos && posPid + 4 + 4 <= devicePath.length())
+		outPid = devicePath.substr(posPid + 4, 4);
+}
+
+// 给定 DevicePath,尝试读取该设备的 BusReportedDeviceDesc、FriendlyName/DeviceDesc、Location 信息等
+static void QueryUsbDeviceDetailsByPath(const std::wstring& targetDevicePath,
+	std::wstring& outBusReported, std::wstring& outRegName, std::wstring& outLocation)
+{
+	outBusReported.clear();
+	outRegName.clear();
+	outLocation.clear();
+
+	// 枚举 GUID 为 USB GUID 的设备并查找与 targetDevicePath 匹配的那个
+	HDEVINFO hDevInfoSet = ::SetupDiGetClassDevs((LPGUID)&USB_GUID, NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
+	if (hDevInfoSet == INVALID_HANDLE_VALUE) return;
+
+	PSP_DEVICE_INTERFACE_DETAIL_DATA pDetail = (PSP_DEVICE_INTERFACE_DETAIL_DATA)::GlobalAlloc(LMEM_ZEROINIT, INTERFACE_DETAIL_SIZE);
+	if (!pDetail)
+	{
+		SetupDiDestroyDeviceInfoList(hDevInfoSet);
+		return;
+	}
+	pDetail->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
+
+	SP_DEVINFO_DATA devInfo = {};
+	SP_DEVICE_INTERFACE_DATA ifData = {};
+	devInfo.cbSize = sizeof(SP_DEVINFO_DATA);
+	ifData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
+
+	for (DWORD idx = 0; ; ++idx)
+	{
+		if (!SetupDiEnumDeviceInfo(hDevInfoSet, idx, &devInfo)) break;
 
-	// 常见 Epson 兼容定义:bit6=1 表示缺纸
-	const unsigned char ESC_POS_PAPER_OUT_MASK = 0x40;
+		ifData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
+		if (!SetupDiEnumDeviceInterfaces(hDevInfoSet, NULL, (LPGUID)&USB_GUID, idx, &ifData))
+			continue;
+
+		if (!SetupDiGetInterfaceDeviceDetail(hDevInfoSet, &ifData, pDetail, INTERFACE_DETAIL_SIZE, NULL, &devInfo))
+			continue;
+
+		std::wstring devPath = pDetail->DevicePath;
+		if (devPath != targetDevicePath) continue; // 未匹配则继续
+
+		// 找到目标设备,读取注册表描述
+		DWORD propType = 0, req = 0;
+		WCHAR buf[MAX_PATH] = { 0 };
+		if (SetupDiGetDeviceRegistryProperty(hDevInfoSet, &devInfo, SPDRP_FRIENDLYNAME, &propType, (PBYTE)buf, sizeof(buf), &req))
+		{
+			outRegName = buf;
+		}
+		else if (SetupDiGetDeviceRegistryProperty(hDevInfoSet, &devInfo, SPDRP_DEVICEDESC, &propType, (PBYTE)buf, sizeof(buf), &req))
+		{
+			outRegName = buf;
+		}
+
+		// 尝试读取 BusReportedDeviceDesc(Product string)
+		{
+			DEVPROPTYPE devPropType = 0;
+			DWORD required = 0;
+			WCHAR smallBuf[256] = { 0 };
+			if (SetupDiGetDevicePropertyW(hDevInfoSet, &devInfo, &PKEY_Device_BusReportedDeviceDesc_local, &devPropType,
+				reinterpret_cast<PBYTE>(smallBuf), sizeof(smallBuf), &required, 0))
+			{
+				outBusReported = smallBuf;
+			}
+			else if (GetLastError() == ERROR_INSUFFICIENT_BUFFER && required > 0)
+			{
+				std::vector<BYTE> bigBuf(required);
+				if (SetupDiGetDevicePropertyW(hDevInfoSet, &devInfo, &PKEY_Device_BusReportedDeviceDesc_local, &devPropType,
+					bigBuf.data(), required, &required, 0))
+				{
+					outBusReported.assign(reinterpret_cast<WCHAR*>(bigBuf.data()));
+				}
+			}
+		}
+
+		// 读取位置/端口信息(LocationInformation)
+		{
+			DWORD required = 0;
+			WCHAR locBuf[256] = { 0 };
+			if (SetupDiGetDeviceRegistryProperty(hDevInfoSet, &devInfo, SPDRP_LOCATION_INFORMATION, &propType, (PBYTE)locBuf, sizeof(locBuf), &required))
+			{
+				outLocation = locBuf;
+			}
+		}
+
+		break; // 找到并读取后退出
+	}
+
+	::GlobalFree(pDetail);
+	::SetupDiDestroyDeviceInfoList(hDevInfoSet);
+}
+
+// 主映射函数实现
+std::vector<UsbPrinterMapping> CPosPrinterWorker::MapUsbDevicesToInstalledPrinters()
+{
+	std::vector<UsbPrinterMapping> result;
+
+	// 1) 枚举已安装的打印机(名字 + 端口),用于后续匹配
+	auto printers = EnumerateInstalledPrinters();
+
+	// 2) 取得系统检测到的 USB 设备 DevicePath 列表(使用现有接口)
+	std::vector<std::wstring> usbDevices = CPosPrinterWorker::GetInstance()->getUsbDevices();
+
+	LOG_INFO("MapUsbDevicesToInstalledPrinters: usbDevices count=" << usbDevices.size());
+
+	// 3) 对每个 DevicePath 查询更多信息并尝试匹配
+	for (const auto& dp : usbDevices)
+	{
+		UsbPrinterMapping item;
+		item.devicePath = dp;
+		ExtractVidPidFromDevicePath(dp, item.vid, item.pid);
+
+		// 读取 BusReported, regName, location
+		QueryUsbDeviceDetailsByPath(dp, item.busReportedName, item.regName, item.vid /* reuse var not needed */);
+		// QueryUsbDeviceDetailsByPath fills busReportedName and regName (location ignored here)
+
+		LOG_INFO(L"DevicePath=" << dp);
+		LOG_INFO(L"  busReported=" << item.busReportedName << L", regName=" << item.regName << L", vid=" << item.vid << L", pid=" << item.pid);
+
+		// 尝试多种匹配策略(逐一尝试)
+		for (const auto& pr : printers)
+		{
+			const std::wstring& printerName = pr.first;
+			const std::wstring& portName = pr.second;
+
+			bool matched = false;
+
+			// 1) 如果 busReported 在打印机名称中(不区分大小写)
+			if (!item.busReportedName.empty() && ci_find_substr(printerName, item.busReportedName))
+			{
+				matched = true;
+			}
+
+			// 2) 如果注册表名称在打印机名称中
+			if (!matched && !item.regName.empty() && ci_find_substr(printerName, item.regName))
+			{
+				matched = true;
+			}
+
+			// 3) 如果打印机端口名包含 VID 或 PID(有些端口字符串会包含硬件id或序号)
+			if (!matched && !item.vid.empty() && ci_find_substr(portName, item.vid))
+			{
+				matched = true;
+			}
+			if (!matched && !item.pid.empty() && ci_find_substr(portName, item.pid))
+			{
+				matched = true;
+			}
+
+			// 4) 如果端口名本身等于 USB001/USB002 且注册表 location 包含相同信息,则匹配(二者需要更多自定义逻辑)
+			//    这里把端口名直接当作可能匹配项的一部分:若端口名出现在 regName/location 中则认为是匹配
+			if (!matched && !portName.empty() && (!item.regName.empty() && ci_find_substr(item.regName, portName) || !item.busReportedName.empty() && ci_find_substr(item.busReportedName, portName)))
+			{
+				matched = true;
+			}
+
+			if (matched)
+			{
+				item.matchedPrinterNames.push_back(printerName);
+				LOG_INFO(L"  Matched printer: " << printerName << L" (port=" << portName << L")");
+			}
+		}
+
+		result.push_back(item);
+	}
+
+	// 输出没有被匹配到的打印机(便于调试)
+	for (const auto& pr : printers)
+	{
+		bool used = false;
+		for (const auto& it : result)
+		{
+			for (const auto& m : it.matchedPrinterNames)
+			{
+				if (m == pr.first)
+				{
+					used = true; break;
+				}
+			}
+			if (used) break;
+		}
+		if (!used)
+		{
+			LOG_INFO(L"Installed printer not matched to any USB device: " << pr.first << L", port=" << pr.second);
+		}
+	}
+
+	return result;
 }
 
 CPosPrinterWorker::CPosPrinterWorker()
@@ -253,12 +495,6 @@ bool CPosPrinterWorker::SendDataToShouyinPirnter(std::string data)
 		{
 			HANDLE hPort = *it;
 
-			if (!WaitPrinterReady(hPort))
-			{
-				bSuccess = false;
-				break;
-			}
-
 			//同步写数据
 			DWORD dwWrite = 0;
 			bool ret = WriteWithTimeout(hPort, data.c_str(), (DWORD)data.length(), 5000, dwWrite);
@@ -272,12 +508,6 @@ bool CPosPrinterWorker::SendDataToShouyinPirnter(std::string data)
 	}
 	else
 	{
-		if (!WaitPrinterReady(m_socket))
-		{
-			m_socket.close();
-			return false;
-		}
-
 		//网口走这里
 		try
 		{
@@ -363,12 +593,6 @@ bool CPosPrinterWorker::SendDataToBiaoqianPirnter(std::string data)
 		for (std::vector<HANDLE>::iterator it = m_hBiaoqianPorts.begin(); it != m_hBiaoqianPorts.end(); it++)
 		{
 			HANDLE hPort = *it;
-
-			if (!WaitPrinterReady(hPort))
-			{
-				bSuccess = false;
-				break;
-			}
 			
 			//同步写数据
 			DWORD dwWrite = 0;
@@ -383,12 +607,6 @@ bool CPosPrinterWorker::SendDataToBiaoqianPirnter(std::string data)
 	}
 	else
 	{
-		if (!WaitPrinterReady(m_socket))
-		{
-			m_socket.close();
-			return false;
-		}
-
 		//网口走这里
 		try
 		{
@@ -448,12 +666,6 @@ bool CPosPrinterWorker::SendDataToChufangPirnter(ChufangPrinterContent chufang_d
 		return false;
 	}
 
-	if (!WaitPrinterReady(m_socket))
-	{
-		m_socket.close();
-		return false;
-	}
-
 	//网口走这里
 	try
 	{
@@ -681,132 +893,151 @@ void CPosPrinterWorker::InitCom()
  **/
 int CPosPrinterWorker::GetDevicePath(LPGUID lpGuid, std::vector<std::wstring>& usb_devices)
 {
-	HDEVINFO hDevInfoSet;
-	SP_DEVINFO_DATA spDevInfoData;
-	SP_DEVICE_INTERFACE_DATA ifData;
-	PSP_DEVICE_INTERFACE_DETAIL_DATA pDetail;
-	int nCount;
-	int nTotle;
-	BOOL bResult;
-
-	//这2个字符串,用于根据usb的名字对比是否为打印机设备
-	std::wstring strUSBPrint = TEXT("USB 打印支持");
-
-	//xp上是英文
-	std::wstring strUSBPrint_EN = L"USB Printing Support";
-
-	// 取得一个该GUID相关的设备信息集句柄
-	hDevInfoSet = ::SetupDiGetClassDevs(lpGuid,     // class GUID
-		NULL,                    // 无关键字
-		NULL,                    // 不指定父窗口句柄
-		DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);    // 目前存在的设备
+	// 返回找到的设备数量
+	int nCount = 0;
 
-// 失败...
+	// GUID 相关设备信息集句柄
+	HDEVINFO hDevInfoSet = ::SetupDiGetClassDevs(lpGuid, NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
 	if (hDevInfoSet == INVALID_HANDLE_VALUE)
 	{
-		LOG_INFO("SetupDiGetClassDevs failed \r\n");
+		LOG_INFO("SetupDiGetClassDevs failed");
 		return 0;
 	}
 
-	// 申请设备接口数据空间
-	pDetail = (PSP_DEVICE_INTERFACE_DETAIL_DATA)::GlobalAlloc(LMEM_ZEROINIT, INTERFACE_DETAIL_SIZE);
+	// 为接口细节分配缓冲
+	PSP_DEVICE_INTERFACE_DETAIL_DATA pDetail = (PSP_DEVICE_INTERFACE_DETAIL_DATA)::GlobalAlloc(LMEM_ZEROINIT, INTERFACE_DETAIL_SIZE);
+	if (pDetail == NULL)
+	{
+		LOG_INFO("GlobalAlloc pDetail failed");
+		::SetupDiDestroyDeviceInfoList(hDevInfoSet);
+		return 0;
+	}
 	pDetail->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
-	nTotle = -1;
-	nCount = 0;
-	bResult = TRUE;
 
-	// 设备序号=0,1,2... 逐一测试设备接口,到失败为止
-	while (bResult)
-	{
-		nTotle++;
-		spDevInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
+	// 用于枚举设备信息
+	SP_DEVINFO_DATA spDevInfoData = {};
+	SP_DEVICE_INTERFACE_DATA ifData = {};
+	spDevInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
+	ifData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
 
-		// 枚举符合该GUID的设备接口
-		bResult = ::SetupDiEnumDeviceInfo(
-			hDevInfoSet,     // 设备信息集句柄
-			(ULONG)nTotle,   // 设备信息集里的设备序号
-			&spDevInfoData);        // 设备接口信息
+	// 用于识别通用 USB 打印类的字符串(中文/英文)
+	std::wstring strUSBPrint = L"USB 打印支持";
+	std::wstring strUSBPrint_EN = L"USB Printing Support";
 
-		if (bResult)
+	// 枚举设备信息条目(按索引)
+	for (DWORD idx = 0; ; ++idx)
+	{
+		// 枚举设备信息项
+		BOOL ok = ::SetupDiEnumDeviceInfo(hDevInfoSet, idx, &spDevInfoData);
+		if (!ok)
 		{
-			DWORD DataT;
-			TCHAR buf[MAX_PATH] = { 0 };
-			DWORD nSize = 0;
+			// 结束或出错(当没有更多项时返回 FALSE)
+			break;
+		}
 
-			// get Friendly Name or Device Description
-			if (SetupDiGetDeviceRegistryProperty(hDevInfoSet, &spDevInfoData,
-				SPDRP_FRIENDLYNAME, &DataT, (PBYTE)buf, sizeof(buf), &nSize))
-			{
-			}
-			else if (SetupDiGetDeviceRegistryProperty(hDevInfoSet, &spDevInfoData,
-				SPDRP_DEVICEDESC, &DataT, (PBYTE)buf, sizeof(buf), &nSize))
+		// 先尝试从注册表获取 FriendlyName / DeviceDesc 作为回退名字
+		TCHAR regBuf[MAX_PATH] = { 0 };
+		DWORD propType = 0;
+		DWORD requiredSize = 0;
+		std::wstring regName;
+		if (SetupDiGetDeviceRegistryProperty(hDevInfoSet, &spDevInfoData, SPDRP_FRIENDLYNAME, &propType,
+			(PBYTE)regBuf, sizeof(regBuf), &requiredSize))
+		{
+			regName = regBuf;
+		}
+		else if (SetupDiGetDeviceRegistryProperty(hDevInfoSet, &spDevInfoData, SPDRP_DEVICEDESC, &propType,
+			(PBYTE)regBuf, sizeof(regBuf), &requiredSize))
+		{
+			regName = regBuf;
+		}
+		else
+		{
+			regName = L"Unknown";
+		}
+
+		// 尝试读取总线报告的设备描述(通常为 USB Product string)
+		std::wstring busReported;
+		{
+			DEVPROPTYPE devPropType = 0;
+			DWORD req = 0;
+			WCHAR smallBuf[256] = { 0 };
+			BOOL got = FALSE;
+
+			// 使用本地定义的 DEVPROPKEY:PKEY_Device_BusReportedDeviceDesc_local(需在文件顶部定义)
+			if (SetupDiGetDevicePropertyW(hDevInfoSet, &spDevInfoData, &PKEY_Device_BusReportedDeviceDesc_local, &devPropType,
+				reinterpret_cast<PBYTE>(smallBuf), sizeof(smallBuf), &req, 0))
 			{
+				busReported = smallBuf;
+				got = TRUE;
 			}
-			else
+			else if (GetLastError() == ERROR_INSUFFICIENT_BUFFER && req > 0)
 			{
-				lstrcpy(buf, _T("Unknown"));
+				std::vector<BYTE> bigBuf(req);
+				if (SetupDiGetDevicePropertyW(hDevInfoSet, &spDevInfoData, &PKEY_Device_BusReportedDeviceDesc_local, &devPropType,
+					bigBuf.data(), req, &req, 0))
+				{
+					// bigBuf 存储为 WCHAR 字符串
+					busReported.assign(reinterpret_cast<WCHAR*>(bigBuf.data()));
+					got = TRUE;
+				}
 			}
-
-			std::wstring ws_buf = buf;
-
-			//是否是要找的设备类型
-			if (ws_buf != strUSBPrint && ws_buf != strUSBPrint_EN)
+			if (got)
 			{
-				LOG_INFO(L"not good usb, buf:" << ws_buf);
-				continue;
+				LOG_INFO(L"BusReportedDeviceDesc: " << busReported);
 			}
+		}
 
-			LOG_INFO(L"good usb, buf:" << ws_buf);
-			ifData.cbSize = sizeof(ifData);
-
-			// 枚舉符合該GUID的設備接口
-			bResult = ::SetupDiEnumDeviceInterfaces(
-				hDevInfoSet,     // 設備信息集句柄
-				NULL,            // 不需額外的設備描述
-				lpGuid,          // GUID
-				(ULONG)nTotle,   // 設備信息集里的設備序號
-				&ifData);        // 設備接口信息
-
-			if (bResult)
-			{
-				// 取得该设备接口的细节(设备路径)
-				bResult = SetupDiGetInterfaceDeviceDetail(
-					hDevInfoSet,    // 设备信息集句柄
-					&ifData,        // 设备接口信息
-					pDetail,        // 设备接口细节(设备路径)
-					INTERFACE_DETAIL_SIZE,    // 输出缓冲区大小
-					NULL,           // 不需计算输出缓冲区大小(直接用设定值)
-					NULL);          // 不需额外的设备描述
-
-				if (bResult)
-				{
-					std::wstring DevicePath = pDetail->DevicePath;
+		// 如果既不是通用打印类也没有 busReported 描述,跳过该设备
+		if (regName != strUSBPrint && regName != strUSBPrint_EN && busReported.empty())
+		{
+			LOG_INFO(L"not good usb, regName:" << regName);
+			continue;
+		}
 
-					std::wstring vid = DevicePath.substr(DevicePath.find(_T("vid_"), 0) + 4, 4);
-					std::wstring pid = DevicePath.substr(DevicePath.find(_T("pid_"), 0) + 4, 4);
+		// 枚举该设备的信息接口以取得 DevicePath
+		ifData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
+		if (!::SetupDiEnumDeviceInterfaces(hDevInfoSet, NULL, lpGuid, idx, &ifData))
+		{
+			LOG_INFO("SetupDiEnumDeviceInterfaces failed for idx=" << idx);
+			continue;
+		}
 
-					LOG_INFO("Vid:" << vid.c_str() << ", Pid:" << pid.c_str());
+		// 取得接口细节(包含 DevicePath)
+		if (!SetupDiGetInterfaceDeviceDetail(hDevInfoSet, &ifData, pDetail, INTERFACE_DETAIL_SIZE, NULL, NULL))
+		{
+			LOG_INFO("SetupDiGetInterfaceDeviceDetail failed for idx=" << idx);
+			continue;
+		}
 
-					// 复制设备路径到输出缓冲区
-					usb_devices.push_back(DevicePath);
+		std::wstring DevicePath = pDetail->DevicePath;
 
-					// 调整计数值
-					nCount++;
+		// 从 DevicePath 中提取 vid/pid 以便后续判断或使用 WinUSB
+		std::wstring vid = L"";
+		std::wstring pid = L"";
+		size_t posVid = DevicePath.find(L"vid_");
+		size_t posPid = DevicePath.find(L"pid_");
+		if (posVid != std::wstring::npos && posVid + 4 + 4 <= DevicePath.length()) vid = DevicePath.substr(posVid + 4, 4);
+		if (posPid != std::wstring::npos && posPid + 4 + 4 <= DevicePath.length()) pid = DevicePath.substr(posPid + 4, 4);
+		LOG_INFO("Vid:" << vid.c_str() << ", Pid:" << pid.c_str());
 
-					LOG_INFO("Cnt = " << nCount << ",pDetail->DevicePath =" << pDetail->DevicePath);
-				}
-			}
+		// 输出检测到的名称(优先 busReported,其次注册表名)
+		if (!busReported.empty())
+		{
+			LOG_INFO(L"Detected printer name: " << busReported);
 		}
 		else
 		{
-			//LOG_INFO("SetupDiEnumDeviceInfo FAILED!@");
+			LOG_INFO(L"Detected registry name: " << regName);
 		}
+
+		// 将 DevicePath 添加到结果集合
+		usb_devices.push_back(DevicePath);
+		++nCount;
+		LOG_INFO("Cnt = " << nCount << ", pDetail->DevicePath =" << pDetail->DevicePath);
 	}
 
-	// 释放设备接口数据空间
+	// 清理并返回
 	::GlobalFree(pDetail);
-
-	// 关闭设备信息集句柄
 	::SetupDiDestroyDeviceInfoList(hDevInfoSet);
 	return nCount;
 }
@@ -820,104 +1051,6 @@ std::vector<std::wstring> CPosPrinterWorker::getUsbDevices()
 	return usb_devices;
 }
 
-bool CPosPrinterWorker::IsPaperOut(HANDLE hPort)
-{
-	if (hPort == NULL || hPort == INVALID_HANDLE_VALUE)
-	{
-		return false;
-	}
-
-	DWORD dwWrite = 0;
-	if (!WriteWithTimeout(hPort, ESC_POS_QUERY_PAPER_STATUS, sizeof(ESC_POS_QUERY_PAPER_STATUS), 500, dwWrite) ||
-		dwWrite != sizeof(ESC_POS_QUERY_PAPER_STATUS))
-	{
-		LOG_INFO("查询打印机缺纸状态失败,WriteWithTimeout Failed!, hPort:" << hPort);
-		return false;
-	}
-
-	unsigned char status = 0;
-	DWORD dwRead = 0;
-	if (!ReadWithTimeout(hPort, &status, 1, 500, dwRead) || dwRead != 1)
-	{
-		LOG_INFO("查询打印机缺纸状态超时或无返回,hPort:" << hPort);
-		return false;
-	}
-
-	return (status & ESC_POS_PAPER_OUT_MASK) == ESC_POS_PAPER_OUT_MASK;
-}
-
-bool CPosPrinterWorker::IsPaperOut(boost::asio::ip::tcp::socket& socket)
-{
-	try
-	{
-		boost::asio::write(socket, boost::asio::buffer(ESC_POS_QUERY_PAPER_STATUS, sizeof(ESC_POS_QUERY_PAPER_STATUS)));
-
-		boost::system::error_code ec;
-		bool oldNonBlocking = socket.non_blocking();
-		socket.non_blocking(true, ec);
-		if (ec)
-		{
-			LOG_INFO("设置网口打印机 non_blocking 失败,错误信息:" << ec.message().c_str());
-			return false;
-		}
-
-		unsigned char status = 0;
-		DWORD startTick = GetTickCount();
-
-		while (GetTickCount() - startTick < 500)
-		{
-			size_t len = socket.read_some(boost::asio::buffer(&status, 1), ec);
-			if (!ec && len == 1)
-			{
-				socket.non_blocking(oldNonBlocking, ec);
-				return (status & ESC_POS_PAPER_OUT_MASK) == ESC_POS_PAPER_OUT_MASK;
-			}
-
-			if (ec == boost::asio::error::would_block || ec == boost::asio::error::try_again)
-			{
-				ec.clear();
-				Sleep(20);
-				continue;
-			}
-
-			LOG_INFO("查询网口打印机缺纸状态失败,错误信息:" << ec.message().c_str());
-			socket.non_blocking(oldNonBlocking, ec);
-			return false;
-		}
-
-		socket.non_blocking(oldNonBlocking, ec);
-		LOG_INFO("查询网口打印机缺纸状态超时");
-		return false;
-	}
-	catch (const std::exception& e)
-	{
-		LOG_INFO("查询网口打印机缺纸状态异常,错误信息:" << e.what());
-		return false;
-	}
-}
-
-bool CPosPrinterWorker::WaitPrinterReady(HANDLE hPort)
-{
-	while (m_is_work && IsPaperOut(hPort))
-	{
-		LOG_INFO("打印机缺纸,1秒后继续检测...");
-		Sleep(1000);
-	}
-
-	return m_is_work;
-}
-
-bool CPosPrinterWorker::WaitPrinterReady(boost::asio::ip::tcp::socket& socket)
-{
-	while (m_is_work && IsPaperOut(socket))
-	{
-		LOG_INFO("网口打印机缺纸,1秒后继续检测...");
-		Sleep(1000);
-	}
-
-	return m_is_work;
-}
-
 bool CPosPrinterWorker::WriteWithTimeout(HANDLE hPort, const void* buffer, DWORD bufferSize, DWORD timeoutMs, DWORD& dwWrite)
 {
 	dwWrite = 0;

+ 14 - 6
zhipuzi_pos_windows/worker/CPosPrinterWorker.h

@@ -11,6 +11,16 @@
 //USB类的GUID,通过这个去找USB打印机
 const GUID USB_GUID = { 0x28d78fad, 0x5a12, 0x11d1, {0xae, 0x5b, 0x00, 0x00, 0xf8, 0x03, 0xa8, 0xc2 } };
 
+struct UsbPrinterMapping
+{
+	std::wstring devicePath;        // CreateFile 使用的 DevicePath
+	std::wstring busReportedName;   // 总线报告的设备描述(Product string),若能读取到
+	std::wstring regName;           // 注册表里的 FriendlyName / DeviceDesc
+	std::wstring vid;               // 从 DevicePath 提取的 VID
+	std::wstring pid;               // 从 DevicePath 提取的 PID
+	std::vector<std::wstring> matchedPrinterNames; // 匹配到的打印队列名称(EnumPrinters)
+};
+
 //这个类采用队列的模式,执行把数据发送给打印机,注意这个类只负责发送,不负责数据内容的组装
 class CPosPrinterWorker
 {
@@ -46,6 +56,10 @@ public:
 	//获取当前电脑上所有的打印usb设备
 	std::vector<std::wstring> getUsbDevices();
 
+	/// 枚举系统已安装的打印队列并把它们与当前系统的 USB 打印设备做一次尽力匹配。、
+	/// 主要用于调试与定位:会返回每个 USB 设备的额外信息(busReported/regName/vid/pid)
+	std::vector<UsbPrinterMapping> MapUsbDevicesToInstalledPrinters();
+
 private:
 	CPosPrinterWorker();
 
@@ -62,12 +76,6 @@ private:
 	//获取USB打印机的路径,用于收银小票打印机的智能识别,也用于设置中心获取所有打印机
 	int GetDevicePath(LPGUID lpGuid, std::vector<std::wstring>& usb_devices);
 
-	bool IsPaperOut(HANDLE hPort);
-	bool IsPaperOut(boost::asio::ip::tcp::socket& socket);
-
-	bool WaitPrinterReady(HANDLE hPort);
-	bool WaitPrinterReady(boost::asio::ip::tcp::socket& socket);
-
 	bool WriteWithTimeout(HANDLE hPort, const void* buffer, DWORD bufferSize, DWORD timeoutMs, DWORD& dwWrite);
 	bool ReadWithTimeout(HANDLE hPort, void* buffer, DWORD bufferSize, DWORD timeoutMs, DWORD& dwRead);