首先对串口操作做了一些封装:
助手类声明如下
CSerialPort.h
#pragma once
#include <string>
#include <windows.h>
#include <tchar.h>
#ifdef _UNICODE
using _tstring = std::wstring;
#else
using _tstring = std::string;
#endif
class CSerialPort
{
public:
CSerialPort();
CSerialPort(const CSerialPort& r) = delete;
~CSerialPort();
// 打开串口
bool Open(
int nComm, //串口号
DWORD dwBaudRate = CBR_115200, //波特率
BYTE bByteSize = 8, //数据位
BYTE bParity = NOPARITY, //校验位
BYTE bStopBits = ONESTOPBIT //停止位
);
// 打开串口
bool Open(
const _tstring& strName = _T("COM1"), //串口名
DWORD dwBaudRate = CBR_115200, //波特率
BYTE bByteSize = 8, //数据位
BYTE bParity = NOPARITY, //校验位
BYTE bStopBits = ONESTOPBIT //停止位
);
// 检测是否已经打开
bool IsOpen() const;
// 设置状态配置
bool SetState(
DWORD dwBaudRate = CBR_115200, //波特率
BYTE bByteSize = 8, //数据位
BYTE bParity = NOPARITY, //校验位
BYTE bStopBits = ONESTOPBIT //停止位
);
// 设置状态配置
bool SetState(const LPDCB lpDcb);
// 设置缓冲区大小
bool SetupComm(
DWORD dwInQueue = 14, // 输入缓冲区 1 - 14
DWORD dwOutQueue = 16 // 输出缓冲区 1 - 16
);
// 设置超时配置
bool SetTimeOut(
DWORD ReadInterval = 50, // 读间隔超时
DWORD ReadTotalMultiplier = 5, // 读时间系数
DWORD ReadTotalConstant = 1000, // 读时间常量
DWORD WriteTotalMultiplier = 10, // 写时间系数
DWORD WriteTotalConstant = 200 // 写时间常量
);
// 设置超时配置
bool SetTimeOut(const LPCOMMTIMEOUTS lpTimeOuts);
// 清空缓冲区
bool Purge(
DWORD dwFlags = PURGE_TXCLEAR | PURGE_RXCLEAR
);
// 清除错误
bool ClearError();
// 关闭串口
void Close();
// 发送数据
bool Write(
LPCVOID lpData,
DWORD cbSize,
LPDWORD lpBytesWritten = nullptr,
DWORD nTimeOut = 1000
);
// 接收数据
bool Read(
LPVOID lpData,
DWORD cbSize,
LPDWORD lpBytesRead = nullptr,
DWORD nTimeOut = 3000
);
private:
// 打开串口
bool OpenComm(int nComm);
// 打开串口
bool OpenComm(const _tstring& strName);
// 等待重叠操作完成
bool WaitForOverlapped(
HANDLE hFile,
LPOVERLAPPED lpOv,
LPDWORD lpBytesTransferred,
DWORD nTimeOut
);
private:
HANDLE m_hComm; // 串口句柄
HANDLE m_hReadEvent; // 重叠读事件句柄
HANDLE m_hWriteEvent; // 重叠写事件句柄
bool m_bExit; // 退出标记
};
串口操作具体实现部分如下, 其中读写采用异步方式, 方便退出, 避免读写时卡住
CSerialPort.cpp
#include "CSerialPort.h"
#include <strsafe.h>
CSerialPort::CSerialPort()
:
m_hComm(INVALID_HANDLE_VALUE),
m_hReadEvent(nullptr),
m_hWriteEvent(nullptr),
m_bExit(false)
{
}
CSerialPort::~CSerialPort()
{
Close();
}
// 打开串口
bool CSerialPort::Open(
int nComm,
DWORD dwBaudRate/* = CBR_115200*/,
BYTE bByteSize/* = 8*/,
BYTE bParity/* = NOPARITY*/,
BYTE bStopBits/* = ONESTOPBIT*/
)
{
if (!OpenComm(nComm))
{
return false;
}
if (!SetState(dwBaudRate, bByteSize, bParity, bStopBits))
{
this->Close();
return false;
}
m_bExit = false;
return true;
}
// 打开串口
bool CSerialPort::Open(
const _tstring& strName/* = _T("COM1")*/, //串口名
DWORD dwBaudRate/* = CBR_115200*/,
BYTE bByteSize/* = 8*/,
BYTE bParity/* = NOPARITY*/,
BYTE bStopBits/* = ONESTOPBIT*/
)
{
if (!OpenComm(strName))
{
return false;
}
if (!SetState(dwBaudRate, bByteSize, bParity, bStopBits))
{
this->Close();
return false;
}
m_bExit = false;
return true;
}
bool CSerialPort::IsOpen() const
{
return INVALID_HANDLE_VALUE != m_hComm;
}
bool CSerialPort::SetState(
DWORD dwBaudRate/* = CBR_115200*/,
BYTE bByteSize/* = 8*/,
BYTE bParity/* = NOPARITY*/,
BYTE bStopBits/* = ONESTOPBIT*/
)
{
if (INVALID_HANDLE_VALUE == m_hComm)
{
return false;
}
DCB dcb = { 0 };
dcb.DCBlength = sizeof(DCB);
if (!::GetCommState(m_hComm, &dcb))
{
return false;
}
dcb.DCBlength = sizeof(DCB);
dcb.BaudRate = dwBaudRate;
dcb.ByteSize = bByteSize;
dcb.Parity = bParity;
dcb.StopBits = bStopBits;
return ::SetCommState(m_hComm, &dcb);
}
bool CSerialPort::SetState(const LPDCB lpDcb)
{
if (nullptr == lpDcb)
{
return false;
}
return ::SetCommState(m_hComm, lpDcb);
}
// 设置缓冲区大小
bool CSerialPort::SetupComm(
DWORD dwInQueue/* = 14*/,
DWORD dwOutQueue/* = 16*/
)
{
if (INVALID_HANDLE_VALUE == m_hComm)
{
return false;
}
return ::SetupComm(m_hComm, dwInQueue, dwOutQueue);
}
bool CSerialPort::SetTimeOut(
DWORD ReadInterval/* = 50*/,
DWORD ReadTotalMultiplier/* = 50*/,
DWORD ReadTotalConstant/* = 100*/,
DWORD WriteTotalMultiplier/* = 50*/,
DWORD WriteTotalConstant/* = 200*/
)
{
if (INVALID_HANDLE_VALUE == m_hComm)
{
return false;
}
COMMTIMEOUTS comTimeOuts = { 0 };
if (!::GetCommTimeouts(m_hComm, &comTimeOuts))
{
return false;
}
comTimeOuts.ReadIntervalTimeout = ReadInterval;
comTimeOuts.ReadTotalTimeoutMultiplier = ReadTotalMultiplier;
comTimeOuts.ReadTotalTimeoutConstant = ReadTotalConstant;
comTimeOuts.WriteTotalTimeoutMultiplier = WriteTotalMultiplier;
comTimeOuts.WriteTotalTimeoutConstant = WriteTotalConstant;
return ::SetCommTimeouts(m_hComm, &comTimeOuts);
}
bool CSerialPort::SetTimeOut(const LPCOMMTIMEOUTS lpTimeOuts)
{
if (nullptr == lpTimeOuts)
{
return false;
}
return ::SetCommTimeouts(m_hComm, lpTimeOuts);
}
bool CSerialPort::Purge(
DWORD dwFlags/* = PURGE_TXCLEAR | PURGE_RXCLEAR*/
)
{
if (INVALID_HANDLE_VALUE == m_hComm)
{
return false;
}
return ::PurgeComm(m_hComm, dwFlags);
}
bool CSerialPort::ClearError()
{
if (INVALID_HANDLE_VALUE == m_hComm)
{
return false;
}
DWORD dwError = 0;
COMSTAT comStat = { 0 };
return ::ClearCommError(m_hComm, &dwError, &comStat);
}
void CSerialPort::Close()
{
m_bExit = true;
if (nullptr != m_hReadEvent)
{
::SetEvent(m_hReadEvent);
::CloseHandle(m_hReadEvent);
m_hReadEvent = nullptr;
}
if (nullptr != m_hWriteEvent)
{
::SetEvent(m_hWriteEvent);
::CloseHandle(m_hWriteEvent);
m_hWriteEvent = nullptr;
}
if (INVALID_HANDLE_VALUE != m_hComm)
{
::CancelIoEx(m_hComm, nullptr);
::CloseHandle(m_hComm);
m_hComm = INVALID_HANDLE_VALUE;
}
}
bool CSerialPort::OpenComm(int nComm)
{
TCHAR szBuf[MAX_PATH];
(void)::StringCchPrintf(szBuf, _countof(szBuf), _T(R"(\\.\COM%d)"), nComm);
// 关闭前一个已打开的串口
this->Close();
m_hComm = ::CreateFile(
szBuf,
GENERIC_READ | GENERIC_WRITE, //读写串口
0, //独占打开
nullptr,
OPEN_EXISTING, //必须存在
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, //重叠操作
nullptr
);
if (INVALID_HANDLE_VALUE == m_hComm)
{
return false;
}
m_hReadEvent = CreateEvent(nullptr, false, false, nullptr);
if (nullptr == m_hReadEvent)
{
this->Close();
return false;
}
m_hWriteEvent = CreateEvent(nullptr, false, false, nullptr);
if (nullptr == m_hWriteEvent)
{
this->Close();
return false;
}
return true;
}
bool CSerialPort::OpenComm(const _tstring& strName)
{
TCHAR szBuf[MAX_PATH];
(void)::StringCchPrintf(szBuf, _countof(szBuf), _T(R"(\\.\%s)"), strName.c_str());
// 关闭前一个已打开的串口
this->Close();
m_hComm = ::CreateFile(
szBuf,
GENERIC_READ | GENERIC_WRITE, //读写串口
0, //独占打开
nullptr,
OPEN_EXISTING, //必须存在
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, //重叠操作
nullptr
);
if (INVALID_HANDLE_VALUE == m_hComm)
{
return false;
}
m_hReadEvent = CreateEvent(nullptr, false, false, nullptr);
if (nullptr == m_hReadEvent)
{
this->Close();
return false;
}
m_hWriteEvent = CreateEvent(nullptr, false, false, nullptr);
if (nullptr == m_hWriteEvent)
{
this->Close();
return false;
}
return true;
}
bool CSerialPort::WaitForOverlapped(
HANDLE hFile,
LPOVERLAPPED lpOv,
LPDWORD lpBytesTransferred,
DWORD nTimeOut
)
{
bool bResult = false;
DWORD dwBytesTransferred = 0;
DWORD dwWait = ::WaitForSingleObject(lpOv->hEvent, nTimeOut);
switch (dwWait)
{
case WAIT_OBJECT_0:
{
if (::GetOverlappedResult(hFile,
lpOv,
&dwBytesTransferred,
true
))
{
bResult = true;
}
else
{
bResult = false;
}
if (lpBytesTransferred)
{
*lpBytesTransferred = dwBytesTransferred;
}
}
break;
case WAIT_TIMEOUT:
break;
default:
break;
}
if (!bResult && !m_bExit)
{
::CancelIoEx(hFile, lpOv);
}
return bResult;
}
bool CSerialPort::Write(
LPCVOID lpData,
DWORD cbSize,
LPDWORD lpBytesWritten,
DWORD nTimeOut/* = 1000*/
)
{
if (INVALID_HANDLE_VALUE == m_hComm ||
nullptr == lpData ||
0 == cbSize ||
m_bExit)
{
return false;
}
OVERLAPPED ov = { 0 };
BOOL bResult = FALSE;
ov.hEvent = m_hWriteEvent;
bResult = ::WriteFile(
m_hComm,
lpData,
cbSize,
nullptr,
&ov
);
if (bResult)
{
goto L_Cleanup;
}
if (ERROR_IO_PENDING != ::GetLastError())
{
goto L_Cleanup;
}
bResult = WaitForOverlapped(m_hComm, &ov, lpBytesWritten, nTimeOut);
L_Cleanup:
return bResult;
}
bool CSerialPort::Read(
LPVOID lpData,
DWORD cbSize,
LPDWORD lpBytesRead/* = nullptr*/,
DWORD nTimeOut/* = 3000*/
)
{
if (INVALID_HANDLE_VALUE == m_hComm ||
nullptr == lpData ||
0 == cbSize ||
m_bExit)
{
return false;
}
OVERLAPPED ov = { 0 };
BOOL bResult = FALSE;
ov.hEvent = m_hReadEvent;
bResult = ::ReadFile(
m_hComm,
lpData,
cbSize,
nullptr,
&ov
);
if (bResult)
{
goto L_Cleanup;
}
if (ERROR_IO_PENDING != ::GetLastError())
{
goto L_Cleanup;
}
bResult = WaitForOverlapped(m_hComm, &ov, lpBytesRead, nTimeOut);
if (bResult)
{
return true;
}
L_Cleanup:
return bResult;
}
接着就是编写Win32 窗口界面, 这里我使用的时对话框, 下面对对话框进行了一些封装, 采取MFC的消息映射方式封装, 方便后期消息映射成员函数, 极大简化编码工作量.
对话框基类声明如下:
CDialogBase.h
#pragma once
#include <Windows.h>
#include <tchar.h>
#include <string>
#ifdef UNICODE
using _tstring = std::wstring;
#else
using _tstring = std::string;
#endif
class CDialogBase;
typedef LRESULT(CDialogBase::* pMapFn)(WPARAM wParam, LPARAM lParam);
struct WND_DLG_MSGMAP_ENTRY
{
pMapFn m_pfn;
UINT m_nMessage;
UINT m_nID;
WND_DLG_MSGMAP_ENTRY(UINT uMsg, pMapFn pfn) : m_nMessage(uMsg), m_pfn(pfn), m_nID(0) {}
WND_DLG_MSGMAP_ENTRY(UINT uMsg, UINT nID, pMapFn pfn) : m_nMessage(uMsg), m_nID(nID), m_pfn(pfn) {}
};
struct WND_DLG_MSGMAP
{
const WND_DLG_MSGMAP* (*pfnGetBaseMap)();
const WND_DLG_MSGMAP_ENTRY* lpEntries;
};
#ifndef dlg_msg
#define dlg_msg
#endif
#define DECLARE_DLG_MESSAGE_MAP() \
protected: \
static const WND_DLG_MSGMAP* GetThisMessageMap(); \
virtual const WND_DLG_MSGMAP* GetMessageMap() const; \
#define BEGIN_DLG_MESSAGE_MAP(theClass, baseClass) \
const WND_DLG_MSGMAP* theClass::GetMessageMap() const \
{ \
return GetThisMessageMap(); \
} \
const WND_DLG_MSGMAP* theClass::GetThisMessageMap() \
{ \
typedef baseClass TheBaseClass; \
static const WND_DLG_MSGMAP_ENTRY _messageEntries[] = \
{ \
#define ON_DLG_MESSAGE(message, memberFxn) \
WND_DLG_MSGMAP_ENTRY(message, static_cast< LRESULT (CDialogBase::*)(WPARAM, LPARAM) >(memberFxn)),
#define ON_DLG_COMMAND(_id, memberFxn) \
WND_DLG_MSGMAP_ENTRY(WM_COMMAND, _id, static_cast< LRESULT (CDialogBase::*)(WPARAM, LPARAM) >(memberFxn)),
#define END_DLG_MESSAGE_MAP() WND_DLG_MSGMAP_ENTRY(0, NULL) }; \
static const WND_DLG_MSGMAP messageMap = \
{&TheBaseClass::GetThisMessageMap , &_messageEntries[0] }; \
return &messageMap; \
} \
#define DECLARE_DLG_BASE_MESSAGE_MAP() \
protected: \
static const WND_DLG_MSGMAP* GetThisMessageMap(); \
virtual const WND_DLG_MSGMAP* GetMessageMap() const; \
static const WND_DLG_MSGMAP* GetBaseMessageMap(); \
#define BEGIN_DLG_BASE_MESSAGE_MAP(theClass) \
typedef theClass TheThisClass; \
const WND_DLG_MSGMAP* TheThisClass::GetMessageMap() const \
{ \
return GetThisMessageMap(); \
} \
const WND_DLG_MSGMAP* TheThisClass::GetBaseMessageMap() \
{ \
return NULL; \
} \
const WND_DLG_MSGMAP* TheThisClass::GetThisMessageMap() \
{ \
static const WND_DLG_MSGMAP_ENTRY _messageEntries[] = \
{ \
#define END_DLG_BASE_MESSAGE_MAP() WND_DLG_MSGMAP_ENTRY(0, NULL) }; \
static const WND_DLG_MSGMAP messageMap = \
{&TheThisClass::GetBaseMessageMap, &_messageEntries[0] }; \
return &messageMap; \
} \
class CDialogBase
{
public:
CDialogBase();
CDialogBase(const CDialogBase& r) = delete;
~CDialogBase();
dlg_msg INT_PTR DoModal(HWND hWndParent, bool bCenter = true);
dlg_msg INT_PTR DoModal(UINT resourceID, HWND hWndParent, bool bCenter = true);
dlg_msg INT_PTR DoModalEx(UINT resourceID, HWND hWndParent, BOOL isShow = TRUE, bool bCenter = true);
dlg_msg HWND DoDialog(UINT resourceID, HWND hWndParent, BOOL isShow = TRUE, bool bCenter = true);
dlg_msg LRESULT OnClose(WPARAM wParam, LPARAM lParam);
dlg_msg LRESULT OnLanguageChange(WPARAM wParam, LPARAM lParam);
VOID SetResourceID(UINT resourceID);
VOID ShowWindow(int cmdShow = SW_SHOW);
BOOL IsVisiable() const;
VOID MoveToCenter(HWND hParent);
_tstring LoadString(UINT resourceID);
VOID ModifyMenuText(HMENU hMnu, UINT uPosition, LPCTSTR lpNewItem, BOOL fByPos = TRUE);
VOID ModifyMenuText(HMENU hMnu, UINT uPosition, UINT resourceID, BOOL fByPos = TRUE);
HWND GetWndHandle() const;
bool EndDialog(INT_PTR nResult);
operator HWND() const
{
return m_hWnd;
}
private:
//假模态对话框
dlg_msg LRESULT DoFakeModal(UINT resourceID, HWND hWndParent, BOOL isShow = TRUE);
static INT_PTR WINAPI DialogProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
INT_PTR ThisDialogProc(UINT uMsg, WPARAM wParam, LPARAM lParam);
protected:
virtual BOOL PreTranslateMessage(LPMSG pMsg);
protected:
HWND m_hWnd;
UINT m_uResID;
BOOL m_bModel;
BOOL m_bFakeModel;
BOOL m_bCenter;
DECLARE_DLG_BASE_MESSAGE_MAP()
};
具体实现部分如下:
CDialogBase.cpp
#include "CDialogBase.h"
#include <Windows.h>
#include <strsafe.h>
#pragma comment(linker,"\"/manifestdependency:type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"")
BEGIN_DLG_BASE_MESSAGE_MAP(CDialogBase)
ON_DLG_MESSAGE(WM_CLOSE, &CDialogBase::OnClose)
END_DLG_BASE_MESSAGE_MAP()
CDialogBase::CDialogBase()
:
m_hWnd(NULL),
m_uResID(FALSE),
m_bModel(FALSE),
m_bFakeModel(FALSE),
m_bCenter(FALSE)
{
}
CDialogBase::~CDialogBase()
{
if (NULL != m_hWnd)
{
::DestroyWindow(m_hWnd);
}
}
HWND CDialogBase::DoDialog(UINT resourceID, HWND hWndParent, BOOL isShow, bool bCenter/* = true*/)
{
m_bCenter = bCenter;
m_bModel = FALSE;
m_uResID = resourceID;
HWND hWnd = ::CreateDialogParam(GetModuleHandle(NULL), MAKEINTRESOURCE(resourceID), hWndParent, DialogProc, (LPARAM)this);
m_hWnd = hWnd;
if (isShow)
{
::ShowWindow(m_hWnd, SW_SHOW);
}
return m_hWnd;
}
INT_PTR CDialogBase::DoModalEx(UINT resourceID, HWND hWndParent, BOOL isShow, bool bCenter/* = true*/)
{
m_bCenter = bCenter;
m_bModel = FALSE;
return DoFakeModal(resourceID, hWndParent, isShow);
}
INT_PTR CDialogBase::DoModal(HWND hWndParent, bool bCenter/* = true*/)
{
m_bCenter = bCenter;
m_bModel = TRUE;
return ::DialogBoxParam(GetModuleHandle(NULL), MAKEINTRESOURCE(m_uResID), hWndParent, DialogProc, (LPARAM)this);
}
INT_PTR CDialogBase::DoModal(UINT resourceID, HWND hWndParent, bool bCenter/* = true*/)
{
m_bCenter = bCenter;
m_uResID = resourceID;
m_bModel = TRUE;
return ::DialogBoxParam(GetModuleHandle(NULL), MAKEINTRESOURCE(m_uResID), hWndParent, DialogProc, (LPARAM)this);
}
BOOL CDialogBase::PreTranslateMessage(LPMSG pMsg)
{
return FALSE;
}
bool CDialogBase::EndDialog(INT_PTR nResult)
{
if (NULL == m_hWnd)
{
return false;
}
if (m_bFakeModel)
{
//启用父窗口
HWND hParent = ::GetParent(m_hWnd);
if (hParent)
{
::EnableWindow(hParent, TRUE);
}
// 投递 WM_QUIT 消息退出消息环 (窗口句柄指定为NULL时,
// 该函数的行为类似于对 PostThreadMessage 的调用,
// 其中 dwThreadId 参数设置为当前线程的标识符。)
::PostMessage(NULL, WM_QUIT, nResult, 0);
}
if (m_bModel)
{
::EndDialog(m_hWnd, nResult);
m_hWnd = NULL;
}
else
{
::DestroyWindow(m_hWnd);
m_hWnd = NULL;
}
return TRUE;
}
LRESULT CDialogBase::OnClose(WPARAM wParam, LPARAM lParam)
{
return EndDialog(wParam);
}
LRESULT CDialogBase::DoFakeModal(UINT resourceID, HWND hWndParent, BOOL isShow)
{
m_bModel = FALSE;
m_uResID = resourceID;
m_bFakeModel = TRUE;
m_hWnd = ::CreateDialogParam(GetModuleHandle(NULL), MAKEINTRESOURCE(resourceID), hWndParent, DialogProc, (LPARAM)this);
if (NULL == m_hWnd)
{
return -1;
}
if (isShow)
{
::ShowWindow(m_hWnd, SW_SHOW);
}
//禁用父窗口
HWND hParent = GetParent(m_hWnd);
if (hParent)
{
::EnableWindow(hParent, FALSE);
::SetForegroundWindow(hParent);
}
MSG msg = { 0 };
BOOL bRet = FALSE;
//如果 hWnd 为 NULL, 则 GetMessage 将检索属于当前线程的任何窗口的消息,以及当前线程的消息队列上 hwnd 值为 NULL 的任何消息,
//因此,如果 hWnd 为 NULL,则同时处理窗口消息和线程消息。
//如果 hWnd 为 - 1,则 GetMessage 仅检索当前线程的消息队列中 hwnd 值为 NULL 的消息,
//即当 hWnd 参数为 NULL 或 PostThreadMessage 时,PostMessage 发布的线程消息。
while (0 != (bRet = GetMessage(&msg, NULL, 0, 0)))
{
if (-1 == bRet)
{
break;
}
//类捕获消息处理与对话框 TAB 按键处理
if (PreTranslateMessage(&msg) || ::IsDialogMessage(m_hWnd, &msg))
{
continue;
}
::TranslateMessage(&msg);
::DispatchMessage(&msg);
}
return msg.wParam;
}
INT_PTR WINAPI CDialogBase::DialogProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
CDialogBase* pThis = (CDialogBase*)GetProp(hWnd, _T("this"));
//CDialogBase* pThis = (CDialogBase*)::GetWindowLongPtr(hWnd, GWLP_USERDATA);
if (pThis)
{
return pThis->ThisDialogProc(uMsg, wParam, lParam);
}
if (WM_INITDIALOG == uMsg)
{
pThis = (CDialogBase*)lParam;
if (pThis)
{
pThis->m_hWnd = hWnd;
::SetProp(hWnd, _T("this"), pThis);
//::SetWindowLongPtr(hWnd, GWLP_USERDATA, (LONG_PTR)pThis);
pThis->ThisDialogProc(uMsg, wParam, lParam);
if (pThis->m_bCenter)
{
pThis->MoveToCenter(::GetParent(hWnd));
}
}
return (INT_PTR)TRUE;
}
return (INT_PTR)FALSE;
}
INT_PTR CDialogBase::ThisDialogProc(UINT uMsg, WPARAM wParam, LPARAM lParam)
{
const WND_DLG_MSGMAP* pEntry = GetMessageMap();
LRESULT lResult = 0;
while (pEntry)
{
const WND_DLG_MSGMAP_ENTRY* lpEntries = pEntry->lpEntries;
while (lpEntries->m_pfn)
{
if (uMsg == lpEntries->m_nMessage)
{
//处理 WM_COMMAND 消息
if (WM_COMMAND == uMsg)
{
WORD wID = LOWORD(wParam);
WORD wNotify = HIWORD(wParam);
if (wID == lpEntries->m_nID)
{
lResult = (this->*lpEntries->m_pfn)(wParam, lParam);
break;
}
}
else
{
lResult = (this->*lpEntries->m_pfn)(wParam, lParam);
break;
}
}
lpEntries++;
}
//消息已经处理
if (lResult)
{
::SetWindowLongPtr(m_hWnd, DWLP_MSGRESULT, lResult);
return lResult;
}
//获取基类的消息映射
pEntry = pEntry->pfnGetBaseMap();
}
return FALSE;
}
VOID CDialogBase::SetResourceID(UINT resourceID)
{
m_uResID = resourceID;
}
VOID CDialogBase::ShowWindow(int cmdShow)
{
::ShowWindow(m_hWnd, cmdShow);
}
BOOL CDialogBase::IsVisiable() const
{
return ::IsWindowVisible(m_hWnd);
}
void CDialogBase::MoveToCenter(HWND hParent)
{
RECT rectParent = { 0 };
RECT rectChild = { 0 };
LONG dwParentW = 0;
LONG dwParentH = 0;
LONG dwChildW = 0;
LONG dwChildH = 0;
if (NULL == hParent)
{
hParent = ::GetDesktopWindow();
}
::GetWindowRect(m_hWnd, &rectChild);
::GetWindowRect(hParent, &rectParent);
dwParentW = rectParent.right - rectParent.left;
dwParentH = rectParent.bottom - rectParent.top;
dwChildW = rectChild.right - rectChild.left;
dwChildH = rectChild.bottom - rectChild.top;
::MoveWindow(
m_hWnd,
rectParent.left + (dwParentW - dwChildW) / 2,
rectParent.top + (dwParentH - dwChildH) / 2,
dwChildW,
dwChildH,
TRUE
);
}
_tstring CDialogBase::LoadString(UINT uID)
{
static TCHAR szBuf[1024] = { 0 };
::LoadString(GetModuleHandle(NULL), uID, szBuf, _countof(szBuf));
return szBuf;
}
LRESULT CDialogBase::OnLanguageChange(WPARAM wParam, LPARAM lParam)
{
return TRUE;
}
VOID CDialogBase::ModifyMenuText(HMENU hMnu, UINT uPosition, LPCTSTR lpNewItem, BOOL fByPos)
{
MENUITEMINFO mii = { 0 };
TCHAR szBuf[MAX_PATH] = { 0 };
mii.cbSize = sizeof(mii);
mii.fMask = MIIM_TYPE | MIIM_STATE | MIIM_DATA;
mii.fType = MFT_STRING;
mii.dwTypeData = szBuf;
mii.cch = _countof(szBuf);
GetMenuItemInfo(hMnu, uPosition, fByPos, &mii);
StringCchCopy(szBuf, _countof(szBuf), lpNewItem);
SetMenuItemInfo(hMnu, uPosition, fByPos, &mii);
}
VOID CDialogBase::ModifyMenuText(HMENU hMnu, UINT uPosition, UINT resourceID, BOOL fByPos)
{
ModifyMenuText(hMnu, uPosition, LoadString(resourceID).c_str(), fByPos);
}
HWND CDialogBase::GetWndHandle() const
{
if (::IsWindow(m_hWnd))
{
return m_hWnd;
}
return NULL;
}
最基础的部分就这两部分, 接下来编写UI界面:
对话框设计如下, 功能简洁, 初期就先这样吧.
资源对应的声明如下:
resource.h
//{{NO_DEPENDENCIES}}
// Microsoft Visual C++ 生成的包含文件。
// 供 CDialogSerialPort.rc 使用
//
#define IDI_ICON 101
#define IDR_MENU 102
#define IDS_FILE_EXIT 103
#define IDS_SETTINGS_SHOW 104
#define IDS_SETTINGS_HIDE 105
#define IDD_DIALOG_SERIAL_PORT 108
#define IDD_DIALOG_ABOUT 110
#define IDC_BUTTON_SEND 1001
#define IDC_EDIT_READ 1002
#define IDC_EDIT_WRITE 1003
#define IDC_COMBO_PORT 1004
#define IDC_COMBO_SPEED 1005
#define IDC_COMBO_DATA 1006
#define IDC_COMBO_PARITY 1007
#define IDC_COMBO_STOP 1008
#define IDC_BUTTON_OPEN 1009
#define IDC_CHECK_READ_HEX 1010
#define IDC_BUTTON_CLEAR 1011
#define IDC_CHECK_READ_HEX2 1012
#define IDC_CHECK_WRITE_HEX 1012
#define IDC_EDIT_READ_INTERVAL 1016
#define IDC_EDIT_READ_TOTAL_MULTIPLIER 1017
#define IDC_EDIT_READ_TOTAL_CONSTANT 1018
#define IDC_EDIT_WRITE_TOTAL_MULTIPLIER 1019
#define IDC_EDIT_WRITE_TOTAL_CONSTANT 1020
#define IDC_BUTTON_TIMEOUT 1021
#define IDC_STATIC_TEXT 1022
#define IDC_SYSLINK_ADDR 1023
#define IDC_EDIT_AUTO_TIME 1024
#define IDC_CHECK_AUTO_SEND 1025
#define ID_FILE_EXIT 40001
#define ID_SETTINGS_SHOW 40002
#define ID_SETTINGS_HIDE 40003
#define ID_STR_CODE_UNICODE 40008
#define ID_SETTINGS_CODE_UNICODE 40009
#define ID_SETTINGS_CODE_ANSI 40010
#define ID_SETTINGS_CODE_UTF_8 40011
#define ID_HELP_ABOUT 40013
#define ID_SETTINGS_TOPMOST 40015
// Next default values for new objects
//
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NEXT_RESOURCE_VALUE 112
#define _APS_NEXT_COMMAND_VALUE 40016
#define _APS_NEXT_CONTROL_VALUE 1026
#define _APS_NEXT_SYMED_VALUE 101
#endif
#endif
CDialogSerialPort.rc
// Microsoft Visual C++ generated resource script.
//
#include "resource.h"
#define APSTUDIO_READONLY_SYMBOLS
/
//
// Generated from the TEXTINCLUDE 2 resource.
//
#include "winres.h"
/
#undef APSTUDIO_READONLY_SYMBOLS
/
// 中文(简体,中国) resources
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_CHS)
LANGUAGE LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED
#pragma code_page(936)
#ifdef APSTUDIO_INVOKED
/
//
// TEXTINCLUDE
//
1 TEXTINCLUDE
BEGIN
"resource.h\0"
END
2 TEXTINCLUDE
BEGIN
"#include ""winres.h""\r\n"
"\0"
END
3 TEXTINCLUDE
BEGIN
"\r\n"
"\0"
END
#endif // APSTUDIO_INVOKED
/
//
// Icon
//
// Icon with lowest ID value placed first to ensure application icon
// remains consistent on all systems.
IDI_ICON ICON "icon.ico"
/
//
// Version
//
VS_VERSION_INFO VERSIONINFO
FILEVERSION 1,0,0,1
PRODUCTVERSION 1,0,0,1
FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
FILEFLAGS 0x1L
#else
FILEFLAGS 0x0L
#endif
FILEOS 0x40004L
FILETYPE 0x1L
FILESUBTYPE 0x0L
BEGIN
BLOCK "StringFileInfo"
BEGIN
BLOCK "080404b0"
BEGIN
VALUE "CompanyName", "TODO: <公司名>"
VALUE "FileDescription", "TODO: <文件说明>"
VALUE "FileVersion", "1.0.0.1"
VALUE "InternalName", "CWindow.exe"
VALUE "LegalCopyright", "Copyright (C) 2023"
VALUE "OriginalFilename", "CWindow.exe"
VALUE "ProductName", "TODO: <产品名>"
VALUE "ProductVersion", "1.0.0.1"
END
END
BLOCK "VarFileInfo"
BEGIN
VALUE "Translation", 0x804, 1200
END
END
/
//
// Menu
//
IDR_MENU MENU
BEGIN
POPUP "文件(&F)"
BEGIN
MENUITEM "退出(&X)", ID_FILE_EXIT
END
POPUP "设置(&S)"
BEGIN
MENUITEM "最前端显示(&T)", ID_SETTINGS_TOPMOST
POPUP "文本编码(&C)"
BEGIN
MENUITEM "UNICODE", ID_SETTINGS_CODE_UNICODE, CHECKED
MENUITEM "ANSI", ID_SETTINGS_CODE_ANSI
MENUITEM "UTF-8", ID_SETTINGS_CODE_UTF_8
END
MENUITEM "显示(&S)", ID_SETTINGS_SHOW
MENUITEM "隐藏(&H)", ID_SETTINGS_HIDE
END
POPUP "帮助(&H)"
BEGIN
MENUITEM "关于(&A)", ID_HELP_ABOUT
END
END
/
//
// Dialog
//
IDD_DIALOG_SERIAL_PORT DIALOGEX 0, 0, 509, 301
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "串口助手 By FlameCyclone"
MENU IDR_MENU
FONT 8, "MS Shell Dlg", 400, 0, 0x1
BEGIN
GROUPBOX "串口配置",IDC_STATIC,6,4,121,290
GROUPBOX "状态配置",IDC_STATIC,13,19,103,110
LTEXT "串口号:",IDC_STATIC,21,33,28,8
LTEXT "波特率:",IDC_STATIC,21,52,28,8
LTEXT "数据位:",IDC_STATIC,21,71,28,8
LTEXT "校验位:",IDC_STATIC,21,90,28,8
LTEXT "停止位:",IDC_STATIC,21,109,28,8
COMBOBOX IDC_COMBO_PORT,58,31,48,30,CBS_DROPDOWNLIST | CBS_SORT | WS_VSCROLL | WS_TABSTOP
COMBOBOX IDC_COMBO_SPEED,58,50,48,30,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
COMBOBOX IDC_COMBO_DATA,58,69,48,30,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
COMBOBOX IDC_COMBO_PARITY,58,88,48,30,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
COMBOBOX IDC_COMBO_STOP,58,107,48,30,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
GROUPBOX "超时配置",IDC_STATIC,13,137,103,103
LTEXT "读间隔超时:",IDC_STATIC,21,153,44,8
LTEXT "读时间系数:",IDC_STATIC,21,170,44,8
LTEXT "读时间常量:",IDC_STATIC,21,187,44,8
LTEXT "写时间系数:",IDC_STATIC,21,204,44,8
LTEXT "写时间常量:",IDC_STATIC,21,221,44,8
EDITTEXT IDC_EDIT_READ_INTERVAL,71,150,35,14,ES_NUMBER
EDITTEXT IDC_EDIT_READ_TOTAL_MULTIPLIER,71,167,35,14,ES_NUMBER
EDITTEXT IDC_EDIT_READ_TOTAL_CONSTANT,71,184,35,14,ES_NUMBER
EDITTEXT IDC_EDIT_WRITE_TOTAL_MULTIPLIER,71,201,35,14,ES_NUMBER
EDITTEXT IDC_EDIT_WRITE_TOTAL_CONSTANT,71,218,35,14,ES_NUMBER
PUSHBUTTON "打开串口",IDC_BUTTON_OPEN,13,264,103,21
GROUPBOX "接收",IDC_STATIC,134,4,368,192
CONTROL "HEX",IDC_CHECK_READ_HEX,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,464,19,29,10
EDITTEXT IDC_EDIT_READ,142,19,316,168,ES_MULTILINE | ES_AUTOVSCROLL | ES_READONLY | WS_VSCROLL | WS_HSCROLL
PUSHBUTTON "清空",IDC_BUTTON_CLEAR,462,170,32,17
GROUPBOX "发送",IDC_STATIC,134,203,368,92
CONTROL "HEX",IDC_CHECK_WRITE_HEX,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,464,217,29,10
EDITTEXT IDC_EDIT_WRITE,142,217,316,72,ES_MULTILINE | ES_AUTOHSCROLL | ES_WANTRETURN | WS_VSCROLL | WS_HSCROLL
PUSHBUTTON "发送",IDC_BUTTON_SEND,462,270,32,17
EDITTEXT IDC_EDIT_AUTO_TIME,68,244,30,14,ES_NUMBER
CONTROL "自动发送",IDC_CHECK_AUTO_SEND,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,13,246,48,10
LTEXT "ms",IDC_STATIC,101,247,10,8
END
IDD_DIALOG_ABOUT DIALOGEX 0, 0, 149, 116
STYLE DS_SETFONT | DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "关于"
FONT 12, "Microsoft Sans Serif", 400, 0, 0x0
BEGIN
PUSHBUTTON "关闭",IDOK,58,96,31,14
CTEXT "FC串口助手\r\n\r\nFlameCyclone\r\n\r\n2023.5.29\r\n\r\n版权我有, 盗版难究",IDC_STATIC_TEXT,17,10,113,70,NOT WS_GROUP
CONTROL "<a href=""http://flamecyclone.ysepan.com/"">访问 FlameCyclone 的网盘主页</a>",IDC_SYSLINK_ADDR,
"SysLink",0x0,21,82,106,15
END
/
//
// DESIGNINFO
//
#ifdef APSTUDIO_INVOKED
GUIDELINES DESIGNINFO
BEGIN
IDD_DIALOG_SERIAL_PORT, DIALOG
BEGIN
END
IDD_DIALOG_ABOUT, DIALOG
BEGIN
LEFTMARGIN, 7
TOPMARGIN, 7
END
END
#endif // APSTUDIO_INVOKED
/
//
// AFX_DIALOG_LAYOUT
//
IDD_DIALOG_SERIAL_PORT AFX_DIALOG_LAYOUT
BEGIN
0
END
IDD_DIALOG_ABOUT AFX_DIALOG_LAYOUT
BEGIN
0
END
/
//
// String Table
//
STRINGTABLE
BEGIN
IDS_FILE_EXIT "退出(&X)"
IDS_SETTINGS_SHOW "显示(&S)"
IDS_SETTINGS_HIDE "隐藏(&H)"
END
#endif // 中文(简体,中国) resources
/
#ifndef APSTUDIO_INVOKED
/
//
// Generated from the TEXTINCLUDE 3 resource.
//
/
#endif // not APSTUDIO_INVOKED
接着实现对话框的消息:
主对话框声明:
CDialogSerialPort.h
#pragma once
#include "CWindow/CDialogBase.h"
#include <vector>
#include "Win32Utils/CSerialPort.h"
#include <imm.h>
#include "CAboutDialog.h"
#ifdef UNICODE
using _tstring = std::wstring;
#else
using _tstring = std::string;
#endif
class CDialogSerialPort :
public CDialogBase
{
public:
protected:
dlg_msg LRESULT OnInitDialog(WPARAM wParam, LPARAM lParam);
dlg_msg LRESULT OnClose(WPARAM wParam, LPARAM lParam);
dlg_msg LRESULT OnTrayIcon(WPARAM wParam, LPARAM lParam);
dlg_msg LRESULT OnRButtonUp(WPARAM wParam, LPARAM lParam);
dlg_msg LRESULT OnColor(WPARAM wParam, LPARAM lParam);
dlg_msg LRESULT OnTimer(WPARAM wParam, LPARAM lParam);
dlg_msg LRESULT OnCommandExit(WPARAM wParam, LPARAM lParam);
dlg_msg LRESULT OnCommandShow(WPARAM wParam, LPARAM lParam);
dlg_msg LRESULT OnCommandHide(WPARAM wParam, LPARAM lParam);
dlg_msg LRESULT OnCommandReadClear(WPARAM wParam, LPARAM lParam);
dlg_msg LRESULT OnCommandReadHexShow(WPARAM wParam, LPARAM lParam);
dlg_msg LRESULT OnCommandWriteHexShow(WPARAM wParam, LPARAM lParam);
dlg_msg LRESULT OnCommandUnicode(WPARAM wParam, LPARAM lParam);
dlg_msg LRESULT OnCommandUtf8(WPARAM wParam, LPARAM lParam);
dlg_msg LRESULT OnCommandAnsi(WPARAM wParam, LPARAM lParam);
dlg_msg LRESULT OnCommandTopmost(WPARAM wParam, LPARAM lParam);
dlg_msg LRESULT OnStatePort(WPARAM wParam, LPARAM lParam);
dlg_msg LRESULT OnStateSpeed(WPARAM wParam, LPARAM lParam);
dlg_msg LRESULT OnStateData(WPARAM wParam, LPARAM lParam);
dlg_msg LRESULT OnStateParity(WPARAM wParam, LPARAM lParam);
dlg_msg LRESULT OnStateStop(WPARAM wParam, LPARAM lParam);
dlg_msg LRESULT OnCommOpen(WPARAM wParam, LPARAM lParam);
dlg_msg LRESULT OnCommSend(WPARAM wParam, LPARAM lParam);
dlg_msg LRESULT OnApplyTime(WPARAM wParam, LPARAM lParam);
dlg_msg LRESULT OnCommandAbout(WPARAM wParam, LPARAM lParam);
dlg_msg LRESULT OnCommandAutoSend(WPARAM wParam, LPARAM lParam);
protected:
virtual BOOL PreTranslateMessage(LPMSG pMsg);
private:
void ShowTrayIcon();
void DeleteTrayIcon();
VOID CreatePopMenu(int xPos, int yPos, bool isTop);
bool ShowForeground(HWND hWnd);
int GetAllSerials(std::vector<_tstring>& CommList);
void UpdateSerialDcb();
void ApplyTimeOut();
_tstring HexToStr(LPCBYTE lpData, size_t nSize);
int StrToHex(const _tstring& str, LPBYTE lpData, size_t nSize);
private:
HMENU m_hPopMenu = NULL;
HMENU m_hMainMenu = NULL;
HWND m_hHideWnd = NULL;
CSerialPort m_SerialPort;
DCB m_SerialDcb;
_tstring m_strRead;
bool m_bReadHex = false;
bool m_bWriteHex = false;
size_t m_nReadCount = 0;
HIMC m_hImc = nullptr;
HWND m_hWndSend = nullptr;
HBRUSH m_hBrush = nullptr;
CAboutDialog m_dlgAbout;
int m_nStrCode = 0;
UINT m_uTimer = 0;
DECLARE_DLG_MESSAGE_MAP()
};
主对话框实现:
CDialogSerialPort.cpp
#include "CDialogSerialPort.h"
#include "Win32Utils/CStrUtils.h"
#include <Windows.h>
#include <strsafe.h>
#include <thread>
#include "resource.h"
#pragma comment (lib ,"imm32.lib")
#define WM_TRAYICON (WM_USER + 10)
BEGIN_DLG_MESSAGE_MAP(CDialogSerialPort, CDialogBase)
ON_DLG_MESSAGE(WM_INITDIALOG, &CDialogSerialPort::OnInitDialog)
ON_DLG_MESSAGE(WM_TRAYICON, &CDialogSerialPort::OnTrayIcon)
ON_DLG_MESSAGE(WM_CLOSE, &CDialogSerialPort::OnClose)
ON_DLG_MESSAGE(WM_RBUTTONUP, &CDialogSerialPort::OnRButtonUp)
ON_DLG_MESSAGE(WM_CTLCOLORSTATIC, &CDialogSerialPort::OnColor)
//ON_DLG_MESSAGE(WM_CTLCOLOREDIT, &CDialogSerialPort::OnColor)
ON_DLG_MESSAGE(WM_CTLCOLORBTN, &CDialogSerialPort::OnColor)
ON_DLG_MESSAGE(WM_CTLCOLORDLG, &CDialogSerialPort::OnColor)
ON_DLG_MESSAGE(WM_TIMER, &CDialogSerialPort::OnTimer)
ON_DLG_COMMAND(ID_FILE_EXIT, &CDialogSerialPort::OnCommandExit)
ON_DLG_COMMAND(ID_SETTINGS_SHOW, &CDialogSerialPort::OnCommandShow)
ON_DLG_COMMAND(ID_SETTINGS_HIDE, &CDialogSerialPort::OnCommandHide)
ON_DLG_COMMAND(IDC_CHECK_READ_HEX, &CDialogSerialPort::OnCommandReadHexShow)
ON_DLG_COMMAND(IDC_CHECK_WRITE_HEX, &CDialogSerialPort::OnCommandWriteHexShow)
ON_DLG_COMMAND(IDC_BUTTON_CLEAR, &CDialogSerialPort::OnCommandReadClear)
ON_DLG_COMMAND(IDC_COMBO_PORT, &CDialogSerialPort::OnStatePort)
ON_DLG_COMMAND(IDC_COMBO_SPEED, &CDialogSerialPort::OnStateSpeed)
ON_DLG_COMMAND(IDC_COMBO_DATA, &CDialogSerialPort::OnStateData)
ON_DLG_COMMAND(IDC_COMBO_PARITY, &CDialogSerialPort::OnStateParity)
ON_DLG_COMMAND(IDC_COMBO_STOP, &CDialogSerialPort::OnStateStop)
ON_DLG_COMMAND(IDC_BUTTON_OPEN, &CDialogSerialPort::OnCommOpen)
ON_DLG_COMMAND(IDC_BUTTON_SEND, &CDialogSerialPort::OnCommSend)
ON_DLG_COMMAND(IDC_BUTTON_TIMEOUT, &CDialogSerialPort::OnApplyTime)
ON_DLG_COMMAND(ID_HELP_ABOUT, &CDialogSerialPort::OnCommandAbout)
ON_DLG_COMMAND(ID_SETTINGS_CODE_UNICODE, &CDialogSerialPort::OnCommandUnicode)
ON_DLG_COMMAND(ID_SETTINGS_CODE_UTF_8, &CDialogSerialPort::OnCommandUtf8)
ON_DLG_COMMAND(ID_SETTINGS_CODE_ANSI, &CDialogSerialPort::OnCommandAnsi)
ON_DLG_COMMAND(IDC_CHECK_AUTO_SEND, &CDialogSerialPort::OnCommandAutoSend)
ON_DLG_COMMAND(ID_SETTINGS_TOPMOST, &CDialogSerialPort::OnCommandTopmost)
END_DLG_MESSAGE_MAP()
BOOL CDialogSerialPort::PreTranslateMessage(LPMSG pMsg)
{
if (WM_KEYDOWN == pMsg->message && pMsg->hwnd == m_hWndSend && m_bWriteHex)
{
TCHAR ch = (TCHAR)pMsg->wParam;
SHORT ctrlState = GetAsyncKeyState(VK_CONTROL) & 0x8000;
if (ctrlState)
{
if (ch == _T('C') ||
ch == _T('V') ||
ch == _T('X') ||
ch == _T('A')
)
{
return FALSE;
}
else
{
return TRUE;
}
}
if (VK_BACK == ch || VK_SPACE == ch || VK_TAB == ch || VK_RETURN == ch)
{
return FALSE;
}
if ((ch >= _T('0') && ch <= _T('9')) ||
(ch >= _T('A') && ch <= _T('F'))
)
{
return FALSE;
}
return TRUE;
}
return FALSE;
}
int CDialogSerialPort::GetAllSerials(std::vector<_tstring>& CommList)
{
HKEY hKey = nullptr;
int nretval = 0;
nretval = ::RegOpenKeyEx(HKEY_LOCAL_MACHINE,
_T("Hardware\\DeviceMap\\SerialComm"),
NULL, KEY_READ, &hKey);
int i = 0;
if (nretval == ERROR_SUCCESS)
{
TCHAR szPortName[MAX_PATH];
DWORD dwLong, dwSize;
while (true)
{
TCHAR szCommName[MAX_PATH] = { 0 };
dwLong = MAX_PATH;
dwSize = MAX_PATH;
nretval = RegEnumValue(hKey, i, szPortName, &dwLong,
NULL, NULL, (PUCHAR)szCommName, &dwSize);
if (nretval != ERROR_NO_MORE_ITEMS)
{
CommList.push_back(szCommName);
}
else
{
break;
}
i++;
}
RegCloseKey(hKey);
}
return i;
}
void CDialogSerialPort::UpdateSerialDcb()
{
// 波特率
{
TCHAR szBuf[MAX_PATH] = { 0 };
HWND hWndSpeed = GetDlgItem(m_hWnd, IDC_COMBO_SPEED);
LRESULT nCurSel = SendMessage(hWndSpeed, CB_GETCURSEL, 0, 0);
if (CB_ERR != nCurSel)
{
SendMessage(hWndSpeed, CB_GETLBTEXT, nCurSel, (LPARAM)szBuf);
m_SerialDcb.BaudRate = _tcstoul(szBuf, nullptr, 10);
}
}
// 数据位
{
HWND hWndSpeed = GetDlgItem(m_hWnd, IDC_COMBO_DATA);
LRESULT nCurSel = SendMessage(hWndSpeed, CB_GETCURSEL, 0, 0);
if (0 <= nCurSel && nCurSel <= 3)
{
m_SerialDcb.ByteSize = (BYTE)(5 + nCurSel);
}
else
{
m_SerialDcb.ByteSize = 8;
}
}
// 校验位
{
HWND hWndParity = GetDlgItem(m_hWnd, IDC_COMBO_PARITY);
LRESULT nCurSel = SendMessage(hWndParity, CB_GETCURSEL, 0, 0);
if (NOPARITY <= nCurSel && nCurSel <= SPACEPARITY)
{
m_SerialDcb.Parity = (BYTE)nCurSel;
}
else
{
m_SerialDcb.Parity = NOPARITY;
}
}
// 停止位
{
HWND hWndStop = GetDlgItem(m_hWnd, IDC_COMBO_STOP);
LRESULT nCurSel = SendMessage(hWndStop, CB_GETCURSEL, 0, 0);
if (ONESTOPBIT <= nCurSel && nCurSel <= TWOSTOPBITS)
{
m_SerialDcb.StopBits = (BYTE)nCurSel;
}
else
{
m_SerialDcb.StopBits = ONESTOPBIT;
}
}
m_SerialPort.SetState(&m_SerialDcb);
}
void CDialogSerialPort::ApplyTimeOut()
{
if (m_SerialPort.IsOpen())
{
DWORD ReadInterval = ::GetDlgItemInt(m_hWnd, IDC_EDIT_READ_INTERVAL, nullptr, false);
DWORD ReadTotalMultiplier = ::GetDlgItemInt(m_hWnd, IDC_EDIT_READ_TOTAL_MULTIPLIER, nullptr, false);
DWORD ReadTotalConstant = ::GetDlgItemInt(m_hWnd, IDC_EDIT_READ_TOTAL_CONSTANT, nullptr, false);
DWORD WriteTotalMultiplier = ::GetDlgItemInt(m_hWnd, IDC_EDIT_WRITE_TOTAL_MULTIPLIER, nullptr, false);
DWORD WriteTotalConstant = ::GetDlgItemInt(m_hWnd, IDC_EDIT_WRITE_TOTAL_CONSTANT, nullptr, false);
m_SerialPort.Purge(PURGE_TXCLEAR |
PURGE_RXCLEAR |
PURGE_TXABORT |
PURGE_RXABORT);
m_SerialPort.ClearError();
m_SerialPort.SetTimeOut(ReadInterval,
ReadTotalMultiplier,
ReadTotalConstant,
WriteTotalMultiplier,
WriteTotalConstant);
}
}
LRESULT CDialogSerialPort::OnInitDialog(WPARAM wParam, LPARAM lParam)
{
// 设置图标
HICON hIcon = LoadIcon(GetModuleHandle(NULL), MAKEINTRESOURCE(IDI_ICON));
if (hIcon)
{
::SendMessage(m_hWnd, WM_SETICON, ICON_BIG, (LPARAM)hIcon);
::SendMessage(m_hWnd, WM_SETICON, ICON_SMALL, (LPARAM)hIcon);
}
m_hHideWnd = CreateWindow(
_T("Static"), _T("Hide"), WS_CHILDWINDOW, 0, 0, 0, 0,
m_hWnd, NULL, GetModuleHandle(NULL), NULL);
if (m_hHideWnd)
{
::SetParent(m_hHideWnd, NULL);
}
m_hMainMenu = ::GetMenu(m_hWnd);
if (nullptr == m_hMainMenu)
{
m_hMainMenu = ::LoadMenu(GetModuleHandle(NULL), MAKEINTRESOURCE(IDR_MENU));
}
if (m_hMainMenu)
{
::SetMenu(m_hWnd, m_hMainMenu);
ShowTrayIcon();
}
{
HWND hWndPort = GetDlgItem(m_hWnd, IDC_COMBO_PORT);
std::vector<_tstring> CommList;
GetAllSerials(CommList);
for (auto item : CommList)
{
SendMessage(hWndPort, CB_ADDSTRING, 0, (LPARAM)item.c_str());
}
if (!CommList.empty())
{
SendMessage(hWndPort, CB_SETCURSEL, 0, 0);
}
}
{
std::vector<int> vSpeed = {
75,
110,
134,
150,
300,
600,
1200,
1800,
2400,
4800,
7200,
9600,
14400,
19200,
38400,
56000,
57600,
115200,
128000,
256000,
};
HWND hWndSpeed = GetDlgItem(m_hWnd, IDC_COMBO_SPEED);
for (auto item : vSpeed)
{
TCHAR szBuf[MAX_PATH] = { 0 };
_ultot_s(item, szBuf, 10);
SendMessage(hWndSpeed, CB_ADDSTRING, 0, (LPARAM)szBuf);
}
if (!vSpeed.empty())
{
SendMessage(hWndSpeed, CB_SETCURSEL, vSpeed.size() - 3, 0);
}
}
{
std::vector<int> vData = { 5,6,7,8 };
HWND hWndData = GetDlgItem(m_hWnd, IDC_COMBO_DATA);
for (auto item : vData)
{
TCHAR szBuf[MAX_PATH] = { 0 };
_ultot_s(item, szBuf, 10);
SendMessage(hWndData, CB_ADDSTRING, 0, (LPARAM)szBuf);
}
if (!vData.empty())
{
SendMessage(hWndData, CB_SETCURSEL, 3, 0);
}
}
{
std::vector<_tstring> vParity = {
_T("None"),
_T("Odd"),
_T("Even"),
_T("Mark"),
_T("Space")
};
HWND hWndParity = GetDlgItem(m_hWnd, IDC_COMBO_PARITY);
for (auto item : vParity)
{
SendMessage(hWndParity, CB_ADDSTRING, 0, (LPARAM)item.c_str());
}
if (!vParity.empty())
{
SendMessage(hWndParity, CB_SETCURSEL, 0, 0);
}
}
{
std::vector<_tstring> vParity = {
_T("1"),
_T("1.5"),
_T("2"),
};
HWND hWndStop = GetDlgItem(m_hWnd, IDC_COMBO_STOP);
for (auto item : vParity)
{
SendMessage(hWndStop, CB_ADDSTRING, 0, (LPARAM)item.c_str());
}
if (!vParity.empty())
{
SendMessage(hWndStop, CB_SETCURSEL, 0, 0);
}
}
CheckDlgButton(m_hWnd, IDC_CHECK_READ_HEX, BST_CHECKED);
m_bReadHex = true;
CheckDlgButton(m_hWnd, IDC_CHECK_WRITE_HEX, BST_CHECKED);
m_bWriteHex = true;
m_hWndSend = ::GetDlgItem(m_hWnd, IDC_EDIT_WRITE);
::SetDlgItemText(m_hWnd, IDC_EDIT_AUTO_TIME, _T("1000"));
m_hImc = ImmAssociateContext(m_hWndSend, nullptr);
UpdateSerialDcb();
::SetDlgItemText(m_hWnd, IDC_EDIT_WRITE, _T("E7 00 00 22 02 00 00 00 0F 33 ED"));
::SetDlgItemInt(m_hWnd, IDC_EDIT_READ_INTERVAL, 50, false);
::SetDlgItemInt(m_hWnd, IDC_EDIT_READ_TOTAL_MULTIPLIER, 5, false);
::SetDlgItemInt(m_hWnd, IDC_EDIT_READ_TOTAL_CONSTANT, 500, false);
::SetDlgItemInt(m_hWnd, IDC_EDIT_WRITE_TOTAL_MULTIPLIER, 0, false);
::SetDlgItemInt(m_hWnd, IDC_EDIT_WRITE_TOTAL_CONSTANT, 0, false);
return TRUE;
}
LRESULT CDialogSerialPort::OnClose(WPARAM wParam, LPARAM lParam)
{
if (m_hBrush)
{
::DeleteObject(m_hBrush);
}
DeleteTrayIcon();
return (LRESULT)FALSE;
}
LRESULT CDialogSerialPort::OnCommandExit(WPARAM wParam, LPARAM lParam)
{
m_dlgAbout.EndDialog(0);
EndDialog(IDOK);
return (LRESULT)TRUE;
}
LRESULT CDialogSerialPort::OnCommandShow(WPARAM wParam, LPARAM lParam)
{
ShowWindow(SW_SHOW);
return (LRESULT)TRUE;
}
LRESULT CDialogSerialPort::OnCommandHide(WPARAM wParam, LPARAM lParam)
{
ShowWindow(SW_HIDE);
return (LRESULT)TRUE;
}
LRESULT CDialogSerialPort::OnCommandReadHexShow(WPARAM wParam, LPARAM lParam)
{
HWND hReadHex = ::GetDlgItem(m_hWnd, IDC_CHECK_READ_HEX);
LRESULT hr = ::SendMessage(hReadHex, BM_GETCHECK, 0, 0);
if (BST_CHECKED == hr)
{
m_bReadHex = true;
}
else
{
m_bReadHex = false;
}
return (LRESULT)TRUE;
}
_tstring CDialogSerialPort::HexToStr(LPCBYTE lpData, size_t nSize)
{
_tstring strRes;
TCHAR szBuf[MAX_PATH] = { 0 };
for (int i = 0; i < nSize; i++)
{
if (i + 1 < nSize)
{
StringCchPrintf(szBuf, _countof(szBuf), _T("%0.2X "), lpData[i]);
}
else
{
StringCchPrintf(szBuf, _countof(szBuf), _T("%0.2X"), lpData[i]);
}
strRes += szBuf;
}
return strRes;
}
int CDialogSerialPort::StrToHex(const _tstring& str, LPBYTE lpData, size_t nSize)
{
_tstring strWide;
std::string strMulti;
int nDataIndex = 0;
strWide = str;
_tstring strHex;
int nIndex = 0;
for (int i = 0; i < strWide.size(); i++)
{
if (0 == nIndex)
{
strHex.clear();
}
if (str[i] == _T(' ') || str[i] == _T('\r') || str[i] == _T('\n'))
{
continue;
}
strHex += str[i];
nIndex++;
if (2 == nIndex && nDataIndex < nSize)
{
nIndex = 0;
lpData[nDataIndex++] = (BYTE)_tcstoul(strHex.c_str(), nullptr, 16);
}
}
return nDataIndex;
}
LRESULT CDialogSerialPort::OnApplyTime(WPARAM wParam, LPARAM lParam)
{
ApplyTimeOut();
return TRUE;
}
LRESULT CDialogSerialPort::OnCommandAbout(WPARAM wParam, LPARAM lParam)
{
m_dlgAbout.DoModalEx(IDD_DIALOG_ABOUT, m_hWnd);
return TRUE;
}
LRESULT CDialogSerialPort::OnCommandAutoSend(WPARAM wParam, LPARAM lParam)
{
LRESULT ret = SendMessage(
::GetDlgItem(m_hWnd, IDC_CHECK_AUTO_SEND),
BM_GETCHECK,
0,
0);
if (BST_CHECKED == ret)
{
UINT uTime = ::GetDlgItemInt(m_hWnd, IDC_EDIT_AUTO_TIME, nullptr, false);
if (uTime < USER_TIMER_MINIMUM)
{
uTime = USER_TIMER_MINIMUM;
::SetDlgItemInt(m_hWnd, IDC_EDIT_AUTO_TIME, uTime, false);
}
m_uTimer = ::SetTimer(m_hWnd, 0x200, uTime, nullptr);
::EnableWindow(::GetDlgItem(m_hWnd, IDC_EDIT_AUTO_TIME), false);
}
else
{
::KillTimer(m_hWnd, m_uTimer);
::EnableWindow(::GetDlgItem(m_hWnd, IDC_EDIT_AUTO_TIME), true);
}
return TRUE;
}
LRESULT CDialogSerialPort::OnCommandWriteHexShow(WPARAM wParam, LPARAM lParam)
{
HWND hWriteHex = ::GetDlgItem(m_hWnd, IDC_CHECK_WRITE_HEX);
LRESULT ret = SendMessage(hWriteHex, BM_GETCHECK, 0, 0);
static TCHAR szWriteBuf[32768] = { 0 };
if (BST_CHECKED == ret)
{
m_bWriteHex = true;
UINT uLen = ::GetDlgItemText(m_hWnd, IDC_EDIT_WRITE, szWriteBuf, _countof(szWriteBuf));
_tstring strText;
if (0 == m_nStrCode)
{
_tstring strDest = szWriteBuf;
strText = HexToStr((LPBYTE)strDest.c_str(), uLen * sizeof(TCHAR));
}
else if (1 == m_nStrCode)
{
std::string strDest = CStrUtils::TStrToAStr(szWriteBuf);
strText = HexToStr((LPBYTE)strDest.c_str(), strDest.size());
}
else if (2 == m_nStrCode)
{
std::string strDest = CStrUtils::TStrToU8Str(szWriteBuf);
strText = HexToStr((LPBYTE)strDest.c_str(), strDest.size());
}
::SetDlgItemText(m_hWnd, IDC_EDIT_WRITE, strText.c_str());
HWND hEditSend = ::GetDlgItem(m_hWnd, IDC_EDIT_WRITE);
m_hImc = ::ImmAssociateContext(hEditSend, nullptr);
}
else
{
m_bWriteHex = false;
::GetDlgItemText(m_hWnd, IDC_EDIT_WRITE, szWriteBuf, _countof(szWriteBuf));
static BYTE szCharBuf[32768] = { 0 };
::ZeroMemory(szCharBuf, sizeof(szCharBuf));
StrToHex(szWriteBuf, szCharBuf, sizeof(szCharBuf));
if (0 == m_nStrCode)
{
::SetDlgItemText(m_hWnd, IDC_EDIT_WRITE, (LPCTSTR)szCharBuf);
}
else if (1 == m_nStrCode)
{
::SetDlgItemText(m_hWnd, IDC_EDIT_WRITE, CStrUtils::AStrToTStr((LPCSTR)szCharBuf).c_str());
}
else if (2 == m_nStrCode)
{
::SetDlgItemText(m_hWnd, IDC_EDIT_WRITE, CStrUtils::U8StrToTStr((LPCSTR)szCharBuf).c_str());
}
HWND hEditSend = ::GetDlgItem(m_hWnd, IDC_EDIT_WRITE);
::ImmAssociateContext(hEditSend, m_hImc);
}
return (LRESULT)TRUE;
}
LRESULT CDialogSerialPort::OnCommandUnicode(WPARAM wParam, LPARAM lParam)
{
m_nStrCode = 0;
for (int i = ID_SETTINGS_CODE_UNICODE; i <= ID_SETTINGS_CODE_UTF_8; i++)
{
::CheckMenuItem(::GetMenu(m_hWnd), i, MF_BYCOMMAND | MF_UNCHECKED);
}
::CheckMenuItem(::GetMenu(m_hWnd), wParam, MF_BYCOMMAND | MF_CHECKED);
return (LRESULT)TRUE;
}
LRESULT CDialogSerialPort::OnCommandAnsi(WPARAM wParam, LPARAM lParam)
{
m_nStrCode = 1;
for (int i = ID_SETTINGS_CODE_UNICODE; i <= ID_SETTINGS_CODE_UTF_8; i++)
{
::CheckMenuItem(::GetMenu(m_hWnd), i, MF_BYCOMMAND | MF_UNCHECKED);
}
::CheckMenuItem(::GetMenu(m_hWnd), wParam, MF_BYCOMMAND | MF_CHECKED);
return (LRESULT)TRUE;
}
LRESULT CDialogSerialPort::OnCommandTopmost(WPARAM wParam, LPARAM lParam)
{
DWORD dwState = ::GetMenuState(GetMenu(m_hWnd), wParam, MF_BYCOMMAND | MF_CHECKED);
::SetWindowPos(m_hWnd,
MF_CHECKED & dwState ? HWND_NOTOPMOST : HWND_TOPMOST,
0, 0, 0, 0,
SWP_NOSIZE | SWP_NOMOVE);
::CheckMenuItem(GetMenu(m_hWnd), wParam, MF_BYCOMMAND | (MF_CHECKED & dwState ? MF_UNCHECKED : MF_CHECKED));
return (LRESULT)TRUE;
}
LRESULT CDialogSerialPort::OnCommandUtf8(WPARAM wParam, LPARAM lParam)
{
m_nStrCode = 2;
for (int i = ID_SETTINGS_CODE_UNICODE; i <= ID_SETTINGS_CODE_UTF_8; i++)
{
::CheckMenuItem(::GetMenu(m_hWnd), i, MF_BYCOMMAND | MF_UNCHECKED);
}
::CheckMenuItem(::GetMenu(m_hWnd), wParam, MF_BYCOMMAND | MF_CHECKED);
return (LRESULT)TRUE;
}
LRESULT CDialogSerialPort::OnCommandReadClear(WPARAM wParam, LPARAM lParam)
{
m_strRead.clear();
HWND hWndRead = ::GetDlgItem(m_hWnd, IDC_EDIT_READ);
::SetWindowText(hWndRead, _T(""));
m_nReadCount = 0;
return TRUE;
}
LRESULT CDialogSerialPort::OnStatePort(WPARAM wParam, LPARAM lParam)
{
if (CBN_SELCHANGE == HIWORD(wParam))
{
UpdateSerialDcb();
if (m_SerialPort.IsOpen())
{
m_SerialPort.Close();
::SetDlgItemText(m_hWnd, IDC_BUTTON_OPEN, _T("打开串口"));
::PostMessage(m_hWnd, WM_COMMAND, IDC_BUTTON_OPEN, 0);
}
}
return TRUE;
}
LRESULT CDialogSerialPort::OnStateSpeed(WPARAM wParam, LPARAM lParam)
{
if (CBN_SELCHANGE == HIWORD(wParam))
{
UpdateSerialDcb();
}
return TRUE;
}
LRESULT CDialogSerialPort::OnStateData(WPARAM wParam, LPARAM lParam)
{
if (CBN_SELCHANGE == HIWORD(wParam))
{
UpdateSerialDcb();
}
return TRUE;
}
LRESULT CDialogSerialPort::OnStateParity(WPARAM wParam, LPARAM lParam)
{
if (CBN_SELCHANGE == HIWORD(wParam))
{
UpdateSerialDcb();
}
return TRUE;
}
LRESULT CDialogSerialPort::OnStateStop(WPARAM wParam, LPARAM lParam)
{
if (CBN_SELCHANGE == HIWORD(wParam))
{
UpdateSerialDcb();
}
return TRUE;
}
LRESULT CDialogSerialPort::OnCommOpen(WPARAM wParam, LPARAM lParam)
{
if (m_SerialPort.IsOpen())
{
m_SerialPort.Close();
::SetDlgItemText(m_hWnd, IDC_BUTTON_OPEN, _T("打开串口"));
::EnableWindow(GetDlgItem(m_hWnd, IDC_EDIT_READ_INTERVAL), TRUE);
::EnableWindow(GetDlgItem(m_hWnd, IDC_EDIT_READ_TOTAL_MULTIPLIER), TRUE);
::EnableWindow(GetDlgItem(m_hWnd, IDC_EDIT_READ_TOTAL_CONSTANT), TRUE);
::EnableWindow(GetDlgItem(m_hWnd, IDC_EDIT_WRITE_TOTAL_MULTIPLIER), TRUE);
::EnableWindow(GetDlgItem(m_hWnd, IDC_EDIT_WRITE_TOTAL_CONSTANT), TRUE);
}
else
{
TCHAR szBuf[MAX_PATH] = { 0 };
HWND hWndPort = GetDlgItem(m_hWnd, IDC_COMBO_PORT);
LRESULT nCurSel = SendMessage(hWndPort, CB_GETCURSEL, 0, 0);
bool bOpen = false;
if (CB_ERR != nCurSel)
{
SendMessage(hWndPort, CB_GETLBTEXT, nCurSel, (LPARAM)szBuf);
bOpen = m_SerialPort.Open(
szBuf,
m_SerialDcb.BaudRate,
m_SerialDcb.ByteSize,
m_SerialDcb.Parity,
m_SerialDcb.StopBits);
ApplyTimeOut();
}
if (!bOpen)
{
MessageBox(m_hWnd, _T("打开串口失败!"), _T("提示"), MB_OK | MB_ICONERROR);
return TRUE;
}
::SetDlgItemText(m_hWnd, IDC_BUTTON_OPEN, _T("关闭串口"));
::EnableWindow(GetDlgItem(m_hWnd, IDC_EDIT_READ_INTERVAL), FALSE);
::EnableWindow(GetDlgItem(m_hWnd, IDC_EDIT_READ_TOTAL_MULTIPLIER), FALSE);
::EnableWindow(GetDlgItem(m_hWnd, IDC_EDIT_READ_TOTAL_CONSTANT), FALSE);
::EnableWindow(GetDlgItem(m_hWnd, IDC_EDIT_WRITE_TOTAL_MULTIPLIER), FALSE);
::EnableWindow(GetDlgItem(m_hWnd, IDC_EDIT_WRITE_TOTAL_CONSTANT), FALSE);
std::thread([this]()->void {
static BYTE szReadBuf[32768] = { 0 };
bool bSuccess = false;
DWORD dwReadSize = 0;
HWND hWndRead = GetDlgItem(m_hWnd, IDC_EDIT_READ);
while (m_SerialPort.IsOpen())
{
m_SerialPort.Purge(PURGE_RXCLEAR);
bSuccess = m_SerialPort.Read(szReadBuf,
sizeof(szReadBuf),
&dwReadSize,
5000);
if (bSuccess)
{
TCHAR szBuf[MAX_PATH] = { 0 };
StringCchPrintf(szBuf, _countof(szBuf), _T("[%0.4d: %d Bytes] "), ++m_nReadCount, dwReadSize);
_tstring strText = szBuf;
szReadBuf[dwReadSize] = 0;
if (m_bReadHex)
{
szReadBuf[dwReadSize + 1] = 0;
strText += HexToStr((LPCBYTE)szReadBuf, dwReadSize);
}
else
{
_tstring strContent;
if (0 == m_nStrCode)
{
strContent = (LPCTSTR)szReadBuf;
}
if (1 == m_nStrCode)
{
strContent = CStrUtils::AStrToTStr((LPCSTR)szReadBuf);
}
if (2 == m_nStrCode)
{
strContent = CStrUtils::U8StrToTStr((LPCSTR)szReadBuf);
}
strText += strContent;
}
if (!m_strRead.empty())
{
m_strRead += _T("\r\n");
}
m_strRead += strText;
::SendMessage(hWndRead, WM_SETREDRAW, FALSE, 0);
::SetWindowText(hWndRead, m_strRead.c_str());
::SendMessage(hWndRead, EM_SCROLL, SB_BOTTOM, 0);
::SendMessage(hWndRead, WM_SETREDRAW, TRUE, 0);
}
}
}).detach();
}
return TRUE;
}
LRESULT CDialogSerialPort::OnCommSend(WPARAM wParam, LPARAM lParam)
{
if (m_SerialPort.IsOpen())
{
static TCHAR szBuf[32768] = { 0 };
HWND hWndEditSend = GetDlgItem(m_hWnd, IDC_EDIT_WRITE);
::GetWindowText(hWndEditSend, szBuf, _countof(szBuf));
_tstring strData = szBuf;
if (strData.empty())
{
return TRUE;
}
m_SerialPort.Purge(PURGE_TXCLEAR);
if (m_bWriteHex)
{
static BYTE szByteBuf[32768] = { 0 };
ZeroMemory(szByteBuf, sizeof(szByteBuf));
int nSize = StrToHex(strData, szByteBuf, sizeof(szByteBuf));
m_SerialPort.Write(szByteBuf, nSize, nullptr, 1000);
}
else
{
if (0 == m_nStrCode)
{
size_t nSize = strData.size() * sizeof(TCHAR);
m_SerialPort.Write(strData.c_str(), (DWORD)nSize, nullptr, (DWORD)1000);
}
else if (1 == m_nStrCode)
{
std::string strDest = CStrUtils::TStrToAStr(szBuf);
m_SerialPort.Write(strDest.c_str(), (DWORD)strDest.size(), nullptr, (DWORD)1000);
}
else if (2 == m_nStrCode)
{
std::string strDest = CStrUtils::TStrToU8Str(szBuf);
m_SerialPort.Write(strDest.c_str(), (DWORD)strDest.size(), nullptr, (DWORD)1000);
}
}
}
return TRUE;
}
LRESULT CDialogSerialPort::OnTrayIcon(WPARAM wParam, LPARAM lParam)
{
if (WM_LBUTTONDBLCLK == lParam)
{
ShowForeground(m_hWnd);
}
if (NULL != m_hHideWnd)
{
::SetForegroundWindow(m_hHideWnd);
}
if (WM_RBUTTONUP == lParam)
{
HWND hForegroundWindow = GetForegroundWindow();
if (hForegroundWindow == m_hHideWnd || hForegroundWindow == m_hWnd)
{
POINT pt = { 0 };
::GetCursorPos(&pt);
CreatePopMenu(pt.x, pt.y, false);
}
}
return FALSE;
}
LRESULT CDialogSerialPort::OnRButtonUp(WPARAM wParam, LPARAM lParam)
{
POINT pt = { 0 };
::GetCursorPos(&pt);
CreatePopMenu(pt.x, pt.y, false);
return (LRESULT)TRUE;
}
LRESULT CDialogSerialPort::OnColor(WPARAM wParam, LPARAM lParam)
{
HDC hdc = (HDC)wParam;
SetBkColor(hdc, RGB(255, 0, 0));
SetBkMode(hdc, TRANSPARENT);
if (NULL == m_hBrush)
{
m_hBrush = CreateSolidBrush(RGB(192, 224, 255));
}
return (LRESULT)m_hBrush;
return (LRESULT)TRUE;
}
LRESULT CDialogSerialPort::OnTimer(WPARAM wParam, LPARAM lParam)
{
if (wParam == m_uTimer)
{
::PostMessage(m_hWnd, WM_COMMAND, IDC_BUTTON_SEND, 0);
}
return (LRESULT)TRUE;
}
bool CDialogSerialPort::ShowForeground(HWND hWnd)
{
HWND hForeWnd = ::GetForegroundWindow();
DWORD dwForeID = ::GetWindowThreadProcessId(hForeWnd, NULL);
DWORD dwCurID = ::GetCurrentThreadId();
::AttachThreadInput(dwCurID, dwForeID, TRUE);
BOOL isSuc = ::SetForegroundWindow(hWnd);
::AttachThreadInput(dwCurID, dwForeID, FALSE);
if (isSuc)
{
//return true;
}
if (!::IsWindowVisible(hWnd))
{
::ShowWindow(hWnd, SW_SHOW);
}
if (IsIconic(hWnd))
{
::ShowWindow(hWnd, SW_SHOWNORMAL);
}
return ::SetForegroundWindow(hWnd);
}
void CDialogSerialPort::ShowTrayIcon()
{
NOTIFYICONDATA nid = { 0 };
nid.cbSize = sizeof(NOTIFYICONDATA);
nid.hWnd = m_hWnd;
nid.uID = 0;
nid.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP;
nid.uCallbackMessage = WM_TRAYICON;
nid.hIcon = ::LoadIcon(GetModuleHandle(NULL), MAKEINTRESOURCE(IDI_ICON));
StringCchCopy(nid.szTip, _countof(nid.szTip), _T("Demo"));
Shell_NotifyIcon(NIM_ADD, &nid);
}
void CDialogSerialPort::DeleteTrayIcon()
{
NOTIFYICONDATA nid = { 0 };
nid.cbSize = sizeof(nid);
nid.hWnd = m_hWnd;
nid.uID = 0;
nid.uFlags = 0;
Shell_NotifyIcon(NIM_DELETE, &nid);
}
VOID CDialogSerialPort::CreatePopMenu(int xPos, int yPos, bool isTop)
{
MENUITEMINFO mii = { 0 };
TCHAR szBuf[MAX_PATH] = { 0 };
mii.cbSize = sizeof(mii);
mii.fMask = MIIM_TYPE | MIIM_STATE | MIIM_SUBMENU | MIIM_ID;
mii.fType = MFT_STRING | MFT_OWNERDRAW;
mii.dwTypeData = szBuf;
if (!m_hWnd)
{
return;
}
{
HMENU hMenu = m_hMainMenu;
ModifyMenuText(hMenu, ID_FILE_EXIT, IDS_FILE_EXIT, FALSE);
ModifyMenuText(hMenu, ID_SETTINGS_SHOW, IDS_SETTINGS_SHOW, FALSE);
ModifyMenuText(hMenu, ID_SETTINGS_HIDE, IDS_SETTINGS_HIDE, FALSE);
}
int nIndex = 0;
if (NULL == m_hPopMenu)
{
m_hPopMenu = CreatePopupMenu();
for (int i = 0; i < 4; i++)
{
mii.cch = _countof(szBuf);
::GetMenuItemInfo(GetSubMenu(m_hMainMenu, 1), i, TRUE, &mii);
::InsertMenuItem(m_hPopMenu, nIndex++, TRUE, &mii);
}
mii.cch = _countof(szBuf);
::GetMenuItemInfo(GetSubMenu(m_hMainMenu, 0), 0, TRUE, &mii);
::InsertMenuItem(m_hPopMenu, nIndex++, TRUE, &mii);
}
else
{
for (int i = 0; i < 4; i++)
{
mii.cch = _countof(szBuf);
::GetMenuItemInfo(GetSubMenu(m_hMainMenu, 1), i, TRUE, &mii);
::SetMenuItemInfo(m_hPopMenu, nIndex++, TRUE, &mii);
}
mii.cch = _countof(szBuf);
::GetMenuItemInfo(GetSubMenu(m_hMainMenu, 0), 0, TRUE, &mii);
::SetMenuItemInfo(m_hPopMenu, nIndex++, TRUE, &mii);
}
TrackPopupMenuEx(m_hPopMenu, TPM_LEFTALIGN | (isTop ? TPM_BOTTOMALIGN : TPM_TOPALIGN),
xPos, yPos, m_hWnd, NULL);
}
主体编码就算完成了, 资源视图如下:
解决方案视图如下:
运行效果如下:
资源链接详见: Win32api编写的串口助手源码与二进制资源-CSDN文库