MFC程序中怎么定义CAN卡的端口

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了MFC程序中怎么定义CAN卡的端口相关的知识,希望对你有一定的参考价值。

参考技术A void CCOMMUNICATIONSet::OnBtnStartcan() //“启动CAN”按钮

// TODO: Add
your control notification handler code here

if(m_connect==1) //如果已经连接


m_connect=0;
m_startcanlight.SetIcon(m_hIConGrey1);
Sleep(500);
GetDlgItem(IDC_EDIT_BTR)->EnableWindow(!m_connect);
GetDlgItem(IDC_EDIT_STARTID)->EnableWindow(!m_connect);
GetDlgItem(IDC_EDIT_ENDID)->EnableWindow(!m_connect);
GetDlgItem(IDC_COMBO_BAUD)->EnableWindow(!m_connect);
GetDlgItem(IDC_COMBO_FILTER)->EnableWindow(!m_connect);
GetDlgItem(IDC_COMBO_MODE)->EnableWindow(!m_connect);
OnSelchangeComboBaud();
OnSelchangeComboFilter();
GetDlgItem(IDC_BTN_STARTCAN)->SetWindowText("启动CAN");
VCI_ResetCAN(m_devtype,m_devind,m_cannum);
VCI_CloseDevice(m_devtype,m_devind);//
此函数用以关闭设备。
return;


//如果未连接
VCI_INIT_CONFIG
init_config;//定义初始化CAN的数据类型的结构体
int index,mode,cannum,baud;

UpdateData(true);//控件的值->变量

index=m_ComboIndex.GetCurSel();//设备索引号

mode=m_ComboMode.GetCurSel();//工作模式

cannum=m_ComboCANInd.GetCurSel();//第几路CAN
sscanf(m_strBTR, _T("%x"),
&baud);
m_devind=index;//设备类型

m_cannum=cannum;//第几路CAN

UpdateData(false);//变量值->控件显示

init_config.Mode=mode;//模式

//滤波设置
DWORD
filterMode=m_ComboFilterMode.GetCurSel();//"滤波模式"
if
(filterMode!=2)

VCI_FILTER_RECORD filterRecord;

filterRecord.ExtFrame=filterMode;
UpdateData(TRUE);//控件的值->变量
DWORD
IDtemp;
IDtemp=atoi(m_strStartID);//"滤波范围起始帧ID"字符转换为整形
//_stscanf_s(m_strStartID,
_T("%d"), &IDtemp);
filterRecord.Start =
IDtemp;//Start:滤波范围的起始帧ID
IDtemp=atoi(m_strEndID);//"滤波范围结束帧ID"字符转换为整形
//_stscanf_s(m_strEndID,
_T("%d"), &IDtemp);
filterRecord.End=
IDtemp;//End:滤波范围的结束帧ID
VCI_SetReference(m_devtype, m_devind,
cannum, 1, &filterRecord);//
设置报文滤波。为1表示操作成功,0表示操作失败
//使滤波表格生效
if
(VCI_SetReference(m_devtype, m_devind, cannum, 2,
NULL)!=STATUS_OK)//参数类型为2????????????????????

MessageBox(_T("设置滤波失败!"),
_T("警告"), MB_OK |
MB_ICONQUESTION);
VCI_CloseDevice(m_devtype,index);
return;




m_connect=1;

GetDlgItem(IDC_EDIT_BTR)->EnableWindow(!m_connect);//不激活"自定义波特率寄存器"编辑框

GetDlgItem(IDC_EDIT_STARTID)->EnableWindow(!m_connect);//不激活"滤波范围起始帧ID"编辑框

GetDlgItem(IDC_EDIT_ENDID)->EnableWindow(!m_connect);//不激活"滤波范围结束帧ID"编辑框

GetDlgItem(IDC_COMBO_BAUD)->EnableWindow(!m_connect);//不激活"波特率"组合框

GetDlgItem(IDC_COMBO_FILTER)->EnableWindow(!m_connect);//不激活"滤波模式"组合框

GetDlgItem(IDC_COMBO_MODE)->EnableWindow(!m_connect);//不激活"工作模式"组合框

GetDlgItem(IDC_BTN_STARTCAN)->SetWindowText("关闭CAN");//改变控件的文本内容

m_startcanlight.SetIcon(m_hIConGreen1);

VCI_StartCAN(m_devtype,m_devind,m_cannum);
AfxBeginThread(ReceiveThread,this);//启动线程,ReceiveThread为线程函数

//Sleep(8000);


UINT
CCOMMUNICATIONSet::ReceiveThread(void *param)//接收CAN报文 线程函数的定义


CCOMMUNICATIONSet *dlg=(CCOMMUNICATIONSet*)param;
CListBox *box=(CListBox
*)dlg->GetDlgItem(IDC_LIST_INFO);
VCI_CAN_OBJ
frameinfo[50];//定义CAN信息帧数据类型的结构体
VCI_ERR_INFO
errinfo;//定义错误信息数据类型的结构体
int len=1;
int i=0;
CString
str,tmpstr;
while(1)

Sleep(1);
if(dlg->m_connect==0)//未连接
break;
len=VCI_Receive(dlg->m_devtype,dlg->m_devind,dlg->m_cannum,frameinfo,50,200);//从指定的设备读取数据
if(len<=0)//没有读到数据

VCI_ReadErrInfo(dlg->m_devtype,dlg->m_devind,dlg->m_cannum,&errinfo);//获取最后一次错误信息

else//读到数据

for(i=0;i<len;i++)


str="接收到数据帧: ";

if(frameinfo[i].TimeFlag==0)//无时间标识
tmpstr="时间标识:无 ";

else
tmpstr.Format("时间标识:%08x
",frameinfo[i].TimeStamp);

str+=tmpstr;//接收到信息帧时的时间标识

tmpstr.Format("帧ID:%08x
",frameinfo[i].ID);
str+=tmpstr;//报文ID

str+="帧格式:";

if(frameinfo[i].RemoteFlag==0)
tmpstr="数据帧
";
else
tmpstr="远程帧
";
str+=tmpstr;

str+="帧类型:";

if(frameinfo[i].ExternFlag==0)
tmpstr="标准帧
";
else
tmpstr="扩展帧
";
str+=tmpstr;

box->InsertString(box->GetCount(),str);//插入字符串

if(frameinfo[i].RemoteFlag==0)//不是远程帧?


str="数据:";
if(frameinfo[i].DataLen>8)
frameinfo[i].DataLen=8;
for(int
j=0;j<frameinfo[i].DataLen;j++)

tmpstr.Format("%02x
",frameinfo[i].Data[j]);
str+=tmpstr;

//EnterCriticalSection(&(dlg->m_Section));//获得指定的临界区对象的所有权
//LeaveCriticalSection(&(dlg->m_Section));//释放指定的临界区对象的所有权
box->InsertString(box->GetCount(),str);


CNaS_BMSDlg *m_Host =
(CNaS_BMSDlg*)AfxGetMainWnd();//获取主界面的指针

if(frameinfo[7].Data[2]!=1)

m_Host->xxx->m_page1.SendMessage(UM_ALARM,0,0);


box->SetCurSel(box->GetCount()-1);//box->GetCount():返回列表框中的字符串数目



return 0;

如何从MFC选项卡控件(TabCtrl)获取额外数据?

我创建了一个基于MFC对话框的应用程序来研究选项卡控件。在选项卡控件中,可以将应用程序特定数据设置到每个选项卡。我试图了解如何设置/检索选项卡控件的各个选项卡的数据。

这是我正在创建的示例应用程序。控件的每个选项卡都应该存储一些GPU信息。

Tab Control

据我了解,添加应用程序特定数据有3个步骤。

  1. 创建用户定义的结构,其第一个成员应为TCITEMHEADER类型。 struct GPU { std::wstring name; int busid; }; struct tabData { TCITEMHEADER tabItemHeader; GPU gpu; };
  2. 告诉tab控件有关额外的字节,用户定义的结构将采取。这是我在DoDataExchange()做的。 int extraBytes = sizeof(tabData) - sizeof(TCITEMHEADER); auto status = tabCtrl1.SetItemExtra(extraBytes);
  3. 添加选项卡时设置用户定义的数据。 static int tabCtr = 0; tabData td; td.tabItemHeader.pszText = _T("TabX"); td.tabItemHeader.mask = TCIF_TEXT; td.gpu.name = L"AMD NVIDIA"; td.gpu.busid = 101; TabCtrl_InsertItem(tabCtrl1.GetSafeHwnd(), tabCtr, &td);

现在要获取数据,我们只需要调用TabCtrl_GetItem()

tabData td2;
td2.tabItemHeader.pszText = new TCHAR[20];
td2.tabItemHeader.cchTextMax = 20;

td2.tabItemHeader.mask = TCIF_TEXT;

td2.gpu.busid = 0;

TabCtrl_GetItem(tabCtrl1.GetSafeHwnd(), 0, &td2);

但正如我们在下图中看到的那样。我确实得到了标签文本(pszText成员 - 图像中的数据项1),但没有得到我之前与之关联的额外数据(图像中的数据项2和3)。

Tab Control get Item

我错过了哪一步? 为什么与应用程序定义的数据相关联的结构未填充?

附加信息

这是应用程序的完整代码。

CPP文件:

// tabCtrlStackOverflowDlg.cpp : implementation file
//

#include "stdafx.h"
#include "tabCtrlStackOverflow.h"
#include "tabCtrlStackOverflowDlg.h"
#include "afxdialogex.h"
#include <string>

#ifdef _DEBUG
#define new DEBUG_NEW
#endif


struct GPU {
    std::wstring name;
    int busid;
};

struct tabData
{
    TCITEMHEADER tabItemHeader;
    GPU gpu;
};



CtabCtrlStackOverflowDlg::CtabCtrlStackOverflowDlg(CWnd* pParent /*=NULL*/)
  : CDialogEx(IDD_TABCTRLSTACKOVERFLOW_DIALOG, pParent)
{
  m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}

void CtabCtrlStackOverflowDlg::DoDataExchange(CDataExchange* pDX)
{
    CDialogEx::DoDataExchange(pDX);
    DDX_Control(pDX, IDC_TAB1, tabCtrl1);

    int extraBytes = sizeof(tabData) - sizeof(TCITEMHEADER);

    auto status = tabCtrl1.SetItemExtra(extraBytes);

    wchar_t *t = status ? L"SetItemExtra() success" : L"SetItemExtra() fail";

    GetDlgItem(IDC_STATUSTEXT)->SetWindowTextW(t);
}

BEGIN_MESSAGE_MAP(CtabCtrlStackOverflowDlg, CDialogEx)
  ON_WM_PAINT()
  ON_WM_QUERYDRAGICON()
    ON_BN_CLICKED(IDADDTAB, &CtabCtrlStackOverflowDlg::OnBnClickedAddtab)
    ON_BN_CLICKED(IDC_GETITEM0, &CtabCtrlStackOverflowDlg::OnBnClickedGetitem0)
    ON_BN_CLICKED(IDCLOSE, &CtabCtrlStackOverflowDlg::OnBnClickedClose)
END_MESSAGE_MAP()


// CtabCtrlStackOverflowDlg message handlers

BOOL CtabCtrlStackOverflowDlg::OnInitDialog()
{
  CDialogEx::OnInitDialog();

  // Set the icon for this dialog.  The framework does this automatically
  //  when the application's main window is not a dialog
  SetIcon(m_hIcon, TRUE);         // Set big icon
  SetIcon(m_hIcon, FALSE);        // Set small icon

  // TODO: Add extra initialization here

  return TRUE;  // return TRUE  unless you set the focus to a control
}

// If you add a minimize button to your dialog, you will need the code below
//  to draw the icon.  For MFC applications using the document/view model,
//  this is automatically done for you by the framework.

void CtabCtrlStackOverflowDlg::OnPaint()
{
  if (IsIconic())
  {
      CPaintDC dc(this); // device context for painting

      SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);

      // Center icon in client rectangle
      int cxIcon = GetSystemMetrics(SM_CXICON);
      int cyIcon = GetSystemMetrics(SM_CYICON);
      CRect rect;
      GetClientRect(&rect);
      int x = (rect.Width() - cxIcon + 1) / 2;
      int y = (rect.Height() - cyIcon + 1) / 2;

      // Draw the icon
      dc.DrawIcon(x, y, m_hIcon);
  }
  else
  {
      CDialogEx::OnPaint();
  }
}

// The system calls this function to obtain the cursor to display while the user drags
//  the minimized window.
HCURSOR CtabCtrlStackOverflowDlg::OnQueryDragIcon()
{
  return static_cast<HCURSOR>(m_hIcon);
}



void CtabCtrlStackOverflowDlg::OnBnClickedAddtab()
{
    static int tabCtr = 0;
    tabData td;
    td.tabItemHeader.pszText = _T("TabX");
    td.tabItemHeader.mask = TCIF_TEXT;

    td.gpu.name = L"AMD NVIDIA";
    td.gpu.busid = 101;

    int status = TabCtrl_InsertItem(tabCtrl1.GetSafeHwnd(), tabCtr, &td);

    wchar_t *t = L"";

    if (status == -1)
    {
        t = L"TabCtrl_InsertItem() Fail";
    }
    else
    {
        t = L"TabCtrl_InsertItem() success";
    }

    GetDlgItem(IDC_STATUSTEXT)->SetWindowTextW(t);
    tabCtr++;
}


void CtabCtrlStackOverflowDlg::OnBnClickedGetitem0()
{
    tabData td2;
    td2.tabItemHeader.pszText = new TCHAR[20];
    td2.tabItemHeader.cchTextMax = 20;

    td2.tabItemHeader.mask = TCIF_TEXT;

    td2.gpu.busid = 0;

    if (TabCtrl_GetItem(tabCtrl1.GetSafeHwnd(), 0, &td2) == TRUE)
    {
        std::wstring text = td2.tabItemHeader.pszText;
        text += std::wstring(L" ") + td2.gpu.name;
        GetDlgItem(IDC_STATUSTEXT)->SetWindowTextW(text.c_str());
    }
    else
    {
        GetDlgItem(IDC_STATUSTEXT)->SetWindowTextW(_T("TabCtrl_GetItem()
error"));
    }
}


void CtabCtrlStackOverflowDlg::OnBnClickedClose()
{
    CDialog::OnCancel();
}

头文件:

// tabCtrlStackOverflowDlg.h : header file
//

#pragma once
#include "afxcmn.h"


// CtabCtrlStackOverflowDlg dialog
class CtabCtrlStackOverflowDlg : public CDialogEx
{
// Construction
public:
  CtabCtrlStackOverflowDlg(CWnd* pParent = NULL); // standard constructor

// Dialog Data
#ifdef AFX_DESIGN_TIME
  enum { IDD = IDD_TABCTRLSTACKOVERFLOW_DIALOG };
#endif

  protected:
  virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support


// Implementation
protected:
  HICON m_hIcon;

  // Generated message map functions
  virtual BOOL OnInitDialog();
  afx_msg void OnPaint();
  afx_msg HCURSOR OnQueryDragIcon();
  DECLARE_MESSAGE_MAP()
public:
    CTabCtrl tabCtrl1;
    afx_msg void OnBnClickedAddtab();
    afx_msg void OnBnClickedGetitem0();
    afx_msg void OnBnClickedClose();
};

解决方案摘要

Barmak Shemirani's answer这里是我的代码不起作用的3个原因。必须阅读他的答案以便更好地理解。

  1. TCIF_PARAM必须设置为面具,同时做TCM_INSERTITEMTCM_GETITEM
  2. 我正在使用在堆栈上创建的局部变量(tabData td2; object)。一旦超出范围,对该变量的引用就变得无效。
  3. 在用于TCM_INSERTITEM的结构中使用std :: wstring。最好使用可以准确确定大小的数据类型(如普通的旧数据类型)。

正如Barmak Shemirani在评论中指出的那样,TCITEMHEADER的文档很少。他的回答提供了彻底的解释。

答案

与文档冲突

qazxsw poi的文档没有提到使用qazxsw poi flag。也许这是文档中的错误!


如果在调用默认程序后将TCITEMHEADER移动到TCIF_PARAM,那会更好。这可以确保在控件为空时只调用一次SetItemExtra

结构OnInitDialog有一个SetItemExtra成员,其数据大小在开始时是未知的。除非您有简单的POD结构,否则GPU无法复制此数据。

要在选项卡中存储数据,请将std::wstring替换为TCM_INSERTITEM,以便数据是具有固定大小的简单POD结构。

std::wstring


Alternative method:

如果wchar_t name[100]不能用struct GPU { //std::wstring name; wchar_t name[100]; int busid; }; struct tabData { TCITEMHEADER tabItemHeader; GPU gpu; }; void CMyDialog::OnBnClickedAddtab() { int index = tab.GetItemCount(); wchar_t tabname[50]; wsprintf(tabname, L"Tab %d", index); tabData sdata = { 0 }; sdata.tabItemHeader.mask = TCIF_TEXT | TCIF_PARAM; sdata.tabItemHeader.pszText = tabname; wsprintf(sdata.gpu.name, L"AMD NVIDIA %d", index); sdata.gpu.busid = 101; tab.SendMessage(TCM_INSERTITEM, index, (LPARAM)(TCITEMHEADER*)(&sdata)); } void CMyDialog::OnBnClickedGetitem0() { int index = tab.GetCurSel(); tabData data = { 0 }; wchar_t buf[20] = { 0 }; data.tabItemHeader.pszText = buf; data.tabItemHeader.cchTextMax = sizeof(buf)/sizeof(wchar_t); data.tabItemHeader.mask = TCIF_TEXT | TCIF_PARAM; if(tab.SendMessage(TCM_GETITEM, index, (LPARAM)(TCITEMHEADER*)(&data))) { CString str; str.Format(L"%d %s", data.gpu.busid, data.gpu.name); GetDlgItem(IDC_STATIC1)->SetWindowText(str); } } 缓冲区替换,我们必须定义一个单独的永久数据,例如使用std::wstring name;。然后我们使用wchar_t中的std::vector值指向向量。

这种方法只需要标准的4个字节的lParam,它不需要TCITEMlParam。你甚至可以定义TCITEMHEADER。例:

SetItemExtra

以上是关于MFC程序中怎么定义CAN卡的端口的主要内容,如果未能解决你的问题,请参考以下文章

全局变量怎么定义

mfc中,"MyApp theApp"起啥作用?

基于VC/MFC 的UDP广播,我怎么接受返回的数据包

如何从MFC选项卡控件(TabCtrl)获取额外数据?

使 MFC CTabCtrl 不使用绘图选项卡的完整控件宽度

用vs2008做的MFC程序,怎么在WINDOWS XP下运行?