<?xml version="1.0" encoding="UTF-8" ?>
<?xml-stylesheet type="text/xsl" href="http://blogs.microsoft.co.il/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>Just code - Tamir Khason : Work process, .NET 3.5</title><link>http://blogs.microsoft.co.il/blogs/tamir/archive/tags/Work+process/.NET+3.5/default.aspx</link><description>Tags: Work process, .NET 3.5</description><dc:language>en</dc:language><generator>CommunityServer 2007.1 (Build: 20917.1142)</generator><item><title>New year – new blog or how to migrate Community Server to any other engine, supports XML-RPC</title><link>http://blogs.microsoft.co.il/blogs/tamir/archive/2009/01/01/new-year-new-blog-or-how-to-migrate-community-server-to-any-other-engine-supports-xml-rpc.aspx</link><pubDate>Fri, 02 Jan 2009 02:33:04 GMT</pubDate><guid isPermaLink="false">b5c4f5bc-c09b-4439-a595-91a98c1847df:205248</guid><dc:creator>Tamir Khason</dc:creator><slash:comments>0</slash:comments><description>&lt;p&gt;Please update your bookmarks, because the new url of this blog is &lt;a href="http://khason.net/"&gt;http://khason.net/&lt;/a&gt; (you have not update RSS feeds, it will be done automatically). Why I did it? Why I decided to go to “stand-alone”… Well. there are some reasons. Generally, I do not want to explain all those here, but trust me, there are some. The main reason is, that there is no responsible person in charge for this blog platform in Microsoft Israel. This why, if your blog is popular and you have a respect to your blog visitors, you cannot host it here… Take a look into new comments notifications in my inbox. Would you answer your readers with such “small amount” of SPAM and capcha, that cannot be fixed already for three years in this platform? This how my inbox looks like for last three years. So now, you should not ask me, why I not answered your email or comments. Aren’t you? :)&lt;/p&gt;  &lt;p&gt;&lt;img style="border-right-width:0px;display:inline;border-top-width:0px;border-bottom-width:0px;border-left-width:0px;" title="Capture" border="0" alt="Capture" src="http://blogs.microsoft.co.il/blogs/tamir/Capture_1D7350A7.jpg" width="354" height="397" /&gt; &lt;/p&gt;  &lt;p&gt;Currently, all comments in this blog are disabled, so if you want to comment, please use new url of posts (this will appear shortly in the beginning of each post). Also, this post will not be syndicated in RSS.&lt;/p&gt;  &lt;p&gt;So, this post is the last. I loved this platform, and loved people started it. But, unfortunately, it seemed, that bloggers community is not important enough for new platform managers. &lt;/p&gt;  &lt;p&gt;Also, If you want to learn &lt;a target="_blank" href="http://khason.net/dev/how-to-migrate-from-cs2007-to-wordpress-movable-type-or-any-other-blog-engine-supports-xml-rpc-with-c/"&gt;how to use C# and XML-RCP to migrate from CS2007, used in this platform, visit my new home&lt;/a&gt; :)&lt;/p&gt;  &lt;p&gt;Have a great year and, as always, be good people. This post marked with all possible tags automatically. Sorry.&lt;/p&gt;&lt;img src="http://blogs.microsoft.co.il/aggbug.aspx?PostID=205248" width="1" height="1"&gt;</description><category domain="http://blogs.microsoft.co.il/blogs/tamir/archive/tags/soft/default.aspx">soft</category><category domain="http://blogs.microsoft.co.il/blogs/tamir/archive/tags/blogging+tools/default.aspx">blogging tools</category><category domain="http://blogs.microsoft.co.il/blogs/tamir/archive/tags/WPF/default.aspx">WPF</category><category domain="http://blogs.microsoft.co.il/blogs/tamir/archive/tags/tutorial/default.aspx">tutorial</category><category domain="http://blogs.microsoft.co.il/blogs/tamir/archive/tags/Tips+and+Tricks/default.aspx">Tips and Tricks</category><category domain="http://blogs.microsoft.co.il/blogs/tamir/archive/tags/Performance/default.aspx">Performance</category><category domain="http://blogs.microsoft.co.il/blogs/tamir/archive/tags/WPF+crossbow/default.aspx">WPF crossbow</category><category domain="http://blogs.microsoft.co.il/blogs/tamir/archive/tags/source/default.aspx">source</category><category domain="http://blogs.microsoft.co.il/blogs/tamir/archive/tags/Mobile/default.aspx">Mobile</category><category domain="http://blogs.microsoft.co.il/blogs/tamir/archive/tags/help/default.aspx">help</category><category domain="http://blogs.microsoft.co.il/blogs/tamir/archive/tags/Windows+Gadgets/default.aspx">Windows Gadgets</category><category domain="http://blogs.microsoft.co.il/blogs/tamir/archive/tags/promo/default.aspx">promo</category><category domain="http://blogs.microsoft.co.il/blogs/tamir/archive/tags/Vista/default.aspx">Vista</category><category domain="http://blogs.microsoft.co.il/blogs/tamir/archive/tags/thoughts/default.aspx">thoughts</category><category domain="http://blogs.microsoft.co.il/blogs/tamir/archive/tags/tools/default.aspx">tools</category><category domain="http://blogs.microsoft.co.il/blogs/tamir/archive/tags/events/default.aspx">events</category><category domain="http://blogs.microsoft.co.il/blogs/tamir/archive/tags/demos/default.aspx">demos</category><category domain="http://blogs.microsoft.co.il/blogs/tamir/archive/tags/WPF_2F00_E/default.aspx">WPF/E</category><category domain="http://blogs.microsoft.co.il/blogs/tamir/archive/tags/download/default.aspx">download</category><category domain="http://blogs.microsoft.co.il/blogs/tamir/archive/tags/jobs/default.aspx">jobs</category><category domain="http://blogs.microsoft.co.il/blogs/tamir/archive/tags/VSTS/default.aspx">VSTS</category><category domain="http://blogs.microsoft.co.il/blogs/tamir/archive/tags/Visual+Studio/default.aspx">Visual Studio</category><category domain="http://blogs.microsoft.co.il/blogs/tamir/archive/tags/Web/default.aspx">Web</category><category domain="http://blogs.microsoft.co.il/blogs/tamir/archive/tags/C_2300_/default.aspx">C#</category><category domain="http://blogs.microsoft.co.il/blogs/tamir/archive/tags/Silverlight/default.aspx">Silverlight</category><category domain="http://blogs.microsoft.co.il/blogs/tamir/archive/tags/WCF/default.aspx">WCF</category><category domain="http://blogs.microsoft.co.il/blogs/tamir/archive/tags/Accessibility/default.aspx">Accessibility</category><category domain="http://blogs.microsoft.co.il/blogs/tamir/archive/tags/Blogging+rules/default.aspx">Blogging rules</category><category domain="http://blogs.microsoft.co.il/blogs/tamir/archive/tags/blogging+general/default.aspx">blogging general</category><category domain="http://blogs.microsoft.co.il/blogs/tamir/archive/tags/fun/default.aspx">fun</category><category domain="http://blogs.microsoft.co.il/blogs/tamir/archive/tags/Vista+Battery+Saver/default.aspx">Vista Battery Saver</category><category domain="http://blogs.microsoft.co.il/blogs/tamir/archive/tags/SkyDrive/default.aspx">SkyDrive</category><category domain="http://blogs.microsoft.co.il/blogs/tamir/archive/tags/Windows+Live+Writer/default.aspx">Windows Live Writer</category><category domain="http://blogs.microsoft.co.il/blogs/tamir/archive/tags/Windows+Live/default.aspx">Windows Live</category><category domain="http://blogs.microsoft.co.il/blogs/tamir/archive/tags/Dell/default.aspx">Dell</category><category domain="http://blogs.microsoft.co.il/blogs/tamir/archive/tags/DevAcademy2/default.aspx">DevAcademy2</category><category domain="http://blogs.microsoft.co.il/blogs/tamir/archive/tags/Microsoft/default.aspx">Microsoft</category><category domain="http://blogs.microsoft.co.il/blogs/tamir/archive/tags/.NET+3.5/default.aspx">.NET 3.5</category><category domain="http://blogs.microsoft.co.il/blogs/tamir/archive/tags/WPF+quiz/default.aspx">WPF quiz</category><category domain="http://blogs.microsoft.co.il/blogs/tamir/archive/tags/x64/default.aspx">x64</category><category domain="http://blogs.microsoft.co.il/blogs/tamir/archive/tags/WF/default.aspx">WF</category><category domain="http://blogs.microsoft.co.il/blogs/tamir/archive/tags/SVG/default.aspx">SVG</category><category domain="http://blogs.microsoft.co.il/blogs/tamir/archive/tags/XPS/default.aspx">XPS</category><category domain="http://blogs.microsoft.co.il/blogs/tamir/archive/tags/TechedIsrael2008/default.aspx">TechedIsrael2008</category><category domain="http://blogs.microsoft.co.il/blogs/tamir/archive/tags/teched/default.aspx">teched</category><category domain="http://blogs.microsoft.co.il/blogs/tamir/archive/tags/XNA/default.aspx">XNA</category><category domain="http://blogs.microsoft.co.il/blogs/tamir/archive/tags/PLINQ/default.aspx">PLINQ</category><category domain="http://blogs.microsoft.co.il/blogs/tamir/archive/tags/LINQ/default.aspx">LINQ</category><category domain="http://blogs.microsoft.co.il/blogs/tamir/archive/tags/Micro+Framework/default.aspx">Micro Framework</category><category domain="http://blogs.microsoft.co.il/blogs/tamir/archive/tags/SAP/default.aspx">SAP</category><category domain="http://blogs.microsoft.co.il/blogs/tamir/archive/tags/ASP.NET/default.aspx">ASP.NET</category><category domain="http://blogs.microsoft.co.il/blogs/tamir/archive/tags/XLINQ/default.aspx">XLINQ</category><category domain="http://blogs.microsoft.co.il/blogs/tamir/archive/tags/DirectX/default.aspx">DirectX</category><category domain="http://blogs.microsoft.co.il/blogs/tamir/archive/tags/Work+process/default.aspx">Work process</category><category domain="http://blogs.microsoft.co.il/blogs/tamir/archive/tags/Linux/default.aspx">Linux</category><category domain="http://blogs.microsoft.co.il/blogs/tamir/archive/tags/Mono/default.aspx">Mono</category><category domain="http://blogs.microsoft.co.il/blogs/tamir/archive/tags/DevAcademy3/default.aspx">DevAcademy3</category><category domain="http://blogs.microsoft.co.il/blogs/tamir/archive/tags/Math/default.aspx">Math</category><category domain="http://blogs.microsoft.co.il/blogs/tamir/archive/tags/GIS/default.aspx">GIS</category><category domain="http://blogs.microsoft.co.il/blogs/tamir/archive/tags/Algorithms/default.aspx">Algorithms</category><category domain="http://blogs.microsoft.co.il/blogs/tamir/archive/tags/DEV/default.aspx">DEV</category><category domain="http://blogs.microsoft.co.il/blogs/tamir/archive/tags/TECH/default.aspx">TECH</category><category domain="http://blogs.microsoft.co.il/blogs/tamir/archive/tags/Windows+7/default.aspx">Windows 7</category><category domain="http://blogs.microsoft.co.il/blogs/tamir/archive/tags/Charity/default.aspx">Charity</category><category domain="http://blogs.microsoft.co.il/blogs/tamir/archive/tags/OFFTOPIC/default.aspx">OFFTOPIC</category><category domain="http://blogs.microsoft.co.il/blogs/tamir/archive/tags/Hardware/default.aspx">Hardware</category><category domain="http://blogs.microsoft.co.il/blogs/tamir/archive/tags/Interop/default.aspx">Interop</category></item><item><title>Read and use FM radio (or any other USB HID device) from C#</title><link>http://blogs.microsoft.co.il/blogs/tamir/archive/2008/12/30/read-and-use-fm-radio-or-any-other-usb-hid-device-from-c.aspx</link><pubDate>Wed, 31 Dec 2008 01:42:18 GMT</pubDate><guid isPermaLink="false">b5c4f5bc-c09b-4439-a595-91a98c1847df:204291</guid><dc:creator>Tamir Khason</dc:creator><slash:comments>1</slash:comments><description>&lt;h3&gt;[This blog was migrated. You will not be able to comment here.&lt;br /&gt;The new URL of this post is &lt;a href="http://khason.net/blog/read-and-use-fm-radio-or-any-other-usb-hid-device-from-c/"&gt;http://khason.net/blog/read-and-use-fm-radio-or-any-other-usb-hid-device-from-c/&lt;/a&gt;]&lt;/h3&gt;&lt;hr /&gt;&lt;p&gt;Last time &lt;a href="http://blogs.microsoft.co.il/blogs/tamir/archive/2008/12/12/reading-and-decoding-rds-radio-data-system-in-c.aspx"&gt;we spoke about reading and decoding RDS information from FM receivers&lt;/a&gt;. Also &lt;a href="http://blogs.microsoft.co.il/blogs/tamir/archive/2008/12/25/capturing-and-streaming-sound-by-using-directsound-with-c.aspx"&gt;we already know how to stream sound from DirectSound compatible devices&lt;/a&gt;. However, before we can do it, we should be able to “speak” with such devices. So, today we’ll spoke about detection and reading information from Radio USB adapters (actually from any Human Input Devices). Let’s start.&lt;/p&gt;  &lt;p&gt;&lt;img style="border-right-width:0px;display:inline;border-top-width:0px;border-bottom-width:0px;border-left-width:0px;" title="USB FM HID" border="0" alt="USB FM HID" src="http://blogs.microsoft.co.il/blogs/tamir/image_460DCF0B.png" width="240" height="211" /&gt; &lt;/p&gt;  &lt;p&gt;First, if you want to do it, go and buy such device. The are not a lot of alternatives, but if you’ll seek, you’ll find it very quickly.&lt;/p&gt;  &lt;p&gt;So, let’s start. First of all, we’ll use platform invoke to get and set the information. Also, we have to preserve handle of the device from being collected by GC. After we’ll finish using the device, we’ll have to dispose it. Thus it makes sense to inherit from SafeHandle and IDisposable.&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;[SecurityPermission(SecurityAction.InheritanceDemand, UnmanagedCode = true)]     &lt;br /&gt;[SecurityPermission(SecurityAction.Demand, UnmanagedCode = true)]      &lt;br /&gt;public class USBDevice : SafeHandleZeroOrMinusOneIsInvalid, IDisposable {&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;Next, we’ll set a number of arguments, that will be in use during the device lifetime.&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;public uint ProductID { get; private set; }     &lt;br /&gt;public uint VendorID { get; private set; }      &lt;br /&gt;public uint VersionNumber { get; private set; }      &lt;br /&gt;public string Name { get; private set; }      &lt;br /&gt;public string SerialNumber { get; private set; }      &lt;br /&gt;public override bool IsInvalid { get { return !isValid; } } &lt;/p&gt;    &lt;p&gt;internal ushort FeatureReportLength { get; private set; }     &lt;br /&gt;internal ushort[] Registers { get; set; }&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;Now, we have to find it. The best way of detection human input devices is by product and vendor IDs. Those values are always unique for certain device type.&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;[SecurityPermission(SecurityAction.Demand, UnmanagedCode = true)]     &lt;br /&gt;internal USBDevice(uint pid, uint vid) : base(true) { findDevice(pid, vid); }&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;Next step is to find a device. To do this, we have to provide extern interfaces to methods of hid.dll and setupapi.dll. Here all methods we will use in our class&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;[SuppressUnmanagedCodeSecurity()]     &lt;br /&gt;internal static class Native {      &lt;br /&gt;&amp;#160;&amp;#160; #region methods      &lt;br /&gt;&amp;#160;&amp;#160; [DllImport(&amp;quot;hid.dll&amp;quot;, SetLastError = true)]      &lt;br /&gt;&amp;#160;&amp;#160; internal static extern void HidD_GetHidGuid(      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; ref Guid lpHidGuid); &lt;/p&gt;    &lt;p&gt;&amp;#160;&amp;#160; [DllImport(&amp;quot;hid.dll&amp;quot;, SetLastError = true)]     &lt;br /&gt;&amp;#160;&amp;#160; internal static extern bool HidD_GetAttributes(      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; IntPtr hDevice,      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; out HIDD_ATTRIBUTES Attributes); &lt;/p&gt;    &lt;p&gt;&amp;#160;&amp;#160; [DllImport(&amp;quot;hid.dll&amp;quot;, SetLastError = true)]     &lt;br /&gt;&amp;#160;&amp;#160; internal static extern bool HidD_GetPreparsedData(      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; IntPtr hDevice,      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; out IntPtr hData); &lt;/p&gt;    &lt;p&gt;&amp;#160;&amp;#160; [DllImport(&amp;quot;hid.dll&amp;quot;, SetLastError = true)]     &lt;br /&gt;&amp;#160;&amp;#160; internal static extern bool HidD_FreePreparsedData(      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; IntPtr hData); &lt;/p&gt;    &lt;p&gt;&amp;#160;&amp;#160; [DllImport(&amp;quot;hid.dll&amp;quot;, SetLastError = true)]     &lt;br /&gt;&amp;#160;&amp;#160; internal static extern bool HidP_GetCaps(      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; IntPtr hData,      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; out HIDP_CAPS capabilities); &lt;/p&gt;    &lt;p&gt;&amp;#160;&amp;#160; [DllImport(&amp;quot;hid.dll&amp;quot;, SetLastError = true, CallingConvention = CallingConvention.StdCall)]     &lt;br /&gt;&amp;#160;&amp;#160; internal static extern bool HidD_GetFeature(      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; IntPtr hDevice,      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; IntPtr hReportBuffer,      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; uint ReportBufferLength); &lt;/p&gt;    &lt;p&gt;&amp;#160;&amp;#160; [DllImport(&amp;quot;hid.dll&amp;quot;, SetLastError = true, CallingConvention = CallingConvention.StdCall)]     &lt;br /&gt;&amp;#160;&amp;#160; internal static extern bool HidD_SetFeature(      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; IntPtr hDevice,      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; IntPtr ReportBuffer,      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; uint ReportBufferLength); &lt;/p&gt;    &lt;p&gt;&amp;#160;&amp;#160; [DllImport(&amp;quot;hid.dll&amp;quot;, SetLastError = true, CallingConvention = CallingConvention.StdCall)]     &lt;br /&gt;&amp;#160;&amp;#160; internal static extern bool HidD_GetProductString(      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; IntPtr hDevice,       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; IntPtr Buffer,       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; uint BufferLength); &lt;/p&gt;    &lt;p&gt;&amp;#160;&amp;#160; [DllImport(&amp;quot;hid.dll&amp;quot;, SetLastError = true, CallingConvention = CallingConvention.StdCall)]     &lt;br /&gt;&amp;#160;&amp;#160; internal static extern bool HidD_GetSerialNumberString(      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; IntPtr hDevice,      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; IntPtr Buffer,      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; uint BufferLength); &lt;/p&gt;    &lt;p&gt;&amp;#160;&amp;#160; [DllImport(&amp;quot;setupapi.dll&amp;quot;, SetLastError = true)]     &lt;br /&gt;&amp;#160;&amp;#160; internal static extern IntPtr SetupDiGetClassDevs(      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; ref Guid ClassGuid,      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; [MarshalAs(UnmanagedType.LPTStr)] string Enumerator,      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; IntPtr hwndParent,      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; UInt32 Flags); &lt;/p&gt;    &lt;p&gt;&amp;#160;&amp;#160; [DllImport(&amp;quot;setupapi.dll&amp;quot;, SetLastError = true)]     &lt;br /&gt;&amp;#160;&amp;#160; internal static extern bool SetupDiEnumDeviceInterfaces(      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; IntPtr DeviceInfoSet,      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; int DeviceInfoData,      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; ref&amp;#160; Guid lpHidGuid,      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; uint MemberIndex,      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; ref&amp;#160; SP_DEVICE_INTERFACE_DATA lpDeviceInterfaceData); &lt;/p&gt;    &lt;p&gt;&amp;#160;&amp;#160; [DllImport(&amp;quot;setupapi.dll&amp;quot;, SetLastError = true)]     &lt;br /&gt;&amp;#160;&amp;#160; internal static extern bool SetupDiGetDeviceInterfaceDetail(      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; IntPtr DeviceInfoSet,      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; ref SP_DEVICE_INTERFACE_DATA lpDeviceInterfaceData,      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; IntPtr hDeviceInterfaceDetailData,      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; uint detailSize,      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; out uint requiredSize,      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; IntPtr hDeviceInfoData); &lt;/p&gt;    &lt;p&gt;&amp;#160;&amp;#160; [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]     &lt;br /&gt;&amp;#160;&amp;#160; [DllImport(&amp;quot;kernel32.dll&amp;quot;, CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall, SetLastError = true)]      &lt;br /&gt;&amp;#160;&amp;#160; internal static extern IntPtr CreateFile(      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; string lpFileName,      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; uint dwDesiredAccess,      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; uint dwShareMode,      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; IntPtr SecurityAttributes,      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; uint dwCreationDisposition,      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; uint dwFlagsAndAttributes,      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; IntPtr hTemplateFile); &lt;/p&gt;    &lt;p&gt;&amp;#160;&amp;#160; [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]     &lt;br /&gt;&amp;#160;&amp;#160; [DllImport(&amp;quot;kernel32.dll&amp;quot;, CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall, SetLastError = true)]      &lt;br /&gt;&amp;#160;&amp;#160; internal static extern bool CloseHandle(IntPtr hHandle);&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;Also, we will need a number of structures, such as device attributes and capabilities.&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;[StructLayout(LayoutKind.Sequential)]     &lt;br /&gt;internal struct SP_DEVICE_INTERFACE_DATA {      &lt;br /&gt;&amp;#160;&amp;#160; public int cbSize;      &lt;br /&gt;&amp;#160;&amp;#160; public Guid InterfaceClassGuid;      &lt;br /&gt;&amp;#160;&amp;#160; public int Flags;      &lt;br /&gt;&amp;#160;&amp;#160; public int Reserved;      &lt;br /&gt;} &lt;/p&gt;    &lt;p&gt;[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]     &lt;br /&gt;internal class PSP_DEVICE_INTERFACE_DETAIL_DATA {      &lt;br /&gt;&amp;#160;&amp;#160; public int cbSize;      &lt;br /&gt;&amp;#160;&amp;#160; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]      &lt;br /&gt;&amp;#160;&amp;#160; public string DevicePath;      &lt;br /&gt;} &lt;/p&gt;    &lt;p&gt;[StructLayout(LayoutKind.Sequential)]     &lt;br /&gt;internal struct HIDD_ATTRIBUTES {      &lt;br /&gt;&amp;#160;&amp;#160; public int Size; // = sizeof (struct _HIDD_ATTRIBUTES) = 10      &lt;br /&gt;&amp;#160;&amp;#160; public UInt16 VendorID;      &lt;br /&gt;&amp;#160;&amp;#160; public UInt16 ProductID;      &lt;br /&gt;&amp;#160;&amp;#160; public UInt16 VersionNumber;      &lt;br /&gt;}      &lt;br /&gt;[StructLayout(LayoutKind.Sequential)]      &lt;br /&gt;internal struct HIDP_CAPS {      &lt;br /&gt;&amp;#160;&amp;#160; public UInt16 Usage;      &lt;br /&gt;&amp;#160;&amp;#160; public UInt16 UsagePage;      &lt;br /&gt;&amp;#160;&amp;#160; public UInt16 InputReportByteLength;      &lt;br /&gt;&amp;#160;&amp;#160; public UInt16 OutputReportByteLength;      &lt;br /&gt;&amp;#160;&amp;#160; public UInt16 FeatureReportByteLength;      &lt;br /&gt;&amp;#160;&amp;#160; [MarshalAs(UnmanagedType.ByValArray, SizeConst = 17)]      &lt;br /&gt;&amp;#160;&amp;#160; public UInt16[] Reserved;      &lt;br /&gt;&amp;#160;&amp;#160; public UInt16 NumberLinkCollectionNodes;      &lt;br /&gt;&amp;#160;&amp;#160; public UInt16 NumberInputButtonCaps;      &lt;br /&gt;&amp;#160;&amp;#160; public UInt16 NumberInputValueCaps;      &lt;br /&gt;&amp;#160;&amp;#160; public UInt16 NumberInputDataIndices;      &lt;br /&gt;&amp;#160;&amp;#160; public UInt16 NumberOutputButtonCaps;      &lt;br /&gt;&amp;#160;&amp;#160; public UInt16 NumberOutputValueCaps;      &lt;br /&gt;&amp;#160;&amp;#160; public UInt16 NumberOutputDataIndices;      &lt;br /&gt;&amp;#160;&amp;#160; public UInt16 NumberFeatureButtonCaps;      &lt;br /&gt;&amp;#160;&amp;#160; public UInt16 NumberFeatureValueCaps;      &lt;br /&gt;&amp;#160;&amp;#160; public UInt16 NumberFeatureDataIndices;      &lt;br /&gt;}&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;And a number of system constants&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;internal const uint DIGCF_PRESENT = 0x00000002;     &lt;br /&gt;internal const uint DIGCF_DEVICEINTERFACE = 0x00000010;      &lt;br /&gt;internal const uint GENERIC_READ = 0x80000000;      &lt;br /&gt;internal const uint GENERIC_WRITE = 0x40000000;      &lt;br /&gt;internal const uint FILE_SHARE_READ = 0x00000001;      &lt;br /&gt;internal const uint FILE_SHARE_WRITE = 0x00000002;      &lt;br /&gt;internal const int OPEN_EXISTING = 3;      &lt;br /&gt;internal const int FILE_FLAG_OVERLAPPED = 0x40000000;      &lt;br /&gt;internal const uint MAX_USB_DEVICES = 16;&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;Now, we are ready to start. So let’s find all devices and get its information&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;Native.HidD_GetHidGuid(ref _hidGuid);     &lt;br /&gt;hHidDeviceInfo = Native.SetupDiGetClassDevs(ref _hidGuid, null, IntPtr.Zero, Native.DIGCF_PRESENT | Native.DIGCF_DEVICEINTERFACE);&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;Now, if a handle we get is valid, we should search our specific device. For this purpose, we have to read device interface information and then get details info about this device.&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;if (hHidDeviceInfo.ToInt32() &amp;gt; -1) {     &lt;br /&gt;&amp;#160;&amp;#160; uint i = 0;      &lt;br /&gt;&amp;#160;&amp;#160; while (!isValid &amp;amp;&amp;amp; i &amp;lt; Native.MAX_USB_DEVICES) {      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; var hidDeviceInterfaceData = new Native.SP_DEVICE_INTERFACE_DATA();      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; hidDeviceInterfaceData.cbSize = Marshal.SizeOf(hidDeviceInterfaceData);      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; if (Native.SetupDiEnumDeviceInterfaces(hHidDeviceInfo, 0, ref _hidGuid, i, ref hidDeviceInterfaceData)) {&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;Once we have all this and information is valid, let’s detect its capabilities&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;bool detailResult;     &lt;br /&gt;uint length, required;      &lt;br /&gt;Native.SetupDiGetDeviceInterfaceDetail(hHidDeviceInfo, ref hidDeviceInterfaceData, IntPtr.Zero, 0, out length, IntPtr.Zero);      &lt;br /&gt;var hidDeviceInterfaceDetailData = new Native.PSP_DEVICE_INTERFACE_DETAIL_DATA();      &lt;br /&gt;hidDeviceInterfaceDetailData.cbSize = 5; //DWORD cbSize (size 4) + Char[0] (size 1) for 32bit only!      &lt;br /&gt;var hDeviceInterfaceDetailData = Marshal.AllocHGlobal(Marshal.SizeOf(hidDeviceInterfaceDetailData));      &lt;br /&gt;Marshal.StructureToPtr(hidDeviceInterfaceDetailData, hDeviceInterfaceDetailData, true);      &lt;br /&gt;detailResult = Native.SetupDiGetDeviceInterfaceDetail(hHidDeviceInfo, ref hidDeviceInterfaceData, hDeviceInterfaceDetailData, length, out required, IntPtr.Zero);      &lt;br /&gt;Marshal.PtrToStructure(hDeviceInterfaceDetailData, hidDeviceInterfaceDetailData);      &lt;br /&gt;if (detailResult) {&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;To do this, we have to create memory file first and then share device attributes by using this file.&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;base.handle = Native.CreateFile(hidDeviceInterfaceDetailData.DevicePath,      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; Native.GENERIC_READ |      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; Native.GENERIC_WRITE,      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; Native.FILE_SHARE_READ |      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; Native.FILE_SHARE_WRITE,       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; IntPtr.Zero,      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; Native.OPEN_EXISTING,      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; Native.FILE_FLAG_OVERLAPPED,       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; IntPtr.Zero);      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; if (base.handle.ToInt32() &amp;gt; -1) {      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; Native.HIDD_ATTRIBUTES hidDeviceAttributes;      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; if (Native.HidD_GetAttributes(base.handle, out hidDeviceAttributes)) {&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;All the rest is straight forward. Just compare info retrieved with one we already have. And, of cause, release all resources were used (remember, we’re in win32 api world!)&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;if ((hidDeviceAttributes.VendorID == vid) &amp;amp;&amp;amp; (hidDeviceAttributes.ProductID == pid)) {     &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; isValid = true;      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; ProductID = pid;      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; VendorID = vid;      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; VersionNumber = hidDeviceAttributes.VersionNumber;      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; IntPtr buffer = Marshal.AllocHGlobal(126);//max alloc for string;      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; if (Native.HidD_GetProductString(this.handle, buffer, 126)) Name = Marshal.PtrToStringAuto(buffer);      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; if (Native.HidD_GetSerialNumberString(this.handle, buffer, 126)) SerialNumber = Marshal.PtrToStringAuto(buffer);      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; Marshal.FreeHGlobal(buffer);      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; var capabilities = new Native.HIDP_CAPS();      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; IntPtr hPreparsedData;      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; if (Native.HidD_GetPreparsedData(this.handle, out hPreparsedData)) {      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; if (Native.HidP_GetCaps(hPreparsedData, out capabilities)) FeatureReportLength = capabilities.FeatureReportByteLength;      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; Native.HidD_FreePreparsedData(hPreparsedData);      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; }      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; break;      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; }      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; } else {      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; Native.CloseHandle(base.handle);      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; }      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; }      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; }      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; Marshal.FreeHGlobal(hDeviceInterfaceDetailData);      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; }      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; i++; &lt;/p&gt;    &lt;p&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; }&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;Now we have a handle to our device and can manipulate it. Like this:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;using (var device = USBRadioDevice.FindDevice(0x0000, 0x1111)) {     &lt;br /&gt;…      &lt;br /&gt;}&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;But we still have to provide methods for such usage. Here there are no very complicated code.&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;public static USBDevice FindDevice(uint pid, uint vid) {     &lt;br /&gt;&amp;#160;&amp;#160; var device = new USBDevice(pid,vid);      &lt;br /&gt;&amp;#160;&amp;#160; var fillRegisters = device.InitRegisters();      &lt;br /&gt;&amp;#160;&amp;#160; if (!device.IsInvalid &amp;amp;&amp;amp; fillRegisters) return device;      &lt;br /&gt;&amp;#160;&amp;#160; else throw new ArgumentOutOfRangeException(string.Format(&amp;quot;Human input device {0} was not found.&amp;quot;, pid));      &lt;br /&gt;} &lt;/p&gt;    &lt;p&gt;public override string ToString() {     &lt;br /&gt;&amp;#160;&amp;#160; return string.Format(&amp;quot;{0} (Product:{1:x}, Vendor:{2:x}, Version:{3:x}, S/N:{4})&amp;quot;, Name, ProductID, VendorID, VersionNumber, SerialNumber);      &lt;br /&gt;} &lt;/p&gt;    &lt;p&gt;[ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]     &lt;br /&gt;protected override bool ReleaseHandle() {      &lt;br /&gt;&amp;#160;&amp;#160; return Native.CloseHandle(base.handle);      &lt;br /&gt;} &lt;/p&gt;    &lt;p&gt;#region IDisposable Members     &lt;br /&gt;public void Dispose() {      &lt;br /&gt;&amp;#160;&amp;#160; Dispose(true);      &lt;br /&gt;&amp;#160;&amp;#160; GC.SuppressFinalize(this); &lt;/p&gt;    &lt;p&gt;}     &lt;br /&gt;[SecurityPermission(SecurityAction.Demand, UnmanagedCode = true)]      &lt;br /&gt;void IDisposable.Dispose() {      &lt;br /&gt;&amp;#160;&amp;#160; if (base.handle != null &amp;amp;&amp;amp; !base.IsInvalid) {      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; // Free the handle      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; base.Dispose();      &lt;br /&gt;&amp;#160;&amp;#160; }      &lt;br /&gt;} &lt;/p&gt;    &lt;p&gt;#endregion&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;We done. Have a nice day and be good people.&lt;/p&gt;&lt;img src="http://blogs.microsoft.co.il/aggbug.aspx?PostID=204291" width="1" height="1"&gt;</description><category domain="http://blogs.microsoft.co.il/blogs/tamir/archive/tags/WPF/default.aspx">WPF</category><category domain="http://blogs.microsoft.co.il/blogs/tamir/archive/tags/tutorial/default.aspx">tutorial</category><category domain="http://blogs.microsoft.co.il/blogs/tamir/archive/tags/Tips+and+Tricks/default.aspx">Tips and Tricks</category><category domain="http://blogs.microsoft.co.il/blogs/tamir/archive/tags/WPF+crossbow/default.aspx">WPF crossbow</category><category domain="http://blogs.microsoft.co.il/blogs/tamir/archive/tags/source/default.aspx">source</category><category domain="http://blogs.microsoft.co.il/blogs/tamir/archive/tags/Vista/default.aspx">Vista</category><category domain="http://blogs.microsoft.co.il/blogs/tamir/archive/tags/C_2300_/default.aspx">C#</category><category domain="http://blogs.microsoft.co.il/blogs/tamir/archive/tags/.NET+3.5/default.aspx">.NET 3.5</category><category domain="http://blogs.microsoft.co.il/blogs/tamir/archive/tags/Work+process/default.aspx">Work process</category><category domain="http://blogs.microsoft.co.il/blogs/tamir/archive/tags/DEV/default.aspx">DEV</category><category domain="http://blogs.microsoft.co.il/blogs/tamir/archive/tags/Windows+7/default.aspx">Windows 7</category><category domain="http://blogs.microsoft.co.il/blogs/tamir/archive/tags/Hardware/default.aspx">Hardware</category><category domain="http://blogs.microsoft.co.il/blogs/tamir/archive/tags/Interop/default.aspx">Interop</category></item><item><title>Capturing and streaming sound by using DirectSound with C#</title><link>http://blogs.microsoft.co.il/blogs/tamir/archive/2008/12/25/capturing-and-streaming-sound-by-using-directsound-with-c.aspx</link><pubDate>Thu, 25 Dec 2008 23:48:20 GMT</pubDate><guid isPermaLink="false">b5c4f5bc-c09b-4439-a595-91a98c1847df:201052</guid><dc:creator>Tamir Khason</dc:creator><slash:comments>3</slash:comments><description>&lt;h3&gt;[This blog was migrated. You will not be able to comment here.&lt;br /&gt;The new URL of this post is &lt;a href="http://khason.net/blog/capturing-and-streaming-sound-by-using-directsound-with-c/"&gt;http://khason.net/blog/capturing-and-streaming-sound-by-using-directsound-with-c/&lt;/a&gt;]&lt;/h3&gt;&lt;hr /&gt;&lt;p&gt;I already wrote a little about &lt;a href="http://blogs.microsoft.co.il/blogs/tamir/archive/2008/02/17/sound-tone-and-dtmf-generation-by-using-managed-directsound-and-c-and-sine-tone-detection-with-pure-managed-goertzel-algorithm-implementation.aspx"&gt;managed way to use DirectX DirectSound&lt;/a&gt;. Today we’ll speak about how to get sound from your microphone or any other DirectSound capturing device (such as &lt;a href="http://blogs.microsoft.co.il/blogs/tamir/archive/2008/12/12/reading-and-decoding-rds-radio-data-system-in-c.aspx"&gt;FM receiver&lt;/a&gt;) and stream it out to your PC speakers and any other DirectSound Output device. So, let’s start creating our first echo service by using managed DirectX.&lt;/p&gt;  &lt;p&gt;&lt;img style="border-bottom:0px;border-left:0px;display:inline;border-top:0px;border-right:0px;" title="image" border="0" alt="image" src="http://blogs.microsoft.co.il/blogs/tamir/image_13541F81.png" width="225" height="229" /&gt; &lt;/p&gt;  &lt;p&gt;First of all we should decide what Wave format we want to use for capturing and recording. So, let’s choose anything reasonable :)&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;var format = new WaveFormat {     &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; SamplesPerSecond = 96000,      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; BitsPerSample = 16,      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; Channels = 2,      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; FormatTag = WaveFormatTag.Pcm      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; };&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;Now, we should calculate block align and average byte per second value for this format. I’m wondering why it cannot be done automatically…&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;format.BlockAlign = (short)(format.Channels * (format.BitsPerSample / 8));     &lt;br /&gt;format.AverageBytesPerSecond = format.SamplesPerSecond * format.BlockAlign;&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;Next step is to set the size of two buffers – one for input and other for output. Generally those buffers are circular, and capturing one should be twice bigger, then output. Why? Because we choose two channels to use. Also, we should decide about chunk size of the buffer, we want to signal when filled.&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;_dwNotifySize = Math.Max(4096, format.AverageBytesPerSecond / 8);     &lt;br /&gt;_dwNotifySize -= _dwNotifySize % format.BlockAlign;      &lt;br /&gt;_dwCaptureBufferSize = NUM_BUFFERS * _dwNotifySize;      &lt;br /&gt;_dwOutputBufferSize = NUM_BUFFERS * _dwNotifySize / 2;&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;Next step is to create CaptureBufferDescriptor and actual capturing buffer. We’ll enumerate all devices and choose one, satisfies given string (captureDescriptor) – for example “Mic” :)&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;var cap = default(Capture);     &lt;br /&gt;var cdc = new CaptureDevicesCollection();      &lt;br /&gt;for (int i = 0; i &amp;lt; cdc.Count; i++) {      &lt;br /&gt;&amp;#160;&amp;#160; if (cdc[i].Description.ToLower().Contains(captureDescriptor.ToLower())) {      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; cap = new Capture(cdc[i].DriverGuid);      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; break;      &lt;br /&gt;&amp;#160;&amp;#160; }      &lt;br /&gt;}      &lt;br /&gt;var capDesc = new CaptureBufferDescription {      &lt;br /&gt;&amp;#160;&amp;#160; Format = format,      &lt;br /&gt;&amp;#160;&amp;#160; BufferBytes = _dwCaptureBufferSize      &lt;br /&gt;};      &lt;br /&gt;_dwCapBuffer = new CaptureBuffer(capDesc, cap);&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;Then we’ll create output device and buffer. To simplify program, we will use default speakers to output, however, you can choose output device the same way we did for capturing. Also, because DirectSound uses any window as it’s message pump, we have to use SetCooperativeLevel method. In my case (windowless application), I’ll use desktop window as message broker. This why you will have to add Windows.Forms as reference for your project, even if it console application. Also, do not forget to set GlobalFocus value to True, if you want to play echo, even if desktop window is not focused.&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;var dev = new Device();     &lt;br /&gt;dev.SetCooperativeLevel(Native.GetDesktopWindow(), CooperativeLevel.Priority); &lt;/p&gt;    &lt;p&gt;var devDesc = new BufferDescription {     &lt;br /&gt;&amp;#160;&amp;#160; BufferBytes = _dwOutputBufferSize,      &lt;br /&gt;&amp;#160;&amp;#160; Format = format,      &lt;br /&gt;&amp;#160;&amp;#160; DeferLocation = true,      &lt;br /&gt;&amp;#160;&amp;#160; GlobalFocus = true      &lt;br /&gt;};      &lt;br /&gt;_dwDevBuffer = new SecondaryBuffer(devDesc, dev);&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;Now, we will subscribe to buffer notifications and set autoResetEvent to be fired when it filled up.&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;var _resetEvent = new AutoResetEvent(false);     &lt;br /&gt;var _notify = new Notify(_dwCapBuffer);      &lt;br /&gt;//half&amp;amp;half      &lt;br /&gt;var bpn1 = new BufferPositionNotify();      &lt;br /&gt;bpn1.Offset = _dwCapBuffer.Caps.BufferBytes / 2 - 1;      &lt;br /&gt;bpn1.EventNotifyHandle = _resetEvent.SafeWaitHandle.DangerousGetHandle();      &lt;br /&gt;var bpn2 = new BufferPositionNotify();      &lt;br /&gt;bpn2.Offset = _dwCapBuffer.Caps.BufferBytes - 1;      &lt;br /&gt;bpn2.EventNotifyHandle = _resetEvent.SafeWaitHandle.DangerousGetHandle(); &lt;/p&gt;    &lt;p&gt;_notify.SetNotificationPositions(new BufferPositionNotify[] { bpn1, bpn2 });&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;Almost done, the only thing we should do is to fire worker thread to take care on messages&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;int offset = 0;     &lt;br /&gt;_dwCaptureThread = new Thread((ThreadStart)delegate {      &lt;br /&gt;&amp;#160;&amp;#160; _dwCapBuffer.Start(true); &lt;/p&gt;    &lt;p&gt;&amp;#160;&amp;#160; while (IsReady) {     &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; _resetEvent.WaitOne();      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; var read = _dwCapBuffer.Read(offset, typeof(byte), LockFlag.None, _dwOutputBufferSize);      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; _dwDevBuffer.Write(0, read, LockFlag.EntireBuffer);      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; offset = (offset + _dwOutputBufferSize) % _dwCaptureBufferSize;      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; _dwDevBuffer.SetCurrentPosition(0);      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; _dwDevBuffer.Play(0, BufferPlayFlags.Default);      &lt;br /&gt;&amp;#160;&amp;#160; }      &lt;br /&gt;&amp;#160;&amp;#160; _dwCapBuffer.Stop();      &lt;br /&gt;});      &lt;br /&gt;_dwCaptureThread.Start();&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;That’s it. Compile and run. Now if you’ll speak, you can hear your echo from PC speakers. &lt;/p&gt;  &lt;p&gt;Merry Christmas for whom concerns and be good people – do not scare your co-workers with strange sounds – be polite and make the volume lower :) &lt;/p&gt;&lt;img src="http://blogs.microsoft.co.il/aggbug.aspx?PostID=201052" width="1" height="1"&gt;</description><category domain="http://blogs.microsoft.co.il/blogs/tamir/archive/tags/WPF/default.aspx">WPF</category><category domain="http://blogs.microsoft.co.il/blogs/tamir/archive/tags/tutorial/default.aspx">tutorial</category><category domain="http://blogs.microsoft.co.il/blogs/tamir/archive/tags/Tips+and+Tricks/default.aspx">Tips and Tricks</category><category domain="http://blogs.microsoft.co.il/blogs/tamir/archive/tags/source/default.aspx">source</category><category domain="http://blogs.microsoft.co.il/blogs/tamir/archive/tags/C_2300_/default.aspx">C#</category><category domain="http://blogs.microsoft.co.il/blogs/tamir/archive/tags/Microsoft/default.aspx">Microsoft</category><category domain="http://blogs.microsoft.co.il/blogs/tamir/archive/tags/.NET+3.5/default.aspx">.NET 3.5</category><category domain="http://blogs.microsoft.co.il/blogs/tamir/archive/tags/DirectX/default.aspx">DirectX</category><category domain="http://blogs.microsoft.co.il/blogs/tamir/archive/tags/Work+process/default.aspx">Work process</category><category domain="http://blogs.microsoft.co.il/blogs/tamir/archive/tags/DEV/default.aspx">DEV</category><category domain="http://blogs.microsoft.co.il/blogs/tamir/archive/tags/Hardware/default.aspx">Hardware</category><category domain="http://blogs.microsoft.co.il/blogs/tamir/archive/tags/Interop/default.aspx">Interop</category></item><item><title>Quick Silverlight (and WPF) tip: How to write program without XAML</title><link>http://blogs.microsoft.co.il/blogs/tamir/archive/2008/12/23/quick-silverlight-and-wpf-tip-how-to-write-program-without-xaml.aspx</link><pubDate>Tue, 23 Dec 2008 23:51:00 GMT</pubDate><guid isPermaLink="false">b5c4f5bc-c09b-4439-a595-91a98c1847df:199696</guid><dc:creator>Tamir Khason</dc:creator><slash:comments>2</slash:comments><description>&lt;h3&gt;[This blog was migrated. You will not be able to comment here.&lt;br /&gt;The new URL of this post is &lt;a href="http://khason.net/blog/quick-silverlight-and-wpf-tip-how-to-write-program-without-xaml/"&gt;http://khason.net/blog/quick-silverlight-and-wpf-tip-how-to-write-program-without-xaml/&lt;/a&gt;]&lt;/h3&gt;&lt;hr /&gt;&lt;p&gt;From the moment, &lt;a href="http://2009.visitmix.com/MIXtify/TenKGallery.aspx"&gt;10K MIX09 contest was launched&lt;/a&gt;, I got more, then 20 people, asking the same question: &lt;b&gt;Is it possible to have Silverlight program up and running without XAML at all?&lt;/b&gt;&lt;/p&gt;  &lt;p&gt;&lt;img src="http://blogs.microsoft.co.il/blogs/tamir/image_5432FC95.png" style="border:0px none;display:inline;" title="image" alt="image" width="315" border="0" height="289" /&gt; &lt;/p&gt;  &lt;p&gt;The answer is “&lt;b&gt;YES, IT IS&lt;/b&gt;”. Here is how:&lt;/p&gt;  &lt;p&gt;All you need for run WPF or Silverlight application is &lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;Class inherited from System.Windows.Application&lt;/li&gt;    &lt;li&gt;Class inherited from System.Windows.Controls.UserControl&lt;/li&gt; &lt;/ol&gt;  &lt;p&gt;So, Let’s create new WPF or Silverlight application and delete all files from the project directory. Then add one file, named App.cs (or Foo.cs or Whatever.cs – the length of the file name is not included :) ) and write there :&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;using System.Windows.Controls;     &lt;br /&gt;using System.Windows;&lt;/p&gt;    &lt;p&gt;public class App : Application {public App() {this.Startup += (s, e) =&amp;gt; { this.RootVisual = Foo.M; };}}&amp;nbsp; &lt;br /&gt;class Foo: UserControl {static Foo _b = new Foo();public static Board M { get { return _b; } }&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;We done. F5, be happy. You just wrote first officially smallest Silverlight functional application. Good luck with Mix09 contest.&lt;/p&gt;&lt;img src="http://blogs.microsoft.co.il/aggbug.aspx?PostID=199696" width="1" height="1"&gt;</description><category domain="http://blogs.microsoft.co.il/blogs/tamir/archive/tags/WPF/default.aspx">WPF</category><category domain="http://blogs.microsoft.co.il/blogs/tamir/archive/tags/tutorial/default.aspx">tutorial</category><category domain="http://blogs.microsoft.co.il/blogs/tamir/archive/tags/Tips+and+Tricks/default.aspx">Tips and Tricks</category><category domain="http://blogs.microsoft.co.il/blogs/tamir/archive/tags/source/default.aspx">source</category><category domain="http://blogs.microsoft.co.il/blogs/tamir/archive/tags/C_2300_/default.aspx">C#</category><category domain="http://blogs.microsoft.co.il/blogs/tamir/archive/tags/Silverlight/default.aspx">Silverlight</category><category domain="http://blogs.microsoft.co.il/blogs/tamir/archive/tags/fun/default.aspx">fun</category><category domain="http://blogs.microsoft.co.il/blogs/tamir/archive/tags/Microsoft/default.aspx">Microsoft</category><category domain="http://blogs.microsoft.co.il/blogs/tamir/archive/tags/.NET+3.5/default.aspx">.NET 3.5</category><category domain="http://blogs.microsoft.co.il/blogs/tamir/archive/tags/Work+process/default.aspx">Work process</category><category domain="http://blogs.microsoft.co.il/blogs/tamir/archive/tags/DEV/default.aspx">DEV</category></item><item><title>Reading and decoding RDS (Radio Data System) in C#</title><link>http://blogs.microsoft.co.il/blogs/tamir/archive/2008/12/12/reading-and-decoding-rds-radio-data-system-in-c.aspx</link><pubDate>Fri, 12 Dec 2008 18:44:24 GMT</pubDate><guid isPermaLink="false">b5c4f5bc-c09b-4439-a595-91a98c1847df:191019</guid><dc:creator>Tamir Khason</dc:creator><slash:comments>4</slash:comments><description>&lt;h3&gt;[This blog was migrated. You will not be able to comment here.&lt;br /&gt;The new URL of this post is &lt;a href="http://khason.net/blog/reading-and-decoding-rds-radio-data-system-in-c/"&gt;http://khason.net/blog/reading-and-decoding-rds-radio-data-system-in-c/&lt;/a&gt;]&lt;/h3&gt;&lt;hr /&gt;&lt;p&gt;&lt;a href="http://en.wikipedia.org/wiki/Radio_Data_System"&gt;RDS or Radio Data System&lt;/a&gt; is very common in US and many European countries. It is communication protocol used to send small amount of digital information using regular FM radio broadcast. This protocol is used to &amp;quot;tell&amp;quot; your receiver about alternative frequencies, time, program notifications, program types, traffic information and regular text (such as singer name or genre). Unfortunately in Israel RDS is not very common and there is very limited number of radio stations broadcasts RDS information. &lt;/p&gt; &lt;p&gt;&lt;img border="0" alt="image" src="http://blogs.microsoft.co.il/blogs/tamir/WindowsLiveWriter/ReadinganddecodingRDSRadioDataSysteminC_1238A/image_01bbfbdd-e89d-4a4e-89cd-e209655b5664.png" width="207" height="54" /&gt; &lt;/p&gt; &lt;h3&gt;How RDS works?&lt;/h3&gt; &lt;p&gt;As mentioned earlier, it uses FM subcarrier to broadcast digital information. It was designed to support 10 and 18 characters numeric and 80 characters alphanumeric displays. RDS operates at 1187.5 bps and based on 26-bit word consisting of 16 data and 10 error detection bits. Due to the fact, that FM carrier is not very reliable, error code allows correct information to be received even if an error of 3-5 bits exists within 26 bit block. Each four data blocks interpreted as 104-bit signal and named &amp;quot;group&amp;quot;. Depending of the type of information, contained within the group, as different group type code is defined and transmitted within the group as upper five bits code. Even if more, then 104 bits required to completely send the information, there is no requirement that the next segment of the transmission be sent in the next group. There are 32 known groups types, defined by &lt;a&gt;RFC&lt;/a&gt;:&lt;/p&gt; &lt;blockquote&gt; &lt;p&gt;private enum groupType : byte {&lt;br /&gt;&amp;nbsp;&amp;nbsp; RDS_TYPE_0A = (0 * 2 + 0),&lt;br /&gt;&amp;nbsp;&amp;nbsp; RDS_TYPE_0B = (0 * 2 + 1),&lt;br /&gt;&amp;nbsp;&amp;nbsp; RDS_TYPE_1A = (1 * 2 + 0),&lt;br /&gt;&amp;nbsp;&amp;nbsp; RDS_TYPE_1B = (1 * 2 + 1),&lt;br /&gt;&amp;nbsp;&amp;nbsp; RDS_TYPE_2A = (2 * 2 + 0),&lt;br /&gt;&amp;nbsp;&amp;nbsp; RDS_TYPE_2B = (2 * 2 + 1),&lt;br /&gt;&amp;nbsp;&amp;nbsp; RDS_TYPE_3A = (3 * 2 + 0),&lt;br /&gt;&amp;nbsp;&amp;nbsp; RDS_TYPE_3B = (3 * 2 + 1),&lt;br /&gt;&amp;nbsp;&amp;nbsp; RDS_TYPE_4A = (4 * 2 + 0),&lt;br /&gt;&amp;nbsp;&amp;nbsp; RDS_TYPE_4B = (4 * 2 + 1),&lt;br /&gt;&amp;nbsp;&amp;nbsp; RDS_TYPE_5A = (5 * 2 + 0),&lt;br /&gt;&amp;nbsp;&amp;nbsp; RDS_TYPE_5B = (5 * 2 + 1),&lt;br /&gt;&amp;nbsp;&amp;nbsp; RDS_TYPE_6A = (6 * 2 + 0),&lt;br /&gt;&amp;nbsp;&amp;nbsp; RDS_TYPE_6B = (6 * 2 + 1),&lt;br /&gt;&amp;nbsp;&amp;nbsp; RDS_TYPE_7A = (7 * 2 + 0),&lt;br /&gt;&amp;nbsp;&amp;nbsp; RDS_TYPE_7B = (7 * 2 + 1),&lt;br /&gt;&amp;nbsp;&amp;nbsp; RDS_TYPE_8A = (8 * 2 + 0),&lt;br /&gt;&amp;nbsp;&amp;nbsp; RDS_TYPE_8B = (8 * 2 + 1),&lt;br /&gt;&amp;nbsp;&amp;nbsp; RDS_TYPE_9A = (9 * 2 + 0),&lt;br /&gt;&amp;nbsp;&amp;nbsp; RDS_TYPE_9B = (9 * 2 + 1),&lt;br /&gt;&amp;nbsp;&amp;nbsp; RDS_TYPE_10A = (10 * 2 + 0),&lt;br /&gt;&amp;nbsp;&amp;nbsp; RDS_TYPE_10B = (10 * 2 + 1),&lt;br /&gt;&amp;nbsp;&amp;nbsp; RDS_TYPE_11A = (11 * 2 + 0),&lt;br /&gt;&amp;nbsp;&amp;nbsp; RDS_TYPE_11B = (11 * 2 + 1),&lt;br /&gt;&amp;nbsp;&amp;nbsp; RDS_TYPE_12A = (12 * 2 + 0),&lt;br /&gt;&amp;nbsp;&amp;nbsp; RDS_TYPE_12B = (12 * 2 + 1),&lt;br /&gt;&amp;nbsp;&amp;nbsp; RDS_TYPE_13A = (13 * 2 + 0),&lt;br /&gt;&amp;nbsp;&amp;nbsp; RDS_TYPE_13B = (13 * 2 + 1),&lt;br /&gt;&amp;nbsp;&amp;nbsp; RDS_TYPE_14A = (14 * 2 + 0),&lt;br /&gt;&amp;nbsp;&amp;nbsp; RDS_TYPE_14B = (14 * 2 + 1),&lt;br /&gt;&amp;nbsp;&amp;nbsp; RDS_TYPE_15A = (15 * 2 + 0),&lt;br /&gt;&amp;nbsp;&amp;nbsp; RDS_TYPE_15B = (15 * 2 + 1)&lt;br /&gt;}&lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;Not all groups are in use all the time. However, there are some commitments, defined by the protocol. For example, 1A have to be transmitted at least once a second. This group contains special information, required for receivers to be synchronized and locked into the transmitting channel. &lt;/p&gt; &lt;p&gt;Within the error correction information we also receive the direction to treat them.&lt;/p&gt; &lt;blockquote&gt; &lt;p&gt;private enum correctedType : byte {&lt;br /&gt;&amp;nbsp;&amp;nbsp; NONE = 0,&lt;br /&gt;&amp;nbsp;&amp;nbsp; ONE_TO_TWO = 1,&lt;br /&gt;&amp;nbsp;&amp;nbsp; THREE_TO_FIVE = 2,&lt;br /&gt;&amp;nbsp;&amp;nbsp; UNCORRECTABLE = 3&lt;br /&gt;}&lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;Also, each message type has it own limits. For example RT (Radio Text - 64 character text to display on your receiver) and PS (Programme Service - eight character station identification) message are limited to 2 groups, when PI (Programme Identification - unique code of the station) and PTY (Programme Type - one of 31 predefined program types - e.g. News, Drama, Music) are limited to 4.&lt;/p&gt; &lt;p&gt;In addition to those constraints, block types are also different. But in this case, there are only 4 kinds&lt;/p&gt; &lt;blockquote&gt; &lt;p&gt;private enum blockType : byte {&lt;br /&gt;&amp;nbsp;&amp;nbsp; A = 6,&lt;br /&gt;&amp;nbsp;&amp;nbsp; B = 4,&lt;br /&gt;&amp;nbsp;&amp;nbsp; C = 2,&lt;br /&gt;&amp;nbsp;&amp;nbsp; D = 0&lt;br /&gt;}&lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;So, what we&amp;#39;re waiting for? Let&amp;#39;s start working.&lt;/p&gt; &lt;h3&gt;Handling errors&lt;/h3&gt; &lt;p&gt;First of all we should take care on errors and fix them if possible. For this purpose, we should first count them and detect the way of fixing&lt;/p&gt; &lt;blockquote&gt; &lt;p&gt;var errorCount = (byte)((registers[0xa] &amp;amp; 0x0E00) &amp;gt;&amp;gt; 9);&lt;br /&gt;var errorFlags = (byte)(registers[0x6] &amp;amp; 0xFF);&lt;br /&gt;if (errorCount &amp;lt; 4) {&lt;br /&gt;&amp;nbsp;&amp;nbsp; _blocksValid += (byte)(4 - errorCount);&lt;br /&gt;} else { /*drop data on more errors*/ return; } &lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;Once it done, we can try to fix them&lt;/p&gt; &lt;blockquote&gt; &lt;p&gt;//Also drop the data if more than two errors were corrected&lt;br /&gt;if (_getErrorsCorrected(errorFlags, blockType.B) &amp;gt; correctedType.ONE_TO_TWO) return;&lt;/p&gt; &lt;p&gt;private correctedType _getErrorsCorrected(byte data, blockType block) { return (correctedType)((data &amp;gt;&amp;gt; (byte)block) &amp;amp; 0x30); }&lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;Now, our registers should be fine and we can start the detection of group type&lt;/p&gt; &lt;h3&gt;Group Type Detection&lt;/h3&gt; &lt;p&gt;This is very simple task, all we have to do is to get five upper bites to get a type and version.&lt;/p&gt; &lt;blockquote&gt; &lt;p&gt;var group_type = (groupType)(registers[0xD] &amp;gt;&amp;gt; 11);&lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;Then we can handle PI and PTY, which we always have in RDS.&lt;/p&gt; &lt;h3&gt;PI and PTY treatment&lt;/h3&gt; &lt;p&gt;Now, let&amp;#39;s update pi code, due to the fact, that B format always have PI in words A and C&lt;/p&gt; &lt;blockquote&gt; &lt;p&gt;_updatePI(registers[0xC]);  &lt;p&gt;if (((byte)group_type &amp;amp; 0x01) != 0) {&lt;br /&gt; _updatePI(registers[0xE]);&lt;br /&gt;}&lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;To update PI, we should check whether the new value is different from the previous and update it only in case it changed. &lt;blockquote&gt; &lt;p&gt;private void _updatePI(byte pi) {&lt;br /&gt;&amp;nbsp;&amp;nbsp; uint rds_pi_validate_count = 0;&lt;br /&gt;&amp;nbsp;&amp;nbsp; uint rds_pi_nonvalidated = 0;  &lt;p&gt;&amp;nbsp;&amp;nbsp; // if the pi value is the same for a certain number of times, update a validated pi variable&lt;br /&gt;&amp;nbsp;&amp;nbsp; if (rds_pi_nonvalidated != pi) {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; rds_pi_nonvalidated = pi;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; rds_pi_validate_count = 1;&lt;br /&gt;&amp;nbsp;&amp;nbsp; } else {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; rds_pi_validate_count++;&lt;br /&gt;&amp;nbsp;&amp;nbsp; }  &lt;p&gt;&amp;nbsp;&amp;nbsp; if (rds_pi_validate_count &amp;gt; PI_VALIDATE_LIMIT) {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; _piDisplay = rds_pi_nonvalidated;&lt;br /&gt;&amp;nbsp;&amp;nbsp; }&lt;br /&gt;}&lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;Then we will update PTY &lt;blockquote&gt; &lt;p&gt;_updatePTY((byte)((registers[0xd] &amp;gt;&amp;gt; 5) &amp;amp; 0x1f));&lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;PTY treatment is very similar to PI, however it can be multiplied.&amp;nbsp; &lt;blockquote&gt; &lt;p&gt;private void _updatePTY(byte pty) {&lt;br /&gt;&amp;nbsp;&amp;nbsp; uint rds_pty_validate_count = 0;&lt;br /&gt;&amp;nbsp;&amp;nbsp; uint rds_pty_nonvalidated = 0;  &lt;p&gt;&amp;nbsp;&amp;nbsp; // if the pty value is the same for a certain number of times, update a validated pty variable&lt;br /&gt;&amp;nbsp;&amp;nbsp; if (rds_pty_nonvalidated != pty) {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; rds_pty_nonvalidated = pty;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; rds_pty_validate_count = 1;&lt;br /&gt;&amp;nbsp;&amp;nbsp; } else {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; rds_pty_validate_count++;&lt;br /&gt;&amp;nbsp;&amp;nbsp; }  &lt;p&gt;&amp;nbsp;&amp;nbsp; if (rds_pty_validate_count &amp;gt; PTY_VALIDATE_LIMIT) {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; _ptyDisplay = rds_pty_nonvalidated;&lt;br /&gt;&amp;nbsp;&amp;nbsp; }&lt;br /&gt;}&lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;When we done with those two groups, we can start handling another. Today, we&amp;#39;ll handle only 0B, 2A and 2B types (I have a good reason for it, due to the fact, that only those are supported in Israel by now :) ) So,  &lt;h3&gt;Handling PS and different RTs&lt;/h3&gt; &lt;p&gt;Simple switch on those groups&lt;/p&gt; &lt;blockquote&gt; &lt;p&gt;switch (group_type) {&lt;br /&gt;&amp;nbsp;&amp;nbsp; case groupType.RDS_TYPE_0B:&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; addr = (byte)((registers[0xd] &amp;amp; 0x3) * 2);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; _updatePS((byte)(addr + 0), (byte)(registers[0xf] &amp;gt;&amp;gt; 8));&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; _updatePS((byte)(addr + 1), (byte)(registers[0xf] &amp;amp; 0xff));&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; break;&lt;br /&gt;&amp;nbsp;&amp;nbsp; case groupType.RDS_TYPE_2A:&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; addr = (byte)((registers[0xd] &amp;amp; 0xf) * 4);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; abflag = (byte)((registers[0xb] &amp;amp; 0x0010) &amp;gt;&amp;gt; 4);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; _updateRT(abflag, 4, addr, (byte[])registers.Skip(0xe), errorFlags);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; break;&lt;br /&gt;&amp;nbsp;&amp;nbsp; case groupType.RDS_TYPE_2B:&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; addr = (byte)((registers[0xd] &amp;amp; 0xf) * 2);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; abflag = (byte)((registers[0xb] &amp;amp; 0x0010) &amp;gt;&amp;gt; 4);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; // The last 32 bytes are unused in this format&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; _rtTmp0[32] = 0x0d;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; _rtTmp1[32] = 0x0d;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; _rtCnt[32] = RT_VALIDATE_LIMIT;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; _updateRT(abflag, 2, addr, (byte[])registers.Skip(0xe), errorFlags);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; break;&lt;br /&gt;}&lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;and let&amp;#39;s dig into PS.&lt;/p&gt; &lt;p&gt;In PS, we have high and low probability bits. So, if new bit in sequence matches the high probability bite and we have recieved enough bytes to max out the counter, we&amp;#39;ll push it into the low probability array.&lt;/p&gt; &lt;blockquote&gt; &lt;p&gt;if (_psTmp0[idx] == default(byte)) {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; if (_psCnt[idx] &amp;lt; PS_VALIDATE_LIMIT) {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; _psCnt[idx]++;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; } else {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; _psCnt[idx] = PS_VALIDATE_LIMIT;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; _psTmp1[idx] = default(byte);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; } &lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;Else, if new byte matches with the low probability byte, we should swap them and then reset the counter, by flagging the text as in transition. &lt;/p&gt; &lt;blockquote&gt; &lt;p&gt;else if (_psTmp1[idx] == default(byte)) {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; if (_psCnt[idx] &amp;gt;= PS_VALIDATE_LIMIT) {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; isTextChange = true;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; _psCnt[idx] = PS_VALIDATE_LIMIT + 1;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; _psTmp1[idx] = _psTmp0[idx];&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; _psTmp0[idx] = default(byte);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; } &lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;When we have an empty byte in high probability array or new bytes does not match anything we know, we should put it into low probability array.&lt;/p&gt; &lt;blockquote&gt; &lt;p&gt;else if (_psCnt[idx] == null) {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; _psTmp0[idx] = default(byte);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; _psCnt[idx] = 1;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; } else {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; _psTmp1[idx] = default(byte);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; } &lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;Now, if we marked our text as changed, we should decrement the count for all characters to prevent displaying of partical message, which in still in transition.&lt;/p&gt; &lt;blockquote&gt; &lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; if (isTextChange) {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; for (byte i = 0; i &amp;lt; _psCnt.Length; i++) {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; if (_psCnt[i] &amp;gt; 1) {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; _psCnt[i]--;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; } &lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;Then by checking PS text for incompetence, when there are characters in high probability array has been seen fewer times, that was limited by validation. &lt;blockquote&gt; &lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; for (byte i = 0; i &amp;lt; _psCnt.Length; i++) {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; if (_psCnt[i] &amp;lt; PS_VALIDATE_LIMIT) {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; isComplete = false;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; break;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; } &lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;Only if PS text in the high probability array is complete, we&amp;#39;ll copy it into display.&lt;/p&gt; &lt;blockquote&gt; &lt;p&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; if (isComplete) {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; for (byte i = 0; i &amp;lt; _psDisplay.Length; i++) {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; _psDisplay[i] = _psTmp0[i];&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;It is not very hard to treat PS. Isn&amp;#39;t it? Let&amp;#39;s see what&amp;#39;s going on with RT.&lt;/p&gt; &lt;p&gt;If A and B message flag changes, we&amp;#39;ll try to force a display by increasing the validation count for each byte. Then, we&amp;#39;ll wipe any cached text.&lt;/p&gt; &lt;blockquote&gt; &lt;p&gt;&amp;nbsp;&amp;nbsp; if (abFlag != _rtFlag &amp;amp;&amp;amp; _rtFlagValid) {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; // If the A/B message flag changes, try to force a display&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; // by increasing the validation count of each byte&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; for (i = 0; i &amp;lt; _rtCnt.Length; i++) _rtCnt[addr + i]++;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; _updateRTValue();  &lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; // Wipe out the cached text &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; for (i = 0; i &amp;lt; _rtCnt.Length; i++) {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; _rtCnt[i] = 0;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; _rtTmp0[i] = 0;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; _rtTmp1[i] = 0;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br /&gt;&amp;nbsp;&amp;nbsp; }&lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;Now A and B flags are safe, sp we can start with message processing. First of all, NULL in RDS means space :)&lt;/p&gt; &lt;blockquote&gt; &lt;p&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp; _rtFlag = abFlag;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;br /&gt;&amp;nbsp;&amp;nbsp; _rtFlagValid = true;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/p&gt; &lt;p&gt;&amp;nbsp;&amp;nbsp; for (i = 0; i &amp;lt; count; i++) {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; if (p[i] == null) p[i] = (byte)&amp;#39; &amp;#39;; &lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;The new byte matches the high probability byte also in this case. We habe to recieve this bite enough to max out counters. Then we can push it into the low probability as well. &lt;blockquote&gt; &lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; if (_rtTmp0[addr + i] == p[i]) {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; if (_rtCnt[addr + i] &amp;lt; RT_VALIDATE_LIMIT) _rtCnt[addr + i]++;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; else {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; _rtCnt[addr + i] = RT_VALIDATE_LIMIT;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; _rtTmp1[addr + i] = p[i];&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; } &lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;When the new byte matches with low probability byte, we&amp;#39;ll swap them as well and reset counters to update text in transition flag. However in this case, our counter will go higher, then the validation limit. So we&amp;#39;ll have to remove it down later.&lt;/p&gt; &lt;blockquote&gt; &lt;p&gt;else if (_rtTmp1[addr + i] == p[i]) { &lt;/p&gt; &lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; if (_rtCnt[addr + i] &amp;gt;= PS_VALIDATE_LIMIT) isChange = true;  &lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; _rtCnt[addr + i] = RT_VALIDATE_LIMIT + 1;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; _rtTmp1[addr + i] = _rtTmp0[addr + i];&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; _rtTmp0[addr + i] = p[i];&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; } &lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;Now, the new byte is replaced an empty byte in the high probability array. Also, if this byte does not match anything, we should move it into low probability.&lt;/p&gt; &lt;blockquote&gt; &lt;p&gt;else if (_rtCnt[addr + i] == null) { &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; _rtTmp0[addr + i] = p[i];&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; _rtCnt[addr + i] = 1;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; } else _rtTmp1[addr + i] = p[i]; &lt;/p&gt; &lt;p&gt;&amp;nbsp;&amp;nbsp; } &lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;Now when the text is changing, we&amp;#39;ll decrement the counter for all characters exactly as we did for PS. &lt;blockquote&gt; &lt;p&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; for (i = 0; i &amp;lt; _rtCnt.Length; i++) {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; if (_rtCnt[i] &amp;gt; 1) _rtCnt[i]--;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br /&gt;&amp;nbsp;&amp;nbsp; } &lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;However, right after, we&amp;#39;ll update display.&amp;nbsp; &lt;/p&gt; &lt;blockquote&gt; &lt;p&gt;&amp;nbsp;&amp;nbsp; _updateRTValue();&lt;br /&gt;}&lt;/p&gt;&lt;/blockquote&gt; &lt;h3&gt;Displaying RT&lt;/h3&gt; &lt;p&gt;But how to convert all those byte arrays into readable message? Simple :)&lt;/p&gt; &lt;p&gt;First of all if text is incomplete, we should keep loading it. Also it makes sense to check whether the target array is shorter then maximum allowed to prevent junk from being displayed.&lt;/p&gt; &lt;blockquote&gt; &lt;p&gt;for (i = 0; i &amp;lt; _rtTmp0.Length; i++) {&lt;br /&gt;&amp;nbsp;&amp;nbsp; if (_rtCnt[i] &amp;lt; RT_VALIDATE_LIMIT) {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; isComplete = false;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; break;&lt;br /&gt;&amp;nbsp;&amp;nbsp; }&lt;br /&gt;&amp;nbsp;&amp;nbsp; if (_rtTmp0[i] == 0x0d) {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; break;&lt;br /&gt;&amp;nbsp;&amp;nbsp; }&lt;br /&gt;} &lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;Now, when our Radio Text is in the high probability and it complete, we should copy buffers.&lt;/p&gt; &lt;blockquote&gt; &lt;p&gt;if (isComplete) {&lt;br /&gt;&amp;nbsp;&amp;nbsp; _Text = string.Empty; &lt;/p&gt; &lt;p&gt;&amp;nbsp;&amp;nbsp; for (i = 0; i &amp;lt; _rtDisplay.Length; i += 2) {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; if ((_rtDisplay[i] != 0x0d) &amp;amp;&amp;amp; (_rtDisplay[i + 1] != 0x0d)) {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; _rtDisplay[i] = _rtTmp0[i + 1];&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; _rtDisplay[i + 1] = _rtTmp0[i];&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; } else {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; _rtDisplay[i] = _rtTmp0[i];&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; _rtDisplay[i + 1] = _rtTmp0[i + 1];&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }  &lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; if (_rtDisplay[i] != 0x0d)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; _Text += _rtDisplay[i];  &lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; if (_rtDisplay[i + 1] != 0x0d)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; _Text += _rtDisplay[i + 1];  &lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; if ((_rtDisplay[i] == 0x0d) || (_rtDisplay[i + 1] == 0x0d))&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; i = (byte)_rtDisplay.Length;&lt;br /&gt;&amp;nbsp;&amp;nbsp; } &lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;And not forget to wipe out everything after the end of the message :)&lt;/p&gt; &lt;blockquote&gt; &lt;p&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp; for (i++; i &amp;lt; _rtDisplay.Length; i++) {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; _rtDisplay[i] = 0;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; _rtCnt[i] = 0;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; _rtTmp0[i] = 0;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; _rtTmp1[i] = 0;&lt;br /&gt;&amp;nbsp;&amp;nbsp; }&lt;br /&gt;} &lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;And finally update the text&lt;/p&gt; &lt;blockquote&gt; &lt;p&gt;Text = _Text;&lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;We done. Now we can handle RDS digital messages, but what to do with analog data we get? Don&amp;#39;t you already know? I &lt;a href="http://blogs.microsoft.co.il/blogs/tamir/archive/2008/02/17/sound-tone-and-dtmf-generation-by-using-managed-directsound-and-c-and-sine-tone-detection-with-pure-managed-goertzel-algorithm-implementation.aspx"&gt;blogged about it here&lt;/a&gt;. &lt;p&gt;Have a nice day and be good people, because you know how to write client, knows to get and parse radio data in managed code. &lt;p&gt;&lt;img border="0" alt="image" src="http://blogs.microsoft.co.il/blogs/tamir/WindowsLiveWriter/ReadinganddecodingRDSRadioDataSysteminC_1238A/image_988a1f1f-0dec-46b1-b494-3c75a0b9ce7d.png" width="263" height="44" /&gt;&lt;/p&gt;&lt;img src="http://blogs.microsoft.co.il/aggbug.aspx?PostID=191019" width="1" height="1"&gt;</description><category domain="http://blogs.microsoft.co.il/blogs/tamir/archive/tags/WPF/default.aspx">WPF</category><category domain="http://blogs.microsoft.co.il/blogs/tamir/archive/tags/tutorial/default.aspx">tutorial</category><category domain="http://blogs.microsoft.co.il/blogs/tamir/archive/tags/Tips+and+Tricks/default.aspx">Tips and Tricks</category><category domain="http://blogs.microsoft.co.il/blogs/tamir/archive/tags/source/default.aspx">source</category><category domain="http://blogs.microsoft.co.il/blogs/tamir/archive/tags/Mobile/default.aspx">Mobile</category><category domain="http://blogs.microsoft.co.il/blogs/tamir/archive/tags/C_2300_/default.aspx">C#</category><category domain="http://blogs.microsoft.co.il/blogs/tamir/archive/tags/.NET+3.5/default.aspx">.NET 3.5</category><category domain="http://blogs.microsoft.co.il/blogs/tamir/archive/tags/Work+process/default.aspx">Work process</category><category domain="http://blogs.microsoft.co.il/blogs/tamir/archive/tags/Math/default.aspx">Math</category><category domain="http://blogs.microsoft.co.il/blogs/tamir/archive/tags/DEV/default.aspx">DEV</category><category domain="http://blogs.microsoft.co.il/blogs/tamir/archive/tags/Hardware/default.aspx">Hardware</category><category domain="http://blogs.microsoft.co.il/blogs/tamir/archive/tags/Interop/default.aspx">Interop</category></item><item><title>How to P/Invoke VarArgs (variable arguments) in C#? ... or hidden junk in CLR</title><link>http://blogs.microsoft.co.il/blogs/tamir/archive/2008/11/19/how-to-p-invoke-varargs-variable-arguments-in-c-or-hidden-junk-in-clr.aspx</link><pubDate>Wed, 19 Nov 2008 11:44:10 GMT</pubDate><guid isPermaLink="false">b5c4f5bc-c09b-4439-a595-91a98c1847df:170664</guid><dc:creator>Tamir Khason</dc:creator><slash:comments>1</slash:comments><description>&lt;h3&gt;[This blog was migrated. You will not be able to comment here.&lt;br /&gt;The new URL of this post is &lt;a href="http://khason.net/blog/how-to-pinvoke-varargs-variable-arguments-in-c-or-hidden-junk-in-clr/"&gt;http://khason.net/blog/how-to-pinvoke-varargs-variable-arguments-in-c-or-hidden-junk-in-clr/&lt;/a&gt;]&lt;/h3&gt;&lt;hr /&gt;&lt;p&gt;Recently I &lt;a href="http://blogs.microsoft.co.il/blogs/tamir/archive/2008/10/20/p-invoke-cheat-sheet.aspx"&gt;wrote a cheat sheet for pinvoking in .NET&lt;/a&gt;. Shortly after I got a question in comments about how to deal with variable arguments, when it&amp;#39;s more, then one parameter. Also what to do if those arguments are heterogeneous? &lt;/p&gt; &lt;p&gt;Let&amp;#39;s say, that we have following method in C:&lt;/p&gt; &lt;blockquote&gt; &lt;p&gt;int VarSum(int nargs, ...){&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; va_list argp;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; va_start( argp, nargs );&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; int sum = 0;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; for( int i = 0 ; i &amp;lt; nargs; i++ ) {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; int arg = va_arg( argp, int );&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; sum += arg;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; va_end( argp );  &lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; return sum;&lt;br /&gt;}&lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;We can expose this method to C# as following:&lt;/p&gt; &lt;blockquote&gt; &lt;p&gt;[System.Runtime.InteropServices.DllImportAttribute(&amp;quot;unmanaged.dll&amp;quot;, EntryPoint = &amp;quot;VarSum&amp;quot;)]&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; public static extern int VarSum(int nargs,int arg1); &lt;p&gt;[System.Runtime.InteropServices.DllImportAttribute(&amp;quot;unmanaged.dll&amp;quot;, EntryPoint = &amp;quot;VarSum&amp;quot;)]&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; public static extern int VarSum(int nargs,int arg1,int arg2);&lt;/p&gt; &lt;p&gt;[System.Runtime.InteropServices.DllImportAttribute(&amp;quot;unmanaged.dll&amp;quot;, EntryPoint = &amp;quot;VarSum&amp;quot;)]&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; public static extern int VarSum(int nargs,int arg1,int arg2,int arg3);&lt;/p&gt; &lt;p&gt;etc...&lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;And it will work. However, if you&amp;#39;ll try to expose it as int array, marshaller will fail to understand how to align things&lt;/p&gt; &lt;blockquote&gt; &lt;p&gt;[System.Runtime.InteropServices.DllImportAttribute(&amp;quot;unmanaged.dll&amp;quot;, EntryPoint = &amp;quot;VarSum&amp;quot;)]&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; public static extern int VarSum(int nargs,int[] arg);&lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;This in spite of the fact, that this method will work properly with another signature&lt;/p&gt; &lt;blockquote&gt; &lt;p&gt;int ArrSum(int* nargs) {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; int sum = 0;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; for( int i = 0 ; i &amp;lt; 2; i++ ) {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; sum += nargs[i];&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; return sum;&lt;br /&gt;}&lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;So what to do? The &lt;u&gt;official&lt;/u&gt; answer is - &lt;strong&gt;you have nothing to do, rather then override all possibilities&lt;/strong&gt;. This is very bad and absolutely not flexible. So, there is small class in C#, named ArgIterator. This one is similar to params object[], but knows to marshal into varargs. The problem is, that you have no way to add things inside. It&amp;#39;s &amp;quot;kind-of-read-only&amp;quot;. &lt;/p&gt; &lt;p&gt;Let&amp;#39;s look into reflected version of ArgIterator. We&amp;#39;ll see there something, named &lt;strong&gt;__arglist and __refvalue&lt;/strong&gt;. OMG, isn&amp;#39;t it good old stuff similar to &amp;quot;__declspec(dllexport) int _stdcall&amp;quot; etc.? It is! But can we use it in C#? We can! Just sign your method as Cdecl and you have working signature for &amp;quot;...&amp;quot;&lt;/p&gt; &lt;blockquote&gt; &lt;p&gt;[System.Runtime.InteropServices.DllImportAttribute(&amp;quot;unmanaged.dll&amp;quot;, EntryPoint = &amp;quot;VarSum&amp;quot;, &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; CallingConvention=System.Runtime.InteropServices.CallingConvention.Cdecl)]&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; public static extern int VarSum(int nargs, __arglist);&lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;Yes, looks strange, and absolutely not CLR compliant. However, this is the only way to expose varargs to CLR via P/Invoke. How to use it? Simple:&lt;/p&gt; &lt;blockquote&gt; &lt;p&gt;c = VarSum(2, __arglist(5, 10));&lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;Have a nice day and be good people. Also, my question to Microsoft is why this stuff is not in MSDN and we, as developers, have no way to get rid of it. &lt;/p&gt; &lt;p&gt;Is not it very good practices to use non-compliant methods? Give us another way to do it!&lt;br /&gt;Is not it very good practices to use variable arguments in unmanaged method signatures? So why you want dynamic types in C# 4?&lt;/p&gt; &lt;p&gt;&lt;a href="http://cid-4e39ecd492e4eec1.skydrive.live.com/self.aspx/Public/VarArgsMarshaller.zip%20"&gt;Source code for this article&lt;/a&gt;&lt;/p&gt;&lt;img src="http://blogs.microsoft.co.il/aggbug.aspx?PostID=170664" width="1" height="1"&gt;</description><category domain="http://blogs.microsoft.co.il/blogs/tamir/archive/tags/WPF/default.aspx">WPF</category><category domain="http://blogs.microsoft.co.il/blogs/tamir/archive/tags/tutorial/default.aspx">tutorial</category><category domain="http://blogs.microsoft.co.il/blogs/tamir/archive/tags/Tips+and+Tricks/default.aspx">Tips and Tricks</category><category domain="http://blogs.microsoft.co.il/blogs/tamir/archive/tags/source/default.aspx">source</category><category domain="http://blogs.microsoft.co.il/blogs/tamir/archive/tags/C_2300_/default.aspx">C#</category><category domain="http://blogs.microsoft.co.il/blogs/tamir/archive/tags/Microsoft/default.aspx">Microsoft</category><category domain="http://blogs.microsoft.co.il/blogs/tamir/archive/tags/.NET+3.5/default.aspx">.NET 3.5</category><category domain="http://blogs.microsoft.co.il/blogs/tamir/archive/tags/Work+process/default.aspx">Work process</category><category domain="http://blogs.microsoft.co.il/blogs/tamir/archive/tags/DEV/default.aspx">DEV</category><category domain="http://blogs.microsoft.co.il/blogs/tamir/archive/tags/Interop/default.aspx">Interop</category></item><item><title>Auto scroll ListBox in WPF</title><link>http://blogs.microsoft.co.il/blogs/tamir/archive/2008/11/10/auto-scroll-listbox-in-wpf.aspx</link><pubDate>Mon, 10 Nov 2008 14:03:00 GMT</pubDate><guid isPermaLink="false">b5c4f5bc-c09b-4439-a595-91a98c1847df:163858</guid><dc:creator>Tamir Khason</dc:creator><slash:comments>2</slash:comments><description>&lt;h3&gt;[This blog was migrated. You will not be able to comment here.&lt;br /&gt;The new URL of this post is &lt;a href="http://khason.net/blog/auto-scroll-listbox-in-wpf/"&gt;http://khason.net/blog/auto-scroll-listbox-in-wpf/&lt;/a&gt;]&lt;/h3&gt;&lt;hr /&gt;&lt;p&gt;In WinForms era it was very simple to autoscroll listbox content in order to select last or newly added item. It become a bit complicated in WPF. However, complicated does not mean impossible. &lt;/p&gt; &lt;p&gt;&lt;img src="http://blogs.microsoft.co.il/blogs/tamir/WindowsLiveWriter/AutoscrollListBoxinWPF_E1D5/image_18053bf1-6da2-454d-a507-d934ba2ba16a.png" alt="image" width="292" border="0" height="293" /&gt; &lt;/p&gt; &lt;p&gt;As for me, Microsoft should add this feature to base ListBox implementation as another attempt to be attractive environment for LOB application. See, for example &lt;a href="http://social.msdn.microsoft.com/Forums/en-US/wpf/thread/0f524459-b14e-4f9a-8264-267953418a2d" target="_blank"&gt;this thread from MSDN forums&lt;/a&gt;. I&amp;#39;m really understand this guy. He do not want to implement it with a lot of code, he just want it to be included in core WPF control (but he should mark answers)&lt;/p&gt; &lt;p&gt;Generally, the simplest way to it is by using attached properties. So, your code will look like this&lt;/p&gt; &lt;blockquote&gt; &lt;p&gt;&amp;lt;ListBox Height=&amp;quot;200&amp;quot; l:SelectorExtenders.IsAutoscroll=&amp;quot;true&amp;quot; IsSynchronizedWithCurrentItem=&amp;quot;True&amp;quot; Name=&amp;quot;list&amp;quot;/&amp;gt;&lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;But what&amp;#39;s going on under the hoods? There it bit complicated :) First of all, we should create attached property, named IsAutoscroll&lt;/p&gt; &lt;blockquote&gt; &lt;p&gt;public class SelectorExtenders : DependencyObject {  &lt;/p&gt;&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; public static bool GetIsAutoscroll(DependencyObject obj) {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; return (bool)obj.GetValue(IsAutoscrollProperty);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }  &lt;/p&gt;&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; public static void SetIsAutoscroll(DependencyObject obj, bool value) {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; obj.SetValue(IsAutoscrollProperty, value);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }  &lt;/p&gt;&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; public static readonly DependencyProperty IsAutoscrollProperty =&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; DependencyProperty.RegisterAttached(&amp;quot;IsAutoscroll&amp;quot;, typeof(bool), typeof(SelectorExtenders), new UIPropertyMetadata(default(bool),OnIsAutoscrollChanged));&lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;now handle it when you set it&amp;#39;s value by handling new items arrivals, set current and then scroll into it&lt;/p&gt; &lt;blockquote&gt; &lt;p&gt;public static void OnIsAutoscrollChanged(DependencyObject s, DependencyPropertyChangedEventArgs e) {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; var val = (bool)e.NewValue;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; var lb = s as ListBox;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; var ic = lb.Items;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; var data = ic.SourceCollection as INotifyCollectionChanged;  &lt;/p&gt;&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; var autoscroller = new System.Collections.Specialized.NotifyCollectionChangedEventHandler(&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; (s1, e1) =&amp;gt; {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; object selectedItem = default(object);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; switch (e1.Action) {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; case NotifyCollectionChangedAction.Add:&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; case NotifyCollectionChangedAction.Move: selectedItem = e1.NewItems[e1.NewItems.Count - 1]; break;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; case NotifyCollectionChangedAction.Remove: if (ic.Count &amp;lt; e1.OldStartingIndex) { selectedItem = ic[e1.OldStartingIndex - 1]; } else if (ic.Count &amp;gt; 0) selectedItem = ic[0]; break;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; case NotifyCollectionChangedAction.Reset: if (ic.Count &amp;gt; 0) selectedItem = ic[0]; break;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }  &lt;/p&gt;&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; if (selectedItem != default(object)) {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; ic.MoveCurrentTo(selectedItem);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; lb.ScrollIntoView(selectedItem);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; });  &lt;/p&gt;&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; if (val) data.CollectionChanged += autoscroller;&amp;nbsp; &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; else&amp;nbsp; data.CollectionChanged -= autoscroller;  &lt;/p&gt;&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;That&amp;#39;s all. Also it can be done by visual tree querying (as thread started proposed). Find scrollviewer inside the ListBox visual tree and then invoke &amp;quot;ScrollToEnd&amp;quot; method of it.&lt;/p&gt; &lt;p&gt;Have a nice day and be good people. And, yes, WPF development team should consider this feature implemented internally for any Selector and ScrollViewer control&lt;/p&gt; &lt;p&gt;Source code for this article is attached&lt;br /&gt;&lt;/p&gt;&lt;img src="http://blogs.microsoft.co.il/aggbug.aspx?PostID=163858" width="1" height="1"&gt;</description><enclosure url="http://blogs.microsoft.co.il/blogs/tamir/attachment/163858.ashx" length="53169" type="application/x-zip-compressed" /><category domain="http://blogs.microsoft.co.il/blogs/tamir/archive/tags/WPF/default.aspx">WPF</category><category domain="http://blogs.microsoft.co.il/blogs/tamir/archive/tags/tutorial/default.aspx">tutorial</category><category domain="http://blogs.microsoft.co.il/blogs/tamir/archive/tags/Tips+and+Tricks/default.aspx">Tips and Tricks</category><category domain="http://blogs.microsoft.co.il/blogs/tamir/archive/tags/Accessibility/default.aspx">Accessibility</category><category domain="http://blogs.microsoft.co.il/blogs/tamir/archive/tags/.NET+3.5/default.aspx">.NET 3.5</category><category domain="http://blogs.microsoft.co.il/blogs/tamir/archive/tags/Work+process/default.aspx">Work process</category><category domain="http://blogs.microsoft.co.il/blogs/tamir/archive/tags/DEV/default.aspx">DEV</category></item><item><title>P/Invoke cheat sheet</title><link>http://blogs.microsoft.co.il/blogs/tamir/archive/2008/10/20/p-invoke-cheat-sheet.aspx</link><pubDate>Mon, 20 Oct 2008 20:02:40 GMT</pubDate><guid isPermaLink="false">b5c4f5bc-c09b-4439-a595-91a98c1847df:155503</guid><dc:creator>Tamir Khason</dc:creator><slash:comments>9</slash:comments><description>&lt;h3&gt;[This blog was migrated. You will not be able to comment here.&lt;br /&gt;The new URL of this post is &lt;a href="http://khason.net/blog/pinvoke-cheat-sheet/"&gt;http://khason.net/blog/pinvoke-cheat-sheet/&lt;/a&gt;]&lt;/h3&gt;&lt;hr /&gt;&lt;p&gt;I’m working a lot with p/invoke, and know how it’s hard to produce correct signature for unmanaged method. So, today I decided to publish basic cheat sheet for methods, parameters and attributes you should use in order to invoke unmanaged methods from managed code without a lot of problems. We start with data type translations. Here the table to understand it.&lt;/p&gt;  &lt;table cellspacing="0" cellpadding="2"&gt;     &lt;tr&gt;       &lt;td valign="top"&gt;Data type from unmanaged signature&lt;/td&gt;        &lt;td valign="top"&gt;Data type in managed signature&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td valign="top"&gt;int&lt;/td&gt;        &lt;td valign="top"&gt;int         &lt;br /&gt;          &lt;br /&gt;&lt;em&gt;the same with all other simple types such as double, uint, etc or private objects&lt;/em&gt;&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td valign="top"&gt;void*&lt;/td&gt;        &lt;td valign="top"&gt;IntPtr&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td valign="top"&gt;int*&lt;/td&gt;        &lt;td valign="top"&gt;ref int         &lt;br /&gt;          &lt;br /&gt;&lt;em&gt;the same with all other simple types such as double, uint, etc &lt;em&gt;or private objects&lt;/em&gt; &lt;/em&gt;&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td valign="top"&gt;char**&lt;/td&gt;        &lt;td valign="top"&gt;ref IntPtr         &lt;br /&gt;          &lt;br /&gt;&lt;em&gt;later, you should get ascii string by using System.Runtime.InteropServices.Marshal.PtrToStringAnsi() method&lt;/em&gt;&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td valign="top"&gt;wcar_t**&lt;/td&gt;        &lt;td valign="top"&gt;ref IntPtr         &lt;br /&gt;          &lt;br /&gt;&lt;em&gt;later, you should get ascii string by using System.Runtime.InteropServices.Marshal.PtrToStringUni() method&lt;/em&gt;&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td valign="top"&gt;const int*&lt;/td&gt;        &lt;td valign="top"&gt;ref int&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td valign="top"&gt;const char*&lt;/td&gt;        &lt;td valign="top"&gt;[System.Runtime.InteropServices.In()] [System.Runtime.InteropServices.MarshalAs(System.Runtime.InteropServices.UnmanagedType.LPWStr)] string&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td valign="top"&gt;… &lt;em&gt;(variable argument)&lt;/em&gt;&lt;/td&gt;        &lt;td valign="top"&gt;[System.Runtime.InteropServices.In()] [System.Runtime.InteropServices.MarshalAs(System.Runtime.InteropServices.UnmanagedType.AsAny)] object&lt;/td&gt;     &lt;/tr&gt;   &lt;/table&gt;  &lt;p&gt;&lt;em&gt;You can use either System.Runtime.InteropServices.In or System.Runtime.InteropServices.Out attribute to specify how arguments should be used.&lt;/em&gt;&lt;/p&gt;  &lt;p&gt;Now we done with simple arguments, let’s see what can be done when argument is actually callback or delegate?&lt;/p&gt;  &lt;table cellspacing="0" cellpadding="2"&gt;     &lt;tr&gt;       &lt;td valign="top"&gt;Unmanaged definition&lt;/td&gt;        &lt;td valign="top"&gt;Managed definition&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td valign="top"&gt;typedef void (*MyCallback)(int Arg)&lt;/td&gt;        &lt;td valign="top"&gt;         &lt;p&gt;[System.Runtime.InteropServices.UnmanagedFunctionPointer(System.Runtime.InteropServices.CallingConvention.Cdecl)]delegate void MyCallback(int Arg)           &lt;br /&gt;&lt;em&gt;Caller cleans stack argument is used to assure, that we can call varargs type function, usually used by API provider. It is very similar to C# overrides for methods. Also you can use StdCall (this is default), ThisCall – stores this first and pushes other parameters on the stack, FastCall – not very supported :(&lt;/em&gt;&lt;/p&gt;       &lt;/td&gt;     &lt;/tr&gt;   &lt;/table&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;p&gt;To call all those methods, we should know managed equivalents of unmanaged types. Here the table. The rule is simple – know how many bytes unmanaged type has and find managed type with the same number of bytes. Other words, you can marshal int into IntPtr too…&lt;/p&gt;  &lt;table cellspacing="0" cellpadding="2"&gt;     &lt;tr&gt;       &lt;td valign="top"&gt;Unmanaged type&lt;/td&gt;        &lt;td valign="top"&gt;Managed equivalent&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td valign="top"&gt;bool&lt;/td&gt;        &lt;td valign="top"&gt;bool&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td valign="top"&gt;char&lt;/td&gt;        &lt;td valign="top"&gt;sbyte (signed), byte (unsigned)&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td valign="top"&gt;wchar_t&lt;/td&gt;        &lt;td valign="top"&gt;char&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td valign="top"&gt;double&lt;/td&gt;        &lt;td valign="top"&gt;double&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td valign="top"&gt;float&lt;/td&gt;        &lt;td valign="top"&gt;single&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td valign="top"&gt;int, long (signed)&lt;/td&gt;        &lt;td valign="top"&gt;Int32&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td valign="top"&gt;int, long (unsigned)&lt;/td&gt;        &lt;td valign="top"&gt;UInt32&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td valign="top"&gt;__int64 (signed)&lt;/td&gt;        &lt;td valign="top"&gt;Int64&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td valign="top"&gt;__int64&lt;/td&gt;        &lt;td valign="top"&gt;UInt64&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td valign="top"&gt;short (signed)&lt;/td&gt;        &lt;td valign="top"&gt;Int16&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td valign="top"&gt;short (unsigned)&lt;/td&gt;        &lt;td valign="top"&gt;UInt16&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td valign="top"&gt;void&lt;/td&gt;        &lt;td valign="top"&gt;void&lt;/td&gt;     &lt;/tr&gt;   &lt;/table&gt;  &lt;p&gt;But not only types are problem in managed/unmanaged transitions. Also structures are aligned differently. For this purpose we can use StructLayout attribute. Even if unmanaged classes are sequential and you used correct managed data types, you can find you with problems in Pack. What “pack” is? Pack is actually slot size in bytes for members of your structure. It can be 0, 1, 2, 4, 8, 16, 32, 64, or 128 and depends on the platform and application setting.&lt;/p&gt;  &lt;p&gt;Now you can see, that it is not very complicated to create managed signatures when you have header of unmanaged assemblies. So go ahead and ask, if I missed something.&lt;/p&gt;  &lt;p&gt;That’s all by now. Have a nice day and be good people.&lt;/p&gt;&lt;img src="http://blogs.microsoft.co.il/aggbug.aspx?PostID=155503" width="1" height="1"&gt;</description><category domain="http://blogs.microsoft.co.il/blogs/tamir/archive/tags/WPF/default.aspx">WPF</category><category domain="http://blogs.microsoft.co.il/blogs/tamir/archive/tags/tutorial/default.aspx">tutorial</category><category domain="http://blogs.microsoft.co.il/blogs/tamir/archive/tags/Tips+and+Tricks/default.aspx">Tips and Tricks</category><category domain="http://blogs.microsoft.co.il/blogs/tamir/archive/tags/WPF+crossbow/default.aspx">WPF crossbow</category><category domain="http://blogs.microsoft.co.il/blogs/tamir/archive/tags/C_2300_/default.aspx">C#</category><category domain="http://blogs.microsoft.co.il/blogs/tamir/archive/tags/Microsoft/default.aspx">Microsoft</category><category domain="http://blogs.microsoft.co.il/blogs/tamir/archive/tags/.NET+3.5/default.aspx">.NET 3.5</category><category domain="http://blogs.microsoft.co.il/blogs/tamir/archive/tags/x64/default.aspx">x64</category><category domain="http://blogs.microsoft.co.il/blogs/tamir/archive/tags/Work+process/default.aspx">Work process</category><category domain="http://blogs.microsoft.co.il/blogs/tamir/archive/tags/Mono/default.aspx">Mono</category><category domain="http://blogs.microsoft.co.il/blogs/tamir/archive/tags/DEV/default.aspx">DEV</category></item><item><title>Set binding, based on trigger</title><link>http://blogs.microsoft.co.il/blogs/tamir/archive/2008/10/13/set-binding-based-on-trigger.aspx</link><pubDate>Mon, 13 Oct 2008 07:53:00 GMT</pubDate><guid isPermaLink="false">b5c4f5bc-c09b-4439-a595-91a98c1847df:152895</guid><dc:creator>Tamir Khason</dc:creator><slash:comments>2</slash:comments><description>&lt;h3&gt;[This blog was migrated. You will not be able to comment here.&lt;br /&gt;The new URL of this post is &lt;a href="http://khason.net/blog/set-binding-based-on-trigger/"&gt;http://khason.net/blog/set-binding-based-on-trigger/&lt;/a&gt;]&lt;/h3&gt;&lt;hr /&gt;&lt;p&gt;Let’s say, that you want to set binding. However, you want to set it by using some trigger. Wait! Why I need it? Let’s say, that I have some very special object, that actually has no hard-coded properties. All it’s properties are created during the runtime, based on some trigger. In this case, I still want to use binding, however, if the property does not exists, I cannot do it. In this special case (that we’ll probably speak more later), we can use this class – TriggerBinding.&lt;/p&gt;  &lt;p&gt;How to do it? How to extend build-in binding and add such functionality? Simple. All we need is to write custom markup extension. So, we’ll create new one&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;public class TriggerBindingExtension : MarkupExtension&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;And expose all regular binding properties + three custom – TriggerSource, TriggerSourceName and Trigger itself&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;public IValueConverter Converter { get; set; }     &lt;br /&gt;public object ConverterParameter { get; set; }      &lt;br /&gt;public string ElementName { get; set; }      &lt;br /&gt;public RelativeSource RelativeSource { get; set; }      &lt;br /&gt;public object Source { get; set; }      &lt;br /&gt;public string TriggerSourceName { get; set; }      &lt;br /&gt;public UIElement TriggerSource { get; set; }      &lt;br /&gt;[TypeConverter(typeof(RoutedEventConverter))]      &lt;br /&gt;public RoutedEvent Trigger { get; set; }      &lt;br /&gt;public bool ValidatesOnDataErrors { get; set; }      &lt;br /&gt;public bool ValidatesOnExceptions { get; set; }      &lt;br /&gt;public string StringFormat { get; set; }      &lt;br /&gt;[TypeConverter(typeof(EnumConverter))]      &lt;br /&gt;public BindingMode Mode { get; set; }      &lt;br /&gt;[TypeConverter(typeof(PropertyPathConverter))]      &lt;br /&gt;public PropertyPath Path { get; set; }      &lt;br /&gt;[TypeConverter(typeof(BooleanConverter))]      &lt;br /&gt;public bool IsAsync { get; set; }      &lt;br /&gt;public string XPath { get; set; }      &lt;br /&gt;[TypeConverter(typeof(CultureInfoIetfLanguageTagConverter))]      &lt;br /&gt;public CultureInfo ConverterCulture { get; set; }&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;Next step is to override ProvideValue method of MarkupExtension and create the actual binding. We still do not want to bind it to any property&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;public override sealed object ProvideValue(IServiceProvider serviceProvider) {     &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; var _valueProvider = serviceProvider.GetService(typeof(IProvideValueTarget)) as IProvideValueTarget;      &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; if (_valueProvider != null) {      &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; var _bindingTarget = _valueProvider.TargetObject as FrameworkElement;      &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; var _bindingProperty = _valueProvider.TargetProperty as DependencyProperty;      &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; var _binding = new Binding();      &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; _binding.Path = Path;      &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; _binding.XPath = XPath;      &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; _binding.Mode = Mode;      &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; _binding.Converter = Converter;      &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; _binding.ConverterCulture = ConverterCulture;      &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; _binding.ConverterParameter = ConverterParameter;      &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; _binding.IsAsync = IsAsync;      &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; if (ElementName != null) _binding.ElementName = ElementName;      &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; if (RelativeSource != null) _binding.RelativeSource = RelativeSource;      &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; if (Source != null) _binding.Source = Source;      &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; _binding.ValidatesOnDataErrors = ValidatesOnDataErrors;      &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; _binding.ValidatesOnExceptions = ValidatesOnExceptions;      &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; _binding.StringFormat = StringFormat;&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;Now, if we have TriggerSource and Trigger, everything fine, we can set subscribe to the trigger event and wire binding in the handler&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;private RoutedEventHandler _bindigHandler; &lt;/p&gt;    &lt;p&gt;private void _registerHandler(FrameworkElement bindingTarget, DependencyProperty bindingProperty, Binding binding) {     &lt;br /&gt;&amp;nbsp;&amp;nbsp; if (_bindigHandler == default(RoutedEventHandler)) {      &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; _bindigHandler = (RoutedEventHandler)(delegate {      &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; var _oldValue = bindingTarget.GetValue(bindingProperty);      &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; bindingTarget.SetBinding(bindingProperty, binding);      &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; if (_oldValue != bindingProperty.DefaultMetadata.DefaultValue) {      &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; bindingTarget.SetValue(bindingProperty, _oldValue);      &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; BindingOperations.GetBindingExpression(bindingTarget, bindingProperty).UpdateSource();      &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }      &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; });      &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; TriggerSource = TriggerSource ?? bindingTarget;      &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; if (Trigger != null &amp;amp;&amp;amp; TriggerSource != null) {      &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; TriggerSource.AddHandler(Trigger, _bindigHandler);      &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; } else {      &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; _bindigHandler.Invoke(this, null);      &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }      &lt;br /&gt;&amp;nbsp;&amp;nbsp; }      &lt;br /&gt;}&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;However, we also want to be able to seek Logical tree and find trigger source by it’s name. Let’s say this way&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;&amp;lt;TextBox Name=&amp;quot;one&amp;quot; Text=&amp;quot;{l:TriggerBinding ElementName=two, Path=Text, Mode=TwoWay, TriggerSourceName=three, Trigger=Button.Click}&amp;quot;/&amp;gt;     &lt;br /&gt;&amp;lt;TextBox Name=&amp;quot;two&amp;quot;/&amp;gt;      &lt;br /&gt;&amp;lt;Button Name=&amp;quot;three&amp;quot; Content=&amp;quot;Click to trigger binding&amp;quot;/&amp;gt;&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;What’s the problem? We also have FrameworkElement.FindName method and LogicalTreeHelper.FindLogicalNode. But wait, in our case, when TextBox “one” is initialized, we still have no Button “three”, so we have to wait until the root element of TextBox will be fully loaded and then try to find logical node. For this purpose, we have very useful extended method&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;public static DependencyObject GetRoot(this DependencyObject current) {     &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; var _root = current;      &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; do { _root = LogicalTreeHelper.GetParent(_root); if (_root != null) current = _root; } while (_root != null);      &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; return current;      &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;So, all we have to do is to subscribe to Loaded event of the root and then wire the trigger for set binding&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;if (!string.IsNullOrEmpty(TriggerSourceName)) {     &lt;br /&gt;&amp;nbsp;&amp;nbsp; var _root = _bindingTarget.GetRoot() as FrameworkElement;      &lt;br /&gt;&amp;nbsp;&amp;nbsp; _root.Loaded += delegate {      &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; TriggerSource = LogicalTreeHelper.FindLogicalNode(_root, TriggerSourceName) as UIElement;      &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; _registerHandler(_bindingTarget, _bindingProperty, _binding);      &lt;br /&gt;&amp;nbsp;&amp;nbsp; };      &lt;br /&gt;} else { _registerHandler(_bindingTarget, _bindingProperty, _binding); }&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;We done. Have a good day and be good people.&lt;/p&gt;  &lt;p&gt;BTW, it’s also possible to postpone binding by using timer. Paul Stovell has &lt;a href="http://www.paulstovell.com/blog/delaybinding-for-wpf" target="_blank"&gt;very good sample&lt;/a&gt; of how to perform it.&lt;/p&gt;  &lt;p&gt;&lt;a href="http://blogs.microsoft.co.il/files/folders/152904/download.aspx" target="_blank"&gt;Source code for this article&lt;/a&gt;&lt;/p&gt;&lt;img src="http://blogs.microsoft.co.il/aggbug.aspx?PostID=152895" width="1" height="1"&gt;</description><enclosure url="http://blogs.microsoft.co.il/blogs/tamir/attachment/152895.ashx" length="8902" type="application/x-zip-compressed" /><category domain="http://blogs.microsoft.co.il/blogs/tamir/archive/tags/WPF/default.aspx">WPF</category><category domain="http://blogs.microsoft.co.il/blogs/tamir/archive/tags/tutorial/default.aspx">tutorial</category><category domain="http://blogs.microsoft.co.il/blogs/tamir/archive/tags/Tips+and+Tricks/default.aspx">Tips and Tricks</category><category domain="http://blogs.microsoft.co.il/blogs/tamir/archive/tags/source/default.aspx">source</category><category domain="http://blogs.microsoft.co.il/blogs/tamir/archive/tags/C_2300_/default.aspx">C#</category><category domain="http://blogs.microsoft.co.il/blogs/tamir/archive/tags/.NET+3.5/default.aspx">.NET 3.5</category><category domain="http://blogs.microsoft.co.il/blogs/tamir/archive/tags/Work+process/default.aspx">Work process</category><category domain="http://blogs.microsoft.co.il/blogs/tamir/archive/tags/DEV/default.aspx">DEV</category></item><item><title>WGS to UTM, UTM to WGS conversions, geo distance, azimuth and other geographical calculations in C#</title><link>http://blogs.microsoft.co.il/blogs/tamir/archive/2008/09/15/wgs-to-utm-utm-to-wgs-conversions-geo-distance-azimuth-and-other-geographical-calculations-in-c.aspx</link><pubDate>Mon, 15 Sep 2008 07:16:37 GMT</pubDate><guid isPermaLink="false">b5c4f5bc-c09b-4439-a595-91a98c1847df:139757</guid><dc:creator>Tamir Khason</dc:creator><slash:comments>2</slash:comments><description>&lt;h3&gt;[This blog was migrated. You will not be able to comment here.&lt;br /&gt;The new URL of this post is &lt;a href="http://khason.net/blog/wgs-to-utm-utm-to-wgs-conversions-geo-distance-azimuth-and-other-geographical-calculations-in-c/"&gt;http://khason.net/blog/wgs-to-utm-utm-to-wgs-conversions-geo-distance-azimuth-and-other-geographical-calculations-in-c/&lt;/a&gt;]&lt;/h3&gt;&lt;hr /&gt;&lt;blockquote&gt; &lt;h4&gt;&lt;em&gt;&amp;quot;The reports of my death are greatly exaggerated&amp;quot;&lt;/em&gt;&lt;/h4&gt; &lt;p&gt;Since &lt;a href="http://blogs.microsoft.co.il/blogs/tamir/archive/2008/08/19/i-m-leaving-consulting-field-joined-new-project-for-full-time.aspx"&gt;my post about leaving consulting field&lt;/a&gt;, I got huge amount of email with questions about all community projects, I&amp;#39;m leading, blogging in general and specific to the future of this blog. &lt;/p&gt; &lt;p&gt;To make things clear, I leaved consulting, and now, I have less time and reasons to blog, however, I&amp;#39;m keep blogging and maintaining almost all of my community projects (see the left side of the main page to list of most of those projects). Also, I try to answer all questions, I got via emails, however it&amp;#39;s too much to handle, thus be prepared for delays.&lt;/p&gt; &lt;p&gt;To be sure, I&amp;#39;m alive, you can &lt;a href="http://twitter.com/tamir"&gt;follow me at twitter&lt;/a&gt; (it demands less time to write) :) Anyway, &lt;strong&gt;that you for reading my blog and supporting me&lt;/strong&gt;.&amp;nbsp; &lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;Now it&amp;#39;s good time to write something useful for you :)&lt;/p&gt; &lt;p&gt;If you ever wrote GIS programs, you, probably, know, that every time we forget how to convert latlon (Latitude-Longitude or, simpler World Geographical System) coordinates into Universal Transverse Mercator coordinates and vise verse, how to calculate geographical distance from point to point, line or segment to point and line to line, how to calculate azimuth between two geo points, or how to calculate destination point, based on start coordinate, distance and bearing. &lt;/p&gt; &lt;p&gt;&lt;img style="border-top-width:0px;border-left-width:0px;border-bottom-width:0px;border-right-width:0px;" height="318" alt="image" src="http://blogs.microsoft.co.il/blogs/tamir/WindowsLiveWriter/WGStoUTMUTMtoWGSconversionsgeodistanceaz_8D93/image_3.png" width="377" border="0" /&gt; &lt;/p&gt; &lt;p&gt;In order to make our life easier, I decided to post number of methods in C#, I always use to perform such GIS calculations. I believe, that those classes will help you to perform your own geographical calculations. Also, do not forget two handy functions to convert degrees to radians and vv&lt;/p&gt; &lt;blockquote&gt; &lt;p&gt;public static double DegToRad(double deg) { return (deg / 180.0 * Math.PI); } &lt;br /&gt;public static double RadToDeg(double rad) { return (rad / Math.PI * 180.0); }&lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;Also, there are some constants should be used, if you&amp;#39;re calculating geo information in the Earth&lt;/p&gt; &lt;blockquote&gt; &lt;p&gt;const double sm_a = 6378137.0; &lt;br /&gt;const double sm_b = 6356752.314; &lt;br /&gt;const double sm_EccSquared = 6.69437999013e-03; &lt;br /&gt;const double UTMScaleFactor = 0.9996;&lt;/p&gt;&lt;/blockquote&gt; &lt;h3&gt;Conversion WGS2UTM (LatLon2UTM)&lt;/h3&gt; &lt;p&gt;Fist of all, we should calculate UTM zone. This one is simple&lt;/p&gt; &lt;blockquote&gt; &lt;p&gt;int zone = (int)(Math.Floor((latlon.Longitude + 180.0) / 6) + 1);&lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;Now, when we have zone, we should calculate UTM central meridian, footprint of latitude and arc length of the meridian&lt;/p&gt; &lt;blockquote&gt; &lt;p&gt;public static double UTMCentralMeridian(int zone) { return DegToRad(-183.0 + (zone * 6.0)); } &lt;br /&gt;&lt;br /&gt;&lt;/p&gt; &lt;p&gt;public static double FootpointLatitude(double y) { &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; /* Precalculate n (Eq. 10.18) */ &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; var n = (sm_a - sm_b) / (sm_a + sm_b); &lt;/p&gt; &lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; /* Precalculate alpha_ (Eq. 10.22) */ &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; /* (Same as alpha in Eq. 10.17) */ &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; var alpha_ = ((sm_a + sm_b) / 2.0) * (1 + (Math.Pow(n, 2.0) / 4) + (Math.Pow(n, 4.0) / 64)); &lt;/p&gt; &lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; /* Precalculate y_ (Eq. 10.23) */ &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; var y_ = y / alpha_; &lt;/p&gt; &lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; /* Precalculate beta_ (Eq. 10.22) */ &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; var beta_ = (3.0 * n / 2.0) + (-27.0 * Math.Pow(n, 3.0) / 32.0) + (269.0 * Math.Pow(n, 5.0) / 512.0); &lt;/p&gt; &lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; /* Precalculate gamma_ (Eq. 10.22) */ &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; var gamma_ = (21.0 * Math.Pow(n, 2.0) / 16.0) + (-55.0 * Math.Pow(n, 4.0) / 32.0); &lt;/p&gt; &lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; /* Precalculate delta_ (Eq. 10.22) */ &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; var delta_ = (151.0 * Math.Pow(n, 3.0) / 96.0) + (-417.0 * Math.Pow(n, 5.0) / 128.0); &lt;/p&gt; &lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; /* Precalculate epsilon_ (Eq. 10.22) */ &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; var epsilon_ = (1097.0 * Math.Pow(n, 4.0) / 512.0); &lt;/p&gt; &lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; /* Now calculate the sum of the series (Eq. 10.21) */ &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; return y_ + (beta_ * Math.Sin(2.0 * y_)) + (gamma_ * Math.Sin(4.0 * y_)) + (delta_ * Math.Sin(6.0 * y_)) + (epsilon_ * Math.Sin(8.0 * y_)); &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; } &lt;br /&gt;&lt;br /&gt;&lt;/p&gt; &lt;p&gt;public static double ArcLengthOfMeridian(double phi) { &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; /* Precalculate n */ &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; var n = (sm_a - sm_b) / (sm_a + sm_b); &lt;/p&gt; &lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; /* Precalculate alpha */ &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; var alpha = ((sm_a + sm_b) / 2.0) * (1.0 + (Math.Pow(n, 2.0) / 4.0) + (Math.Pow(n, 4.0) / 64.0)); &lt;/p&gt; &lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; /* Precalculate beta */ &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; var beta = (-3.0 * n / 2.0) + (9.0 * Math.Pow(n, 3.0) / 16.0) + (-3.0 * Math.Pow(n, 5.0) / 32.0); &lt;/p&gt; &lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; /* Precalculate gamma */ &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; var gamma = (15.0 * Math.Pow(n, 2.0) / 16.0) + (-15.0 * Math.Pow(n, 4.0) / 32.0); &lt;/p&gt; &lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; /* Precalculate delta */ &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; var delta = (-35.0 * Math.Pow(n, 3.0) / 48.0) + (105.0 * Math.Pow(n, 5.0) / 256.0); &lt;/p&gt; &lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; /* Precalculate epsilon */ &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; var epsilon = (315.0 * Math.Pow(n, 4.0) / 512.0); &lt;/p&gt; &lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; /* Now calculate the sum of the series and return */ &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; return alpha * (phi + (beta * Math.Sin(2.0 * phi)) + (gamma * Math.Sin(4.0 * phi)) + (delta * Math.Sin(6.0 * phi)) + (epsilon * Math.Sin(8.0 * phi))); &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;Now, we have everything to calculate UTM&lt;/p&gt; &lt;blockquote&gt; &lt;p&gt;public static GeoPoint MapLatLonToXY(double phi, double lambda, double lambda0) { &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; /* Precalculate ep2 */ &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; var ep2 = (Math.Pow(sm_a, 2.0) - Math.Pow(sm_b, 2.0)) / Math.Pow(sm_b, 2.0); &lt;/p&gt; &lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; /* Precalculate nu2 */ &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; var nu2 = ep2 * Math.Pow(Math.Cos(phi), 2.0); &lt;/p&gt; &lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; /* Precalculate N */ &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; var N = Math.Pow(sm_a, 2.0) / (sm_b * Math.Sqrt(1 + nu2)); &lt;/p&gt; &lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; /* Precalculate t */ &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; var t = Math.Tan(phi); &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; var t2 = t * t; &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; var tmp = (t2 * t2 * t2) - Math.Pow(t, 6.0); &lt;/p&gt; &lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; /* Precalculate l */ &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; var l = lambda - lambda0; &lt;/p&gt; &lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; /* Precalculate coefficients for l**n in the equations below &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; so a normal human being can read the expressions for easting &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; and northing &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; -- l**1 and l**2 have coefficients of 1.0 */ &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; var l3coef = 1.0 - t2 + nu2; &lt;/p&gt; &lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; var l4coef = 5.0 - t2 + 9 * nu2 + 4.0 * (nu2 * nu2); &lt;/p&gt; &lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; var l5coef = 5.0 - 18.0 * t2 + (t2 * t2) + 14.0 * nu2 - 58.0 * t2 * nu2; &lt;/p&gt; &lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; var l6coef = 61.0 - 58.0 * t2 + (t2 * t2) + 270.0 * nu2 - 330.0 * t2 * nu2; &lt;/p&gt; &lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; var l7coef = 61.0 - 479.0 * t2 + 179.0 * (t2 * t2) - (t2 * t2 * t2); &lt;/p&gt; &lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; var l8coef = 1385.0 - 3111.0 * t2 + 543.0 * (t2 * t2) - (t2 * t2 * t2); &lt;/p&gt; &lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; var xy = new GeoPoint(); &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; /* Calculate easting (x) */ &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; xy.X = N * Math.Cos(phi) * l + (N / 6.0 * Math.Pow(Math.Cos(phi), 3.0) * l3coef * Math.Pow(l, 3.0)) + (N / 120.0 * Math.Pow(Math.Cos(phi), 5.0) * l5coef * Math.Pow(l, 5.0)) + (N / 5040.0 * Math.Pow(Math.Cos(phi), 7.0) * l7coef * Math.Pow(l, 7.0)); &lt;/p&gt; &lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; /* Calculate northing (y) */ &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; xy.Y = ArcLengthOfMeridian(phi) + (t / 2.0 * N * Math.Pow(Math.Cos(phi), 2.0) * Math.Pow(l, 2.0)) + (t / 24.0 * N * Math.Pow(Math.Cos(phi), 4.0) * l4coef * Math.Pow(l, 4.0)) + (t / 720.0 * N * Math.Pow(Math.Cos(phi), 6.0) * l6coef * Math.Pow(l, 6.0)) + (t / 40320.0 * N * Math.Pow(Math.Cos(phi), 8.0) * l8coef * Math.Pow(l, 8.0)); &lt;/p&gt; &lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; return xy; &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; } &lt;br /&gt;&lt;br /&gt;&lt;/p&gt; &lt;p&gt;public static GeoCoord MapXYToLatLon(double x, double y, double lambda0) { &lt;br /&gt;&amp;nbsp;&amp;nbsp; /* Get the value of phif, the footpoint latitude. */ &lt;br /&gt;&amp;nbsp;&amp;nbsp; double phif = FootpointLatitude(y); &lt;/p&gt; &lt;p&gt;&amp;nbsp;&amp;nbsp; /* Precalculate ep2 */ &lt;br /&gt;&amp;nbsp;&amp;nbsp; double ep2 = (Math.Pow(sm_a, 2.0) - Math.Pow(sm_b, 2.0)) / Math.Pow(sm_b, 2.0); &lt;/p&gt; &lt;p&gt;&amp;nbsp;&amp;nbsp; /* Precalculate cos (phif) */ &lt;br /&gt;&amp;nbsp;&amp;nbsp; var cf = Math.Cos(phif); &lt;/p&gt; &lt;p&gt;&amp;nbsp;&amp;nbsp; /* Precalculate nuf2 */ &lt;br /&gt;&amp;nbsp;&amp;nbsp; var nuf2 = ep2 * Math.Pow(cf, 2.0); &lt;/p&gt; &lt;p&gt;&amp;nbsp;&amp;nbsp; /* Precalculate Nf and initialize Nfpow */ &lt;br /&gt;&amp;nbsp;&amp;nbsp; var Nf = Math.Pow(sm_a, 2.0) / (sm_b * Math.Sqrt(1 + nuf2)); &lt;br /&gt;&amp;nbsp;&amp;nbsp; var Nfpow = Nf; &lt;/p&gt; &lt;p&gt;&amp;nbsp;&amp;nbsp; /* Precalculate tf */ &lt;br /&gt;&amp;nbsp;&amp;nbsp; var tf = Math.Tan(phif); &lt;br /&gt;&amp;nbsp;&amp;nbsp; var tf2 = tf * tf; &lt;br /&gt;&amp;nbsp;&amp;nbsp; var tf4 = tf2 * tf2; &lt;/p&gt; &lt;p&gt;&amp;nbsp;&amp;nbsp; /* Precalculate fractional coefficients for x**n in the equations &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; below to simplify the expressions for latitude and longitude. */ &lt;br /&gt;&amp;nbsp;&amp;nbsp; var x1frac = 1.0 / (Nfpow * cf); &lt;/p&gt; &lt;p&gt;&amp;nbsp;&amp;nbsp; Nfpow *= Nf;&amp;nbsp;&amp;nbsp; /* now equals Nf**2) */ &lt;br /&gt;&amp;nbsp;&amp;nbsp; var x2frac = tf / (2.0 * Nfpow); &lt;/p&gt; &lt;p&gt;&amp;nbsp;&amp;nbsp; Nfpow *= Nf;&amp;nbsp;&amp;nbsp; /* now equals Nf**3) */ &lt;br /&gt;&amp;nbsp;&amp;nbsp; var x3frac = 1.0 / (6.0 * Nfpow * cf); &lt;/p&gt; &lt;p&gt;&amp;nbsp;&amp;nbsp; Nfpow *= Nf;&amp;nbsp;&amp;nbsp; /* now equals Nf**4) */ &lt;br /&gt;&amp;nbsp;&amp;nbsp; var x4frac = tf / (24.0 * Nfpow); &lt;/p&gt; &lt;p&gt;&amp;nbsp;&amp;nbsp; Nfpow *= Nf;&amp;nbsp;&amp;nbsp; /* now equals Nf**5) */ &lt;br /&gt;&amp;nbsp;&amp;nbsp; var x5frac = 1.0 / (120.0 * Nfpow * cf); &lt;/p&gt; &lt;p&gt;&amp;nbsp;&amp;nbsp; Nfpow *= Nf;&amp;nbsp;&amp;nbsp; /* now equals Nf**6) */ &lt;br /&gt;&amp;nbsp;&amp;nbsp; var x6frac = tf / (720.0 * Nfpow); &lt;/p&gt; &lt;p&gt;&amp;nbsp;&amp;nbsp; Nfpow *= Nf;&amp;nbsp;&amp;nbsp; /* now equals Nf**7) */ &lt;br /&gt;&amp;nbsp;&amp;nbsp; var x7frac = 1.0 / (5040.0 * Nfpow * cf); &lt;/p&gt; &lt;p&gt;&amp;nbsp;&amp;nbsp; Nfpow *= Nf;&amp;nbsp;&amp;nbsp; /* now equals Nf**8) */ &lt;br /&gt;&amp;nbsp;&amp;nbsp; var x8frac = tf / (40320.0 * Nfpow); &lt;/p&gt; &lt;p&gt;&amp;nbsp;&amp;nbsp; /* Precalculate polynomial coefficients for x**n. &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; -- x**1 does not have a polynomial coefficient. */ &lt;br /&gt;&amp;nbsp;&amp;nbsp; var x2poly = -1.0 - nuf2; &lt;/p&gt; &lt;p&gt;&amp;nbsp;&amp;nbsp; var x3poly = -1.0 - 2 * tf2 - nuf2; &lt;/p&gt; &lt;p&gt;&amp;nbsp;&amp;nbsp; var x4poly = 5.0 + 3.0 * tf2 + 6.0 * nuf2 - 6.0 * tf2 * nuf2 - 3.0 * (nuf2 * nuf2) - 9.0 * tf2 * (nuf2 * nuf2); &lt;/p&gt; &lt;p&gt;&amp;nbsp;&amp;nbsp; var x5poly = 5.0 + 28.0 * tf2 + 24.0 * tf4 + 6.0 * nuf2 + 8.0 * tf2 * nuf2; &lt;/p&gt; &lt;p&gt;&amp;nbsp;&amp;nbsp; var x6poly = -61.0 - 90.0 * tf2 - 45.0 * tf4 - 107.0 * nuf2 + 162.0 * tf2 * nuf2; &lt;/p&gt; &lt;p&gt;&amp;nbsp;&amp;nbsp; var x7poly = -61.0 - 662.0 * tf2 - 1320.0 * tf4 - 720.0 * (tf4 * tf2); &lt;/p&gt; &lt;p&gt;&amp;nbsp;&amp;nbsp; var x8poly = 1385.0 + 3633.0 * tf2 + 4095.0 * tf4 + 1575 * (tf4 * tf2); &lt;/p&gt; &lt;p&gt;&amp;nbsp;&amp;nbsp; var philambda = new GeoCoord(); &lt;br /&gt;&amp;nbsp;&amp;nbsp; /* Calculate latitude */ &lt;br /&gt;&amp;nbsp;&amp;nbsp; philambda.Latitude = phif + x2frac * x2poly * (x * x) + x4frac * x4poly * Math.Pow(x, 4.0) + x6frac * x6poly * Math.Pow(x, 6.0) + x8frac * x8poly * Math.Pow(x, 8.0); &lt;/p&gt; &lt;p&gt;&amp;nbsp;&amp;nbsp; /* Calculate longitude */ &lt;br /&gt;&amp;nbsp;&amp;nbsp; philambda.Longitude = lambda0 + x1frac * x + x3frac * x3poly * Math.Pow(x, 3.0) + x5frac * x5poly * Math.Pow(x, 5.0) + x7frac * x7poly * Math.Pow(x, 7.0); &lt;/p&gt; &lt;p&gt;&amp;nbsp;&amp;nbsp; return philambda; &lt;br /&gt;}&lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;We done, the only thing, should be adjusted is easting and northing for UTM system&lt;/p&gt; &lt;blockquote&gt; &lt;p&gt;xy.X = xy.X * UTMScaleFactor + 500000.0; &lt;br /&gt;xy.Y = xy.Y * UTMScaleFactor; &lt;br /&gt;if (xy.Y &amp;lt; 0.0) xy.Y += 10000000.0;&lt;/p&gt;&lt;/blockquote&gt; &lt;h3&gt;Conversion UTM2WGS (UTM2LatLon)&lt;/h3&gt; &lt;p&gt;After al had all thin math in previous chapter, now we should calculate opposite conversion&lt;/p&gt; &lt;p&gt;First adjust&lt;/p&gt; &lt;blockquote&gt; &lt;p&gt;x -= 500000.0; &lt;br /&gt;x /= UTMScaleFactor; &lt;/p&gt; &lt;p&gt;/* If in southern hemisphere, adjust y accordingly. */ &lt;br /&gt;if (southhemi) y -= 10000000.0; &lt;/p&gt; &lt;p&gt;y /= UTMScaleFactor; &lt;/p&gt; &lt;p&gt;var cmeridian = UTMCentralMeridian(zone);&lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;Now calculate&lt;/p&gt; &lt;blockquote&gt; &lt;p&gt;public static GeoCoord MapXYToLatLon(double x, double y, double lambda0) { &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; /* Get the value of phif, the footpoint latitude. */ &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; double phif = FootpointLatitude(y); &lt;/p&gt; &lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; /* Precalculate ep2 */ &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; double ep2 = (Math.Pow(sm_a, 2.0) - Math.Pow(sm_b, 2.0)) / Math.Pow(sm_b, 2.0); &lt;/p&gt; &lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; /* Precalculate cos (phif) */ &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; var cf = Math.Cos(phif); &lt;/p&gt; &lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; /* Precalculate nuf2 */ &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; var nuf2 = ep2 * Math.Pow(cf, 2.0); &lt;/p&gt; &lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; /* Precalculate Nf and initialize Nfpow */ &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; var Nf = Math.Pow(sm_a, 2.0) / (sm_b * Math.Sqrt(1 + nuf2)); &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; var Nfpow = Nf; &lt;/p&gt; &lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; /* Precalculate tf */ &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; var tf = Math.Tan(phif); &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; var tf2 = tf * tf; &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; var tf4 = tf2 * tf2; &lt;/p&gt; &lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; /* Precalculate fractional coefficients for x**n in the equations &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; below to simplify the expressions for latitude and longitude. */ &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; var x1frac = 1.0 / (Nfpow * cf); &lt;/p&gt; &lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Nfpow *= Nf;&amp;nbsp;&amp;nbsp; /* now equals Nf**2) */ &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; var x2frac = tf / (2.0 * Nfpow); &lt;/p&gt; &lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Nfpow *= Nf;&amp;nbsp;&amp;nbsp; /* now equals Nf**3) */ &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; var x3frac = 1.0 / (6.0 * Nfpow * cf); &lt;/p&gt; &lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Nfpow *= Nf;&amp;nbsp;&amp;nbsp; /* now equals Nf**4) */ &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; var x4frac = tf / (24.0 * Nfpow); &lt;/p&gt; &lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Nfpow *= Nf;&amp;nbsp;&amp;nbsp; /* now equals Nf**5) */ &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; var x5frac = 1.0 / (120.0 * Nfpow * cf); &lt;/p&gt; &lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Nfpow *= Nf;&amp;nbsp;&amp;nbsp; /* now equals Nf**6) */ &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; var x6frac = tf / (720.0 * Nfpow); &lt;/p&gt; &lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Nfpow *= Nf;&amp;nbsp;&amp;nbsp; /* now equals Nf**7) */ &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; var x7frac = 1.0 / (5040.0 * Nfpow * cf); &lt;/p&gt; &lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Nfpow *= Nf;&amp;nbsp;&amp;nbsp; /* now equals Nf**8) */ &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; var x8frac = tf / (40320.0 * Nfpow); &lt;/p&gt; &lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; /* Precalculate polynomial coefficients for x**n. &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; -- x**1 does not have a polynomial coefficient. */ &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; var x2poly = -1.0 - nuf2; &lt;/p&gt; &lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; var x3poly = -1.0 - 2 * tf2 - nuf2; &lt;/p&gt; &lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; var x4poly = 5.0 + 3.0 * tf2 + 6.0 * nuf2 - 6.0 * tf2 * nuf2 - 3.0 * (nuf2 * nuf2) - 9.0 * tf2 * (nuf2 * nuf2); &lt;/p&gt; &lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; var x5poly = 5.0 + 28.0 * tf2 + 24.0 * tf4 + 6.0 * nuf2 + 8.0 * tf2 * nuf2; &lt;/p&gt; &lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; var x6poly = -61.0 - 90.0 * tf2 - 45.0 * tf4 - 107.0 * nuf2 + 162.0 * tf2 * nuf2; &lt;/p&gt; &lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; var x7poly = -61.0 - 662.0 * tf2 - 1320.0 * tf4 - 720.0 * (tf4 * tf2); &lt;/p&gt; &lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; var x8poly = 1385.0 + 3633.0 * tf2 + 4095.0 * tf4 + 1575 * (tf4 * tf2); &lt;/p&gt; &lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; var philambda = new GeoCoord(); &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; /* Calculate latitude */ &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; philambda.Latitude = phif + x2frac * x2poly * (x * x) + x4frac * x4poly * Math.Pow(x, 4.0) + x6frac * x6poly * Math.Pow(x, 6.0) + x8frac * x8poly * Math.Pow(x, 8.0); &lt;/p&gt; &lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; /* Calculate longitude */ &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; philambda.Longitude = lambda0 + x1frac * x + x3frac * x3poly * Math.Pow(x, 3.0) + x5frac * x5poly * Math.Pow(x, 5.0) + x7frac * x7poly * Math.Pow(x, 7.0); &lt;/p&gt; &lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; return philambda; &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;At the end do not forget to return Latitude and Longitude in degrees, rather, then in radians&lt;/p&gt; &lt;h3&gt;Azimuth calculation&lt;/h3&gt; &lt;p&gt;We done with coordinates, now azimuth&lt;/p&gt; &lt;blockquote&gt; &lt;p&gt;public static double GetAzimuth(WGSCoord c1, WGSCoord c2) { &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; var lat1 = DegToRad(c1.Latitude); &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; var lon1 = DegToRad(c1.Longitude); &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; var lat2 = DegToRad(c2.Latitude); &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; var lon2 = DegToRad(c2.Longitude); &lt;/p&gt; &lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; return RadToDeg(Math.Asin(Math.Sin(lon1 - lon2) * Math.Cos(lat2) / Math.Sin(Math.Acos(Math.Sin(lat2) * Math.Sin(lat1) + Math.Cos(lat1) * Math.Cos(lat2) * Math.Cos(lon2 - lon1))))); &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/p&gt;&lt;/blockquote&gt; &lt;h3&gt;Distance calculations&lt;/h3&gt; &lt;blockquote&gt; &lt;p&gt;public static double GetDistance(WGSCoord c1, WGSCoord c2) { &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; var dLat = DegToRad(c2.Latitude - c1.Latitude); &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; var dLon = DegToRad(c2.Longitude - c2.Longitude); &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; var a = Math.Sin(dLat / 2) * Math.Sin(dLat / 2) + Math.Cos(DegToRad(c1.Latitude)) * Math.Cos(DegToRad(c2.Latitude)) * Math.Sin(dLon / 2) * Math.Sin(dLon / 2); &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; var c = 2 * Math.Atan2(Math.Sqrt(a), Math.Sqrt(1 - a)); &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; return sm_a * c; &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/p&gt;&lt;/blockquote&gt; &lt;h3&gt;Final destination coordinates, based on start coordinate, bearing and distance&lt;/h3&gt; &lt;blockquote&gt; &lt;p&gt;public static WGSCoord GetDestination(WGSCoord start, double distance, double azimuth) { &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; var lat = RadToDeg(Math.Asin(Math.Sin(DegToRad(start.Latitude)) * Math.Cos(DegToRad(distance / sm_a)) + Math.Cos(DegToRad(start.Latitude)) * Math.Sin(DegToRad(distance / sm_a)) * Math.Cos(DegToRad(azimuth)))); &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; var lon = start.Longitude + DegToRad(Math.Atan2(Math.Sin(DegToRad(azimuth)) * Math.Sin(DegToRad(distance / sm_a)) * Math.Cos(DegToRad(start.Latitude)), Math.Cos(DegToRad(distance / sm_a)) - Math.Sin(DegToRad(start.Latitude)) * Math.Sin(DegToRad(lat)))); &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; return new WGSCoord(lon,lat); &lt;/p&gt; &lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/p&gt;&lt;/blockquote&gt; &lt;h3&gt;Midpoint calculation&lt;/h3&gt; &lt;blockquote&gt; &lt;p&gt;public static WGSCoord GetMidpoint(WGSCoord start, WGSCoord end) { &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; var dLat = DegToRad(end.Latitude - start.Latitude); &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; var dLon = DegToRad(end.Longitude - start.Longitude); &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; var lat2 = DegToRad(end.Latitude); &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; var lat1 = DegToRad(start.Latitude); &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; var lon1 = DegToRad(start.Longitude); &lt;/p&gt; &lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; var Bx = Math.Cos(lat2) * Math.Cos(dLon); &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; var By = Math.Cos(lat2) * Math.Sin(dLon); &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; var lat3 = Math.Atan2(Math.Sin(lat1) + Math.Sin(lat2), Math.Sqrt((Math.Cos(lat1) + Bx) * (Math.Cos(lat1) + Bx) + By * By)); &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; var lon3 = lon1 + Math.Atan2(By, Math.Cos(lat1) + Bx); &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; return new WGSCoord(RadToDeg(lon3), RadToDeg(lat3)); &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/p&gt;&lt;/blockquote&gt; &lt;h3&gt;Rhumb lines calculation&lt;/h3&gt; &lt;p&gt;First of all, what is rhumb lines? Rhumb lines or loxodrome is a path of constant bearing, which crosses all meridians at the same angle. This calculation is very useful, if you want to follow constant compass bearing, instead of continually adjustment of it.&lt;/p&gt; &lt;blockquote&gt; &lt;p&gt;public static double GetRhumbDistance(WGSCoord start, WGSCoord end) { &lt;br /&gt;&amp;nbsp;&amp;nbsp; var dLat = DegToRad(end.Latitude - start.Latitude); &lt;br /&gt;&amp;nbsp;&amp;nbsp; var dLon = DegToRad(end.Longitude - start.Longitude); &lt;br /&gt;&amp;nbsp;&amp;nbsp; var lat1 = DegToRad(start.Latitude); &lt;br /&gt;&amp;nbsp;&amp;nbsp; var lon1 = DegToRad(start.Longitude); &lt;br /&gt;&amp;nbsp;&amp;nbsp; var lat2 = DegToRad(end.Latitude); &lt;br /&gt;&amp;nbsp;&amp;nbsp; var lon2 = DegToRad(end.Longitude); &lt;/p&gt; &lt;p&gt;&amp;nbsp;&amp;nbsp; var dPhi = Math.Log(Math.Tan(lat2 / 2 + Math.PI / 4) / Math.Tan(lat1 / 2 + Math.PI / 4)); &lt;br /&gt;&amp;nbsp;&amp;nbsp; var q = (Math.Abs(dLat) &amp;gt; 1e-10) ? dLat / dPhi : Math.Cos(lat1); &lt;br /&gt;&amp;nbsp;&amp;nbsp; if (Math.Abs(dLon) &amp;gt; Math.PI) { &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; dLon = dLon &amp;gt; 0 ? -(2 * Math.PI - dLon) : (2 * Math.PI + dLon); &lt;br /&gt;&amp;nbsp;&amp;nbsp; } &lt;br /&gt;&amp;nbsp;&amp;nbsp; return Math.Sqrt(dLat * dLat + q * q * dLon * dLon) * sm_a; &lt;br /&gt;}&lt;/p&gt; &lt;p&gt;public static double GetRhumbBearing(WGSCoord start, WGSCoord end) { &lt;br /&gt;&amp;nbsp;&amp;nbsp; var dLat = DegToRad(end.Latitude - start.Latitude); &lt;br /&gt;&amp;nbsp;&amp;nbsp; var dLon = DegToRad(end.Longitude - start.Longitude); &lt;/p&gt; &lt;p&gt;&amp;nbsp;&amp;nbsp; var lat1 = DegToRad(start.Latitude); &lt;br /&gt;&amp;nbsp;&amp;nbsp; var lon1 = DegToRad(start.Longitude); &lt;br /&gt;&amp;nbsp;&amp;nbsp; var lat2 = DegToRad(end.Latitude); &lt;br /&gt;&amp;nbsp;&amp;nbsp; var lon2 = DegToRad(end.Longitude); &lt;/p&gt; &lt;p&gt;&amp;nbsp;&amp;nbsp; var dPhi = Math.Log(Math.Tan(lat2 / 2 + Math.PI / 4) / Math.Tan(lat1 / 2 + Math.PI / 4)); &lt;br /&gt;&amp;nbsp;&amp;nbsp; if (Math.Abs(dLon) &amp;gt; Math.PI) { &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; dLon = dLon &amp;gt; 0 ? -(2 * Math.PI - dLon) : (2 * Math.PI + dLon); &lt;br /&gt;&amp;nbsp;&amp;nbsp; } &lt;br /&gt;&amp;nbsp;&amp;nbsp; return Math.Atan2(dLon, dPhi); &lt;br /&gt;}&lt;/p&gt; &lt;p&gt;public static WGSCoord GetRhumbDestination(WGSCoord start, WGSCoord end) { &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; var lat1 = DegToRad(start.Latitude); &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; var lon1 = DegToRad(start.Longitude); &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; var lat2 = DegToRad(end.Latitude); &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; var lon2 = DegToRad(end.Longitude); &lt;/p&gt; &lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; var d = GetRhumbDistance(start, end); &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; var b = GetRhumbBearing(start, end); &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; lat2 = lat1 +&amp;nbsp; d * Math.Cos(b); &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; var dPhi = Math.Log(Math.Tan(lat2 / 2 + Math.PI / 4) / Math.Tan(lat1 / 2 + Math.PI / 4)); &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; var q = (Math.Abs(lat2 - lat1) &amp;gt; 1e-10) ? (lat2 - lat1) / dPhi : Math.Cos(lat1); &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; var dLon = d * Math.Sin(b) / q; &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; if (Math.Abs(lat2) &amp;gt; Math.PI / 2) lat2 = lat2 &amp;gt; 0 ? Math.PI - lat2 : -Math.PI - lat2; &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; lon2 = (lon1 + dLon + Math.PI) % (2 * Math.PI) - Math.PI; &lt;/p&gt; &lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; return new WGSCoord(RadToDeg(lon2), RadToDeg(lat2)); &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/p&gt;&lt;/blockquote&gt; &lt;h3&gt;Conversion between decimal degrees to degrees-minutes-seconds&lt;/h3&gt; &lt;blockquote&gt; &lt;p&gt;public static Pair&amp;lt;double,double&amp;gt; ToD_Mm(this double decCoord) { &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; var degSeg = (int)decCoord; &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; return new Pair&amp;lt;double, double&amp;gt;(degSeg, decCoord % degSeg * 60); &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;Now it&amp;#39;s good time for small math (if there were not enough until now) :) All following methods are not geo spatial oriented. All those are only geometry. The only helper method, you need here is Dot vector operation&lt;/p&gt; &lt;blockquote&gt; &lt;p&gt;private static double dot(Vector v1, Vector v2) { return (v1.X * v2.X + v1.Y * v2.Y); }&lt;/p&gt;&lt;/blockquote&gt; &lt;h3&gt;Get the distance between two points&lt;/h3&gt; &lt;blockquote&gt; &lt;p&gt;private static double distance(Point p1, Point p2) { &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; var a = Math.Pow(p1.X, 2) - Math.Pow(p2.X, 2); &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; var b = Math.Pow(p1.Y, 2) - Math.Pow(p2.Y, 2); &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; return Math.Sqrt(Math.Abs(a + b)); &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/p&gt;&lt;/blockquote&gt; &lt;h3&gt;Get the shortest distance between point and line segment&lt;/h3&gt; &lt;blockquote&gt; &lt;p&gt;private static double distance(Point p1, Point p2, Point p) { &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; var v = p1 - p2; &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; var w = p - p2; &lt;/p&gt; &lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; var c1 = dot(w, v); &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; if (c1 &amp;lt;= 0) return distance(p, p1); &lt;/p&gt; &lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; var c2 = dot(v, v); &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; if (c2 &amp;lt;= c1) return distance(p, p2); &lt;/p&gt; &lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; var b = c1 / c2; &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Point Pb = p1 + b * v; &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; return distance(p, Pb); &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;Isn&amp;#39;t it enough math for now? It is. Have a nice day and be good people. Next time, we&amp;#39;ll speak about different path finding algorithms, edges, nodes and other fun math optimizations.&lt;/p&gt;&lt;img src="http://blogs.microsoft.co.il/aggbug.aspx?PostID=139757" width="1" height="1"&gt;</description><category domain="http://blogs.microsoft.co.il/blogs/tamir/archive/tags/tutorial/default.aspx">tutorial</category><category domain="http://blogs.microsoft.co.il/blogs/tamir/archive/tags/Tips+and+Tricks/default.aspx">Tips and Tricks</category><category domain="http://blogs.microsoft.co.il/blogs/tamir/archive/tags/source/default.aspx">source</category><category domain="http://blogs.microsoft.co.il/blogs/tamir/archive/tags/C_2300_/default.aspx">C#</category><category domain="http://blogs.microsoft.co.il/blogs/tamir/archive/tags/.NET+3.5/default.aspx">.NET 3.5</category><category domain="http://blogs.microsoft.co.il/blogs/tamir/archive/tags/Work+process/default.aspx">Work process</category><category domain="http://blogs.microsoft.co.il/blogs/tamir/archive/tags/Math/default.aspx">Math</category><category domain="http://blogs.microsoft.co.il/blogs/tamir/archive/tags/GIS/default.aspx">GIS</category><category domain="http://blogs.microsoft.co.il/blogs/tamir/archive/tags/Algorithms/default.aspx">Algorithms</category></item><item><title>Configuring and running Mono ASP.NET 3.5 (AJAX.NET) on Linux computers</title><link>http://blogs.microsoft.co.il/blogs/tamir/archive/2008/07/24/configuring-and-running-mono-asp-net-3-5-ajax-net-on-linux-computers.aspx</link><pubDate>Thu, 24 Jul 2008 17:27:10 GMT</pubDate><guid isPermaLink="false">b5c4f5bc-c09b-4439-a595-91a98c1847df:126309</guid><dc:creator>Tamir Khason</dc:creator><slash:comments>10</slash:comments><description>&lt;h3&gt;[This blog was migrated. You will not be able to comment here.&lt;br /&gt;The new URL of this post is &lt;a href="http://khason.net/blog/configuring-and-running-mono-aspnet-35-ajaxnet-on-linux-computers/"&gt;http://khason.net/blog/configuring-and-running-mono-aspnet-35-ajaxnet-on-linux-computers/&lt;/a&gt;]&lt;/h3&gt;&lt;hr /&gt;&lt;p&gt;Before we will start, we should install Linux. To do this, you can download any of LiveCDs with live installation. Officially, Mono supported only on one free Linux - &lt;a href="http://software.opensuse.org/"&gt;openSuse&lt;/a&gt;. However, you can make it work on any RedHat (and its alternatives), &lt;a href="http://opensolaris.com/get"&gt;OpenSolaris&lt;/a&gt;. It works, but unsupported on Debians, Ubuntu and Maemo. We’ll stick to openSuse by now. &lt;/p&gt;  &lt;p&gt;&lt;img title="image" border="0" alt="image" src="http://blogs.microsoft.co.il/blogs/tamir/WindowsLiveWriter/Configuringandrunnin.NETonLinuxcomputers_11F9A/image_3947ac10-c1ff-4b7b-bcbf-3b74b1d4b29b.png" width="347" height="155" /&gt; &lt;/p&gt;  &lt;h3&gt;Let’s install it - OS&lt;/h3&gt;  &lt;p&gt;I’m assuming, that you’re installing Linux as the only OS on the machine, so insert liveCD (it can be either Gnome or KDE) and wait for Linux to run. It will run live image directly on your machine without installation.&lt;/p&gt;  &lt;p&gt;When it’ll up, you’ll see liveInstall icon in your desktop. Click it and skip first two screens (it is only language and local settings). Next screen (disk partitions) is necessary for us. &lt;/p&gt;  &lt;p&gt;On this screen, first delete all automatic partitions. The only one main partition will remain (/DEV/SDA or /DEV/HDA). Next you should choose non-LVM option and then start creating partitions.&lt;/p&gt;  &lt;p&gt;Create first partition with &lt;em&gt;mount point&lt;/em&gt; &lt;strong&gt;/boot&lt;/strong&gt; and &lt;em&gt;size&lt;/em&gt; of &lt;strong&gt;100Mb&lt;/strong&gt;. &lt;em&gt;File system&lt;/em&gt; for this partition should be &lt;strong&gt;ext3&lt;/strong&gt;.&lt;/p&gt;  &lt;p&gt;Create second partition with &lt;em&gt;file system&lt;/em&gt; &lt;strong&gt;SWAP&lt;/strong&gt; (you will not have &lt;em&gt;mount point&lt;/em&gt;) and set the &lt;em&gt;size&lt;/em&gt; &lt;strong&gt;twice bigger, then RAM&lt;/strong&gt; amount.&lt;/p&gt;  &lt;p&gt;Create last partition with &lt;em&gt;mount point&lt;/em&gt; &lt;strong&gt;/&lt;/strong&gt; and all &lt;strong&gt;remaining size on disk&lt;/strong&gt;.&lt;/p&gt;  &lt;p&gt;All other steps are optional, you can just click Next button.&lt;/p&gt;  &lt;p&gt;After about 10 minutes you’ll have up and running openSuse system. (If you forgot to remove CD, choose HardDisk as boot option)&lt;/p&gt;  &lt;h3&gt;Web Server installation&lt;/h3&gt;  &lt;p&gt;Now we have to install web server. You can choose either &lt;strong&gt;Apache&lt;/strong&gt;, &lt;strong&gt;FastCGI&lt;/strong&gt;&amp;#160; or use build-in server within Mono – &lt;strong&gt;XSP&lt;/strong&gt;. We’ll choose Apache&lt;/p&gt;  &lt;p&gt;Goto “Computer” it’s in the same place as Start button :) and choose &lt;strong&gt;YaST&lt;/strong&gt;. You’ll be asked for admin password, you entered while installing the system.    &lt;p&gt;&lt;/p&gt;    &lt;p&gt;&lt;/p&gt;    &lt;p&gt;&lt;/p&gt;    &lt;p&gt;&lt;/p&gt;    &lt;p&gt;&lt;/p&gt;    &lt;p&gt;&lt;/p&gt;    &lt;p&gt;&lt;/p&gt;    &lt;p&gt;&lt;/p&gt;    &lt;p&gt;&lt;/p&gt;    &lt;p&gt;&lt;/p&gt;    &lt;p&gt;&lt;/p&gt;    &lt;p&gt;&lt;/p&gt;    &lt;p&gt;&lt;/p&gt;    &lt;p&gt;&lt;/p&gt;    &lt;p&gt;&lt;/p&gt;    &lt;p&gt;&lt;/p&gt;    &lt;p&gt;&lt;/p&gt;    &lt;p&gt;&lt;/p&gt;    &lt;p&gt;&lt;/p&gt;    &lt;p&gt;&lt;/p&gt;    &lt;p&gt;&lt;/p&gt;    &lt;p&gt;&lt;/p&gt;    &lt;p&gt;&lt;/p&gt;    &lt;p&gt;&lt;/p&gt;    &lt;p&gt;&lt;/p&gt;    &lt;p&gt;&lt;/p&gt;    &lt;p&gt;&lt;/p&gt;    &lt;p&gt;&lt;/p&gt;    &lt;p&gt;&lt;/p&gt;    &lt;p&gt;&lt;/p&gt;    &lt;p&gt;&lt;/p&gt;    &lt;p&gt;&lt;/p&gt;    &lt;p&gt;&lt;/p&gt;    &lt;p&gt;&lt;/p&gt;    &lt;p&gt;Now in the &lt;em&gt;Filter &lt;/em&gt;field, type “Install”. Choose “Software Management” from the available programs at right. Now, when Package Selection dialog opens, type “apache”, you’ll find &lt;strong&gt;apache2&lt;/strong&gt;. Select it and click Install. Apache will move to the right column. Optionally, you can install also prefork and utils packages.&lt;/p&gt;    &lt;p&gt;Now hit “Apply” to install it. Within two minutes, you’ll be asked to log off and log on. Do it.&lt;/p&gt;    &lt;p&gt;By now apache is not running, you should run it and set it starts automatically. To do this, enter terminal window (you can either do it from “Computer” menu or right clicking desktop).&lt;/p&gt;    &lt;p&gt;You need elevation to administrate startup programs. So type: “&lt;strong&gt;su –&lt;/strong&gt;“ and enter your password. Terminal color turns red. Type “&lt;strong&gt;chkconfig apache2 on&lt;/strong&gt;”. Now you should check whether it done, so type: “&lt;strong&gt;chkconfig apache2 –list&lt;/strong&gt;”. You should see “On” near &lt;strong&gt;number&lt;/strong&gt; &lt;strong&gt;3&lt;/strong&gt; and &lt;strong&gt;5&lt;/strong&gt;.&lt;/p&gt;    &lt;p&gt;To run apache manually, just type “&lt;strong&gt;/etc/init.d/apache2 start&lt;/strong&gt;” to stop “&lt;strong&gt;/etc/init.d/apache2 stop&lt;/strong&gt;”, to restart “&lt;strong&gt;/etc/init.d/apache2 restart&lt;/strong&gt;” and to check the status “&lt;strong&gt;/etc/init.d/apache2 status&lt;/strong&gt;”&lt;/p&gt; &lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;We done, apache is up and running. Now we should install mono&lt;/p&gt;  &lt;h3&gt;Mono installation&lt;/h3&gt;  &lt;p&gt;Start with the same &lt;em&gt;YaST&lt;strong&gt; &lt;/strong&gt;&lt;/em&gt;but this time, type “mono” – you’&amp;#39;ll get a lot of programs. To simplified installation, choose (or type) &lt;strong&gt;mono-complete&lt;/strong&gt;. This will all available Mono modules.&lt;/p&gt;  &lt;p&gt;After Mono will be installed, you should install also &lt;strong&gt;apache2-mod_mono&lt;/strong&gt; to make possible running ASP.NET mono pages in Apache. do this.&lt;/p&gt;  &lt;p&gt;Log off – log on and move to configuration&lt;/p&gt;  &lt;h3&gt;Mono configuration&lt;/h3&gt;  &lt;p&gt;Now it’s time to configure what ASP.NET pages you want to run. We want ASP.NET 2.0, so we should run mono apache mode for this version. To do this, go to the terminal, elevate yourself (su –) and type following: “&lt;strong&gt;vi /etc/apache2/httpd.conf&lt;/strong&gt;” This will open VI editor with apache configuration file in it. &lt;/p&gt;  &lt;p&gt;Now it’s time to learn VI a little. To &lt;em&gt;start editing&lt;/em&gt;, you should type “&lt;strong&gt;A&lt;/strong&gt;” – it will write “INSERT” in the lower left corner. To &lt;em&gt;return to the command mode&lt;/em&gt;, hit &lt;strong&gt;escape key&lt;/strong&gt;. To &lt;em&gt;save&lt;/em&gt; (from command mode) “&lt;strong&gt;:w&lt;/strong&gt;” to &lt;em&gt;exit and save&lt;/em&gt; “&lt;strong&gt;:wq&lt;/strong&gt;” to &lt;em&gt;exit without save&lt;/em&gt; “&lt;strong&gt;:q!&lt;/strong&gt;”. To &lt;em&gt;find&lt;/em&gt; “&lt;strong&gt;/&lt;/strong&gt;” and string the pattern you are looking for.&lt;/p&gt;  &lt;p&gt;Now go the the very end of the file&amp;#160; and write under Include “/etc/apache2/vhosts.d/*.conf” following:   &lt;br /&gt;(to short string “[D]” is your virtual directory (slash blank is root), “[P]” is physical path to your site without trailing slash)&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;MonoServerPath default /usr/bin/mod-mono_server2     &lt;br /&gt;Alias [D] “[P]”      &lt;br /&gt;AddMonoApplications default “[D]:[P]”      &lt;br /&gt;&amp;lt;Location [D]&amp;gt;      &lt;br /&gt; SetHandler mono      &lt;br /&gt;&amp;lt;/Location&amp;gt;&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;So, if your site is MySite and it is in /srv/www/htdocs/MySite, this section will looks as following:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;MonoServerPath default /usr/bin/mod-mono_server2     &lt;br /&gt;Alias /MySite “/srv/www/htdocs/MySite”      &lt;br /&gt;AddMonoApplications default “/MySite:/srv/www/htdocs/MySite”      &lt;br /&gt;&amp;lt;Location /MySite&amp;gt;      &lt;br /&gt; SetHandler mono      &lt;br /&gt;&amp;lt;/Location&amp;gt;&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;If you want to turn it to the root site, this will looks following:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;MonoServerPath default /usr/bin/mod-mono_server2     &lt;br /&gt;AddMonoApplications default “/:/srv/www/htdocs/MySite”      &lt;br /&gt;&amp;lt;Location /&amp;gt;      &lt;br /&gt; SetHandler mono      &lt;br /&gt;&amp;lt;/Location&amp;gt;&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;Now, we’ll add mono administrative site to be able to restart mono only without touching apache itself. To do this, after last &amp;lt;/Location&amp;gt; you should add following:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;&amp;lt;Location /mono&amp;gt;     &lt;br /&gt; SetHandler mono-ctrl      &lt;br /&gt; Order deny,allow      &lt;br /&gt; Deny from all      &lt;br /&gt; Allow from 127.0.0.1      &lt;br /&gt;&amp;lt;/Location&amp;gt;&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;I think it’s very clear what it did :)&lt;/p&gt;  &lt;p&gt;If you have more, then one site and want to configure mono differently for each one of those, you should add VirtualHost section. To do this, include your configuration in to &lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;&amp;lt;VirtualHost [IP and port you want, for example 1.1.1.1:80 or *:80 for all IPs on port 80]&amp;gt;     &lt;br /&gt;ServerName [Name you want]      &lt;br /&gt;…      &lt;br /&gt;&amp;lt;/VirtualHost&amp;gt;&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;We done. Restart apache and enter the url you set (for example &lt;a href="http://localhost/MySite/"&gt;http://localhost/MySite/&lt;/a&gt;)&lt;/p&gt;  &lt;p&gt;Working? Good. You finished. &lt;/p&gt;  &lt;p&gt;Not working (familiar yellow error 500 screen)? Keep reading…&lt;/p&gt;  &lt;h3&gt;Debugging Mono website&lt;/h3&gt;  &lt;p&gt;Do you remember, that you have no development environment in this machine? You can install it, or &lt;a href="http://www.go-mono.com/mono-downloads/download.html"&gt;download&lt;/a&gt; Mono liveCD with openSuse. But before doing it, please note, that GTK# (it’s devenv) is not very user friendly. It even worse, then &lt;a href="http://www.eclipse.org/"&gt;Eclipse&lt;/a&gt;. So let’s try to understand first whether we can fix small compatibility problems without entering code.&lt;/p&gt;  &lt;p&gt;The most convenient method to debug web site on Mono is by using XSP and XSP2 mini web servers. Just enter the directory of the site and run it. By default you’ll be able to access the site by using “http://localhost:8080” (it also be written for you). Enter and notice whether you have any errors in console. No? Keep doing&lt;/p&gt;  &lt;p&gt;The most common problem is “error 500” with nonsense stack. If it contains ScriptManager error Type not found, the problem is in Web.config file. Try to regenerate it to be compatible to Mono (for example, Mono has different version of System.Web.Extensions assembly. In ASP.NET 3.5 it has version 3.5, Mono has only 1.0.61025.0 (the old AJAX.NET). To recreate your web.config all you have to do is to execute “&lt;strong&gt;mconfig af AJAX Web.config&lt;/strong&gt;” It will create default web.config file, supports System.Web.Extensions (AJAX features).&lt;/p&gt;  &lt;div&gt;Not helped? Keep doing. Let’s look another time into the stack – if it contains errors in “EnablePageMethods” or “ShouldGenerateScript” or “EncryptString” – the problem is serialization. Mono has very limited support for JSON, XML and SOAP serialization. Try to look into your code and notice if you have classes, marked with [Serializable] or you are transferring your own classes by using PageMethods. If so, replace it with regular strings (my grandma serialization).    &lt;p&gt;&lt;/p&gt;    &lt;p&gt;&lt;/p&gt;    &lt;p&gt;&lt;/p&gt;    &lt;p&gt;&lt;/p&gt;    &lt;p&gt;&lt;/p&gt;    &lt;p&gt;&lt;/p&gt;    &lt;p&gt;&lt;/p&gt;    &lt;p&gt;&lt;/p&gt;    &lt;p&gt;&lt;/p&gt;    &lt;p&gt;&lt;/p&gt;    &lt;p&gt;&lt;/p&gt;    &lt;p&gt;&lt;/p&gt;    &lt;p&gt;&lt;/p&gt;    &lt;p&gt;&lt;/p&gt;    &lt;p&gt;&lt;/p&gt;    &lt;p&gt;&lt;/p&gt;    &lt;p&gt;&lt;/p&gt;    &lt;p&gt;&lt;/p&gt;    &lt;p&gt;&lt;/p&gt;    &lt;p&gt;&lt;/p&gt;    &lt;p&gt;&lt;/p&gt;    &lt;p&gt;&lt;/p&gt;    &lt;p&gt;&lt;/p&gt;    &lt;p&gt;&lt;/p&gt;    &lt;p&gt;&lt;/p&gt;    &lt;p&gt;&lt;/p&gt;    &lt;p&gt;&lt;/p&gt;    &lt;p&gt;&lt;/p&gt;    &lt;p&gt;&lt;/p&gt;    &lt;p&gt;&lt;/p&gt;    &lt;p&gt;&lt;/p&gt;    &lt;p&gt;&lt;/p&gt;    &lt;p&gt;&lt;/p&gt;    &lt;p&gt;&lt;/p&gt;    &lt;p&gt;&lt;/p&gt;    &lt;p&gt;&lt;/p&gt;    &lt;p&gt;&lt;/p&gt;    &lt;p&gt;&lt;/p&gt;    &lt;p&gt;&lt;/p&gt;    &lt;p&gt;&lt;/p&gt;    &lt;p&gt;&lt;/p&gt;    &lt;p&gt;&lt;/p&gt;    &lt;p&gt;&lt;/p&gt;    &lt;p&gt;&lt;/p&gt;    &lt;p&gt;&lt;/p&gt;    &lt;p&gt;&lt;/p&gt;    &lt;p&gt;&lt;/p&gt;    &lt;p&gt;&lt;/p&gt;    &lt;p&gt;&lt;/p&gt;    &lt;p&gt;&lt;/p&gt;    &lt;p&gt;&lt;/p&gt;    &lt;p&gt;&lt;/p&gt;    &lt;p&gt;&lt;/p&gt;    &lt;p&gt;&lt;/p&gt;    &lt;p&gt;&lt;/p&gt;    &lt;p&gt;&lt;/p&gt;    &lt;p&gt;&lt;/p&gt;    &lt;p&gt;&lt;/p&gt;    &lt;p&gt;&lt;/p&gt;    &lt;p&gt;&lt;/p&gt;    &lt;p&gt;&lt;/p&gt;    &lt;p&gt;&lt;/p&gt;    &lt;p&gt;&lt;/p&gt;    &lt;p&gt;&lt;/p&gt;    &lt;p&gt;&lt;/p&gt;    &lt;p&gt;&lt;/p&gt;    &lt;p&gt;&lt;/p&gt;    &lt;p&gt;&lt;/p&gt;    &lt;p&gt;&lt;/p&gt;    &lt;p&gt;&lt;/p&gt;    &lt;p&gt;&lt;/p&gt;    &lt;p&gt;&lt;/p&gt;    &lt;p&gt;&lt;/p&gt;    &lt;p&gt;&lt;/p&gt;    &lt;p&gt;&lt;/p&gt;    &lt;p&gt;&lt;/p&gt;    &lt;p&gt;&lt;/p&gt;    &lt;p&gt;&lt;/p&gt;    &lt;p&gt;&lt;/p&gt;    &lt;p&gt;&lt;/p&gt;    &lt;p&gt;&lt;/p&gt;    &lt;p&gt;&lt;/p&gt;    &lt;p&gt;&lt;/p&gt;    &lt;p&gt;&lt;/p&gt;    &lt;p&gt;&lt;/p&gt;    &lt;p&gt;&lt;/p&gt;    &lt;p&gt;&lt;/p&gt;    &lt;p&gt;&lt;/p&gt;    &lt;p&gt;&lt;/p&gt;    &lt;p&gt;&lt;/p&gt;    &lt;p&gt;&lt;/p&gt;    &lt;p&gt;&lt;/p&gt;    &lt;p&gt;&lt;/p&gt;    &lt;p&gt;&lt;/p&gt;    &lt;p&gt;&lt;/p&gt;    &lt;p&gt;&lt;/p&gt;    &lt;p&gt;&lt;/p&gt;    &lt;p&gt;&lt;/p&gt;    &lt;p&gt;&lt;/p&gt;    &lt;p&gt;&lt;/p&gt;    &lt;p&gt;&lt;/p&gt;    &lt;p&gt;&lt;/p&gt;    &lt;p&gt;&lt;/p&gt;    &lt;p&gt;&lt;/p&gt;    &lt;p&gt;&lt;/p&gt;    &lt;p&gt;&lt;/p&gt;    &lt;p&gt;&lt;/p&gt;    &lt;p&gt;&lt;/p&gt;    &lt;p&gt;&lt;/p&gt;    &lt;p&gt;&lt;/p&gt;    &lt;p&gt;&lt;/p&gt;    &lt;p&gt;&lt;/p&gt;    &lt;p&gt;&lt;/p&gt;    &lt;p&gt;&lt;/p&gt;    &lt;p&gt;&lt;/p&gt;    &lt;p&gt;&lt;/p&gt;    &lt;p&gt;&lt;/p&gt;    &lt;p&gt;&lt;/p&gt;    &lt;p&gt;&lt;/p&gt;    &lt;p&gt;&lt;/p&gt;    &lt;p&gt;&lt;/p&gt;    &lt;p&gt;&lt;/p&gt;    &lt;p&gt;&lt;/p&gt;    &lt;p&gt;&lt;/p&gt;    &lt;p&gt;&lt;/p&gt;    &lt;p&gt;&lt;/p&gt;    &lt;blockquote&gt;     &lt;p&gt;Person p = new Person();       &lt;br /&gt;string sstr = string.Format(“{0}|{1}|{2}|{3}”, p.FirstName, p.LastName, p.Age, p.Wage);        &lt;br /&gt;return sstr;        &lt;br /&gt;…        &lt;br /&gt;var sstr = persons[i].split(&amp;quot;|&amp;quot;);        &lt;br /&gt;var p.FirstName =&amp;#160; sstr[0];        &lt;br /&gt;var p.LastName =&amp;#160; sstr[1];        &lt;br /&gt;var p.Age =&amp;#160; sstr[2];        &lt;br /&gt;var p.Wage =&amp;#160; sstr[3];&lt;/p&gt;   &lt;/blockquote&gt;    &lt;p&gt;Not helped? Try to rename “Bin” directory into “bin” “&lt;strong&gt;mv Bin bin –r&lt;/strong&gt;”. Actually this was fixed in latest versions of Mono, but who knows?…&lt;/p&gt;    &lt;p&gt;No? Check whether you have partial classes, which is not supported by Mono. If so, recompile it like this&lt;/p&gt;    &lt;blockquote&gt;     &lt;p&gt;mcs /t:library /out:bin/test.dll –r:System.Web –r:System.Data –r:System.Web.Services –r:System.Web.UI.Controls test.aspx.cs&lt;/p&gt;   &lt;/blockquote&gt;    &lt;p&gt;If you have Generics in your code, you should use &lt;strong&gt;gmcs&lt;/strong&gt;, rather then &lt;strong&gt;mcs&lt;/strong&gt;.&lt;/p&gt; &lt;/div&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;Not helped? It looks, that you have to either install Mono on your Windows machine and debug your code with it. Or, alternatively install GTK# and do in on Linux.&lt;/p&gt;  &lt;p&gt;But wait, before doing such big step, install and check the binary compatibility of your code. To do this, you need “&lt;a href="http://www.mono-project.com/MoMA"&gt;Moma&lt;/a&gt;” – a simple tool, that tell you if everything is ok for Mono in your assemblies.&lt;/p&gt;  &lt;p&gt;Good luck and see you in &lt;a href="http://blogs.microsoft.co.il/blogs/tamir/archive/tags/teched/default.aspx"&gt;my forthcoming TechEd session&lt;/a&gt;, where I’m presenting openSuse, running UDP multicast server with ASP.NET 3.5 extended methods (It uses recompiled ISAPI filters for apache, rather then regular limited AJAX support in Mono)&lt;/p&gt;  &lt;p&gt;Have a nice day and be good people.&lt;/p&gt;&lt;img src="http://blogs.microsoft.co.il/aggbug.aspx?PostID=126309" width="1" height="1"&gt;</description><category domain="http://blogs.microsoft.co.il/blogs/tamir/archive/tags/tutorial/default.aspx">tutorial</category><category domain="http://blogs.microsoft.co.il/blogs/tamir/archive/tags/Tips+and+Tricks/default.aspx">Tips and Tricks</category><category domain="http://blogs.microsoft.co.il/blogs/tamir/archive/tags/C_2300_/default.aspx">C#</category><category domain="http://blogs.microsoft.co.il/blogs/tamir/archive/tags/.NET+3.5/default.aspx">.NET 3.5</category><category domain="http://blogs.microsoft.co.il/blogs/tamir/archive/tags/teched/default.aspx">teched</category><category domain="http://blogs.microsoft.co.il/blogs/tamir/archive/tags/ASP.NET/default.aspx">ASP.NET</category><category domain="http://blogs.microsoft.co.il/blogs/tamir/archive/tags/Work+process/default.aspx">Work process</category><category domain="http://blogs.microsoft.co.il/blogs/tamir/archive/tags/Linux/default.aspx">Linux</category><category domain="http://blogs.microsoft.co.il/blogs/tamir/archive/tags/Mono/default.aspx">Mono</category></item></channel></rss>