// CDlgManualUSB.cpp: 实现文件 // #include "stdafx.h" #include "hgjson.h" #include "DlgManualUSB.h" #include "afxdialogex.h" #include "resource.h" #include #include // CDlgManualUSB 对话框 extern int get_list_sel(CListCtrl* lc); std::wstring get_wnd_text(HWND h) { int len = GetWindowTextLengthW(h); wchar_t* buf = new wchar_t[len + 8]; std::wstring ret(L""); memset(buf, 0, (len + 8) * 2); GetWindowTextW(h, buf, len + 2); ret = buf; delete[] buf; return std::move(ret); } std::wstring now(void) { time_t n = time(NULL); struct tm* t = localtime(&n); wchar_t buf[40] = { 0 }; swprintf_s(buf, _countof(buf) - 1, L"%04d-%02d-%02d %02d:%02d:%02d" , t->tm_year + 1900, t->tm_mon + 1, t->tm_mday , t->tm_hour, t->tm_min, t->tm_sec); return buf; } IMPLEMENT_DYNAMIC(CDlgManualUSB, CDialogEx) CDlgManualUSB::CDlgManualUSB(CWnd* pParent /*=nullptr*/) : CDialogEx(IDD_RAW_USB, pParent) { } CDlgManualUSB::~CDlgManualUSB() { close(); DestroyMenu(ep_menu_); } void CDlgManualUSB::DoDataExchange(CDataExchange* pDX) { CDialogEx::DoDataExchange(pDX); DDX_Control(pDX, IDC_LIST_EP, eps_); DDX_Control(pDX, IDC_COMBO1, types_); DDX_Control(pDX, IDC_COMBO_EP, oper_ep_); } BEGIN_MESSAGE_MAP(CDlgManualUSB, CDialogEx) ON_BN_CLICKED(IDC_BUTTON_OPEN, &CDlgManualUSB::OnBnClickedButtonOpen) ON_BN_CLICKED(IDC_BUTTON_ADD_EP, &CDlgManualUSB::OnBnClickedButtonAddEp) ON_BN_CLICKED(IDC_BUTTON_CMD, &CDlgManualUSB::OnBnClickedButtonCmd) ON_BN_CLICKED(IDC_BUTTON_CLOSE, &CDlgManualUSB::OnBnClickedButtonClose) ON_NOTIFY(NM_RCLICK, IDC_LIST_EP, &CDlgManualUSB::OnNMRClickListEp) ON_COMMAND(ID_USB_OPEN, &CDlgManualUSB::OnUsbOpen) ON_COMMAND(ID_USB_CLOSE, &CDlgManualUSB::OnUsbClose) ON_COMMAND(ID_USB_DELETE, &CDlgManualUSB::OnUsbDelete) ON_BN_CLICKED(IDC_BUTTON_CLEAR, &CDlgManualUSB::OnBnClickedButtonClear) END_MESSAGE_MAP() void CDlgManualUSB::close(void) { for (auto& v : endpoints_) CloseHandle(v.second); endpoints_.clear(); if (main_ != INVALID_HANDLE_VALUE) CloseHandle(main_); main_ = INVALID_HANDLE_VALUE; for (int i = 0; i < eps_.GetItemCount(); ++i) { eps_.SetItemText(i, 3, TEXT("Closed")); } oper_ep_.ResetContent(); GetDlgItem(IDC_BUTTON_CMD)->EnableWindow(FALSE); cur_sel_ = -1; } HANDLE CDlgManualUSB::open_usb(const wchar_t* name) { return CreateFileW(name, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE , NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL); } std::wstring CDlgManualUSB::error_message(int err) { if (err == -1) err = GetLastError(); wchar_t* lpMsgBuf = NULL; std::wstring msg(L""); FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS , NULL, err, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT) , (LPWSTR)&lpMsgBuf, 0, NULL); msg = lpMsgBuf; LocalFree(lpMsgBuf); return std::move(msg); } void CDlgManualUSB::append_message(const wchar_t* msg) { std::wstring prev(get_wnd_text(GetDlgItem(IDC_EDIT_STATUS)->m_hWnd)), n(now()); n += L": "; n += msg; n += L"\r\n"; ::SetDlgItemTextW(m_hWnd, IDC_EDIT_STATUS, (prev + n).c_str()); // scroll bottom ... ((CEdit*)GetDlgItem(IDC_EDIT_STATUS))->LineScroll(1); } // CDlgManualUSB 消息处理程序 BOOL CDlgManualUSB::OnInitDialog(void) { CDialogEx::OnInitDialog(); int ind = 0; eps_.SetExtendedStyle(eps_.GetExtendedStyle() | LVS_EX_FULLROWSELECT | LVS_EX_GRIDLINES | LVS_EX_INFOTIP); eps_.InsertColumn(ind++, TEXT("No."), 0, 45); eps_.InsertColumn(ind++, TEXT("Type"), 0, 75); eps_.InsertColumn(ind++, TEXT("Address"), 0, 75); eps_.InsertColumn(ind++, TEXT("Status"), 0, 60); ep_menu_ = LoadMenu(NULL, MAKEINTRESOURCE(IDR_MENU_USB_EP)); SetDlgItemInt(IDC_EDIT_TYPE, 64); SetDlgItemInt(IDC_EDIT_REQ, 100); SetDlgItemInt(IDC_EDIT_IND, 0); SetDlgItemInt(IDC_EDIT_VAL, 18); SetDlgItemInt(IDC_EDIT_LEN, 4); SetDlgItemText(IDC_EDIT_SHORT_NAME, TEXT("\\\\.\\Usbscan2")); return TRUE; } void CDlgManualUSB::OnBnClickedButtonOpen() { // TODO: 在此添加控件通知处理程序代码 wchar_t name[256] = { 0 }; ::GetDlgItemTextW(m_hWnd, IDC_EDIT_SHORT_NAME, name, _countof(name) - 1); if (name[0] == 0) { MessageBox(TEXT("Input Name please.")); GotoDlgCtrl(GetDlgItem(IDC_EDIT_SHORT_NAME)); } close(); main_ = open_usb(name); if (main_ == INVALID_HANDLE_VALUE) { int err = GetLastError(); std::wstring msg(error_message(err)); ::MessageBoxW(m_hWnd, (std::to_wstring(err) + L": " + msg).c_str(), L"Open failed", MB_OK); msg.insert(0, std::wstring(L"Open '") + name + L"' failed - "); append_message(msg.c_str()); } else { GetDlgItem(IDC_EDIT_LONG_NAME)->EnableWindow(FALSE); GetDlgItem(IDC_EDIT_SHORT_NAME)->EnableWindow(FALSE); append_message((std::wstring(L"Open '") + name + L"' success").c_str()); oper_ep_.InsertString(-1, TEXT("Control")); GetDlgItem(IDC_BUTTON_CMD)->EnableWindow(TRUE); } } void CDlgManualUSB::OnBnClickedButtonClose() { // TODO: 在此添加控件通知处理程序代码 close(); GetDlgItem(IDC_EDIT_LONG_NAME)->EnableWindow(); GetDlgItem(IDC_EDIT_SHORT_NAME)->EnableWindow(); append_message((L"Closed '" + get_wnd_text(GetDlgItem(IDC_EDIT_SHORT_NAME)->m_hWnd)).c_str()); } void CDlgManualUSB::OnBnClickedButtonAddEp() { // TODO: 在此添加控件通知处理程序代码 int sn = GetDlgItemInt(IDC_EDIT_EP_SN), addr = GetDlgItemInt(IDC_EDIT_EP_ADDR); TCHAR type[128] = { 0 }, val[128] = { 0 }; types_.GetWindowText(type, _countof(type) - 1); for (int i = 0; i < eps_.GetItemCount(); ++i) { eps_.GetItemText(i, 0, val, _countof(val) - 1); if (_ttoi(val) == sn) { ::MessageBoxW(m_hWnd, (std::wstring(L"An endpoint with sequence ") + std::to_wstring(sn) + L" has already in list!").c_str(), L"Repeat value", MB_OK); return; } } _stprintf_s(val, _countof(val) - 1, TEXT("%d"), sn); sn = eps_.InsertItem(eps_.GetItemCount(), val); eps_.SetItemText(sn, 1, type); _stprintf_s(val, _countof(val) - 1, TEXT("%d"), addr); eps_.SetItemText(sn, 2, val); eps_.SetItemText(sn, 3, TEXT("Closed")); } void CDlgManualUSB::OnBnClickedButtonCmd() { // TODO: 在此添加控件通知处理程序代码 std::wstring ep(get_wnd_text(oper_ep_.m_hWnd)); if (ep == L"Control") { int t = GetDlgItemInt(IDC_EDIT_TYPE), r = GetDlgItemInt(IDC_EDIT_REQ), i = GetDlgItemInt(IDC_EDIT_IND), v = GetDlgItemInt(IDC_EDIT_VAL), l = GetDlgItemInt(IDC_EDIT_LEN), tmp = 0; _IO_BLOCK_EX irp; OVERLAPPED ovl = { 0 }; PUCHAR data = (PUCHAR)&tmp; DWORD io = 0; BOOL ret = FALSE; std::wstring msg(L""); ovl.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); irp.bmRequestType = (t >> 5) & 0x03; irp.bRequest = r; irp.fTransferDirectionIn = t >> 7; irp.pbyData = data; irp.uIndex = i; irp.uLength = l; irp.uOffset = v; ret = DeviceIoControl(main_, IOCTL_SEND_USB_REQUEST, &irp, sizeof(irp), data, l, &io, &ovl); if (ret) { msg = L"success. IO bytes = " + std::to_wstring(io) + L", ovl.Internal = " + std::to_wstring(ovl.Internal) + L", ovl.InternalHigg = " + std::to_wstring(ovl.InternalHigh); } else { if (GetLastError() == ERROR_IO_PENDING) { append_message(L"IO PENDING, wait up to 5 seconds ..."); DWORD wait = WaitForSingleObject(ovl.hEvent, 5000); if (wait == WAIT_OBJECT_0) { msg = L"Waited. IO bytes = " + std::to_wstring(io) + L", ovl.Internal = " + std::to_wstring(ovl.Internal) + L", ovl.InternalHigg = " + std::to_wstring(ovl.InternalHigh); } else { msg = error_message(); msg += L". IO bytes = " + std::to_wstring(io) + L", ovl.Internal = " + std::to_wstring(ovl.Internal) + L", ovl.InternalHigg = " + std::to_wstring(ovl.InternalHigh); } } else { msg = error_message(); msg += L". IO bytes = " + std::to_wstring(io) + L", ovl.Internal = " + std::to_wstring(ovl.Internal) + L", ovl.InternalHigg = " + std::to_wstring(ovl.InternalHigh); } } CloseHandle(ovl.hEvent); append_message((L"Control - " + msg).c_str()); } else { int addr = _wtoi(ep.c_str()); if (endpoints_.count(addr)) { unsigned char buf[256] = { 0 }; OVERLAPPED ovl = { 0 }; DWORD io = 0; BOOL ret = FALSE; std::wstring msg(L""), str(L""); wchar_t hex[8] = { 0 }; ovl.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); if (addr & 0x80) { bool bulk = true; for (int i = 0; i < eps_.GetItemCount(); ++i) { TCHAR tmp[40] = { 0 }; eps_.GetItemText(i, 2, tmp, _countof(tmp) - 1); if (_ttoi(tmp) == addr) { eps_.GetItemText(i, 1, tmp, _countof(tmp) - 1); bulk = _tcscmp(tmp, TEXT("bulk")) == 0; break; } } msg = bulk ? L"BulkRead - " : L"IntRead - "; if(bulk) ret = ReadFile(endpoints_[addr], buf, sizeof(buf), &io, &ovl); else ret = DeviceIoControl(endpoints_[addr], IOCTL_WAIT_ON_DEVICE_EVENT, NULL, 0, buf, sizeof(buf), &io, &ovl); if (ret) { msg += L"success. IO bytes = " + std::to_wstring(io) + L", ovl.Internal = " + std::to_wstring(ovl.Internal) + L", ovl.InternalHigg = " + std::to_wstring(ovl.InternalHigh); for (int i = 0; i < io; ++i) { if ((i % 16) == 0) { msg += L" " + str + L"\r\n\t\t"; str = L""; } else if ((i % 8) == 0) msg += L" "; swprintf_s(hex, _countof(hex) - 1, L"%02X ", buf[i]); if (buf[i] >= 0x20 && buf[i] < 0x80) { hex[0] = buf[i]; hex[1] = 0; str += hex; } else str += L"."; } if (str.length()) msg += L" " + str; } else { if (GetLastError() == ERROR_IO_PENDING) { append_message((msg + L"IO PENDING, wait up to 5 seconds ...").c_str()); DWORD wait = WaitForSingleObject(ovl.hEvent, 5000); if (wait == WAIT_OBJECT_0) { msg += L"Waited. IO bytes = " + std::to_wstring(io) + L", ovl.Internal = " + std::to_wstring(ovl.Internal) + L", ovl.InternalHigg = " + std::to_wstring(ovl.InternalHigh); for (int i = 0; i < io; ++i) { if ((i % 16) == 0) { msg += L" " + str + L"\r\n\t\t"; str = L""; } else if ((i % 8) == 0) msg += L" "; swprintf_s(hex, _countof(hex) - 1, L"%02X ", buf[i]); if (buf[i] >= 0x20 && buf[i] < 0x80) { hex[0] = buf[i]; hex[1] = 0; str += hex; } else str += L"."; } if (str.length()) msg += L" " + str; } else { msg += error_message(); msg += L"\t. IO bytes = " + std::to_wstring(io) + L", ovl.Internal = " + std::to_wstring(ovl.Internal) + L", ovl.InternalHigg = " + std::to_wstring(ovl.InternalHigh); } } else { msg = error_message(); msg += L"\t. IO bytes = " + std::to_wstring(io) + L", ovl.Internal = " + std::to_wstring(ovl.Internal) + L", ovl.InternalHigg = " + std::to_wstring(ovl.InternalHigh); } } } else { } CloseHandle(ovl.hEvent); append_message(msg.c_str()); } else { MessageBox(TEXT("No endpoint found!")); } } } void CDlgManualUSB::OnNMRClickListEp(NMHDR* pNMHDR, LRESULT* pResult) { LPNMITEMACTIVATE pNMItemActivate = reinterpret_cast(pNMHDR); // TODO: 在此添加控件通知处理程序代码 cur_sel_ = pNMItemActivate->iItem; if (cur_sel_ != -1 && main_ != INVALID_HANDLE_VALUE) { TCHAR status[40] = { 0 }; POINT pt = { 0 }; eps_.GetItemText(cur_sel_, 3, status, _countof(status) - 1); EnableMenuItem(GetSubMenu(ep_menu_, 0), ID_USB_OPEN, _tcscmp(status, TEXT("Open")) ? MF_ENABLED : MF_DISABLED); EnableMenuItem(GetSubMenu(ep_menu_, 0), ID_USB_CLOSE, _tcscmp(status, TEXT("Open")) ? MF_DISABLED : MF_ENABLED); GetCursorPos(&pt); TrackPopupMenu(GetSubMenu(ep_menu_, 0), 0, pt.x, pt.y, 0, m_hWnd, NULL); } *pResult = 0; } static DWORD WINAPI twice_read_bulk(LPVOID lp) { DWORD* para = (DWORD*)lp; HANDLE h = (HANDLE)para[0]; DWORD ind = para[1], l = 256; char *buf = new char[l]; OVERLAPPED ovl = { 0 }; BOOL ret = FALSE; DWORD r = 0; std::string msg(""); delete[] para; memset(buf, 0, l); ovl.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); ret = ReadFile(h, buf, l, &r, &ovl); if (!ret) { if (GetLastError() == ERROR_IO_PENDING) { if (ind == 0) ind = 500; else ind = INFINITE; if (WaitForSingleObject(ovl.hEvent, ind) == WAIT_TIMEOUT) //if(!GetOverlappedResult(h, &ovl, &r, TRUE)) { sprintf_s(buf, l - 1, "Wait failed: ovl.Internal = %x, ovl.InternalHigh = %x, ovl.Offset = %x, ovl.OffsetHigh = %x, error = %d" , ovl.Internal, ovl.InternalHigh, ovl.Offset, ovl.OffsetHigh, GetLastError()); } GetOverlappedResult(h, &ovl, &r, FALSE); } else { sprintf_s(buf, l - 1, "Read failed: ovl.Internal = %x, ovl.InternalHigh = %x, ovl.Offset = %x, ovl.OffsetHigh = %x, error = %d" , ovl.Internal, ovl.InternalHigh, ovl.Offset, ovl.OffsetHigh, GetLastError()); } } CloseHandle(ovl.hEvent); if (ind != INFINITE) { char addr[40] = { 0 }; // 除非调用IO操作的线程退出,否则异步IO优先按照队列满足最前面的任务,即使你退出IO函数。调用下面这句可撤销本次操作 ^_^ CancelIoEx(h, &ovl); sprintf_s(addr, _countof(addr) - 1, "0x%x: ", buf); delete[] buf; msg = addr; buf = NULL; Sleep(5000); } msg += "Read " + std::to_string(r) + " byte(s): "; if (buf) { msg += buf; delete[] buf; } MessageBoxA(NULL, msg.c_str(), ("Thread " + std::to_string(GetCurrentThreadId())).c_str(), MB_OK); if (!buf) Sleep(1000 * 60); return 0; } void CDlgManualUSB::OnUsbOpen() { // TODO: 在此添加命令处理程序代码 wchar_t root[128] = { 0 }; TCHAR val[40] = { 0 }; std::wstring name(L""); ::GetDlgItemTextW(m_hWnd, IDC_EDIT_SHORT_NAME, root, _countof(root) - 1); name = root; name += L"\\"; eps_.GetItemText(cur_sel_, 0, val, _countof(val) - 1); swprintf_s(root, _countof(root) - 1, L"%d", _ttoi(val)); name += root; // open HANDLE h = open_usb(name.c_str()); if (h == INVALID_HANDLE_VALUE) append_message((L"Open '" + name + L"' failed with error " + error_message()).c_str()); else { eps_.SetItemText(cur_sel_, 3, TEXT("Open")); eps_.GetItemText(cur_sel_, 2, val, _countof(val) - 1); endpoints_[_ttoi(val)] = h; oper_ep_.InsertString(-1, val); append_message((L"Open '" + name + L"' success").c_str()); eps_.GetItemText(cur_sel_, 1, val, _countof(val) - 1); //if (_tcscmp(val, TEXT("bulk")) == 0) //{ // for (int i = 0; i < 2; ++i) // { // DWORD id = 0, * param = new DWORD[2]; // HANDLE ht = NULL; // // param[0] = (DWORD)h; // param[1] = i; // ht = CreateThread(NULL, 0, twice_read_bulk, param, 0, &id); // CloseHandle(ht); // append_message((L"Thread " + std::to_wstring(id) + L" started ...").c_str()); // Sleep(1000); // } //} } } void CDlgManualUSB::OnUsbClose() { // TODO: 在此添加命令处理程序代码 TCHAR val[128] = { 0 }; eps_.GetItemText(cur_sel_, 2, val, _countof(val) - 1); if (endpoints_.count(_ttoi(val))) { CloseHandle(endpoints_[_ttoi(val)]); endpoints_.erase(_ttoi(val)); eps_.SetItemText(cur_sel_, 3, TEXT("Closed")); } } void CDlgManualUSB::OnUsbDelete() { // TODO: 在此添加命令处理程序代码 eps_.DeleteItem(cur_sel_); cur_sel_ = -1; } void CDlgManualUSB::OnBnClickedButtonClear() { // TODO: 在此添加控件通知处理程序代码 ::SetDlgItemTextW(m_hWnd, IDC_EDIT_STATUS, L""); }