WinCE5.0移动平台开发笔记(OpenNETCF.Desktop.Communication连接和断开使用心得)
Posted on 2010-03-20 08:27 Charles Chen 阅读(4790) 评论(8) 编辑 收藏 举报当用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获取子线程中异常,导致程序无法正常运行下去。相关代码如下:
{
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
为了在主线程中捕捉在子线程中出现的异常,我们对上面的代码做一些修改:
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初始化时: 获取连接失败的提示,给用户展示提示信息。
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。做为学习的记录:
{
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