<?xml version="1.0" encoding="UTF-8" ?>
<?xml-stylesheet type="text/xsl" href="http://blogs.msdn.com/utility/FeedStylesheets/rss.xsl" media="screen"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:wfw="http://wellformedweb.org/CommentAPI/"><channel><title>Anthony Wong's Blog : IO</title><link>http://blogs.msdn.com/anthonywong/archive/tags/IO/default.aspx</link><description>Tags: IO</description><dc:language>en-US</dc:language><generator>CommunityServer 2.1 SP1 (Build: 61025.2)</generator><item><title>SerialPort issue transmitting Unicode characters</title><link>http://blogs.msdn.com/anthonywong/archive/2006/04/25/583548.aspx</link><pubDate>Wed, 26 Apr 2006 00:04:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:583548</guid><dc:creator>antwong</dc:creator><slash:comments>1</slash:comments><comments>http://blogs.msdn.com/anthonywong/comments/583548.aspx</comments><wfw:commentRss>http://blogs.msdn.com/anthonywong/commentrss.aspx?PostID=583548</wfw:commentRss><description>&lt;P&gt;The managed implementation in .NET Framework 2.0 and .NET Compact Framework 2.0 supports the Encoding property that allows developers to specify the encoding they would use to transmit data over a serial port connection. The property defaults to ASCIIEncoding, which only allows ASCII characters to be transmitted. To transmit non-ASCII Unicode characters over the wire, developers may set the property to specify UTF8 or Unicode encodings. However, there is an issue in the implementation of SerialPort.ReadExisting() in V2 RTM that causes data corruption in some cases when Unicode characters are read. The issue reproduces against both NET FX 2.0 and NETCF 2.0.&lt;/P&gt;
&lt;P&gt;To work around the issue, use SerialPort.Read instead of SerialPort.ReadExisting(). For example, if you have the following DataReceived event handler:&lt;/P&gt;
&lt;P&gt;&amp;nbsp; private void serial_DataReceived(object o, SerialDataReceivedEventArgs e)&lt;BR&gt;&amp;nbsp; {&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; if (e.EventType == SerialData.Chars)&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; string str = m_port1.ReadExisting();&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; // Process the returned string below&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;BR&gt;&amp;nbsp; }&lt;/P&gt;
&lt;P&gt;Use the following code instead:&lt;/P&gt;
&lt;P&gt;&amp;nbsp; private void serial_DataReceived(object o, SerialDataReceivedEventArgs e)&lt;BR&gt;&amp;nbsp; {&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; if (e.EventType == SerialData.Chars)&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; int bnread = m_port1.BytesToRead;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; char[] a_char = new char[bnread];&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; int nread = 0;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; nread = m_port1.Read(a_char, 0, bnread);&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; string str = new string(a_char, 0, nread);&lt;BR&gt;&amp;nbsp; &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; // Process the returned string below&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;BR&gt;&amp;nbsp; }&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;Cheers,&lt;/P&gt;
&lt;P&gt;Anthony Wong [MSFT]&lt;/P&gt;
&lt;P&gt;&lt;FONT size=2&gt;This posting is provided "AS IS" with no warranties, and confers no rights.&lt;/FONT&gt;&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=583548" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/anthonywong/archive/tags/IO/default.aspx">IO</category></item><item><title>Deadlock issue on closing SerialPort</title><link>http://blogs.msdn.com/anthonywong/archive/2006/03/03/542625.aspx</link><pubDate>Fri, 03 Mar 2006 05:02:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:542625</guid><dc:creator>antwong</dc:creator><slash:comments>1</slash:comments><comments>http://blogs.msdn.com/anthonywong/comments/542625.aspx</comments><wfw:commentRss>http://blogs.msdn.com/anthonywong/commentrss.aspx?PostID=542625</wfw:commentRss><description>&lt;P&gt;NETCF V2's SerialPort implementation provides four public events for developers. They can add custom event handlers to handle these events. Since these event handlers are executed by ThreadPool threads,&amp;nbsp;if the developer wants to update form fields with the received data, he/she would need to invoke the associated methods on the form to ask the GUI thread owning the control to update itself.&lt;/P&gt;
&lt;P&gt;The correct way to invoke the control update function is to use Control.BeginInvoke() instead of Control.Invoke(). This is because the serial port base stream is locked while&amp;nbsp;serial port&amp;nbsp;events are handled. If the serial port is closed (SerialPort.Close() called)&amp;nbsp;with the GUI thread while the events are being handled (e.g. the user clicked a button to close the serial port, or the user exits the application), the serial port, as part of the port closing process, will attempt to acquire the lock on the base serial stream, and will wait until the lock is acquired. Therefore, the data event handler which has the lock will wait on the Control.Invoke() call for access to the GUI thread indefinitely, and the GUI thread will wait on the SerialPort.Close() call for access to the lock indefinitely.&amp;nbsp;This causes a deadlock on the application, and the user will likely require a reset on the device to be able to rerun the application.&lt;/P&gt;
&lt;P&gt;To prevent the issue,&amp;nbsp;simply&amp;nbsp;replace&amp;nbsp;calls that might block for a long time on the serial port event handlers with non-blocking versions of the calls like Control.BeginInvoke().&lt;/P&gt;
&lt;P&gt;This suggestion applies to the SerialPort implementation in both the compact and desktop versions of the .NET framework V2.&lt;/P&gt;
&lt;P&gt;This posting is provided "AS IS" with no warranties, and confers no rights.&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=542625" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/anthonywong/archive/tags/IO/default.aspx">IO</category></item><item><title>Directory.Exists() Issue</title><link>http://blogs.msdn.com/anthonywong/archive/2006/01/31/520820.aspx</link><pubDate>Tue, 31 Jan 2006 21:13:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:520820</guid><dc:creator>antwong</dc:creator><slash:comments>0</slash:comments><comments>http://blogs.msdn.com/anthonywong/comments/520820.aspx</comments><wfw:commentRss>http://blogs.msdn.com/anthonywong/commentrss.aspx?PostID=520820</wfw:commentRss><description>&lt;p&gt;On Windows CE 4.X based devices, Directory.Exists() treats path names ending with a slash "\" differently. As an example,&lt;/p&gt;
&lt;p&gt;Directory.Exists("\\temp")&lt;/p&gt;
&lt;p&gt;will return true if the "temp" directory exists. However, the following call will return false even though the directory exists:&lt;/p&gt;
&lt;p&gt;Directory.Exists("\\temp\\")&lt;/p&gt;
&lt;p&gt;On Windows Mobile 5.0 devices, NETCF's behavior is consistent with Desktop's; that is, Directory.Exists() returns true if and only if the directory exists, no matter whether there is a trailing slash in the path or not. For the above example, we will return true for both calls if the directory exists.&lt;/p&gt;
&lt;p&gt;Cheers,&lt;/p&gt;
&lt;p&gt;Anthony Wong [MSFT]&lt;/p&gt;
&lt;p&gt;This posting is provided "AS IS" with no warranties, and confers no rights.&lt;/p&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=520820" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/anthonywong/archive/tags/IO/default.aspx">IO</category></item><item><title>Power Notifications and Serial Port</title><link>http://blogs.msdn.com/anthonywong/archive/2005/06/07/426392.aspx</link><pubDate>Tue, 07 Jun 2005 15:53:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:426392</guid><dc:creator>antwong</dc:creator><slash:comments>3</slash:comments><comments>http://blogs.msdn.com/anthonywong/comments/426392.aspx</comments><wfw:commentRss>http://blogs.msdn.com/anthonywong/commentrss.aspx?PostID=426392</wfw:commentRss><description>&lt;P&gt;NETCF&amp;nbsp;V2 adds the support of a managed SerialPort class to allow developers to directly access the serial ports on mobile devices, enabling communication with GPS, bar code readers, or other mobile devices within managed code. These peripherals may be sending data to the device on a continuous or intermittent basis. Thus, it is important that the device be listening to the serial port round the clock and be able to respond to the serial input data as they arrive. However, when a Pocket PC is in&amp;nbsp;the idle state for a period of time, the OS automatically puts the device into a suspended state to conserve battery. This causes the serial port objects to become invalid, and they must be closed and re-opened before any data can be sent/received over the port again. NETCF V2 does not provide managed APIs to receive power notifications. However, we can use the RequestPowerNotifications API in Windows CE to obtain notifications whenever the power state of the device changes. This API has been present in Windows CE since 4.0, so it is available to Pocket PC 2003 as well. The following code is an implementation of a managed wrapper to the API.&lt;/P&gt;&lt;PRE&gt;using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.IO;
using System.Runtime.InteropServices;
using System.Threading;

public class PMTest
{
	static void Main() 
	{
		PowerNotifications pn = new PowerNotifications();
		pn.Start();
		Console.WriteLine("starting to sleep");
		Thread.Sleep(20000);
		pn.Stop();
		Console.WriteLine("finally done");
	}
}

public class PowerNotifications
{
	IntPtr ptr = IntPtr.Zero;
	Thread t = null;
	bool done = false;

	[DllImport ("coredll.dll")]
	private static extern IntPtr RequestPowerNotifications(IntPtr hMsgQ, uint Flags);

	[DllImport ("coredll.dll")]
	private static extern uint WaitForSingleObject(IntPtr hHandle, int wait);

	[DllImport ("coredll.dll")]
	private static extern IntPtr CreateMsgQueue(string name, ref MsgQOptions options);

	[DllImport ("coredll.dll")]
	private static extern bool ReadMsgQueue(IntPtr hMsgQ, byte[] lpBuffer, uint cbBufSize, ref uint lpNumRead, int dwTimeout, ref uint pdwFlags);

	public PowerNotifications()
	{
		MsgQOptions options = new MsgQOptions();
		options.dwFlags = 0;
		options.dwMaxMessages = 20;
		options.cbMaxMessage = 10000;
		options.bReadAccess = true;
		options.dwSize = (uint) System.Runtime.InteropServices.Marshal.SizeOf(options);
		ptr = CreateMsgQueue("Test", ref options);
		RequestPowerNotifications(ptr, 0xFFFFFFFF);
		t = new Thread(new ThreadStart(DoWork));
	}

	public void Start()
	{
		t.Start();
	}

	public void Stop()
	{
		done = true;
		t.Abort();
	}

	private void DoWork()
	{
		byte[] buf = new byte[10000];
		uint nRead = 0, flags = 0, res = 0;

		Console.WriteLine("starting loop");
		try
		{
			while(!done)
			{
				res = WaitForSingleObject(ptr, 1000);
				if (res == 0)
				{
					ReadMsgQueue(ptr, buf, (uint) buf.Length, ref nRead, -1, ref flags);
					//Console.WriteLine("message: " + ConvertByteArray(buf, 0) + " flag: " + ConvertByteArray(buf, 4));
					uint flag = ConvertByteArray(buf, 4);
					string msg = null;
					switch(flag)
					{
						case 65536:
							msg = "Power On";
							break;
						case 131072:
							msg = "Power Off";
							break;
						case 262144:
							msg = "Power Critical";
							break;
						case 524288:
							msg = "Power Boot";
							break;
						case 1048576:
							msg = "Power Idle";
							break;
						case 2097152:
							msg = "Power Suspend";
							break;
						case 8388608:
							msg = "Power Reset";
							break;
						case 0:
							// non power transition messages are ignored
							break;
						default:
							msg = "Unknown Flag: " + flag;
							break;
					}
					if (msg != null)
						Console.WriteLine(msg);
				}
			}
		}
		catch(Exception ex)
		{
			if (!done)
			{
				Console.WriteLine("Got exception: " + ex.ToString());
			}
		}
	}

	uint ConvertByteArray(byte[] array, int offset)
	{
		uint res = 0;
		res += array[offset];
		res += array[offset+1] * (uint) 0x100;
		res += array[offset+2] * (uint) 0x10000;
		res += array[offset+3] * (uint) 0x1000000;
		return res;
	}

	[StructLayout(LayoutKind.Sequential)]
		public struct MsgQOptions
	{
		public uint dwSize;
		public uint dwFlags;
		public uint dwMaxMessages;
		public uint cbMaxMessage;
		public bool bReadAccess;
	}
}
&lt;/PRE&gt;
&lt;P&gt;You can compile and run the code on a Pocket PC, switch off/on the device and observe the power notification messages on the console (You&amp;nbsp;will&amp;nbsp;need to install the console add-on). Of course, you can modify the power message handling code to close and re-open the serial port instances you have when you receive a "Power On" transition.&lt;/P&gt;
&lt;P&gt;Cheers,&lt;/P&gt;
&lt;P&gt;Anthony&lt;/P&gt;
&lt;P&gt;&lt;FONT face="Times New Roman" color=#000000&gt;This posting is provided "AS IS" with no warranties, and confers no rights. &lt;/FONT&gt;&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=426392" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/anthonywong/archive/tags/IO/default.aspx">IO</category></item></channel></rss>