<?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 : Interop, Mobile</title><link>http://blogs.microsoft.co.il/blogs/tamir/archive/tags/Interop/Mobile/default.aspx</link><description>Tags: Interop, Mobile</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>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>Creating transparent buttons, panels and other control with Compact Framework and putting one into other</title><link>http://blogs.microsoft.co.il/blogs/tamir/archive/2008/11/21/creating-transparent-buttons-panels-and-other-control-with-compact-framework-and-putting-one-into-other.aspx</link><pubDate>Fri, 21 Nov 2008 18:09:29 GMT</pubDate><guid isPermaLink="false">b5c4f5bc-c09b-4439-a595-91a98c1847df:172845</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/creating-transparent-buttons-panels-and-other-control-with-compact-framework-and-putting-one-into-other/"&gt;http://khason.net/blog/creating-transparent-buttons-panels-and-other-control-with-compact-framework-and-putting-one-into-other/&lt;/a&gt;]&lt;/h3&gt;&lt;hr /&gt;&lt;p&gt;In &lt;a href="http://blogs.microsoft.co.il/blogs/tamir/archive/tags/WPF/default.aspx"&gt;WPF&lt;/a&gt;/&lt;a href="http://blogs.microsoft.co.il/blogs/tamir/archive/tags/Silverlight/default.aspx"&gt;Silverlight&lt;/a&gt; world it&amp;#39;s very simple to make transparent controls and put anything inside anything. However, that&amp;#39;s not the situation in WinForms, and even worth in the world of compact devices with CF. Within this worlds, there is only one way to make controls transparent - to use color masks. Today, we&amp;#39;ll create transparent controls with Compact Framework and put it into panel, which has image background.&lt;/p&gt; &lt;p&gt;&lt;img border="0" alt="image" src="http://blogs.microsoft.co.il/blogs/tamir/WindowsLiveWriter/Creatingtransparentbuttonspanelsandother_11B71/image_679149a5-fff2-40ab-8966-6c6ffa40b692.png" width="259" height="397" /&gt; &lt;/p&gt; &lt;p&gt;So let&amp;#39;s start. First of all, we need create our own control. For this purpose, we have to inherit from Control and override couple of things. More precise: OnPaint and OnPaintBackground. We do not want to paint background for transparent control, so let&amp;#39;s prevent it.&lt;/p&gt; &lt;blockquote&gt; &lt;p&gt;public class TransparentImageButton : Control&lt;br /&gt;&lt;/p&gt; &lt;p&gt;protected override void OnPaintBackground(PaintEventArgs e) {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; //prevent&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }  &lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; protected override void OnPaint(PaintEventArgs e) {&lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;Next, we have to get graphics, delivered by OnPain event argument and draw our image over it. However, BitBlt (which is used by core graphics system) is not very fast method, so it&amp;#39;s better for us to draw everything first and then copy final image to the device.&lt;/p&gt; &lt;blockquote&gt; &lt;p&gt;Graphics gxOff; &lt;br /&gt;Rectangle imgRect;&lt;br /&gt;var image = (_isPressed &amp;amp;&amp;amp; PressedImage != null) ? PressedImage : Image;  &lt;p&gt;if (_imgOffscreen == null) {&lt;br /&gt; _imgOffscreen = new Bitmap(ClientSize.Width, ClientSize.Height);&lt;br /&gt;}  &lt;p&gt;gxOff = Graphics.FromImage(_imgOffscreen); &lt;br /&gt;gxOff.Clear(this.BackColor);&amp;nbsp; &lt;br /&gt;...&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;p&gt;if (image != null) {&lt;br /&gt;var imageLeft = (this.Width - image.Width) / 2;&lt;br /&gt;var imageTop = (this.Height - image.Height) / 2;  &lt;p&gt;if (!_isPressed) imgRect = new Rectangle(imageLeft, imageTop, image.Width, image.Height);&lt;br /&gt;else imgRect = new Rectangle(imageLeft + 1, imageTop + 1, image.Width, image.Height);&lt;br /&gt;var imageAttr = new ImageAttributes();&lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;To make images transparent, we have to use (as mentioned earlier) transparency color key (to tell windows what color it should not draw. We can code or provide this value to detect it by hitting any pixel on the image. Just like this: &lt;/p&gt; &lt;blockquote&gt; &lt;p&gt;public static Color BackgroundImageColor(this Bitmap bmp) {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; return bmp.GetPixel(0, 0);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;Now we can keep working.&lt;/p&gt; &lt;blockquote&gt; &lt;p&gt;imageAttr.SetColorKey(image.BackgroundImageColor(), image.BackgroundImageColor());&lt;br /&gt;gxOff.DrawImage(image, imgRect, 0, 0, image.Width, image.Height, GraphicsUnit.Pixel, imageAttr);&lt;br /&gt;} if (_isPressed) {&lt;br /&gt; var rc = this.ClientRectangle;&lt;br /&gt;&amp;nbsp; rc.Width--;&lt;br /&gt;&amp;nbsp; rc.Height--;&lt;br /&gt;&amp;nbsp; gxOff.DrawRectangle(new Pen(Color.Black), rc);&lt;br /&gt; }&lt;br /&gt;e.Graphics.DrawImage(_imgOffscreen, 0, 0);&lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;Also, we have to provide others with possibility to handle this even too, thus we will not forget to add base.OnPaint(e); at&amp;nbsp; the end.&lt;/p&gt; &lt;p&gt;Next step is to detect whether our button is clicked or not. We&amp;#39;ll override keyboard and mouse events to detect this.&lt;/p&gt; &lt;blockquote&gt; &lt;p&gt;protected override void OnKeyDown(KeyEventArgs 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; _isPressed = this.Focused; this.Invalidate();&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; base.OnKeyDown(e);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }  &lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; protected override void OnKeyUp(KeyEventArgs 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; _isPressed = false; this.Invalidate();&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; base.OnKeyUp(e);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }  &lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; protected override void OnMouseDown(MouseEventArgs 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; _isPressed = this.Focused; this.Invalidate();&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; base.OnMouseDown(e);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }  &lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; protected override void OnMouseUp(MouseEventArgs 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; _isPressed = false; this.Invalidate();&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; base.OnMouseUp(e);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;Compile and run to see no problem, when our transparent button lies on solid color control, however, we want to put it into panel with background - just like this one. In this case, you can use real transparent PNG and GIF images, also you can replace transparent color with well known Magenta (or any other color).&lt;/p&gt; &lt;blockquote&gt; &lt;p&gt;public class ImagePanel : Panel {  &lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; public Bitmap Image { get; set; }  &lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; protected override void OnPaintBackground(PaintEventArgs 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; e.Graphics.DrawImage(Image, 0, 0);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;When we&amp;#39;ll put it onto anything, that has no background color, we&amp;#39;ll see that our &amp;quot;fake transparency&amp;quot; disappears. Why this happen? To provide transparency Windows uses color masks, also while confederating facts, clipping algorithm within GDI is not very trustful, thus the only thing can be taken into account is color. But what to do if we have an image? We should clip it manually. We cannot just get the handle to parent device surface (see above about trustful GDI), so the only way to do it is by providing something, that we know for sure. For example interface, telling us, that parent has image, which drawn on the screen.&lt;/p&gt; &lt;blockquote&gt; &lt;p&gt;internal interface IHaveImage {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Bitmap Image { get; set; }&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;When we know it, all we have to do is to clip the region of this image (not device context) and draw it as part of our really transparent control.&lt;/p&gt; &lt;blockquote&gt; &lt;p&gt;if (this.Parent is IHaveImage) {&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; var par = this.Parent as IHaveImage;&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; gxOff.DrawImage(par.Image.Clip(this.Bounds), 0, 0);&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;/p&gt;&lt;/blockquote&gt; &lt;p&gt;The implementation of Image.Clip is very straight forward.&lt;/p&gt; &lt;blockquote&gt; &lt;p&gt;public static Bitmap GetSS(this Graphics grx, Rectangle bounds) {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; var res = new Bitmap(bounds.Width, bounds.Height);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; var gxc = Graphics.FromImage(res);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; IntPtr hdc = grx.GetHdc();&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; PlatformAPI.BitBlt(gxc.GetHdc(), 0, 0, bounds.Width, bounds.Height, hdc, bounds.Left, bounds.Top, PlatformAPI.SRCCOPY);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; grx.ReleaseHdc(hdc);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; return res;&lt;br /&gt;}  &lt;p&gt;public static Bitmap Clip(this Bitmap source, Rectangle bounds) {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; var grx = Graphics.FromImage(source);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; return grx.GetSS(bounds);&lt;br /&gt;}&lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;We done. Compiling all together will fake transparency for controls, even when it&amp;#39;s parents background is not pained with&amp;nbsp; solid color brush.&lt;/p&gt; &lt;p&gt;&lt;a href="http://cid-4e39ecd492e4eec1.skydrive.live.com/self.aspx/Public/TransButton.zip"&gt;Source code for this article&lt;/a&gt;&lt;/p&gt; &lt;p&gt;P.S. Do not even try to inherit your custom Button control from framework Button class, dev team &amp;quot;forgot&amp;quot; to expose it&amp;#39;s event for override. So, OnPaint, OnPaintBackground, OnKeyUp, OnKeydown, OnMouseUp and OnMouseDown aside with most of other base events will not work for you, also BaseButton class has no default constructor, so the only class you can inherit from is Control.&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=172845" 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/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/DEV/default.aspx">DEV</category><category domain="http://blogs.microsoft.co.il/blogs/tamir/archive/tags/Interop/default.aspx">Interop</category></item></channel></rss>