• WinCE应用程序开发进程间通信


     上篇博文介绍了线程间同步,本博文将介绍进程间通信。实现进程间通信的方式有好几种,其中最常用的而且最可靠的是采用内存映射的方式实现这一功能。

    1. 目的:通过内存映射的方式实现进程间通信。

    2. 实现:

    2.1 平台:WinCE + VS2005

    2.2 具体实现过程

    为了叙述的方便,将主应用程序对应的进程称为Host进程,程序称为Host程序;将从应用程序对应的进程称为Target进程,程序称为Target程序。

    2.2.1 Host端

    首先在Host程序的头文件中添加如下自定义消息,注意自定义消息

    /************************************************************************/
    // 用于访问内存映射文件的用户自定义消息

    #define WM_MSG_SEND_COMMAND   WM_USER+111   // 发送消息(命令)给Bottom窗口

    #define WM_MSG_SEND_DATA   WM_USER+112   // 发送消息(数据)给Bottom窗口

    #define WM_MSG_RECEIVE_COMMAND  WM_USER+113   // 接收来自Bottom的消息(命令)

    #define WM_MSG_RECEIVE_DATA   WM_USER+114   // 接收来自Bottom的消息(数据)

    /************************************************************************/

    其次,在Host程序的源文件中添加想要发送到Target程序的消息,比如

    ::SendMessage(m_hTarget, WM_MSG_SEND_COMMAND, (WPARAM)QueryUSBStatus,(LPARAM)0);

    // 参数1表示Target程序对应的窗口句柄,有几种方式可获得窗口的句柄,在本博文小结中,我会给出具体的获取窗口句柄的方法。

    // 参数2表示自定义消息,这个消息就是Target程序要响应的,因此该消息同样要在Target程序的头文件中有定义。

    // 参数3和参数4是用户可灵活使用的,一般用于告诉接受端访问哪段内存区域,告诉用户指针的偏移地址和数据长度,以方便接受端从指定的内存区域取数据。内存映射访问共享数据就用到了这个方法。

    为了方便叙述,给出了Host程序向Target程序发送的部分命令样式。

    /************************************************************************/
    // WinCE发给USB端的命令
    #define  QueryUSBStatus  1         // 0x01
    #define  USBStatusReturn  16         // 0x10表示USB正常,0x12表示USB不正常
    #define  QueryUSBReady  17           // 0x11表示正常,仅用在USBConnectRigth为FALSE的情况下才使用这个命令
    #define  WinCEStatusReturn 32       // 0x20表示WinCE正常,0x22表示WinCE端不正常
    #define  WinCEToUSBStart  33        // 0x21表示WinCE通知USB开始发送数据
    #define  NotifyWinCEGetData 48      // 0x30表示USB通知WinCE取数据
    #define  WinCEToUSBStop  49        // 0x31表示WinCE通知USB停止发送数据
    #define  USBSendDataFinish 64       // 0x40表示USB通知此次测试已经完毕
    #define  SetUSBWndMinimized  65   // 0x41表示WinCE通知USB窗口最小化
    #define  CloseUSB   80                   // 0x50表示WinCE通知USB退出程序
    #define  USBReady   97                  // 0x61表示USB通知WinCE端USB已经准备好
    /************************************************************************/

    2.2.2 Target端

    接受端Target程序有4处需要注意。

    1)在Target的头文件中添加与Host头文件中一样的自定义消息定义,如下所示。

    /************************************************************************/
    // 用于访问内存映射文件的用户自定义消息,这个定义直接来自WinCE程序
    #define WM_MSG_SEND_COMMAND   WM_USER+111  // 发送消息(命令)给Bottom窗口

    #define WM_MSG_SEND_DATA   WM_USER+112  // 发送消息(数据)给Bottom窗口

    #define WM_MSG_RECEIVE_COMMAND  WM_USER+113  // 接收来自Bottom的消息(命令)

    #define WM_MSG_RECEIVE_DATA   WM_USER+114  // 接收来自Bottom的消息(数据)

    #define WM_MSG_ExitWindow   WM_USER+115  // 如果已经有个实例在运行,则直接让之后打开的实例退出
    /************************************************************************/

    2)在Target的源文件中添加自定义消息映射

    BEGIN_MESSAGE_MAP(CTVLFUSBCommunicationDlg, CDialog)

      ON_MESSAGE(WM_MSG_SEND_COMMAND, OnReceiveCommand) // 对于Host是发送命令,对于Target则是接收命令

    END_MESSAGE_MAP()

    3)在Target程序的头文件中添加消息响应函数的定义

    afx_msg LRESULT OnReceiveCommand(WPARAM wParam,LPARAM lParam); // 收到来自Top的命令

    4)完善自定义消息对应的消息响应函数

    LRESULT CTVLFUSBCommunicationDlg::OnReceiveCommand(WPARAM wParam,LPARAM lParam)
    {
       int CommandID  = wParam;
       int usedBufferLen = lParam;

      switch(CommandID)
       {
           case QueryUSBStatus:
           { // 向WinCE返回当前USB的状态
              int USBstatus = 16;
              memset(m_pCommandBuf+sizeof(int), 0 ,sizeof(int));
              memcpy(m_pCommandBuf+sizeof(int), &USBstatus, sizeof(int));
              break;
           }
           case WinCEToUSBStart:
           {
              // 收到WinCE的命令,以及积分次数和每个测点号的数据点个数,然后开始发送数据给WinCE
              memcpy(&IntegrationNumbers, m_pCommandBuf+sizeof(int)*10, sizeof(int));
              memcpy(&DataNumbers, m_pCommandBuf+sizeof(int)*11, sizeof(int)); 
              currentIntegralCount = 0;
              this->SetTimer(1, TimerPeriod, NULL);
              break;
           }
           case WinCEToUSBStop:
           {
              currentIntegralCount = 0;
              this->KillTimer(1);
              break;
           }
           ...........  
       }
     return 0;

    }

    3. 总结:

    3.1 在进程A中使用SendMessage()函数向进程B发送消息,需明确进程B对应的窗口句柄。在进程B源程序中获取窗口句柄的方式有:

    1)hTarget = ::FindWindow(NULL, TargetExeWindowName);    // 其中TargetExeWindowName为CString类型,表示进程B对应的窗口名称

    2)hTarget= AfxGetApp()->GetMainWnd()->m_hWnd;

    3)hTarget= AfxGetMainWnd()->m_hWnd;

    4)hTarget= this->GetSafeHwnd();

    3.2 SendMessage()和PostMessage()发送消息的区别在于发送消息是否立即返回,可根据实际需要权衡利弊选择最适合项目程序的发送消息方式。

    3.3 文中只介绍了发送命令接受命令的方法,发送数据和接受数据的方法与其类似,不再赘述,区别仅在于发送数据时传递了2个参数,1个参数是指针的起始偏移地址,1个参数是数据长度。

    注:转载请注明出处http://www.cnblogs.com/zaishuiyifang006 人生如棋,我愿为卒,行动虽缓,可谁见我后退一步。
  • 相关阅读:
    输入框联想
    SyntaxError: missing ; before statement 错误的解决
    Oracle数据库DECODE函数的使用.
    MySQL ----命令总结!
    个介!
    递归函数
    闭包函数与装饰器
    函数对象
    力扣题
    函数基础
  • 原文地址:https://www.cnblogs.com/zaishuiyifang006/p/2732573.html
Copyright © 2020-2023  润新知