-
问题
error C2664: "BuildCommDCBW": 不能将参数 1 从"char *"转换为"LPCWSTR"经常出现这样的错误?
对于上面的错误,主要是字符编码设置的问题,修改下面的选项即可:
http://bbs.csdn.net/topics/310076558 这篇帖子里面有解决方案.
不能想当然的,就做强制转换,不然可能会出错。下面的做法是错误的。
正确的解决方案:
类似下面这种:
当我们将上面的改为 支持多字符集的时候,我们需要将下面的 OpenEventW (xxxx) 改为:
-
MFC当中创建线程
参考文档: http://www.cnblogs.com/mx113/archive/2009/12/03/1616445.html 使用MFC中的AfxBeginThread创建多线程
用户界面线程和工作线程区别:继承主用户界面进程。
error C2248: "CObject::operator =": 无法访问 private 成员(在"CObject"类中声明)
参考资料: http://blog.csdn.net/cxf7394373/article/details/12389507 这种对控件操作的对象最好都声明成指针
多线程中,数据传递:通过消息机制实现。
下面这个解释和android当中控件必须在子线程当中的解释几乎一致。
不要在线程函数体内操作MFC控件,因为每个线程都有自己的线程模块状态映射表,在一个线程中操作另一个线程中创建的MFC对象,会带来意想不到的问题。更不要在线程函数里,直接调用UpdataData()函数更新用户界面,这会导致程序直接crash。而应该通过发送消息给主线程的方式,在主线程的消息响应函数里操作控件。
不过,我们虽然不能对控件进行操作,但是我们还是可以操作主界面的。
我们完全可以通过获取 AfxGetApp() -> m_pMainWnd -> GetDC(); 来与主窗体进行联系。
但是如何联系里面的控件? 目前还没有好的方法。不过,我觉得肯定是有方法的。
-
如何对MFC当中的EDIT控件进行操作。
这里我们需要通过EDIT控件的ID进行操作。通过其ID我们可以得到很多东西。
参考文章:http://blog.csdn.net/jiayanhui2877/article/details/7589756 MFC Edit控件操作
-
字节,字节,字节
一定要控制好,昨天闲来没事,改了一个字节,把 unsigned short 改为 unsigned int .折腾好久才搞定。后来,竟然是我自己程序出错。我也是无语了。
-
写了一个简单的界面显示:
左边是C++版本,真是丑。右边是C#版本。
遇到的问题颇多,下面说说整体结构。
程序在主线程,也就是 下面这个地方进行开辟2个新的线程进行数据处理:
上面的代码涉及到 EDIT控件的设置问题,我们可以联想到android当中eidtview的设置问题,其实还是蛮像的。
当我们在子线程中,想要获取到主线程的东西的话,比较麻烦,可以通过得到其上下文的方式来进行操作。
如上图的代码就是这样一回事。
当然,这里就涉及到数据通讯的问题。以及数据共享的问题。
还有就是主线程一般是用户界面线程,它有消息循环队列,而我们创建的工作线程中没有这种工作机制。
所以,一般我们想要更新主线程当中的控件的时候,我们一般通过消息队列去通知主线程,然后让主线程去绘制窗体。
毕竟,我们执行程序的时候,所有的东西都是"被实例化的"
继续接上面的开了两个线程之后,怎么办?
线程1:
虚拟总线初始化,等待用户输入,输入0K之后,我们进入到数据采集部分。
还有就是m_run 是由主线程提供的。
线程2:处理线程
处理线程,专门处理子线程1当中采集到的数据,这里我们用了循环数组来进行线程间的通讯。采集完之后,我们直接显示即可。
在用画笔绘制图形的过程中,我想强调一点,适当的sleep是必须的,因为绘制需要时间,不然上一个图形还没绘制完,新图形又过来了,
这样会造成界面的卡顿十分严重。
两个主要的程序代码:
Dlg.h
- // DatasShowDlg.h : 头文件
- //
- #pragma once
- #include "afxwin.h"
- #include "VirtualSwitchPlus.h"
- DWORD WINAPI DealThread(LPVOID pParam);
- DWORD WINAPI ReceiverThread(LPVOID pParam);
- extern char szbuffer[10][arrayBytes];
- extern int recvcount;
- extern bool m_run;
- extern CRect* pictureWH;
- extern string msgLable;
- extern string busNum;
- typedef struct Point //点转换为矩阵的x与y坐标。
- {
- unsigned short x;
- unsigned short y;
- unsigned char value;
- unsigned char U;
- } Point;
- typedef struct Matrix //稀疏矩阵数据结构
- {
- int Num;
- Point point[3000];
- } Matrix;
- static const int PointLength = 6; //一个point点的长度
- static const int startoffset = 4; //头字节的长度
- void DrawPoints(Matrix *marix,LPVOID pParam);
- // CDatasShowDlg 对话框
- class CDatasShowDlg : public CDialogEx
- {
- // 构造
- public:
- CDatasShowDlg(CWnd* pParent = NULL); // 标准构造函数
- // 对话框数据
- enum { IDD = IDD_DATASSHOW_DIALOG };
- protected:
- virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持
- // 实现
- protected:
- HICON m_hIcon;
- // 生成的消息映射函数
- virtual BOOL OnInitDialog();
- afx_msg void OnPaint();
- afx_msg HCURSOR OnQueryDragIcon();
- DECLARE_MESSAGE_MAP()
- public:
- CButton m_show;
- CEdit m_msgLable;
- CEdit m_busNum;
- afx_msg void OnBnClickedOk();
- CString m_msgLabelNum;
- CString m_busNumValue;
- };
Dlg.cpp
- // DatasShowDlg.cpp : 实现文件
- //
- #include "stdafx.h"
- #include "DatasShow.h"
- #include "DatasShowDlg.h"
- #include "afxdialogex.h"
- #ifdef _DEBUG
- #define new DEBUG_NEW
- #endif
- // CDatasShowDlg 对话框
- char szbuffer[10][arrayBytes];
- int recvcount;
- bool m_run;
- CRect* pictureWH = new CRect();
- string msgLable;
- string busNum;
- CDatasShowDlg::CDatasShowDlg(CWnd* pParent /*=NULL*/)
- : CDialogEx(CDatasShowDlg::IDD, pParent)
- , m_msgLabelNum(_T(""))
- , m_busNumValue(_T(""))
- {
- m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
- }
- void CDatasShowDlg::DoDataExchange(CDataExchange* pDX)
- {
- CDialogEx::DoDataExchange(pDX);
- DDX_Control(pDX, IDOK, m_show);
- DDX_Control(pDX, IDC_EDIT1, m_msgLable);
- DDX_Control(pDX, IDC_EDIT2, m_busNum);
- //DDX_Control(pDX, IDC_PICTURE, m_picture);
- DDX_Text(pDX, IDC_EDIT1, m_msgLabelNum);
- DDX_Text(pDX, IDC_EDIT2, m_busNumValue);
- }
- BEGIN_MESSAGE_MAP(CDatasShowDlg, CDialogEx)
- ON_WM_PAINT()
- ON_WM_QUERYDRAGICON()
- ON_BN_CLICKED(IDOK, &CDatasShowDlg::OnBnClickedOk)
- END_MESSAGE_MAP()
- // CDatasShowDlg 消息处理程序
- BOOL CDatasShowDlg::OnInitDialog()
- {
- CDialogEx::OnInitDialog();
- // 设置此对话框的图标。当应用程序主窗口不是对话框时,框架将自动
- // 执行此操作
- SetIcon(m_hIcon, TRUE); // 设置大图标
- SetIcon(m_hIcon, FALSE); // 设置小图标
- // TODO: 在此添加额外的初始化代码
- m_run = false;
- recvcount = 0;
- CRect rect;
- /*m_picture.GetWindowRect(rect);*/
- /*pictureWH = ▭ 下面的参数没什么卵用*/
- AfxBeginThread((AFX_THREADPROC)DealThread,(LPVOID)GetSafeHwnd(),THREAD_BASE_PRIORITY_IDLE);
- AfxBeginThread((AFX_THREADPROC)ReceiverThread,NULL,THREAD_BASE_PRIORITY_IDLE);
- //对edit控件赋值
- /*char label[20] = {0};
- char busnum[20] = {0};*/
- SetDlgItemText(IDC_EDIT1,"Path_GPS");
- SetDlgItemText(IDC_EDIT2,"");
- return TRUE; // 除非将焦点设置到控件,否则返回 TRUE
- }
- // 如果向对话框添加最小化按钮,则需要下面的代码
- // 来绘制该图标。对于使用文档/视图模型的 MFC 应用程序,
- // 这将由框架自动完成。
- DWORD WINAPI DealThread(LPVOID pParam)
- {
- //CRect* rect = (CRect*)pParam;
- while(1)
- {
- if (m_run)
- {
- unsigned char str1[arrayBytes] = {0}; //获取数据
- //开辟两个无符号类型,这里是加了锁机制处理,string 默认并不是无符号类型
- for (int i = 0; i < arrayBytes; ++i)
- {
- str1[i] = szbuffer[(recvcount-1+10)%10][i];
- }
- Matrix *matrixH = new Matrix(); //记得释放
- memset(matrixH,0,sizeof(Matrix));
- matrixH->Num = str1[3]*16*16*16*16*16*16*16*16 + str1[2]*16*16*16*16 + str1[1]*16*16 + str1[0];
- int obs1 = 0;
- for (int i = 0; i < matrixH->Num; ++i)
- {
- matrixH->point[obs1].x = str1[startoffset + 1 + i*PointLength]*16*16 + str1[startoffset + 0 + i*PointLength];
- matrixH->point[obs1].y = str1[startoffset + 3 + i*PointLength]*16*16 + str1[startoffset + 2 + i*PointLength];
- matrixH->point[obs1].value = str1[startoffset + 4 + i*PointLength];
- //matrixH->point[obs1].value = 50;
- matrixH->point[obs1].U = str1[startoffset + 5 + i*PointLength];
- obs1++; //注意清零
- }
- DrawPoints(matrixH,pParam);
- delete matrixH;
- }//end if
- else
- {
- Sleep(1);
- }
- }
- return 0;
- }
- void DrawPoints(Matrix *marix,LPVOID pParam)
- {
- //HWND hWnd = (HWND)pParam;
- CRect rect;
- AfxGetApp()->m_pMainWnd->GetWindowRect(rect);
- int PicW = rect.Width();
- int PicH = rect.Height() - 145;
- //曲线轮廓显示
- //以下是画在主线程中,我们需要画在picture控件中
- CDC* pDC = AfxGetApp()->m_pMainWnd->GetDC(); //通过GetDc()获取的HDC直接与相关设备沟通, CDC* pDC = picture.GetDC();
- CDC memDC;
- CBitmap bmp; //本函数创建的DC,则是与内存中的一个表,面相关联。
- memDC.CreateCompatibleDC(pDC); //该函数创建一个与指定设备兼容的内存设备上下文环境(DC)。
- bmp.CreateCompatibleBitmap( pDC, PicW, PicH); //该函数创建与指定的设备环境相关的设备兼容的位图
- memDC.SelectObject(bmp); //该函数选择一对象到指定的设备上下文环境中,该新对象替换先前的相同类型的对象
- memDC.SelectStockObject(WHITE_BRUSH);//该语句把终端字体选入设备环境
- memDC.SelectStockObject(WHITE_PEN);
- pDC->SelectStockObject(WHITE_BRUSH);
- pDC->SelectStockObject(WHITE_PEN);
- int yGap = 10;
- memDC.Ellipse( PicW/2-5, PicH-yGap-5, PicW/2+5, PicH-yGap+5); //小圆形,用来标识雷达
- int n = 0;
- int m = 0;
- for (int i = 0; i < marix->Num; ++i)
- {
- n = marix->point[i].x;
- m = marix->point[i].y;
- if ((n > 0 && n < 350) && (m > 0 && m < 100))
- {
- n = n * PicH / 400;
- m = m * PicW / 100;
- memDC.SetPixel(m, n,RGB(255,255,255));
- //memDC.Ellipse( m-5, n-yGap-5, m+5, n-yGap+5); //小圆形,用来标识雷达
- }
- }
- pDC->StretchBlt(0,0,PicH,PicH,&memDC,0,0,PicH,PicH,SRCCOPY); //函数从源矩形中复制一个位图到目标矩形
- bmp.DeleteObject(); //必要时按目标设备设置的模式进行图像的拉伸或压缩
- /*目标区域左上角点的x坐标
- 目标区域左上角点的y坐标
- 目标区域的宽度
- 目标区域的高度
- 源贴图区域DC的指针
- 源贴图区域x坐标
- 源贴图区域y坐标
- 像素直接拷贝模式*/
- memDC.DeleteDC();
- AfxGetApp()->m_pMainWnd->ReleaseDC(pDC);
- Sleep(50);
- }
- DWORD WINAPI ReceiverThread(LPVOID pParam)
- {
- VirtualSwitchPlusRecv *vspR;
- while(1) //等待用户输入
- {
- if (m_run)
- {
- int BUSNUM = busNum[0] - '0';
- vspR = new VirtualSwitchPlusRecv(BUSNUM);
- break;
- }
- else
- {
- Sleep(1);
- }
- }
- while (true)
- {
- vspR->SubMsg(msgLable); //数据必须这样接收,每次判断一次
- for (int i = 0; i < 3000; ++i)
- {
- szbuffer[recvcount][i] = vspR->szbuffer[i];
- }
- int nRet = vspR->nRet;
- if (nRet == SOCKET_ERROR)
- {
- cout << "Path_GPS not receive!" << endl;
- }
- if(nRet > 0) //主程序需要循环检测
- {
- cout << "flag0: "<<recvcount<<endl;
- recvcount = (recvcount + 1) % 10;
- }else{
- recvcount = 0;
- }
- }
- delete vspR;
- }
- void CDatasShowDlg::OnPaint()
- {
- if (IsIconic())
- {
- CPaintDC dc(this); // 用于绘制的设备上下文
- SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);
- // 使图标在工作区矩形中居中
- 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;
- // 绘制图标
- dc.DrawIcon(x, y, m_hIcon);
- }
- else
- {
- CDialogEx::OnPaint();
- }
- }
- //当用户拖动最小化窗口时系统调用此函数取得光标
- //显示。
- HCURSOR CDatasShowDlg::OnQueryDragIcon()
- {
- return static_cast<HCURSOR>(m_hIcon);
- }
- void CDatasShowDlg::OnBnClickedOk()
- {
- // TODO: 在此添加控件通知处理程序代码
- if (!m_run){
- m_show.SetWindowText(_T("暂停"));
- m_run = true;
- char label[20] = {0};
- char busnum[20] = {0};
- GetDlgItemText(IDC_EDIT1,label,20);
- GetDlgItemText(IDC_EDIT2,busnum,20);
- busNum = busnum[0];
- for (int i = 0; i < 20; ++i)
- {
- if (label[i] != 0)
- {
- msgLable += label[i];
- }
- }
- }else{
- m_show.SetWindowText(_T("显示"));
- m_run = false;
- }
- }
-
MFC 的生存周期
参考资料:
http://blog.csdn.net/lesky/article/details/2470907 MFC应用程序的初始化过程
构造全局对象CWinApp è 调用WINMain中的AfxGetAPP
得到全局对象的pApp,然后调用 initInstance,并在里面完成注册,显示窗体。然后执行消息循环。
关于Mfc的好的帖子,值得一看: http://blog.csdn.net/lesky/article/details/2471039 MFC要点概括