zoukankan      html  css  js  c++  java
  • WinCE5.0移动平台开发笔记(OpenNETCF.Desktop.Communication连接和断开使用心得)

        当用PC机读取和操作PDA时候,需要用到RAPI,那么为了更好的使用RAPI,我们会使用到OpenNETCF.Desktop.Communication.dll文件,这个文件在Rapi.dll(win32 api)的基础上进行了NET封装。我们更能方便的使用它。对于连接和断开移动设备的方法,在使用过程中出现了一点问题,这里将记录下来,和朋友们分享:

         1、当我们首先实例化时:RAPI m_rapi = new RAPI();调用:m_rapi.Connect(false, 2).如果当PDA和PC没有连接成功时候,根据OpenNetCF.Desktop.Communication里面的方法,就会在子线程中抛出异常,主线程不能Catch获取子线程中异常,导致程序无法正常运行下去。相关代码如下:

    代码
        public void Connect(bool WaitForInit, int TimeoutSeconds)
            {
                
    int ret = 0;
                m_timeout 
    = TimeoutSeconds;

                
    if(WaitForInit)
                {
                    ret 
    = CeRapiInit();
                    
    if( ret != 0)
                    {
                        
    int e = CeRapiGetError();

                        Marshal.ThrowExceptionForHR(ret);
                    }

                    
    lock(this)
                    {
                        m_connected 
    = true;
                    }

                    
    // throw the connected event
                    if(RAPIConnected != null)
                    {
                        RAPIConnected();
                    }

                    
    return;
                }

                
    // non-blocking init call
                m_ri = new RAPIINIT();

                m_ri.cbSize 
    = Marshal.SizeOf(m_ri);
                m_ri.hrRapiInit 
    = m_InitResult;

                m_hInitEvent 
    = CreateEvent(IntPtr.Zero, 00"OpenNETCF.RAPI");

                
    if((uint)m_hInitEvent == uint.MaxValue)
                {
                    
    throw new RAPIException("Failed to Initialize RAPI");
                }

                m_ri.heRapiInit 
    = m_hInitEvent;

                ret 
    = CeRapiInitEx(ref m_ri);
                
    if(ret != 0)
                {
                    Marshal.ThrowExceptionForHR(ret);
                }

                
    // create a wait thread
                m_initThread = new Thread(new ThreadStart(InitThreadProc));

                
    // Start thread
                m_initThread.Start();
            }
            private void InitThreadProc()
            {
                
    int ret = 0;
                
    int timeout = m_timeout * 4;
                
    bool infinitetimeout = (timeout < 0);

                
    // check for Init event 4 times / sec
                do
                {
                    
    // check for abort command from Dispose()
                    if(m_killThread)
                    {
                        
    return;
                    }

                    
    // see if the event is set
                    ret = WaitForSingleObject(m_ri.heRapiInit, 250);

                    
    if((ret == WAIT_FAILED) || (ret == WAIT_ABANDONED))
                    {
                        
    throw new RAPIException("Failed to Initialize RAPI");
                    }

                    
    if(! infinitetimeout)
                    {
                        
    if(timeout-- < 0)
                        {
                            
    throw new RAPIException("Timeout waiting for device connection");
                        }
                    }
                } 
    while(ret != WAIT_OBJECT_0);

                
    // check the hresult
                if(m_InitResult != 0)
                {
                    Marshal.ThrowExceptionForHR(m_InitResult);
                }

                
    lock(this)
                {
                    m_connected 
    = true;
                }

                
    // throw the connected event
                if(RAPIConnected != null)
                {
                    RAPIConnected();
                }

                
    // clean up
                CloseHandle(m_hInitEvent);
            }

     上面的代码当我们调用m_rapi.Connect(false,2)时候,最终在子线程中抛出异常:Timeout waiting for device connection

     为了在主线程中捕捉在子线程中出现的异常,我们对上面的代码做一些修改:

    代码
        public delegate void ExceptionEventHandler(RAPIException e);
        
    public event ExceptionEventHandler ThrowException;
        
    protected virtual void OnThrowException(RAPIException e)
            {
                
    if (ThrowException != null)
                {
                    ThrowException(e);
                }
            }
        private void InitThreadProc()
            {
                
    int ret = 0;
                
    int timeout = m_timeout * 4;
                
    bool infinitetimeout = (timeout < 0);

                
    // check for Init event 4 times / sec
                do
                {
                    
    // check for abort command from Dispose()
                    if(m_killThread)
                    {
                        
    return;
                    }

                    
    // see if the event is set
                    ret = WaitForSingleObject(m_ri.heRapiInit, 250);

                    
    if((ret == WAIT_FAILED) || (ret == WAIT_ABANDONED))
                    {
                                 CeRapiUninit();
                                 OnThrowException(
    new RAPIException("Failed to Initialize RAPI"));
                                 return;                           
                   }
                   
    if(! infinitetimeout)
                    {
                        
    if(timeout-- < 0)
                        {
                                 CeRapiUninit();
                                 OnThrowException(
    new RAPIException("Timeout waiting for device connection"));
                                 return;        
                        }                                                          
                    }
                } 
    while(ret != WAIT_OBJECT_0);

                
    // check the hresult
                if(m_InitResult != 0)
                {
                    Marshal.ThrowExceptionForHR(m_InitResult);
                }

                
    lock(this)
                {
                    m_connected 
    = true;
                }

                
    // throw the connected event
                if(RAPIConnected != null)
                {
                    RAPIConnected();
                }

                
    // clean up
                CloseHandle(m_hInitEvent);
            }

    通过对上面代码的修改,我们定义了ExceptionEventHandler委托,那么当m_rapi初始化时:   获取连接失败的提示,给用户展示提示信息。

     m_rapi.ThrowException += new ExceptionEventHandler(m_rapi_ThrowException);
     
    void m_rapi_ThrowException(RAPIException e)
     {
            MessageBox.Show(
    "连接超时!请确认把PDA和PC机连接好!");
     }

     上面的修改的代码中添加了CeRapiUninit()这个方法的调用,也就是说当PC和PDA没有连接时候,调用CeRapiInitEx方法,连接超时,但是资源仍然被占用,因此需要调用这个方法来释放资源。

      [DllImport("rapi.dll", CharSet = CharSet.Unicode)]
            internal static extern int CeRapiUninit();

    曾经在项目中因没有调用这个CeRapiUninit时候,在pda和pc机没有连接:设备断开,抛出上面的异常情况给用户提示后,再将pda和pc连接,发现当pda和pc连接不成功,再一次断开,再一次连接,断开,始终都是连接不成功。最后发现问题是第一次连接设备抛出异常后没有释放资源引起的。

    2、为了详细说明关于pda和pc连接状况监控,自己写了一个简单demo。做为学习的记录:

    代码
      public partial class MainForm : Form
        {
            
    internal class MyEventArgs : EventArgs
            {
                
    public Control Target;
                
    public string Text;
                
    public MyEventArgs(Control target, string text)
                {
                    Target 
    = target;
                    Text 
    = text;
                }
            }

            
    private RAPI m_rapi = new RAPI();
            
    private EventHandler statusUpdate;

            
    public MainForm()
            {
                InitializeComponent();
                m_rapi.RAPIConnected 
    += new RAPIConnectedHandler(m_rapi_RAPIConnected);
                m_rapi.RAPIDisconnected 
    += new RAPIConnectedHandler(m_rapi_RAPIDisconnected);
                m_rapi.ActiveSync.Listen 
    += new ListenHandler(ActiveSync_Listen);
                m_rapi.ActiveSync.Answer 
    += new AnswerHandler(ActiveSync_Answer);
                m_rapi.ThrowException 
    += new ExceptionEventHandler(m_rapi_ThrowException);
                statusUpdate 
    = new EventHandler(StatusUpdate);
                 m_rapi.Connect(
    false2);
            }

            
    private void StatusUpdate(object sender, EventArgs args)
            {
                (sender 
    as Label).Text = (args as MyEventArgs).Text;
            }

            
    void m_rapi_ThrowException(RAPIException e)
            {
                MessageBox.Show(
    "连接超时!请确认把PDA和PC机连接好!");
            }

            
    void ActiveSync_Answer()
            {
                
    if (this.label1.InvokeRequired)
                {
                    
    this.Invoke(statusUpdate, new object[] { this.label1, new MyEventArgs(this.label1, "连接状态:连接中...!") });
                }
                
    else
                {
                    statusUpdate(
    this.label1, new MyEventArgs(this.label1, "连接状态:连接中...!"));
                }
            }

            
    void ActiveSync_Listen()
            {
                
    if (this.label1.InvokeRequired)
                {
                    
    this.Invoke(statusUpdate, new object[] { this.label1, new MyEventArgs(this.label1, "连接状态:设备未连接!") });
                }
                
    else
                {
                    statusUpdate(
    this.label1, new MyEventArgs(this.label1, "连接状态:设备未连接!"));
                }
            }

            
    void m_rapi_RAPIDisconnected()
            {
                
    if (this.label1.InvokeRequired)
                {
                    
    this.Invoke(statusUpdate, new object[] { this.label1, new MyEventArgs(this.label1, "连接状态:连接关闭!") });
                }
                
    else
                {
                    statusUpdate(
    this.label1, new MyEventArgs(this.label1, "连接状态:连接关闭!"));
                }
            }

            
    void m_rapi_RAPIConnected()
            {
                
    if (this.label1.InvokeRequired)
                {
                    
    this.Invoke(statusUpdate, new object[] { this.label1, new MyEventArgs(this.label1, "连接状态:设备已连接!") });
                }
                
    else
                {
                    statusUpdate(
    this.label1, new MyEventArgs(this.label1, "连接状态:设备已连接!"));
                }
            }

            
    private void MainForm_Load(object sender, EventArgs e)
            {
              
            }

            
    private void button1_Click(object sender, EventArgs e)
            {
                
    if (m_rapi.DeviceFileExists(@"\***\****.sdf"))
                {
                    MessageBox.Show(
    "文件存在!连接是成功的!");
                }
                
    else
                {
                    MessageBox.Show(
    "文件不存在!,连接不成功!");
                }
            }
        }

    通过demo发现,连接状态的变化过程:

    1.连接pda时候:设备未连接---->连接中...----->设备已连接

    2.断开pda上:设备已连接----->连接关闭------->设备未连接

    Best Regards,

    Charles Chen

  • 相关阅读:
    【转载】Python tips: 什么是*args和**kwargs?
    Python关于File学习过程
    tensorflow训练中出现nan
    axis调用Web服务报axis unexpected wrapper element{XXXX}XXX错误的解决
    微信小程序windowHeight的值在ios和android平台不一致问题解决办法
    微信小程序scroll-view滚动一次多次触发的问题解决方案
    微信小程序自定义TabBar
    微信小程序页面列表与详情页跳转的正确姿势
    Spring动态获取已注入的对象的方法
    MAVEN项目不扫描mybatis的mapper.xml问题
  • 原文地址:https://www.cnblogs.com/Charles2008/p/1690220.html
Copyright © 2011-2022 走看看