doc_and_tools/tools/apps/hgjson/DlgManualUSB.cpp

567 lines
15 KiB
C++
Raw Normal View History

// 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"");
}