OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 7385|回复: 3

VC+MScomm32控件制作串口通讯工具(VS2012平台)

[复制链接]

5

主题

105

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
419
金钱
419
注册时间
2015-9-16
在线时间
122 小时
发表于 2016-5-24 15:06:06 | 显示全部楼层 |阅读模式
之前在本板块发过一个关于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]

由于是公司的项目,我就不上传工程文件了。抱歉。希望能对大家有帮助。

正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

1

主题

232

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
2866
金钱
2866
注册时间
2018-1-24
在线时间
256 小时
发表于 2018-11-14 15:40:59 | 显示全部楼层
m_mscomm_uart.put_InBufferCount(0);
                        //strtemp.Empty();
                        variant_inp = m_mscomm_uart.get_Input(); //读缓冲区  
                        //AfxMessageBox(_T("为什么不执行了!!!!"));

楼主,我真心想请教一下你,为什么我换成PL2303串口接收时一到get_Input()这里就不往下执行了,接收有数据就是没法显示,而用CH340的就可以,请你帮我回答一下
回复 支持 反对

使用道具 举报

1

主题

232

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
2866
金钱
2866
注册时间
2018-1-24
在线时间
256 小时
发表于 2018-11-15 11:33:25 | 显示全部楼层
另外我看也有用CSerial Port类实现的,有没有这个类的正确下载途径,麻烦上传一份,谢谢
回复 支持 反对

使用道具 举报

0

主题

2

帖子

0

精华

新手入门

积分
5
金钱
5
注册时间
2019-5-16
在线时间
0 小时
发表于 2019-9-28 11:51:06 | 显示全部楼层
你好,请问MSCOMM32控件怎么添加呢
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则



关闭

原子哥极力推荐上一条 /2 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2024-5-29 03:32

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

快速回复 返回顶部 返回列表