WinCE5.0移动平台开发笔记(OpenNETCF.Desktop.Communication连接和断开使用心得)

时间:2022-04-06 17:50:13

    当用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获取子线程中异常,导致程序无法正常运行下去。相关代码如下:

WinCE5.0移动平台开发笔记(OpenNETCF.Desktop.Communication连接和断开使用心得)WinCE5.0移动平台开发笔记(OpenNETCF.Desktop.Communication连接和断开使用心得)代码
     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,  0 0 " 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

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

WinCE5.0移动平台开发笔记(OpenNETCF.Desktop.Communication连接和断开使用心得)WinCE5.0移动平台开发笔记(OpenNETCF.Desktop.Communication连接和断开使用心得)代码
     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。做为学习的记录:

WinCE5.0移动平台开发笔记(OpenNETCF.Desktop.Communication连接和断开使用心得)WinCE5.0移动平台开发笔记(OpenNETCF.Desktop.Communication连接和断开使用心得)代码
   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(
false 2 );
        }

        
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