doc_and_tools/tools/apps/hgjson/DlgManualUSB.cpp

567 lines
15 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// CDlgManualUSB.cpp: 实现文件
//
#include "stdafx.h"
#include "hgjson.h"
#include "DlgManualUSB.h"
#include "afxdialogex.h"
#include "resource.h"
#include <winioctl.h>
#include <usbscan.h>
// 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<LPNMITEMACTIVATE>(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"");
}