中级会员
 
- 积分
- 419
- 金钱
- 419
- 注册时间
- 2015-9-16
- 在线时间
- 122 小时
|
之前在本板块发过一个关于CSerialPort 求助,最近有坛友询问关于这方面的问题。
也是为了给更多人提供帮助,把我目前调试过的东西跟大家分享一下。
PS,我也是个上位机菜鸟,希望大家多给建议。
http://blog.sina.com.cn/s/blog_6ca5ea9f0101fdv1.html,我是参照这个里面的内容写的。内容很详细,我就不再赘述了。
其中要注意:
1.将OnComm()函数中的
safearray_inp=variant_inp; //VARIANT型变量转换为ColeSafeArray型变量
改为 safearray_inp.Attach(variant_inp);
如果不改的话,会有内存泄露。
2.在一次接收事件结束后,要清缓存。
调用 m_MSComm.put_InBufferCount(0);
如果需要自动寻找串口号,可添加下面2个函数,也是网上别人写的,我稍微改了一下,自己测过可以用。
[mw_shl_code=cpp,true]int m_nComArray[20];
//
///查询注册表的串口号,将值存于数组中
///本代码参考于mingojiang的获取串口逻辑名代码
//
void CxDlg: ueryKey(HKEY hKey)
{
#define MAX_KEY_LENGTH 255
#define MAX_VALUE_NAME 16383
// TCHAR achKey[MAX_KEY_LENGTH]; // buffer for subkey name
// DWORD cbName; // size of name string
TCHAR achClass[MAX_PATH] = TEXT(""); // buffer for class name
DWORD cchClassName = MAX_PATH; // size of class string
DWORD cSubKeys=0; // number of subkeys
DWORD cbMaxSubKey; // longest subkey size
DWORD cchMaxClass; // longest class string
DWORD cValues; // number of values for key
DWORD cchMaxValue; // longest value name
DWORD cbMaxValueData; // longest value data
DWORD cbSecurityDescriptor; // size of security descriptor
FILETIME ftLastWriteTime; // last write time
DWORD i, retCode;
TCHAR achValue[MAX_VALUE_NAME];
DWORD cchValue = MAX_VALUE_NAME;
// Get the class name and the value count.
retCode = RegQueryInfoKey(
hKey, // key handle
achClass, // buffer for class name
&cchClassName, // size of class string
NULL, // reserved
&cSubKeys, // number of subkeys
&cbMaxSubKey, // longest subkey size
&cchMaxClass, // longest class string
&cValues, // number of values for this key
&cchMaxValue, // longest value name
&cbMaxValueData, // longest value data
&cbSecurityDescriptor, // security descriptor
&ftLastWriteTime); // last write time
for (i=0;i<20;i++)///存放串口号的数组初始化
{
m_nComArray = -1;
}
// Enumerate the key values.
if (cValues > 0) {
for (i=0, retCode=ERROR_SUCCESS; i<cValues; i++) {
cchValue = MAX_VALUE_NAME; achValue[0] = '\0';
if (ERROR_SUCCESS == RegEnumValue(hKey, i, achValue, &cchValue, NULL, NULL, NULL, NULL)) {
CString szName(achValue);
if (-1 != szName.Find(_T("Serial")) || -1 != szName.Find(_T("VCom")) ){
BYTE strDSName[10]; memset(strDSName, 0, 10);
DWORD nValueType = 0, nBuffLen = 10;
if (ERROR_SUCCESS == RegQueryValueEx(hKey, (LPCTSTR)achValue, NULL, &nValueType, strDSName, &nBuffLen)){
int nIndex = -1;
while(++nIndex < MaxSerialPortNum){
if (-1 == m_nComArray[nIndex]) {
m_nComArray[nIndex] = atoi((char*)(strDSName + 3));
break;
}
}
}
}
}
}
}
else{
AfxMessageBox(_T("本机没有串口....."));
}
}
void CxDlg::Hkey2ComboBox(CComboBox& m_PortNO)
{
HKEY hTestKey;
bool Flag = FALSE;
///仅是XP系统的注册表位置,其他系统根据实际情况做修改
if(ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE, TEXT("HARDWARE\\DEVICEMAP\\SERIALCOMM"), 0, KEY_READ, &hTestKey) ){
QueryKey(hTestKey);
}
RegCloseKey(hTestKey);
int i=0,x = 0;
int y = 0;
m_PortNO.ResetContent();///刷新时,清空下拉列表内容
int Index = 0;
while(i < MaxSerialPortNum && -1 != m_nComArray){
i++;
}
if(i > 1)
{
int temp;
for (x = 0; x < i - 1; x++)
{
for (y = 0; y < i - 1 - x; y++)
{
if(m_nComArray[y] > m_nComArray[y + 1])
{
temp = m_nComArray[y];
m_nComArray[y] = m_nComArray[y + 1];
m_nComArray[y + 1] = temp;
}
}
}
}
i = 0;
while(i < MaxSerialPortNum && -1 != m_nComArray){
CString szCom;
szCom.Format(_T("COM%d"), m_nComArray);
m_PortNO.InsertString(i, szCom.GetBuffer(5));
++i;
Flag = TRUE;
}
if (Flag)///把第一个发现的串口设为下拉列表的默认值
m_PortNO.SetCurSel(0);
}[/mw_shl_code]
由于现在有很多系统没有自带的Mscomm32.ocx的控件,需要注册,我自己写了一个简单的注册(其实就是复制)。
RegisterMSComm32.cpp文件
[mw_shl_code=cpp,true]#include "stdafx.h"
#include "RegisterMSComm32.h"
CRegisterMSComm32::CRegisterMSComm32(void)
{
}
CRegisterMSComm32::~CRegisterMSComm32(void)
{
}
//注册控件 修改注册表
BOOL CRegisterMSComm32::RegisterMSComm32(void)
{
HKEY key;
if(ERROR_SUCCESS != RegOpenKeyEx(HKEY_VALUE,KEYROAD_FIRST,0,KEY_ALL_ACCESS,&key)) //打开失败 就创建 一级目录是否存在
{
if (ERROR_SUCCESS != RegCreateKey(HKEY_VALUE,KEYROAD_FIRST,&key)) //创建
{
::RegCloseKey(key); //失败就退出
return FALSE;
}
}
if(ERROR_SUCCESS != RegOpenKeyEx(HKEY_VALUE,KEYROAD,0,KEY_ALL_ACCESS,&key))
{
if (ERROR_SUCCESS != RegCreateKey(HKEY_VALUE,KEYROAD,&key)) //创建
{
::RegCloseKey(key);
return FALSE;
}
}
char *szValueName=""; //修改默认键值
char *szValueDate=KEYVALUE;
UINT cbLen=strlen(szValueDate);
if(ERROR_SUCCESS != RegSetValueExA(key,szValueName,0,REG_SZ,(const unsigned char *)szValueDate,cbLen))
{
::RegCloseKey(key);
return FALSE;
}
::RegCloseKey(key);
return TRUE;
}
///目录是否存在的检查:
BOOL CRegisterMSComm32::CheckFolderExist(CString const& strPath)
{
//判断是否存在
if(!PathFileExists(strPath))
return false;
//判断是否为目录
DWORD attributes = ::GetFileAttributes(strPath);
attributes &= FILE_ATTRIBUTE_DIRECTORY;
return attributes == FILE_ATTRIBUTE_DIRECTORY;
}
//复制文件
void CRegisterMSComm32::MyCFileCopy(CString const& CopyFromFile,CString const& CopyToFile)
{
//以只读|二进制的方式打开第一个文件
CFile hFile;
int len;
hFile.Open(CopyFromFile,CFile::modeRead|CFile::typeBinary,0);
len = int(hFile.GetLength());
//分配缓冲区
char *buf;
buf = new char[len+1];
hFile.Read(buf,len); //读文件
hFile.Close();
//--------------------------------------------
if(hFile.Open(CopyToFile,CFile::modeRead|CFile::typeBinary,0)) //打开成功
{
hFile.Close();
delete[] buf; //释放缓冲区
return;
}
//只写|二进制|创建的方式打开第二个文件
hFile.Open(CopyToFile,CFile::modeWrite|CFile::typeBinary|CFile::modeCreate,0);
hFile.Write(buf,len); //写文件
hFile.Close();
delete[] buf; //释放缓冲区
}
void CRegisterMSComm32::CallCmd(void) //调用cmd.exe
{
// ShellExecute(NULL,"open","C:\\Windows\\System32\\cmd.exe","regsvr32 mscomm32.ocx",NULL,SW_MAXIMIZE);
ShellExecute(NULL,"open","cmd.exe","C:\\Windows\\System32",NULL,SW_HIDE);
/*------------cmd 回显----------*/
SECURITY_ATTRIBUTES sa;
HANDLE hRead,hWrite;
sa.nLength = sizeof(SECURITY_ATTRIBUTES);
sa.lpSecurityDescriptor = NULL; //使用系统默认的安全描述符
sa.bInheritHandle = TRUE; //创建的进程继承句柄
if (!CreatePipe(&hRead,&hWrite,&sa,0)) //创建匿名管道
{
AfxMessageBox("CreatePipe Failed!",MB_OK | MB_ICONWARNING);
return;
}
STARTUPINFO si;
PROCESS_INFORMATION pi;
ZeroMemory(&si,sizeof(STARTUPINFO));
si.cb = sizeof(STARTUPINFO);
GetStartupInfo(&si);
si.hStdError = hWrite;
si.hStdOutput = hWrite; //新创建进程的标准输出连在写管道一端
si.wShowWindow = SW_HIDE; //隐藏窗口
si.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES;
char cmdline[200];
CString tmp,stredit2;
//GetDlgItemText(IDC_EDIT_CMD,stredit2); //获取编辑框中输入的命令行
tmp.Format("cmd /C %s","regsvr32 mscomm32.ocx"); //注册控件
sprintf_s(cmdline,"%s",tmp);
if (!CreateProcess(NULL,cmdline,NULL,NULL,TRUE,NULL,NULL,NULL,&si,&pi)) //创建子进程
{
AfxMessageBox("CreateProcess Failed!",MB_OK | MB_ICONWARNING);
return;
}
CloseHandle(hWrite); //关闭管道句柄
char buffer[4096] = {0};
CString strOutput;
DWORD bytesRead;
while (true)
{
if (ReadFile(hRead,buffer,4095,&bytesRead,NULL) == NULL) //读取管道
break;
// strOutput += buffer;
// SetDlgItemText(IDC_EDIT_OUTPUT,strOutput); //显示输出信息到编辑框,并刷新窗口
// UpdateWindow();
Sleep(100);
}
CloseHandle(hRead);
system("taskkill -f -im cmd.exe"); //关闭cmd.exe
}
void CRegisterMSComm32::RegAx(CWnd * cwnd) //注册
{
CString strRoad,strSysRoad;
TCHAR szFilePath[MAX_PATH + 1];
GetModuleFileName(NULL, szFilePath, MAX_PATH); //获得exe执行文件所在路径
(_tcsrchr(szFilePath, _T('\\')))[1] = 0;
strRoad = szFilePath;
strRoad = strRoad + "mscomm32.ocx";
if(CheckFolderExist(SYSTEM_64BIT_ROAD)) //检测是否是64位系统(sysWOW64文件夹是否存在)
{
strSysRoad = SYSTEM_64BIT_ROAD;
strSysRoad += AX_NAME;
MyCFileCopy(strRoad,strSysRoad);
}
strSysRoad = SYSTEM_32BIT_ROAD;
strSysRoad += AX_NAME;
MyCFileCopy(strRoad,strSysRoad);
if(RegisterMSComm32()) //注册控件成功
{
CallCmd();
AfxMessageBox("请点确定关闭,再重新打开软件。");
cwnd-> ostMessage(WM_CLOSE,0,0); //关闭窗口
}
else
{
AfxMessageBox("控件注册失败,请手动操作。");
cwnd-> ostMessage(WM_CLOSE,0,0); //关闭窗口
}
}
[/mw_shl_code]
RegisterMSComm32.h文件
[mw_shl_code=cpp,true]#pragma once
#define HKEY_VALUE HKEY_CLASSES_ROOT
#define KEYROAD_FIRST "Licenses" //第一层路径
#define KEYROAD "Licenses\\4250E830-6AC2-11cf-8ADB-00AA00C00905" //全路径
#define KEYVALUE "kjljvjjjoquqmjjjvpqqkqmqykypoqjquoun" //键值
#define AX_NAME "\\mscomm32.ocx" //AX控件名称
#define SYSTEM_32BIT_ROAD "C:\\Windows\\System32" //32位操作系统路径
#define SYSTEM_64BIT_ROAD "C:\\Windows\\sysWOW64" //64位操作系统路径
class CRegisterMSComm32
{
public:
CRegisterMSComm32(void);
~CRegisterMSComm32(void);
void MyCFileCopy(CString const& CopyFromFile,CString const& CopyToFile);
BOOL CheckFolderExist(CString const& strPath);
BOOL RegisterMSComm32(void);
void CallCmd(void);
void RegAx(CWnd * cwnd);
};[/mw_shl_code]
由于是公司的项目,我就不上传工程文件了。抱歉。希望能对大家有帮助。
|
|