<?xml version="1.0" encoding="UTF-8" ?>
<?xml-stylesheet type="text/xsl" href="http://blogs.msdn.com/utility/FeedStylesheets/rss.xsl" media="screen"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:wfw="http://wellformedweb.org/CommentAPI/"><channel><title>Mobile Development</title><link>http://blogs.msdn.com/raffael/default.aspx</link><description>"Support Side Story"</description><dc:language>en-US</dc:language><generator>CommunityServer 2.1 SP1 (Build: 61025.2)</generator><item><title>Microsoft released a HotFix for NETCF v3.5 on Windows Mobile 6.1.4 onwards, to address basic functionalities of WebBrowser control</title><link>http://blogs.msdn.com/raffael/archive/2009/09/29/microsoft-released-a-hotfix-for-netcf-v3-5-on-windows-mobile-6-1-4-onwards-to-address-basic-functionalities-of-webbrowser-control.aspx</link><pubDate>Tue, 29 Sep 2009 16:52:01 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9900786</guid><dc:creator>Raffaele Limosani</dc:creator><slash:comments>0</slash:comments><comments>http://blogs.msdn.com/raffael/comments/9900786.aspx</comments><wfw:commentRss>http://blogs.msdn.com/raffael/commentrss.aspx?PostID=9900786</wfw:commentRss><description>&lt;ul&gt;   &lt;li&gt;&lt;em&gt;Yet another demonstration of the added value provided by the Technical Support&lt;/em&gt; &lt;/li&gt;    &lt;li&gt;&lt;em&gt;A very impressive example of collaboration between Technical Support and Dev Team&lt;/em&gt; &lt;/li&gt;    &lt;li&gt;&lt;em&gt;FIX is public now&lt;/em&gt; &lt;em&gt;(&lt;a href="http://support.microsoft.com/kb/975281" target="_blank"&gt;link to KB Article&lt;/a&gt;)&lt;/em&gt; &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;A few weeks ago I’ve started handling a Service Request coming from a ISV whose NETCF v3.5 Application relied on the WebBrowser control to display a HTML FORM with some links on it… Imagine simply the following form’s code:&lt;/p&gt;  &lt;blockquote&gt;   &lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; m_Html = 
&lt;span class="str"&gt;&amp;quot;&amp;lt;html&amp;gt;&amp;lt;body&amp;gt;&amp;quot;&lt;/span&gt; +
&lt;span class="str"&gt;&amp;quot;&amp;lt;a href=\&amp;quot;http://www.msn.com\&amp;quot;&amp;gt;MSN&amp;lt;/a&amp;gt;&amp;lt;BR&amp;gt;&amp;quot;&lt;/span&gt; +
&lt;span class="str"&gt;&amp;quot;&amp;lt;a href=\&amp;quot;http://www.msn.com\&amp;quot;&amp;gt;MSN&amp;lt;/a&amp;gt;&amp;lt;BR&amp;gt;&amp;quot;&lt;/span&gt; +
&lt;span class="str"&gt;&amp;quot;&amp;lt;a href=\&amp;quot;http://www.msn.com\&amp;quot;&amp;gt;MSN    &amp;lt;/a&amp;gt;&amp;lt;a href=\&amp;quot;http://www.msn.com\&amp;quot;&amp;gt;MSN    &amp;lt;/a&amp;gt;&amp;lt;BR&amp;gt;&amp;quot;&lt;/span&gt; +
&lt;span class="str"&gt;&amp;quot;&amp;lt;a href=\&amp;quot;http://www.msn.com\&amp;quot;&amp;gt;MSN    &amp;lt;/a&amp;gt;&amp;lt;a href=\&amp;quot;http://www.msn.com\&amp;quot;&amp;gt;MSN    &amp;lt;/a&amp;gt;&amp;lt;a href=\&amp;quot;http://www.msn.com\&amp;quot;&amp;gt;MSN&amp;lt;/a&amp;gt;&amp;lt;BR&amp;gt;&amp;quot;&lt;/span&gt; +
&lt;span class="str"&gt;&amp;quot;&amp;lt;a href=\&amp;quot;http://www.msn.com\&amp;quot;&amp;gt;MSN&amp;lt;/a&amp;gt;&amp;lt;BR&amp;gt;&amp;quot;&lt;/span&gt; +
&lt;span class="str"&gt;&amp;quot;&amp;lt;/body&amp;gt;&amp;lt;/html&amp;gt;&amp;quot;&lt;/span&gt;;

&lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; menuItem2_Click(&lt;span class="kwrd"&gt;object&lt;/span&gt; sender, EventArgs e)
{
       &lt;span class="kwrd"&gt;this&lt;/span&gt;.webBrowser1.DocumentText = m_Html;
}&lt;/pre&gt;
&lt;/blockquote&gt;
&lt;style type="text/css"&gt;








.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }&lt;/style&gt;

&lt;p&gt;Problem is that, after the HTML is loaded, when using navigation “buttons” (up\down\left\right):&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;On WM6 I can navigate through the links: this is the expected behavior… and when pressing the action button the control navigates to the href link. &lt;/li&gt;

  &lt;li&gt;On WM6.1.4 &lt;strong&gt;the whole page is moved instead&lt;/strong&gt;; and &lt;strong&gt;when tapping on a link, nothing happens &lt;/strong&gt;(the expected behavior was that the control navigates) apart from “giving focus” to the link: at this point even if you press the action button the control doesn’t navigate &lt;/li&gt;

  &lt;li&gt;On WM6.5 the behavior is similar to 6.1.4’s, and here even horizontal and vertical scrollbars don’t appear &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The problem is easily reproduced on the Emulators as well, thus demonstrating that the issue is not OEM-ish…&lt;/p&gt;

&lt;p&gt;I also found at least 2 other developers reporting the problem through &lt;strong&gt;Microsoft Connect&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href="http://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=474666"&gt;http://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=474666&lt;/a&gt; &lt;/li&gt;

  &lt;li&gt;&lt;a href="http://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=484076"&gt;http://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=484076&lt;/a&gt; &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Troubleshooting steps included verifying which native control is wrapped by the NETCF v3.5’s WebBrowser: I noticed that when using the NATIVE code &lt;strong&gt;Mike Francis &lt;/strong&gt;provided in &lt;a href="http://blogs.msdn.com/mikefrancis/archive/2009/07/21/windows-mobile-6-5-web-browser-control-enabling-selection-support.aspx" target="_blank"&gt;his blog post&lt;/a&gt; (code sample available &lt;a href="http://cid-e91b74403814953e.skydrive.live.com/self.aspx/BrowserWithGestures/BrowserWithGestures.zip" target="_blank"&gt;here&lt;/a&gt;), then I get the desired behavior on all the 3 Emulators. Mike’s code is based on the WM6’s SDK Sample named “Browse” (\Samples\CPP\Win32\Browse\browse) and explains how to add gesture- and selection-support to a native application hosting the NATIVE web-browser control.&lt;/p&gt;

&lt;p&gt;So, the problem was just with the NETCF v3.5’s WebBrowser here! And interestingly &lt;u&gt;&lt;strong&gt;it’ NOT reproduced with NETCF v2 SP2 that ships in-ROM on WM6.x&lt;/strong&gt;&lt;/u&gt;. So… what are the loaded DLLs (i.e. what is the native control wrapped by the NETCF v3.5’s WebBrowser)? And which Windows? [I was intereseted on Windows’ ClassNames due to a possible technique to customize the WebBrowser’s context-menu, which I discussed &lt;a href="http://blogs.msdn.com/raffael/archive/2009/01/08/disable-webbrowser-s-context-menu-in-netcf-applications.aspx" target="_blank"&gt;here&lt;/a&gt;]&lt;/p&gt;

&lt;table border="1" cellspacing="1" cellpadding="2" width="400"&gt;&lt;tbody&gt;
    &lt;tr&gt;
      &lt;td valign="top" width="124"&gt;&lt;em&gt;using 
          &lt;br /&gt;NETCF v3.5 WebBrowser&lt;/em&gt;&lt;/td&gt;

      &lt;td valign="top" width="100"&gt;
        &lt;p align="center"&gt;WM6&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top" width="100"&gt;
        &lt;p align="center"&gt;WM6.1.4&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top" width="100"&gt;
        &lt;p align="center"&gt;WM6.5&lt;/p&gt;
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td valign="top" width="124"&gt;WND ClassName&lt;/td&gt;

      &lt;td valign="top" width="76"&gt;PIEHTML&lt;/td&gt;

      &lt;td valign="top" width="100"&gt;Internet Explorer_Server&lt;/td&gt;

      &lt;td valign="top" width="100"&gt;Internet Explorer_server&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td valign="top" width="124"&gt;Loaded DLL&lt;/td&gt;

      &lt;td valign="top" width="76"&gt;webview&lt;/td&gt;

      &lt;td valign="top" width="100"&gt;shdocvw&lt;/td&gt;

      &lt;td valign="top" width="100"&gt;shdocvw&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;&lt;/table&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;table border="1" cellspacing="1" cellpadding="2" width="400"&gt;&lt;tbody&gt;
    &lt;tr&gt;
      &lt;td valign="top" width="124"&gt;&lt;em&gt;using 
          &lt;br /&gt;Native Control (Mike’s code)&lt;/em&gt;&lt;/td&gt;

      &lt;td valign="top" width="100"&gt;
        &lt;p align="center"&gt;WM6&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top" width="100"&gt;
        &lt;p align="center"&gt;WM6.1.4&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top" width="100"&gt;
        &lt;p align="center"&gt;WM6.5&lt;/p&gt;
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td valign="top" width="124"&gt;WND ClassName&lt;/td&gt;

      &lt;td valign="top" width="76"&gt;PIEHTML&lt;/td&gt;

      &lt;td valign="top" width="100"&gt;PIEHTML&lt;/td&gt;

      &lt;td valign="top" width="100"&gt;PIEHTML&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td valign="top" width="124"&gt;Loaded DLL&lt;/td&gt;

      &lt;td valign="top" width="76"&gt;webview + htmlview&lt;/td&gt;

      &lt;td valign="top" width="100"&gt;webview + htmlview&lt;/td&gt;

      &lt;td valign="top" width="100"&gt;webview + htmlview&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;&lt;/table&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;p&gt;To recap: the issues are due to the NETCF v3.5’s WebBrowser control loading the new native IE6on6 (&lt;b&gt;&lt;font color="#ff0000"&gt;shdocvw.dll&lt;/font&gt;&lt;/b&gt;) instead of relying on the native webview.dll + htmlview.dll, and this makes impossible for the user to (a) click a href link and (b) to navigate through them by using the up\down\left\right pad. Also, (c) on 6.5 the scrollbars are not created. When loading the same HTML by the same NETCF application on a WM6, the behavior is as expected. There’s &lt;u&gt;NO problem&lt;/u&gt; on WM6.1.4 and 6.5 when using the native control directly (&lt;font color="#ff0000"&gt;&lt;strong&gt;htmlview.dll&lt;/strong&gt; &lt;font color="#000000"&gt;and&lt;/font&gt; &lt;strong&gt;webview.dll&lt;/strong&gt;&lt;/font&gt;), for example through the WM6 SDK Sample \Samples\CPP\Win32\Browse\browse.&lt;/p&gt;

&lt;p&gt;What happened at this point? As I mentioned other times (for example &lt;a href="http://blogs.msdn.com/raffael/archive/2009/05/18/yet-another-technical-support-s-added-value-engagement-of-dev-teams.aspx" target="_blank"&gt;here&lt;/a&gt;), one of the added values provided by &lt;strong&gt;Technical Support&lt;/strong&gt; is that we have a channel to the &lt;strong&gt;Dev Teams&lt;/strong&gt; which we can use to &lt;strong&gt;advocate final users’ needs&lt;/strong&gt;. You can imagine how many customers the Technical Support reaches every single day: we’re basically one of the ears of the Product Groups. And also this time I received an impressive collaboration from&amp;#160; the NETCF Dev Team, which firstly accepted to package the FIX, and then did it in a very few days: this is not the usual way it works, so if you’ll ever request a fix then don’t expect this in general. As you can imagine this depends on the code that needs to be modified, in terms of both the complexity and the possible regression risks that a modification introduces, compared to the risks of application usability and other factors if the fix is not provided. For example, many times developers and users can accept a “workaround” while waiting for next version of the product or the possible next Service Pack – I’ve discussed about an example of this &lt;a href="http://blogs.msdn.com/raffael/archive/2009/07/27/sip-button-icon-disappears-after-closing-dialogs-in-netcf-v2-applications.aspx" target="_blank"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;To conclude: &lt;strong&gt;a FIX is ready to be asked to the Technical Support&lt;/strong&gt;. KB Article is:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;a href=" http://support.microsoft.com/kb/975281" target="_blank"&gt;&lt;strong&gt;FIX: You cannot scroll through a Web page or browse to a link by using a .NET Compact Framework 3.5-based application that hosts a WebBrowser control in Windows Mobile 6.1.4 and 6.5&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;For the time being it’s a separate hotfix, maybe the Dev team will consider packaging it within a Service Pack – this is not yet decided. This is another demonstration of a kind of historical change, as this is just the second separate hotfix provided for NETCF on Windows Mobile-based OSs. First one was release few months ago and I blogged about it &lt;a href="http://blogs.msdn.com/raffael/archive/2009/05/20/microsoft-released-a-hotfix-for-netcf-v3-5-on-windows-mobile-now-you-can-use-web-services-over-ssl-without-worrying-about-empty-packets.aspx" target="_blank"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;A question may arise: can ISVs distribute the FIX? I mean, imagine I’m an ISV and developed a NETCF v3.5 app based on the WebBrowser control: if I want to make my app usable on WM6.1.4 and 6.5 devices of my clients, do I need to ask each of them to open a Service Request to Microsoft asking for the hotfix? The answer is: &lt;strong&gt;ISVs can distribute also the “patched” NETCF’s CAB&lt;/strong&gt;. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;font color="#ff0000"&gt;WARNING&lt;/font&gt;&lt;/strong&gt;! Remember that analogously to every other hotfix you can ask to Technical Support about whatever Microsoft’s product, you should install it only if you're sure it’s for the problem you're being affected by. This is because a hotfix is meant to address a specific issue and has been tested precisely for that: it didn't go through the whole regression testing that it's usually done when packaging many hotfixes into a Service Pack. In this precise case, &lt;u&gt;you don’t have to install this hotfix if your NETCF v3.5 applications doesn’t use the WebBrowser control&lt;/u&gt;.&lt;/p&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;p&gt;Cheers, 
  &lt;br /&gt;~raffaele&lt;/p&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9900786" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/raffael/archive/tags/.NET+Compact+Framework/default.aspx">.NET Compact Framework</category><category domain="http://blogs.msdn.com/raffael/archive/tags/Windows+Mobile/default.aspx">Windows Mobile</category><category domain="http://blogs.msdn.com/raffael/archive/tags/Technical+Support/default.aspx">Technical Support</category><category domain="http://blogs.msdn.com/raffael/archive/tags/HotFix/default.aspx">HotFix</category><category domain="http://blogs.msdn.com/raffael/archive/tags/IE6on6/default.aspx">IE6on6</category><category domain="http://blogs.msdn.com/raffael/archive/tags/WebBrowser/default.aspx">WebBrowser</category></item><item><title>GPS.NET 3.0: thanks Jon!!</title><link>http://blogs.msdn.com/raffael/archive/2009/09/14/gps-net-3-0-thanks-jon.aspx</link><pubDate>Mon, 14 Sep 2009 17:55:42 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9894980</guid><dc:creator>Raffaele Limosani</dc:creator><slash:comments>0</slash:comments><comments>http://blogs.msdn.com/raffael/comments/9894980.aspx</comments><wfw:commentRss>http://blogs.msdn.com/raffael/commentrss.aspx?PostID=9894980</wfw:commentRss><description>&lt;p&gt;Unfortunately I had to put GPS-Programming in stand-by mode… &lt;img alt="Sad" src="http://messenger.msn.com/MMM2006-04-19_17.00/Resource/emoticons/sad_smile.gif" /&gt; but finally some days ago I was reading one of the &lt;a href="http://blogs.msdn.com/raffael/archive/tags/GPS/default.aspx"&gt;posts I wrote about GPS&lt;/a&gt; roughly one year ago, and tried to navigate to a company’s webpage I remembered containing a lot of interesting info and controls about GPS, i.e. &lt;b&gt;GeoFrameworks&lt;/b&gt;: well, I realized that &lt;a href="http://www.geoframeworks.com/Closed.aspx"&gt;GeoFrameworks is now closed&lt;/a&gt;! Luckily their &lt;a href="http://www.geoframeworks.com/Articles/WritingApps1_1.aspx"&gt;Mastering GPS Programming&lt;/a&gt; is still available, but, much better… the founder of GeoFrameworks, &lt;a href="http://www.codeplex.com/site/users/view/jperson"&gt;Jon Person&lt;/a&gt;, “[…] &lt;em&gt;decided to release the full source code of GPS.NET to the public domain for the benefit of the open source development community&lt;/em&gt;”. If you’re interested on GPS-Programming, you must visit &lt;a href="http://gps3.codeplex.com"&gt;&lt;strong&gt;http://gps3.codeplex.com&lt;/strong&gt;&lt;/a&gt;! &lt;/p&gt;  &lt;p&gt;Cheers,   &lt;br /&gt;~raffaele&lt;/p&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9894980" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/raffael/archive/tags/.NET+Compact+Framework/default.aspx">.NET Compact Framework</category><category domain="http://blogs.msdn.com/raffael/archive/tags/GPS/default.aspx">GPS</category><category domain="http://blogs.msdn.com/raffael/archive/tags/Scatter+Thoughts/default.aspx">Scatter Thoughts</category><category domain="http://blogs.msdn.com/raffael/archive/tags/GPS.NET/default.aspx">GPS.NET</category></item><item><title>Remote Desktop Mobile (RDP Client) disconnects after 10 minutes of inactivity</title><link>http://blogs.msdn.com/raffael/archive/2009/09/11/remote-desktop-mobile-rdp-client-disconnects-after-10-minutes-of-inactivity.aspx</link><pubDate>Fri, 11 Sep 2009 18:03:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9894219</guid><dc:creator>Raffaele Limosani</dc:creator><slash:comments>0</slash:comments><comments>http://blogs.msdn.com/raffael/comments/9894219.aspx</comments><wfw:commentRss>http://blogs.msdn.com/raffael/commentrss.aspx?PostID=9894219</wfw:commentRss><description>&lt;P&gt;&lt;EM&gt;[&lt;STRONG&gt;UPDATE 10/9/2009: Source-Code and CAB are now available at &lt;/STRONG&gt;&lt;A href="http://mobilerdpnotimeout.codeplex.com/"&gt;&lt;STRONG&gt;http://mobilerdpnotimeout.codeplex.com/&lt;/STRONG&gt;&lt;/A&gt;]&amp;nbsp;&lt;/EM&gt;&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;&lt;EM&gt;Error Message: “&lt;FONT color=#ff0000&gt;The remote session was ended because the idle timeout limit was reached. This limit is set by the server administrator or by network policy&lt;/FONT&gt;.”&lt;/EM&gt; 
&lt;LI&gt;&lt;EM&gt;RDP\TSC Clients and Windows Mobile OEMs&lt;/EM&gt; 
&lt;LI&gt;&lt;EM&gt;What’s new in Windows Mobile 6.5 about Remote Desktop Mobile&lt;/EM&gt; &lt;/LI&gt;&lt;/UL&gt;
&lt;P&gt;This issue should be somehow well known by the Community, but I couldn’t easily find a solution so I had to think one by myself… :-) After &lt;STRONG&gt;10 minutes of inactivity&lt;/STRONG&gt; of a Terminal Server session on Windows Mobile devices, the Remote Desktop Mobile application needs you to logon again stating that a timeout “&lt;EM&gt;&lt;FONT color=#ff0000&gt;set by the server administrator or by network policy&lt;/FONT&gt;&lt;/EM&gt;” occurred. Unfortunately it’s not really a good error message, since many times the server is correctly set and the problem is just client-side... Anyway, probably it was not very frustrating since in the most of the cases one is logged via RDP only to actively work on the server. But this is not always true, so I’d guess either I wasn’t able to find someone with a possible solution, either simply people accepted to live with it…&lt;/P&gt;
&lt;P&gt;Remote Desktop Mobile on WM6.x (and, before this, the TSC client on WM5) is a component that OEMs are not required to include to have their OSs pass the Windows Mobile Logo Test Kit, and this is basically why you may find devices with it in-ROM and others where you need to find alternative solutions. In any case, regarding the inactivity timeout issue, luckily &lt;STRONG&gt;Windows Mobile 6.5 _&lt;EM&gt;should&lt;/EM&gt;_ now have an updated version of the Remote Desktop Mobile application that OEMs can include in their images&lt;/STRONG&gt;, easier to use on the field as it allows, for example, to finally customize an idle timeout!! Unfortunately it’s not included in the emulators coming with the &lt;A href="http://www.microsoft.com/downloads/details.aspx?displaylang=en&amp;amp;FamilyID=20686a1d-97a8-4f80-bc6a-ae010e085a6e" target=_blank mce_href="http://www.microsoft.com/downloads/details.aspx?displaylang=en&amp;amp;FamilyID=20686a1d-97a8-4f80-bc6a-ae010e085a6e"&gt;Windows Mobile 6.5 Developer Tool Kit&lt;/A&gt;. &lt;/P&gt;
&lt;P&gt;Back to the problem… after some researches I understood that&lt;STRONG&gt; &lt;EM&gt;the timer is reset only when the Remote Desktop Mobile’s application window receives mouse or keyboard input&lt;/EM&gt;&lt;/STRONG&gt;. Refreshing the window, or sending exotic WM_xx messages wasn’t enough. So, I came to thinking what was a possible keypress or mouseevent that can be programmatically simulated (through keybd_event() or mouse_event()) that wouldn’t impact application at all?? After some tests I’ve realized that &lt;STRONG&gt;MOUSEEVENTF_MOVE&lt;/STRONG&gt;, which is the event of user “moving the mouse”, has no effect on current Windows Mobile-based devices: that event is maintained as codebase with Windows CE, where an OEM may also include a non-touch screen where you really have a mouse to move... but its only effect on Windows Mobile device is for example to modify display’s brightness, in case the display entered a sort of power-safe state (well, obviously the mouse-pointer is moved on the remote server)&lt;/P&gt;
&lt;P&gt;So, the idea was to develop a Win32 Console application that simply launches the Remote Desktop Mobile application and every X minutes (5? 9?) simulates a mouse-movement of some pixels and after a short time another one to place the mouse on the previous position.&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;This is NOT elegant code at all, absolutely, but it does what was meant to run a specific task… &lt;IMG alt=Nerd src="http://messenger.msn.com/MMM2006-04-19_17.00/Resource/emoticons/49_49.gif" mce_src="http://messenger.msn.com/MMM2006-04-19_17.00/Resource/emoticons/49_49.gif"&gt;&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;Obviously this watch-dog application would “waste” one of the 30 process slots… is it acceptable? As you can see the application doesn’t do anything special or unsupported: it’s simply a monitor-console application with no particularly elegant code. As usual, I would strongly encourage on adding some error-checking!!&lt;/P&gt;
&lt;BLOCKQUOTE&gt;&lt;PRE class=csharpcode&gt;&lt;FONT color=#008000&gt;&lt;/FONT&gt;
&lt;SPAN class=kwrd&gt;int&lt;/SPAN&gt; _tmain(&lt;SPAN class=kwrd&gt;int&lt;/SPAN&gt; argc, _TCHAR* argv[])
{
    &lt;SPAN class=kwrd&gt;int&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;const&lt;/SPAN&gt; FIVEMINUTES = 1000*60*5;
    HWND hWndRDM = NULL;
    
    &lt;SPAN class=rem&gt;//Firstly launch RDP Client&lt;/SPAN&gt;
    SHELLEXECUTEINFO sei = {0};
    sei.cbSize = &lt;SPAN class=kwrd&gt;sizeof&lt;/SPAN&gt;(sei);
    sei.nShow = SW_SHOWNORMAL; 
    sei.lpFile = TEXT(&lt;SPAN class=str&gt;"\\Windows\\wpctsc.exe"&lt;/SPAN&gt;);
    sei.lpParameters = TEXT(&lt;SPAN class=str&gt;" "&lt;/SPAN&gt;);
    &lt;SPAN class=kwrd&gt;if&lt;/SPAN&gt; (!ShellExecuteEx(&amp;amp;sei))
    {
        MessageBox(NULL, TEXT(&lt;SPAN class=str&gt;"Couldn't launch RDP Client"&lt;/SPAN&gt;), TEXT(&lt;SPAN class=str&gt;"Remote Desktop Launcher"&lt;/SPAN&gt;), MB_OK);
        &lt;SPAN class=kwrd&gt;goto&lt;/SPAN&gt; Exit;
    }


    &lt;SPAN class=rem&gt;//Now every X minutes check if it's still running and if so "refresh" its window&lt;/SPAN&gt;
    &lt;SPAN class=rem&gt;//if it's no longer running, exit&lt;/SPAN&gt;
    &lt;SPAN class=kwrd&gt;do&lt;/SPAN&gt; 
    {
        &lt;SPAN class=rem&gt;//check if RDP Client is running, otherwise exit&lt;/SPAN&gt;
        hWndRDM = FindWindow(_T(&lt;SPAN class=str&gt;"TSSHELLWND"&lt;/SPAN&gt;), NULL);
        &lt;SPAN class=kwrd&gt;if&lt;/SPAN&gt; (NULL != hWndRDM)
        {
            &lt;SPAN class=rem&gt;////Get foreground window -- this is not needed if RDM is launched Full-Screen as it was in this case&lt;/SPAN&gt;
            &lt;SPAN class=rem&gt;//hWndForeground = GetForegroundWindow();&lt;/SPAN&gt;
            &lt;SPAN class=rem&gt;//Sleep(500);&lt;/SPAN&gt;

            &lt;SPAN class=rem&gt;//Give focus to the RDP Client window (even if the logon screen, in case user logged out in the meantime)&lt;/SPAN&gt;
            SetForegroundWindow(hWndRDM);

            &lt;SPAN class=rem&gt;//The timer is reset when the rdp window receives mouse or keyboard input&lt;/SPAN&gt;
            &lt;SPAN class=rem&gt;//with no MOUSEEVENTF_ABSOLUTE the move is relative&lt;/SPAN&gt;

            mouse_event(MOUSEEVENTF_MOVE, 100, 0, 0, 0);
            Sleep(250);
            mouse_event(MOUSEEVENTF_MOVE, -100, 0, 0, 0);

            &lt;SPAN class=rem&gt;////Give focus back to previous foreground window&lt;/SPAN&gt;
            &lt;SPAN class=rem&gt;//SetForegroundWindow(hWndForeground);&lt;/SPAN&gt;

            &lt;SPAN class=rem&gt;//Sleep &lt;/SPAN&gt;
            Sleep(FIVEMINUTES);
        }
        &lt;SPAN class=kwrd&gt;else&lt;/SPAN&gt; 
        {
            &lt;SPAN class=rem&gt;//RDP Client is not running - let's exit&lt;/SPAN&gt;
            &lt;SPAN class=kwrd&gt;goto&lt;/SPAN&gt; Exit;
        }
    }
    &lt;SPAN class=kwrd&gt;while&lt;/SPAN&gt; (TRUE); &lt;SPAN class=rem&gt;//The check (NULL != hWndRDM) is already done inside the loop&lt;/SPAN&gt;


Exit:
    &lt;SPAN class=kwrd&gt;if&lt;/SPAN&gt; (NULL != hWndRDM)
        CloseHandle(hWndRDM);
    
    &lt;SPAN class=kwrd&gt;return&lt;/SPAN&gt; 0;
}&lt;/PRE&gt;&lt;PRE class=csharpcode&gt;&amp;nbsp;&lt;/PRE&gt;&lt;/BLOCKQUOTE&gt;
&lt;STYLE type=text/css&gt;



.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }&lt;/STYLE&gt;

&lt;P&gt;I can imagine that this problem affects more the WinMo Users rather than the WinMo “Devs”, therefore I had in mind to distribute directly the CAB of the application, if anyone else doesn’t want to do it for the Community. I’m wondering if CodePlex would be a good place, I’ll see and update this post. In any case, remember that it’s up to the OEMs to decide if including RDM (\Windows\wpctsc.exe) in their OSs based on Windows Mobile platform!&lt;/P&gt;
&lt;P&gt;Cheers! &lt;BR&gt;~raffaele &lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9894219" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/raffael/archive/tags/Windows+Mobile/default.aspx">Windows Mobile</category><category domain="http://blogs.msdn.com/raffael/archive/tags/Utilities/default.aspx">Utilities</category><category domain="http://blogs.msdn.com/raffael/archive/tags/Remote+Desktop+Mobile/default.aspx">Remote Desktop Mobile</category></item><item><title>New opening: Italian Dev Support blog</title><link>http://blogs.msdn.com/raffael/archive/2009/09/11/new-opening-italian-dev-support-blog.aspx</link><pubDate>Fri, 11 Sep 2009 16:03:19 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9894166</guid><dc:creator>Raffaele Limosani</dc:creator><slash:comments>0</slash:comments><comments>http://blogs.msdn.com/raffael/comments/9894166.aspx</comments><wfw:commentRss>http://blogs.msdn.com/raffael/commentrss.aspx?PostID=9894166</wfw:commentRss><description>&lt;p&gt;Yesterday my Italian colleagues in Developer Support and I officially inaugurated our new team blog: if you can read Italian then join us at &lt;a href="http://blogs.msdn.com/itasupport"&gt;http://blogs.msdn.com/itasupport&lt;/a&gt;. &lt;img alt="Hot" src="http://messenger.msn.com/MMM2006-04-19_17.00/Resource/emoticons/shades_smile.gif" /&gt;&lt;/p&gt;  &lt;p&gt;CIAO!    &lt;br /&gt;~raffaele&lt;/p&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9894166" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/raffael/archive/tags/Miscellanea/default.aspx">Miscellanea</category><category domain="http://blogs.msdn.com/raffael/archive/tags/Technical+Support/default.aspx">Technical Support</category><category domain="http://blogs.msdn.com/raffael/archive/tags/Scatter+Thoughts/default.aspx">Scatter Thoughts</category><category domain="http://blogs.msdn.com/raffael/archive/tags/Italian/default.aspx">Italian</category></item><item><title>SIP Button Icon disappears after closing dialogs in NETCF v2 applications</title><link>http://blogs.msdn.com/raffael/archive/2009/07/27/sip-button-icon-disappears-after-closing-dialogs-in-netcf-v2-applications.aspx</link><pubDate>Mon, 27 Jul 2009 14:39:29 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9849910</guid><dc:creator>Raffaele Limosani</dc:creator><slash:comments>0</slash:comments><comments>http://blogs.msdn.com/raffael/comments/9849910.aspx</comments><wfw:commentRss>http://blogs.msdn.com/raffael/commentrss.aspx?PostID=9849910</wfw:commentRss><description>&lt;p&gt;I thought this was something well known by the Mobile Dev Community, but maybe this is not true, since I’ve recently worked on a similar case.. so it may be worth sharing it here! &lt;/p&gt;  &lt;p&gt;Under some special circumstances, which weren’t possible to reproduce for Technical Support and NETCF Dev Team at that time (about 2-3 years ago) – also because it was resolved in NETCF v3.5 – it happened that on NETCF v2 applications when a form gains back the focus after it was given to a dialog (&lt;em&gt;MessageBox.Show()&lt;/em&gt; or &lt;em&gt;anotherForm.ShowDialog()&lt;/em&gt;), then _&lt;em&gt;sometimes&lt;/em&gt;_ that little squared SIP icon at the middle of the menubar at the bottom suddenly disappeared. &lt;/p&gt;  &lt;p&gt;That nasty problem was due to some faulty interaction between the OS and the .NET runtime, in any case no longer reproduced with v3.5. In some cases it had sufficed to reset this.Menu (or this.Parent.Menu) to the main menu. But that wasn’t the case in our service request… and also the simple refresh of the form at form’s OnActivated was NOT enough:&lt;/p&gt;  &lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;protected&lt;/span&gt; &lt;span class="kwrd"&gt;override&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; OnActivated(EventArgs e)
{
     &lt;span class="kwrd"&gt;this&lt;/span&gt;.Menu = mainMnu;
     &lt;span class="kwrd"&gt;this&lt;/span&gt;.Refresh();

     &lt;span class="kwrd"&gt;base&lt;/span&gt;.OnActivated(e);
}&lt;/pre&gt;
&lt;style type="text/css"&gt;


.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }&lt;/style&gt;

&lt;p&gt;So we had to find a satisfactory temporary solution for NETCF v2 applications (migration to v3.5 was already in progress..). As usual I proposed to play with WINDOWS… :-) and we came up with the following propositions – the first one did the trick! (remember to add error-handling to whatever code I may suggest!!)&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;&lt;b&gt;FindWindow + ShowWindow&lt;/b&gt; 

    &lt;ol&gt;
      &lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;protected&lt;/span&gt; &lt;span class="kwrd"&gt;override&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; OnActivated(EventArgs e)
{
    IntPtr hSip = FindWindow(&lt;span class="str"&gt;&amp;quot;MS_SIPBUTTON&amp;quot;&lt;/span&gt;, &lt;span class="str"&gt;&amp;quot;MS_SIPBUTTON&amp;quot;&lt;/span&gt;);
    &lt;span class="kwrd"&gt;if&lt;/span&gt; ((hSip != IntPtr.Zero) &lt;span class="rem"&gt;/*&amp;amp;&amp;amp; (!IsWindowVisible(hSip))) */&lt;/span&gt;
    {
        &lt;span class="kwrd"&gt;bool&lt;/span&gt; retShowWin = ShowWindow(hSip, EShowWindow.SW_SHOW);
    }
    &lt;span class="kwrd"&gt;base&lt;/span&gt;.OnActivated(e);
}


[DllImport(&lt;span class="str"&gt;&amp;quot;coredll.dll&amp;quot;&lt;/span&gt;, SetLastError = &lt;span class="kwrd"&gt;true&lt;/span&gt;)]
&lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;extern&lt;/span&gt; IntPtr FindWindow(&lt;span class="kwrd"&gt;string&lt;/span&gt; _ClassName, &lt;span class="kwrd"&gt;string&lt;/span&gt; _WindowName);

[DllImport(&lt;span class="str"&gt;&amp;quot;coredll.dll&amp;quot;&lt;/span&gt;, SetLastError = &lt;span class="kwrd"&gt;true&lt;/span&gt;)]
&lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;extern&lt;/span&gt; &lt;span class="kwrd"&gt;bool&lt;/span&gt; IsWindowVisible(IntPtr hWnd);

[DllImport(&lt;span class="str"&gt;&amp;quot;coredll.dll&amp;quot;&lt;/span&gt;, SetLastError = &lt;span class="kwrd"&gt;true&lt;/span&gt;)]
&lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;extern&lt;/span&gt; &lt;span class="kwrd"&gt;bool&lt;/span&gt; ShowWindow(IntPtr hwnd, EShowWindow nCmdShow);

&lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;enum&lt;/span&gt; EShowWindow : &lt;span class="kwrd"&gt;uint&lt;/span&gt;
{ 
    SW_HIDE = 0,
    SW_SHOWNORMAL = 1,
    &lt;span class="rem"&gt;//SW_SHOWNOACTIVATE = 4,&lt;/span&gt;
    SW_SHOW           = 5 ,
    &lt;span class="rem"&gt;//SW_MINIMIZE       = 6,&lt;/span&gt;
    SW_SHOWNA         = 8 &lt;span class="rem"&gt;//,&lt;/span&gt;
    &lt;span class="rem"&gt;//SW_SHOWMAXIMIZED  = 11,&lt;/span&gt;
    &lt;span class="rem"&gt;//SW_MAXIMIZE           = 12,&lt;/span&gt;
    &lt;span class="rem"&gt;//SW_RESTORE            = 13&lt;/span&gt;
}&lt;/pre&gt;

      &lt;pre class="csharpcode"&gt;&amp;#160;&lt;/pre&gt;
      &lt;style type="text/css"&gt;

.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }&lt;/style&gt;&lt;/ol&gt;
  &lt;/li&gt;

  &lt;li&gt;&lt;b&gt;FindWindow + BringWindowToTop&lt;/b&gt; 

    &lt;ol&gt;
      &lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;protected&lt;/span&gt; &lt;span class="kwrd"&gt;override&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; OnActivated(EventArgs e)
{
    IntPtr hSip = FindWindow(&lt;span class="str"&gt;&amp;quot;MS_SIPBUTTON&amp;quot;&lt;/span&gt;, &lt;span class="str"&gt;&amp;quot;MS_SIPBUTTON&amp;quot;&lt;/span&gt;);
    &lt;span class="kwrd"&gt;if&lt;/span&gt; ((hSip != IntPtr.Zero) &lt;span class="rem"&gt;/*&amp;amp;&amp;amp; (!IsWindowVisible(hSip))) */&lt;/span&gt;
    {
        &lt;span class="kwrd"&gt;bool&lt;/span&gt; retBringWin = BringWindowToTop(hSip);
    }
    &lt;span class="kwrd"&gt;base&lt;/span&gt;.OnActivated(e);
}


[DllImport(&lt;span class="str"&gt;&amp;quot;coredll.dll&amp;quot;&lt;/span&gt;, SetLastError = &lt;span class="kwrd"&gt;true&lt;/span&gt;)]
&lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;extern&lt;/span&gt; IntPtr FindWindow(&lt;span class="kwrd"&gt;string&lt;/span&gt; _ClassName, &lt;span class="kwrd"&gt;string&lt;/span&gt; _WindowName);

[DllImport(&lt;span class="str"&gt;&amp;quot;coredll.dll&amp;quot;&lt;/span&gt;, SetLastError = &lt;span class="kwrd"&gt;true&lt;/span&gt;)]
&lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;extern&lt;/span&gt; &lt;span class="kwrd"&gt;bool&lt;/span&gt; IsWindowVisible(IntPtr hWnd);

[DllImport(&lt;span class="str"&gt;&amp;quot;coredll.dll&amp;quot;&lt;/span&gt;, SetLastError = &lt;span class="kwrd"&gt;true&lt;/span&gt;)]
&lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;extern&lt;/span&gt; &lt;span class="kwrd"&gt;bool&lt;/span&gt; BringWindowToTop(IntPtr hWnd);&lt;/pre&gt;

      &lt;pre class="csharpcode"&gt;&amp;#160;&lt;/pre&gt;
      &lt;style type="text/css"&gt;

.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }&lt;/style&gt;&lt;/ol&gt;
  &lt;/li&gt;

  &lt;li&gt;&lt;strong&gt;FindWindow + GetWindowLong&lt;/strong&gt; 

    &lt;ol&gt;
      &lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;protected&lt;/span&gt; &lt;span class="kwrd"&gt;override&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; OnActivated(EventArgs e)
{
    IntPtr hSip = FindWindow(&lt;span class="str"&gt;&amp;quot;MS_SIPBUTTON&amp;quot;&lt;/span&gt;, &lt;span class="str"&gt;&amp;quot;MS_SIPBUTTON&amp;quot;&lt;/span&gt;);
    &lt;span class="kwrd"&gt;if&lt;/span&gt; ((hSip != IntPtr.Zero) &lt;span class="rem"&gt;/*&amp;amp;&amp;amp; (!IsWindowVisible(hSip))) */&lt;/span&gt;
    { 
        &lt;span class="kwrd"&gt;int&lt;/span&gt; style = GetWindowLong(hSip, GWL_STYLE);
        style |= WS_POPUP | WS_VISIBLE;
        &lt;span class="kwrd"&gt;int&lt;/span&gt; retSetWin = SetWindowLong(hSip, GWL_STYLE, style);

        &lt;span class="kwrd"&gt;int&lt;/span&gt; exstyle = GetWindowLong(hSip, GWL_EXSTYLE);
        exstyle |= WS_EX_ABOVESTARTUP | WS_EX_NOACTIVATE | WS_EX_TOOLWINDOW | WS_EX_TOPMOST;
        retSetWin = SetWindowLong(hSip, GWL_EXSTYLE, exstyle);
    }
    &lt;span class="kwrd"&gt;base&lt;/span&gt;.OnActivated(e);
}


[DllImport(&lt;span class="str"&gt;&amp;quot;coredll.dll&amp;quot;&lt;/span&gt;, SetLastError = &lt;span class="kwrd"&gt;true&lt;/span&gt;)]
&lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;extern&lt;/span&gt; IntPtr FindWindow(&lt;span class="kwrd"&gt;string&lt;/span&gt; _ClassName, &lt;span class="kwrd"&gt;string&lt;/span&gt; _WindowName);

[DllImport(&lt;span class="str"&gt;&amp;quot;coredll.dll&amp;quot;&lt;/span&gt;, SetLastError = &lt;span class="kwrd"&gt;true&lt;/span&gt;)]
&lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;extern&lt;/span&gt; &lt;span class="kwrd"&gt;bool&lt;/span&gt; IsWindowVisible(IntPtr hWnd);

&lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;const&lt;/span&gt; &lt;span class="kwrd"&gt;int&lt;/span&gt; GWL_EXSTYLE = (-20);
&lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;const&lt;/span&gt; &lt;span class="kwrd"&gt;int&lt;/span&gt; GWL_STYLE = (-16);

[DllImport(&lt;span class="str"&gt;&amp;quot;coredll&amp;quot;&lt;/span&gt;, SetLastError = &lt;span class="kwrd"&gt;true&lt;/span&gt;)]
&lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;extern&lt;/span&gt; &lt;span class="kwrd"&gt;int&lt;/span&gt; GetWindowLong(IntPtr hWnd, &lt;span class="kwrd"&gt;int&lt;/span&gt; nIndex);

[DllImport(&lt;span class="str"&gt;&amp;quot;coredll&amp;quot;&lt;/span&gt;, SetLastError = &lt;span class="kwrd"&gt;true&lt;/span&gt;)]
&lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;extern&lt;/span&gt; &lt;span class="kwrd"&gt;int&lt;/span&gt; SetWindowLong(IntPtr hWnd, &lt;span class="kwrd"&gt;int&lt;/span&gt; nIndex, &lt;span class="kwrd"&gt;int&lt;/span&gt; dwNewLong);

&lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;const&lt;/span&gt; &lt;span class="kwrd"&gt;int&lt;/span&gt;
    WS_POPUP = &lt;span class="kwrd"&gt;unchecked&lt;/span&gt;((&lt;span class="kwrd"&gt;int&lt;/span&gt;)0x80000000),
    WS_VISIBLE = 0x10000000,
    WS_EX_ABOVESTARTUP = 0x20000000,
    WS_EX_NOACTIVATE = 0x08000000,
    WS_EX_TOOLWINDOW = 0x00000080,
    WS_EX_TOPMOST = 0x00000008;&lt;/pre&gt;
      &lt;style type="text/css"&gt;

.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }&lt;/style&gt;&lt;/ol&gt;
  &lt;/li&gt;
&lt;/ol&gt;
&lt;b&gt;
  &lt;p&gt;&lt;/p&gt;&amp;#160;&amp;#160; &lt;/b&gt;

&lt;p&gt;Cheers, 
  &lt;br /&gt;~raffaele&lt;/p&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9849910" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/raffael/archive/tags/.NET+Compact+Framework/default.aspx">.NET Compact Framework</category><category domain="http://blogs.msdn.com/raffael/archive/tags/Technical+Support/default.aspx">Technical Support</category><category domain="http://blogs.msdn.com/raffael/archive/tags/Win32/default.aspx">Win32</category><category domain="http://blogs.msdn.com/raffael/archive/tags/SIP/default.aspx">SIP</category><category domain="http://blogs.msdn.com/raffael/archive/tags/Windows+Forms/default.aspx">Windows Forms</category></item><item><title>Resolution-Aware CAB on Windows Mobile</title><link>http://blogs.msdn.com/raffael/archive/2009/06/17/resolution-aware-cab-on-windows-mobile.aspx</link><pubDate>Wed, 17 Jun 2009 15:46:47 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9769273</guid><dc:creator>Raffaele Limosani</dc:creator><slash:comments>0</slash:comments><comments>http://blogs.msdn.com/raffael/comments/9769273.aspx</comments><wfw:commentRss>http://blogs.msdn.com/raffael/commentrss.aspx?PostID=9769273</wfw:commentRss><description>&lt;ul&gt;   &lt;li&gt;GetSystemMetrics or GetDeviceCaps inside a CAB’s Setup.dll &lt;/li&gt;    &lt;li&gt;wceload.exe is not resolution- and DPI-aware &lt;/li&gt;    &lt;li&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/bb158675.aspx"&gt;RESDLL&lt;/a&gt; SDK Sample&amp;#160; &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;Sincerely I haven’t easily found entries about this over the web, so I think it’s worth mentioning it. Maybe many know, but possible many others don’t… &lt;img alt="smile_regular" src="http://spaces.live.com/rte/emoticons/smile_regular.gif" /&gt; Imagine you want to perform different actions during install depending on the device’s resolution. A possible code to retrieve resolution can use GetSystemMetrics or GetDeviceCaps. My troubleshooting, as initial step, was as usual to verify if I could reproduce ISV’s problem, even on Device Emulator (thus avoiding possible problems related to OEMs’ customizations). So I included the following in a CAB’s Setup.dll’s Install_Init (Install_Exit is the same):&lt;/p&gt;  &lt;pre class="csharpcode"&gt;        HRESULT hr = S_OK;

        LPTSTR pszBuf = &lt;span class="kwrd"&gt;new&lt;/span&gt; TCHAR[256];
        ZeroMemory(pszBuf, 255);

        &lt;span class="kwrd"&gt;int&lt;/span&gt; X = GetSystemMetrics(SM_CXSCREEN);
        &lt;span class="kwrd"&gt;int&lt;/span&gt; Y = GetSystemMetrics(SM_CYSCREEN);

        hr = StringCchPrintf(pszBuf, 
                        LocalSize(pszBuf) / &lt;span class="kwrd"&gt;sizeof&lt;/span&gt;(TCHAR),
                        TEXT(&lt;span class="str"&gt;&amp;quot;X: %d\r\nY: %d&amp;quot;&lt;/span&gt;), 
                        X, Y);
        CHR(hr);

        MessageBox(hwndParent, pszBuf, TEXT(&lt;span class="str"&gt;&amp;quot;Install_Exit&amp;quot;&lt;/span&gt;), MB_OK);

    Exit:
        &lt;span class="kwrd"&gt;return&lt;/span&gt; codeINSTALL_INIT_CONTINUE; &lt;span class="rem"&gt;//or codeINSTALL_EXIT_DONE for Install_Exit&lt;/span&gt;&lt;/pre&gt;
&lt;style type="text/css"&gt;



.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }&lt;/style&gt;

&lt;p&gt;Specifically:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;on a VGA WM6 Emulator (&lt;strong&gt;640x480&lt;/strong&gt;) it returned &lt;strong&gt;&lt;font color="#ff0000"&gt;320x240&lt;/font&gt;&lt;/strong&gt; &lt;/li&gt;

  &lt;li&gt;on a square VGA WM6 Emulator (&lt;strong&gt;480x480&lt;/strong&gt;) it returned &lt;strong&gt;&lt;font color="#ff0000"&gt;240x240&lt;/font&gt;&lt;/strong&gt; &lt;/li&gt;

  &lt;li&gt;on a square QVGA WM6 Emulator (&lt;strong&gt;320x320&lt;/strong&gt;) it returned &lt;strong&gt;&lt;font color="#ff0000"&gt;240x240&lt;/font&gt;&lt;/strong&gt; &lt;/li&gt;

  &lt;li&gt;on a WM6.1.4 EMULATOR (&lt;strong&gt;480x800&lt;/strong&gt;) it returned &lt;strong&gt;&lt;font color="#ff0000"&gt;240x400&lt;/font&gt;&lt;/strong&gt; &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When using precisely the same code in a Win32 Smart Device Console application, the values returned were the expected ones…&lt;/p&gt;

&lt;p&gt;After working with a colleague (&lt;font color="#ff0000"&gt;thanks Manfred!&lt;/font&gt; &lt;img alt="smile_regular" src="http://spaces.live.com/rte/emoticons/smile_regular.gif" /&gt;) I got the confirmation about an idea… the problem here is that a CAB’s Setup.dll gets loaded by wceload.exe when installing the CAB, and &lt;strong&gt;wceload.exe is not resolution- and DPI-aware &lt;/strong&gt;. Therefore when setup.dll’s code runs inside the wceload’s context it can’t successfully call GetSystemMetrics or also GetDeviceCaps. &lt;/p&gt;

&lt;p&gt;It turned out that to address this limitation, a sample is provided in the SDKs explaining how to do this: &amp;quot;C:\Program Files (x86)\Windows Mobile 6 SDK\Samples\PocketPC\CPP\win32\resdll&amp;quot; (MSDN Doc &lt;a href="http://msdn.microsoft.com/en-us/library/bb158675.aspx"&gt;&lt;strong&gt;here&lt;/strong&gt;&lt;/a&gt;). Notice that setup.dll’s Install_Exit\_Init containing code to run an external DPI-aware application, whose sample code is also provided.&lt;/p&gt;

&lt;p&gt;Cheers, 
  &lt;br /&gt;~raffaele&lt;/p&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9769273" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/raffael/archive/tags/Windows+Mobile/default.aspx">Windows Mobile</category><category domain="http://blogs.msdn.com/raffael/archive/tags/CAB/default.aspx">CAB</category></item><item><title>The right approach to get a Contact’s last communication (IItem’s PIMPR_SMARTPROP)</title><link>http://blogs.msdn.com/raffael/archive/2009/05/28/the-right-approach-to-get-a-contact-s-last-communication-iitem-s-pimpr-smartprop.aspx</link><pubDate>Thu, 28 May 2009 16:21:55 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9647145</guid><dc:creator>Raffaele Limosani</dc:creator><slash:comments>1</slash:comments><comments>http://blogs.msdn.com/raffael/comments/9647145.aspx</comments><wfw:commentRss>http://blogs.msdn.com/raffael/commentrss.aspx?PostID=9647145</wfw:commentRss><description>&lt;p&gt;I've discussed about the “wrong” approach in &lt;a href="http://blogs.msdn.com/raffael/archive/2009/05/04/the-wrong-approach-to-get-a-contact-s-last-communication-edb.aspx"&gt;a previous post of mine&lt;/a&gt;, where I also talked about why using &lt;strong&gt;PIMPR_SMARTPROP&lt;/strong&gt; to retrieve the info about the last way a Windows Mobile-device user communicated with a given contact. Recently 2 MSDN Forums users asked for help about this (“&lt;a href="http://social.msdn.microsoft.com/Forums/en-US/vssmartdevicesnative/thread/0686b076-0c07-4c2a-b060-f71ccba90f34"&gt;How to get the information of a selected phonecall number?&lt;/a&gt;” and “&lt;a href="http://social.msdn.microsoft.com/Forums/en-US/vssmartdevicesvbcs/thread/3ca57baf-a4f8-483d-8efa-5325cb2c2cdd"&gt;How to read LastNumber in contact&lt;/a&gt;”) and therefore I wanted to invest some time for the Community, hoping this may help others as well! &lt;img alt="smile_shades" src="http://spaces.live.com/rte/emoticons/smile_shades.gif"&gt; (and also to play with POOM, since managed APIs wrapped so many properties making POOM _&lt;em&gt;quite&lt;/em&gt;_ obsolete…)&lt;/p&gt; &lt;p&gt;Before spreading the code, let me state a thing: &lt;u&gt;the SmartProp property is not set for a contact until the first time the user &lt;br&gt;explicitly changes the default contact method, or it is otherwise explicitly set by an application&lt;/u&gt;. I noticed this when coding this sample, and later I understood that this is the expected behavior. &lt;/p&gt; &lt;p&gt;Ehy, remember that this is not production code: this is for testing\didactic purposes only… indeed the code is simply meant to dump out to a text-file only the First Name, Last Name and the string representing the last way user communicated with the selected contact. The code doesn’t even use the IPOutlookItemCollection::Find to get a specific contact, as this was not the goal here. Yet, I think it was worth sharing as it is, so that who wants can customize it… &lt;img alt="smile_regular" src="http://spaces.live.com/rte/emoticons/smile_regular.gif"&gt; enjoy!!&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;NOTES:&lt;/p&gt; &lt;ol&gt; &lt;li&gt;PIMPR_SMARTPROP is a property of the IItem, not of the IContact: that’s why for example the old POOM NETCF sample code didn’t contain it. So what we need is to retrieve the collection of Contacts and handle them as IItem.  &lt;li&gt;Once you have all the contacts as a collection (IPOutlookItemCollection), you can’t directly retrieve each item – even if IItem implements IDispatch, the right way is the one for example mentioned by my colleague &lt;strong&gt;Xiaoyun Li&lt;/strong&gt; &lt;a href="http://social.msdn.microsoft.com/Forums/en-US/vssmartdevicesnative/thread/d49c0cfe-0246-47cd-9fcf-0191e8c19efd"&gt;here&lt;/a&gt;, i.e. invoke IPOutlookItemCollection::Item by passing a IContact as IDispatch, then call IContact::get_Oid to retrieve the unique OID and finally use this with IPOutlookApp2::GetItemFromOidEx (see function DumpOutToText below).  &lt;li&gt;At this point you have an IItem object and can query its properties in the usual old way, considering that PIMPR_SMARTPROP will return the property id (e.g. PIMPR_MOBILE_TELEPHONE_NUMBER, PIMPR_SMS, etc); all the propIDs that can be returned as smart prop are listed in the documentation &lt;a href="http://msdn.microsoft.com/en-us/library/bb415504.aspx"&gt;here&lt;/a&gt;.  &lt;li&gt;For each returned property, remember to check if it was really found (&lt;em&gt;.wFlags != CEDB_PROPNOTFOUND&lt;/em&gt;) and if it’s of the expected data type (&lt;em&gt;.propid == CEVT_LPWSTR&lt;/em&gt;). &lt;/li&gt;&lt;/ol&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;If you know of any smarter way I’ll be more than welcome on continuing this saga about PIMPR_SMARTPROP… &lt;img alt="smile_teeth" src="http://spaces.live.com/rte/emoticons/smile_teeth.gif"&gt;&lt;/p&gt; &lt;p&gt;&amp;nbsp; &lt;/p&gt;&lt;pre class="csharpcode"&gt;&lt;span class="preproc"&gt;#include&lt;/span&gt; &lt;span class="str"&gt;"stdafx.h"&lt;/span&gt;
&lt;span class="preproc"&gt;#include&lt;/span&gt; &lt;span class="str"&gt;&amp;lt;pimstore.h&amp;gt;&lt;/span&gt;

&lt;span class="rem"&gt;// **************************************************************************&lt;/span&gt;
&lt;span class="rem"&gt;// Globals&lt;/span&gt;
IPOutlookApp2 * g_polApp = NULL;
IUnknown * g_pUnknown = NULL;
LPCTSTR g_pszFilename = TEXT(&lt;span class="str"&gt;"contacts.txt"&lt;/span&gt;);

&lt;span class="rem"&gt;// **************************************************************************&lt;/span&gt;
&lt;span class="rem"&gt;//Functions&lt;/span&gt;
HRESULT InitPoom(&lt;span class="kwrd"&gt;void&lt;/span&gt;);
HRESULT GetPoomFolder(&lt;span class="kwrd"&gt;int&lt;/span&gt; nFolder, IFolder ** ppFolder);
HRESULT FillFileWithContacts(&lt;span class="kwrd"&gt;void&lt;/span&gt;);
HRESULT DumpOutToText(IPOutlookItemCollection * pItemCol);
HRESULT WriteItemSmartProp(IItem *pItem);
HRESULT Log(LPTSTR szLog);
HRESULT LogToFile(LPTSTR szLog, LPCTSTR pszFilename);

&lt;span class="rem"&gt;// **************************************************************************&lt;/span&gt;
&lt;span class="rem"&gt;//MAIN&lt;/span&gt;
&lt;span class="kwrd"&gt;int&lt;/span&gt; _tmain(&lt;span class="kwrd"&gt;int&lt;/span&gt; argc, _TCHAR* argv[])
{
    HRESULT hr = E_FAIL;

    &lt;span class="rem"&gt;//Initialize POOM&lt;/span&gt;
    hr = InitPoom();
    CHR(hr);

    &lt;span class="rem"&gt;//Fill file with Contacts&lt;/span&gt;
    hr = FillFileWithContacts();
    CHR(hr);
    
    &lt;span class="rem"&gt;//Success&lt;/span&gt;
    MessageBox(NULL, TEXT(&lt;span class="str"&gt;"Done"&lt;/span&gt;), TEXT(&lt;span class="str"&gt;"Test"&lt;/span&gt;), MB_OK);

Exit:
    &lt;span class="kwrd"&gt;return&lt;/span&gt; 0;
}


&lt;span class="rem"&gt;// ************************************************************************** &lt;/span&gt;
&lt;span class="rem"&gt;//InitPoom&lt;/span&gt;
HRESULT InitPoom(&lt;span class="kwrd"&gt;void&lt;/span&gt;) 
{
    HRESULT hr = E_FAIL;

    hr = CoInitializeEx(NULL, 0);
    CHR(hr);

    hr = CoCreateInstance(CLSID_Application, NULL, CLSCTX_INPROC_SERVER, IID_IUnknown, (&lt;span class="kwrd"&gt;void&lt;/span&gt; **)&amp;amp;g_pUnknown);
    CHR(hr);

    hr = g_pUnknown-&amp;gt;QueryInterface(IID_IPOutlookApp, (&lt;span class="kwrd"&gt;void&lt;/span&gt;**)&amp;amp;g_polApp); 
    CHR(hr);

    hr = g_polApp-&amp;gt;Logon(NULL);
    CHR(hr);

    &lt;span class="rem"&gt;//success&lt;/span&gt;
    hr = S_OK;

Exit:
    RELEASE_OBJ(g_polApp);
    &lt;span class="kwrd"&gt;return&lt;/span&gt; hr;
}


&lt;span class="rem"&gt;// ************************************************************************** &lt;/span&gt;
&lt;span class="rem"&gt;//FillFileWithContacts&lt;/span&gt;
HRESULT FillFileWithContacts(&lt;span class="kwrd"&gt;void&lt;/span&gt;)
{
    HRESULT hr = E_FAIL;
    IFolder * pCurrFldr = NULL;
    IPOutlookItemCollection * pItemCol = NULL;
    
    &lt;span class="rem"&gt;// Get the Contacts folder and its items&lt;/span&gt;
    hr = GetPoomFolder(olFolderContacts, &amp;amp;pCurrFldr);
    CHR(hr);
        
    &lt;span class="kwrd"&gt;if&lt;/span&gt; (SUCCEEDED(pCurrFldr-&amp;gt;get_Items(&amp;amp;pItemCol)))
    {
        &lt;span class="rem"&gt;//Dump out First Name, Last Name, SMARTPROP for each item&lt;/span&gt;
        hr = DumpOutToText(pItemCol);
        CHR(hr);
    }

    &lt;span class="rem"&gt;//success &lt;/span&gt;
    hr = S_OK;

Exit:
    RELEASE_OBJ(pItemCol);
    RELEASE_OBJ(pCurrFldr);
    &lt;span class="kwrd"&gt;return&lt;/span&gt; hr;
}


&lt;span class="rem"&gt;// **************************************************************************&lt;/span&gt;
&lt;span class="rem"&gt;//GetPoomFolder&lt;/span&gt;
HRESULT GetPoomFolder(&lt;span class="kwrd"&gt;int&lt;/span&gt; nFolder, IFolder ** ppFolder)
{
    HRESULT hr = E_FAIL;
    &lt;span class="kwrd"&gt;if&lt;/span&gt; (SUCCEEDED(g_polApp-&amp;gt;GetDefaultFolder(nFolder, ppFolder)))
    {
        hr = S_OK;
    }

    &lt;span class="kwrd"&gt;return&lt;/span&gt; hr;
}


&lt;span class="rem"&gt;// ************************************************************************** &lt;/span&gt;
&lt;span class="rem"&gt;//DumpOutToText&lt;/span&gt;
HRESULT DumpOutToText(IPOutlookItemCollection * pItemCol)
{
    HRESULT hr = E_FAIL;
    IContact * pContact = NULL;
    IItem * pItem = NULL;
    CEOID oid = 0;   
    &lt;span class="kwrd"&gt;int&lt;/span&gt; cItems = 0;

    &lt;span class="rem"&gt;//Count contacts&lt;/span&gt;
    pItemCol-&amp;gt;get_Count(&amp;amp;cItems);    
    &lt;span class="kwrd"&gt;for&lt;/span&gt; (&lt;span class="kwrd"&gt;int&lt;/span&gt; i = 1; i &amp;lt;= cItems; i++)
    {
        &lt;span class="rem"&gt;//get the item as a IContact&lt;/span&gt;
        &lt;span class="kwrd"&gt;if&lt;/span&gt; (SUCCEEDED(pItemCol-&amp;gt;Item (i, &lt;span class="kwrd"&gt;reinterpret_cast&lt;/span&gt;&amp;lt;IDispatch**&amp;gt;(&amp;amp;pContact))))
        {
            &lt;span class="rem"&gt;//convert the IContact into a IItem...&lt;/span&gt;
            &lt;span class="kwrd"&gt;if&lt;/span&gt; (SUCCEEDED(pContact-&amp;gt;get_Oid((&lt;span class="kwrd"&gt;long&lt;/span&gt;*)&amp;amp;oid)))
            {
                &lt;span class="rem"&gt;//... by using the Oid&lt;/span&gt;
                &lt;span class="kwrd"&gt;if&lt;/span&gt; (SUCCEEDED(g_polApp-&amp;gt;GetItemFromOidEx(oid, 0, &amp;amp;pItem)))
                {
                    &lt;span class="rem"&gt;//Write item's properties to file&lt;/span&gt;
                    hr = WriteItemSmartProp(pItem);
                    
                    RELEASE_OBJ(pItem);
                    CHR(hr);
                }
            }
        }
    }

    &lt;span class="rem"&gt;//success&lt;/span&gt;
    hr = S_OK;

Exit:
    &lt;span class="kwrd"&gt;return&lt;/span&gt; hr;
}


&lt;span class="rem"&gt;// **************************************************************************&lt;/span&gt;
&lt;span class="rem"&gt;//GetItemSmartProp&lt;/span&gt;
HRESULT WriteItemSmartProp(IItem *pItem)
{
    HRESULT hr = E_FAIL;
    &lt;span class="kwrd"&gt;int&lt;/span&gt; cProps = 20;
    CEPROPID rgPropId[20] = {0};
    CEPROPVAL *prgPropvalUser = NULL;
    ULONG cbBuffer = 0;

    &lt;span class="rem"&gt;// FROM http://msdn.microsoft.com/en-us/library/bb415504.aspx&lt;/span&gt;
    &lt;span class="rem"&gt;// The Smart Property (PIMPR_SMARTPROP) is the Contact property that contains the property ID of the default communication mode.&lt;/span&gt;
    rgPropId[0] = PIMPR_FIRST_NAME; &lt;span class="rem"&gt;//type: CEVT_LPWSTR&lt;/span&gt;
    rgPropId[1] = PIMPR_LAST_NAME;  &lt;span class="rem"&gt;//type: CEVT_LPWSTR&lt;/span&gt;
    rgPropId[2] = PIMPR_SMARTPROP;  &lt;span class="rem"&gt;//type: CEVT_UI4&lt;/span&gt;

    &lt;span class="rem"&gt;//all of the following are of type: CEVT_LPWSTR&lt;/span&gt;
    rgPropId[3] = PIMPR_IM2_ADDRESS;                    
    rgPropId[4] = PIMPR_ASSISTANT_TELEPHONE_NUMBER;        
    rgPropId[5] = PIMPR_BUSINESS_TELEPHONE_NUMBER;        
    rgPropId[6] = PIMPR_BUSINESS2_TELEPHONE_NUMBER;        
    rgPropId[7] = PIMPR_CAR_TELEPHONE_NUMBER;            
    rgPropId[8] = PIMPR_COMPANY_TELEPHONE_NUMBER;        
    rgPropId[9] = PIMPR_EMAIL1_ADDRESS;                    
    rgPropId[10] = PIMPR_EMAIL2_ADDRESS;                    
    rgPropId[11] = PIMPR_EMAIL3_ADDRESS;                
    rgPropId[12] = PIMPR_HOME_TELEPHONE_NUMBER;            
    rgPropId[13] = PIMPR_HOME2_TELEPHONE_NUMBER;        
    rgPropId[14] = PIMPR_IM1_ADDRESS;                                        
    rgPropId[15] = PIMPR_IM3_ADDRESS;                    
    rgPropId[16] = PIMPR_MOBILE_TELEPHONE_NUMBER;        
    rgPropId[17] = PIMPR_PAGER_NUMBER;                    
    rgPropId[18] = PIMPR_RADIO_TELEPHONE_NUMBER;        
    rgPropId[19] = PIMPR_SMS;                            


    &lt;span class="rem"&gt;//FROM: http://msdn.microsoft.com/en-us/library/ms859378.aspx&lt;/span&gt;
    &lt;span class="rem"&gt;// Allocate memory, then get item properties&lt;/span&gt;
    cbBuffer = 0;
    hr = pItem-&amp;gt;GetProps(rgPropId, 0, cProps, &amp;amp;prgPropvalUser, &amp;amp;cbBuffer, NULL);
    &lt;span class="kwrd"&gt;if&lt;/span&gt;(HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER) == hr)
    {
        prgPropvalUser = (CEPROPVAL *) LocalAlloc(0, cbBuffer); 
    }

    &lt;span class="rem"&gt;// cbBuffer is set to the number of bytes required to hold the data.&lt;/span&gt;
    hr = pItem-&amp;gt;GetProps(rgPropId, 0, cProps, (CEPROPVAL **)&amp;amp;prgPropvalUser, &amp;amp;cbBuffer, NULL);

    &lt;span class="rem"&gt;//better error-checking to do here...&lt;/span&gt;
    &lt;span class="kwrd"&gt;if&lt;/span&gt;(FAILED(hr) || 0 == cbBuffer)
    {
        &lt;span class="kwrd"&gt;goto&lt;/span&gt; Exit;
    }

    &lt;span class="kwrd"&gt;if&lt;/span&gt;(prgPropvalUser[0].wFlags!=CEDB_PROPNOTFOUND)   
    {   
        &lt;span class="kwrd"&gt;if&lt;/span&gt;(LOWORD(prgPropvalUser[0].propid) == CEVT_LPWSTR)
        {
            Log(prgPropvalUser[0].val.lpwstr);
            Log(TEXT(&lt;span class="str"&gt;"\t"&lt;/span&gt;));
        }
    }

    &lt;span class="kwrd"&gt;if&lt;/span&gt;(prgPropvalUser[1].wFlags!=CEDB_PROPNOTFOUND)   
    {   
        &lt;span class="kwrd"&gt;if&lt;/span&gt;(LOWORD(prgPropvalUser[1].propid) == CEVT_LPWSTR)  
        {
            Log(prgPropvalUser[1].val.lpwstr);
            Log(TEXT(&lt;span class="str"&gt;"\t"&lt;/span&gt;));
        }
    }

    &lt;span class="kwrd"&gt;if&lt;/span&gt;(prgPropvalUser[2].wFlags!=CEDB_PROPNOTFOUND)   
    {   
        &lt;span class="kwrd"&gt;if&lt;/span&gt;(LOWORD(prgPropvalUser[2].propid) == CEVT_UI4)   
        {
            &lt;span class="kwrd"&gt;switch&lt;/span&gt; (prgPropvalUser[2].val.ulVal)
            {
                &lt;span class="kwrd"&gt;case&lt;/span&gt; PIMPR_IM2_ADDRESS:
                    &lt;span class="kwrd"&gt;if&lt;/span&gt;(prgPropvalUser[3].wFlags!=CEDB_PROPNOTFOUND)   
                    {   
                        &lt;span class="kwrd"&gt;if&lt;/span&gt;(LOWORD(prgPropvalUser[3].propid) == CEVT_LPWSTR)   
                        {
                            Log(prgPropvalUser[3].val.lpwstr);
                        }
                    }
                    &lt;span class="kwrd"&gt;break&lt;/span&gt;;
                &lt;span class="kwrd"&gt;case&lt;/span&gt; PIMPR_ASSISTANT_TELEPHONE_NUMBER:
                    &lt;span class="kwrd"&gt;if&lt;/span&gt;(prgPropvalUser[4].wFlags!=CEDB_PROPNOTFOUND)   
                    {   
                        &lt;span class="kwrd"&gt;if&lt;/span&gt;(LOWORD(prgPropvalUser[4].propid) == CEVT_LPWSTR)   
                        {
                            Log(prgPropvalUser[4].val.lpwstr);
                        }
                    }
                    &lt;span class="kwrd"&gt;break&lt;/span&gt;;
                &lt;span class="kwrd"&gt;case&lt;/span&gt; PIMPR_BUSINESS_TELEPHONE_NUMBER:    
                    &lt;span class="kwrd"&gt;if&lt;/span&gt;(prgPropvalUser[5].wFlags!=CEDB_PROPNOTFOUND)   
                    {   
                        &lt;span class="kwrd"&gt;if&lt;/span&gt;(LOWORD(prgPropvalUser[5].propid) == CEVT_LPWSTR)   
                        {
                            Log(prgPropvalUser[5].val.lpwstr);
                        }
                    }
                    &lt;span class="kwrd"&gt;break&lt;/span&gt;;
                &lt;span class="kwrd"&gt;case&lt;/span&gt; PIMPR_BUSINESS2_TELEPHONE_NUMBER:    
                    &lt;span class="kwrd"&gt;if&lt;/span&gt;(prgPropvalUser[6].wFlags!=CEDB_PROPNOTFOUND)   
                    {   
                        &lt;span class="kwrd"&gt;if&lt;/span&gt;(LOWORD(prgPropvalUser[6].propid) == CEVT_LPWSTR)   
                        {
                            Log(prgPropvalUser[6].val.lpwstr);
                        }
                    }
                    &lt;span class="kwrd"&gt;break&lt;/span&gt;;
                &lt;span class="kwrd"&gt;case&lt;/span&gt; PIMPR_CAR_TELEPHONE_NUMBER:        
                    &lt;span class="kwrd"&gt;if&lt;/span&gt;(prgPropvalUser[7].wFlags!=CEDB_PROPNOTFOUND)   
                    {   
                        &lt;span class="kwrd"&gt;if&lt;/span&gt;(LOWORD(prgPropvalUser[7].propid) == CEVT_LPWSTR)   
                        {
                            Log(prgPropvalUser[7].val.lpwstr);
                        }
                    }
                    &lt;span class="kwrd"&gt;break&lt;/span&gt;;
                &lt;span class="kwrd"&gt;case&lt;/span&gt; PIMPR_COMPANY_TELEPHONE_NUMBER:
                    &lt;span class="kwrd"&gt;if&lt;/span&gt;(prgPropvalUser[8].wFlags!=CEDB_PROPNOTFOUND)   
                    {   
                        &lt;span class="kwrd"&gt;if&lt;/span&gt;(LOWORD(prgPropvalUser[8].propid) == CEVT_LPWSTR)   
                        {
                            Log(prgPropvalUser[8].val.lpwstr);
                        }
                    }
                    &lt;span class="kwrd"&gt;break&lt;/span&gt;;
                &lt;span class="kwrd"&gt;case&lt;/span&gt; PIMPR_EMAIL1_ADDRESS:                
                    &lt;span class="kwrd"&gt;if&lt;/span&gt;(prgPropvalUser[9].wFlags!=CEDB_PROPNOTFOUND)   
                    {   
                        &lt;span class="kwrd"&gt;if&lt;/span&gt;(LOWORD(prgPropvalUser[9].propid) == CEVT_LPWSTR)   
                        {
                            Log(prgPropvalUser[9].val.lpwstr);
                        }
                    }
                    &lt;span class="kwrd"&gt;break&lt;/span&gt;;
                &lt;span class="kwrd"&gt;case&lt;/span&gt; PIMPR_EMAIL2_ADDRESS:                
                    &lt;span class="kwrd"&gt;if&lt;/span&gt;(prgPropvalUser[10].wFlags!=CEDB_PROPNOTFOUND)   
                    {   
                        &lt;span class="kwrd"&gt;if&lt;/span&gt;(LOWORD(prgPropvalUser[10].propid) == CEVT_LPWSTR)   
                        {
                            Log(prgPropvalUser[10].val.lpwstr);
                        }
                    }
                    &lt;span class="kwrd"&gt;break&lt;/span&gt;;
                &lt;span class="kwrd"&gt;case&lt;/span&gt; PIMPR_EMAIL3_ADDRESS:                
                    &lt;span class="kwrd"&gt;if&lt;/span&gt;(prgPropvalUser[11].wFlags!=CEDB_PROPNOTFOUND)   
                    {   
                        &lt;span class="kwrd"&gt;if&lt;/span&gt;(LOWORD(prgPropvalUser[11].propid) == CEVT_LPWSTR)   
                        {
                            Log(prgPropvalUser[11].val.lpwstr);
                        }
                    }
                    &lt;span class="kwrd"&gt;break&lt;/span&gt;;
                &lt;span class="kwrd"&gt;case&lt;/span&gt; PIMPR_HOME_TELEPHONE_NUMBER:        
                    &lt;span class="kwrd"&gt;if&lt;/span&gt;(prgPropvalUser[12].wFlags!=CEDB_PROPNOTFOUND)   
                    {   
                        &lt;span class="kwrd"&gt;if&lt;/span&gt;(LOWORD(prgPropvalUser[12].propid) == CEVT_LPWSTR)   
                        {
                            Log(prgPropvalUser[12].val.lpwstr);
                        }
                    }
                    &lt;span class="kwrd"&gt;break&lt;/span&gt;;
                &lt;span class="kwrd"&gt;case&lt;/span&gt; PIMPR_HOME2_TELEPHONE_NUMBER:        
                    &lt;span class="kwrd"&gt;if&lt;/span&gt;(prgPropvalUser[13].wFlags!=CEDB_PROPNOTFOUND)   
                    {   
                        &lt;span class="kwrd"&gt;if&lt;/span&gt;(LOWORD(prgPropvalUser[13].propid) == CEVT_LPWSTR)   
                        {
                            Log(prgPropvalUser[13].val.lpwstr);
                        }
                    }
                    &lt;span class="kwrd"&gt;break&lt;/span&gt;;
                &lt;span class="kwrd"&gt;case&lt;/span&gt; PIMPR_IM1_ADDRESS:                    
                    &lt;span class="kwrd"&gt;if&lt;/span&gt;(prgPropvalUser[14].wFlags!=CEDB_PROPNOTFOUND)   
                    {   
                        &lt;span class="kwrd"&gt;if&lt;/span&gt;(LOWORD(prgPropvalUser[14].propid) == CEVT_LPWSTR)   
                        {
                            Log(prgPropvalUser[14].val.lpwstr);                            
                        }
                    }
                    &lt;span class="kwrd"&gt;break&lt;/span&gt;;
                &lt;span class="kwrd"&gt;case&lt;/span&gt; PIMPR_IM3_ADDRESS:                    
                    &lt;span class="kwrd"&gt;if&lt;/span&gt;(prgPropvalUser[15].wFlags!=CEDB_PROPNOTFOUND)   
                    {   
                        &lt;span class="kwrd"&gt;if&lt;/span&gt;(LOWORD(prgPropvalUser[15].propid) == CEVT_LPWSTR)   
                        {
                            Log(prgPropvalUser[15].val.lpwstr);
                        }
                    }
                    &lt;span class="kwrd"&gt;break&lt;/span&gt;;
                &lt;span class="kwrd"&gt;case&lt;/span&gt; PIMPR_MOBILE_TELEPHONE_NUMBER:        
                    &lt;span class="kwrd"&gt;if&lt;/span&gt;(prgPropvalUser[16].wFlags!=CEDB_PROPNOTFOUND)   
                    {   
                        &lt;span class="kwrd"&gt;if&lt;/span&gt;(LOWORD(prgPropvalUser[16].propid) == CEVT_LPWSTR)   
                        {
                            Log(prgPropvalUser[16].val.lpwstr);
                        }
                    }
                    &lt;span class="kwrd"&gt;break&lt;/span&gt;;
                &lt;span class="kwrd"&gt;case&lt;/span&gt; PIMPR_PAGER_NUMBER:                
                    &lt;span class="kwrd"&gt;if&lt;/span&gt;(prgPropvalUser[17].wFlags!=CEDB_PROPNOTFOUND)   
                    {   
                        &lt;span class="kwrd"&gt;if&lt;/span&gt;(LOWORD(prgPropvalUser[17].propid) == CEVT_LPWSTR)   
                        {
                            Log(prgPropvalUser[17].val.lpwstr);
                        }
                    }
                    &lt;span class="kwrd"&gt;break&lt;/span&gt;;
                &lt;span class="kwrd"&gt;case&lt;/span&gt; PIMPR_RADIO_TELEPHONE_NUMBER:        
                    &lt;span class="kwrd"&gt;if&lt;/span&gt;(prgPropvalUser[18].wFlags!=CEDB_PROPNOTFOUND)   
                    {   
                        &lt;span class="kwrd"&gt;if&lt;/span&gt;(LOWORD(prgPropvalUser[18].propid) == CEVT_LPWSTR)   
                        {
                            Log(prgPropvalUser[18].val.lpwstr);
                        }
                    }
                    &lt;span class="kwrd"&gt;break&lt;/span&gt;;
                &lt;span class="kwrd"&gt;case&lt;/span&gt; PIMPR_SMS:                            
                    &lt;span class="kwrd"&gt;if&lt;/span&gt;(prgPropvalUser[19].wFlags!=CEDB_PROPNOTFOUND)   
                    {   
                        &lt;span class="kwrd"&gt;if&lt;/span&gt;(LOWORD(prgPropvalUser[19].propid) == CEVT_LPWSTR)   
                        {
                            Log(prgPropvalUser[19].val.lpwstr);
                        }
                    }
                    &lt;span class="kwrd"&gt;break&lt;/span&gt;;
            } &lt;span class="rem"&gt;//switch&lt;/span&gt;
        }            
    }
    Log(TEXT(&lt;span class="str"&gt;"\r\n"&lt;/span&gt;));

    &lt;span class="rem"&gt;//success&lt;/span&gt;
    hr = S_OK;

Exit:
    LocalFree(prgPropvalUser); 
    &lt;span class="kwrd"&gt;return&lt;/span&gt; hr;
}&lt;/pre&gt;&lt;pre class="csharpcode"&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre class="csharpcode"&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre class="csharpcode"&gt;&lt;span class="rem"&gt;// ************************************************************************** &lt;/span&gt;
&lt;span class="rem"&gt;// Log &lt;/span&gt;
HRESULT Log(LPTSTR szLog)
{
    HRESULT hr = E_FAIL;
    hr = LogToFile(szLog, g_pszFilename);
    CHR(hr);

Exit:
    &lt;span class="kwrd"&gt;return&lt;/span&gt; hr;
}


&lt;span class="rem"&gt;// ************************************************************************** &lt;/span&gt;
&lt;span class="rem"&gt;// LogToFile &lt;/span&gt;
&lt;span class="rem"&gt;// Writes szLog into the file named pszFilename&lt;/span&gt;
HRESULT LogToFile(LPTSTR szLog, LPCTSTR pszFilename)
{
    HRESULT hr = E_FAIL;
    
    &lt;span class="rem"&gt;//Open the handle to the file (and create it if it doesn't exist&lt;/span&gt;
    HANDLE hFile = CreateFile(pszFilename, GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
    &lt;span class="kwrd"&gt;if&lt;/span&gt; (INVALID_HANDLE_VALUE == hFile)
        &lt;span class="kwrd"&gt;goto&lt;/span&gt; Exit;

    &lt;span class="rem"&gt;//Set the pointer at the end so that we can append szLog&lt;/span&gt;
    DWORD dwFilePointer = SetFilePointer(hFile, 0, NULL, FILE_END);
    &lt;span class="kwrd"&gt;if&lt;/span&gt; (0xFFFFFFFF == dwFilePointer)
        &lt;span class="kwrd"&gt;goto&lt;/span&gt; Exit;

    &lt;span class="rem"&gt;//Write to the file&lt;/span&gt;
    DWORD dwBytesWritten = 0;
    BOOL bWriteFileRet = WriteFile(hFile, szLog, wcslen(szLog) * 2, &amp;amp;dwBytesWritten, NULL);
    &lt;span class="kwrd"&gt;if&lt;/span&gt; (!bWriteFileRet)
        &lt;span class="kwrd"&gt;goto&lt;/span&gt; Exit;

    &lt;span class="rem"&gt;//Flush the buffer&lt;/span&gt;
    BOOL bFlushFileBuffersRet = FlushFileBuffers(hFile);
    &lt;span class="kwrd"&gt;if&lt;/span&gt; (!bFlushFileBuffersRet)
        &lt;span class="kwrd"&gt;goto&lt;/span&gt; Exit;

    &lt;span class="rem"&gt;//Success&lt;/span&gt;
    hr = S_OK;

Exit:
    &lt;span class="kwrd"&gt;if&lt;/span&gt; (NULL != hFile)
    CloseHandle(hFile);

    &lt;span class="kwrd"&gt;return&lt;/span&gt; hr;
}&lt;/pre&gt;&lt;pre class="csharpcode"&gt;&amp;nbsp;&lt;/pre&gt;
&lt;style type="text/css"&gt;


.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }&lt;/style&gt;

&lt;p&gt;Cheers,&lt;br&gt;~raffaele&lt;/p&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9647145" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/raffael/archive/tags/Windows+Mobile/default.aspx">Windows Mobile</category><category domain="http://blogs.msdn.com/raffael/archive/tags/POOM/default.aspx">POOM</category><category domain="http://blogs.msdn.com/raffael/archive/tags/PIMPR_5F00_SMARTPROP/default.aspx">PIMPR_SMARTPROP</category></item><item><title>MAPI on Windows Mobile: Backup and Restore Mails</title><link>http://blogs.msdn.com/raffael/archive/2009/05/26/mapi-on-windows-mobile-backup-and-restore-mails.aspx</link><pubDate>Tue, 26 May 2009 09:49:02 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9641139</guid><dc:creator>Raffaele Limosani</dc:creator><slash:comments>4</slash:comments><comments>http://blogs.msdn.com/raffael/comments/9641139.aspx</comments><wfw:commentRss>http://blogs.msdn.com/raffael/commentrss.aspx?PostID=9641139</wfw:commentRss><description>&lt;ul&gt;   &lt;li&gt;&lt;em&gt;Backup\Restore: is there a standard way?&lt;/em&gt; &lt;/li&gt;    &lt;li&gt;&lt;em&gt;How to programmatically mark messages so that they are downloaded at next sync&lt;/em&gt; &lt;/li&gt;    &lt;li&gt;&lt;em&gt;About linked attachments&lt;/em&gt; &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;Yet another post about MAPI on Windows Mobile, it seems it became an common topic (not well covered over the web probably)… I recently worked with one of my colleagues in Redmond (&lt;font color="#ff0000"&gt;thanks Alex!&lt;strong&gt; &lt;img alt="smile_regular" src="http://spaces.live.com/rte/emoticons/smile_regular.gif" /&gt;&lt;/strong&gt;&lt;/font&gt;) about the following topic: how to use MAPI, if possible, to backup and restore e-mails sync-ed with a backend Exchange server (so by using ActiveSync MAPI Store). &lt;/p&gt;  &lt;p&gt;After some investigation about the possible combination of properties, we understood that if the message is partially downloaded (only the header, or partially downloaded, or without downloading attachments) the is no standard way on how to retrieve the rest of information, such as a link or so to click for downloading, after restoring the messages from a backup file – simply because the server at that point will consider the message as different from the initial one.&lt;/p&gt;  &lt;p&gt;At the beginning we imagined the problem was only with message body… and you can programmatically state if a message hasn't fully downloaded by looking at its properties MSGSTATUS_HEADERONLY, MSGSTATUS_PARTIAL_DOWNLOAD or MSGSTATUS_PARTIAL. So… how to programmatically mark messages so that they are downloaded at next sync? To mark a message for download, you should close the messaging application (tmail.exe), add the property &lt;strong&gt;MSGSTATUS_REMOTE_DOWNLOAD&lt;/strong&gt; to the message and then restart the messaging application (tmail.exe). Note that if you don't want the download to start immediately, then you should also modify the message's PR_CE_SUPPRESS_FETCH property in the same call to IItem::SetProps, accordingly to &lt;a href="http://msdn.microsoft.com/en-us/library/bb446137.aspx"&gt;documentation&lt;/a&gt;. I’m talking about something like:&lt;/p&gt;  &lt;blockquote&gt;   &lt;pre class="csharpcode"&gt;SPropValue rgProps[2];

rgProps[0].ulPropTag = PR_MSG_STATUS;
rgProps[0].Value.ul&amp;#160; = ulMsgStatus | MSGSTATUS_REMOTE_DOWNLOAD | MSGSTATUS_REMOTE_DOWNLOAD_ATTACH;
rgProps[1].ulPropTag = PR_CE_SUPPRESS_FETCH;
rgProps[1].Value.ul&amp;#160; = 1;

hr = pMsg-&amp;gt;SetProps(2, &amp;amp;rgProps, NULL);
CHR(hr);&lt;/pre&gt;
&lt;/blockquote&gt;
&lt;style type="text/css"&gt;




.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }&lt;/style&gt;

&lt;p&gt;Note: MSGSTATUS_REMOTE_DOWNLOAD is not mentioned under the &lt;a href="http://msdn.microsoft.com/en-us/library/bb446051.aspx"&gt;&amp;quot;Windows Mobile Defined MAPI Properties&amp;quot; documentation&lt;/a&gt;, but you can see it defined in the related SDK's header file (&amp;quot;C:\Program Files (x86)\Windows Mobile 6 SDK\PocketPC\Include\Armv4i\cemapi.h&amp;quot;), so you can use it – in other words, the documentation is not complete on that page.&lt;/p&gt;

&lt;p&gt;Note that this may not be a complete solution, accordingly to &lt;strong&gt;Jay Ongg&lt;/strong&gt;'s answer to a comment on a Windows Mobile Dev Team's blog post (&lt;a href="http://blogs.msdn.com/windowsmobile/archive/2007/03/21/getting-started-with-mapi.aspx#2332771"&gt;here&lt;/a&gt;):&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;&amp;quot;[...] &lt;i&gt;Regarding MSGSTATUS_PARTIAL, downloading a whole message is actually more complicated than just setting a flag.&amp;#160; Depending on the transport, you have to think about downloading attachments, which is done different for HTML mail vs normal attachments, I believe.&amp;#160; With that said, this might work... try setting the MSGSTATUS_REMOTE_DOWNLOAD flag to start out, and MSGSTATUS_REMOTE_DOWNLOAD_ATTACH as well.&lt;/i&gt;&amp;quot;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Indeed, as reported by Jay, the approach above resolved the problem for message bodies, but not for attachments! &lt;img alt="smile_sad" src="http://spaces.live.com/rte/emoticons/smile_sad.gif" /&gt; So… to recap: imagine you wish to copy a MAPI message that has a non-downloaded attachment into an unspecified backup storage; later, you copy the message from the backup store into the messaging store. What we expected was that the attachment to still be part of the message, but we found that the message's link to download the attachment is missing. &lt;u&gt;Is there any supported way so that the attachment remains in the message after performing the backup and then retrieving the message&lt;/u&gt;? The answer is simply “no”. &lt;strong&gt;Trying to copy (backup) the email message with a non-downloaded attachment will not work.&lt;/strong&gt; The link to the attachment will be lost, the attachment won’t be retrievable. The email and the non-downloaded attachment are associated with each other in Exchange, however the attachment is not actually a part of the message, so copying the message will not make a copy of the attachment. So the solution is to force the attachment to be downloaded before backing up the message (if user wants to maintain the attachment). Obviously saving the message and attachment on the device might not be a workable solution due to the storage space required… but, as usual, that depends on scenarios.&lt;/p&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;p&gt;Cheers! 
  &lt;br /&gt;~raffaele &lt;font color="#ff0000"&gt;&amp;amp; Alex&lt;/font&gt;&lt;/p&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9641139" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/raffael/archive/tags/Windows+Mobile/default.aspx">Windows Mobile</category><category domain="http://blogs.msdn.com/raffael/archive/tags/MAPI/default.aspx">MAPI</category></item><item><title>Microsoft released a HotFix for NETCF v3.5 on Windows Mobile: now you can use Web Services over SSL (without worrying about empty packets)</title><link>http://blogs.msdn.com/raffael/archive/2009/05/20/microsoft-released-a-hotfix-for-netcf-v3-5-on-windows-mobile-now-you-can-use-web-services-over-ssl-without-worrying-about-empty-packets.aspx</link><pubDate>Wed, 20 May 2009 18:38:37 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9632376</guid><dc:creator>Raffaele Limosani</dc:creator><slash:comments>1</slash:comments><comments>http://blogs.msdn.com/raffael/comments/9632376.aspx</comments><wfw:commentRss>http://blogs.msdn.com/raffael/commentrss.aspx?PostID=9632376</wfw:commentRss><description>&lt;ul&gt;   &lt;li&gt;&lt;em&gt;System.Net.WebException: Unable to read data from the transport connection (System.Net.Sockets.SocketException: Unknown error (0x0))&lt;/em&gt; &lt;/li&gt;    &lt;li&gt;&lt;em&gt;Use HotFix responsibly!&lt;/em&gt; &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;Today my co-worker &lt;strong&gt;Carmelo &lt;/strong&gt;(thanks for sharing this! &lt;img alt="smile_regular" src="http://spaces.live.com/rte/emoticons/smile_regular.gif" /&gt;) found something that NETCF Developers were waiting since long time ago… a fixed version of NETCF CAB for Windows Mobile that would allow to address a bug about calling Web Services over SSL, which was greatly described by Andrew Arnott &lt;a href="http://blogs.msdn.com/andrewarnottms/archive/2007/11/19/why-net-compact-framework-fails-to-call-some-https-web-servers.aspx"&gt;here&lt;/a&gt; some time ago. The problem was that NETCF couldn’t work with Web Services over SSL that respond with empty encryption packets.&lt;/p&gt;  &lt;p&gt;The link to the hotfix is “&lt;strong&gt;&lt;a href="http://support.microsoft.com/kb/970549"&gt;FIX: A System.Net.WebException occurs when you run an application to send HTTPS Web requests to a server in an embedded device&lt;/a&gt;&lt;/strong&gt;”.&lt;/p&gt;  &lt;p&gt;Does this mean that also NETCF Developers can begin waiting for hotfixes for bugs? No, I personally think that this is a one-shot FIX coming from the NETCF Dev Team, because the problem was affecting so many customers around the globe… they simply deserve it. &lt;u&gt;And, again, Technical Support is your friend&lt;/u&gt;!! I don’t know the story behind this fix, however to convince the Dev Team to produce it I’m sure that a “certain” number of customers made their voice be heard through Service Requests… &lt;/p&gt;  &lt;p&gt;&lt;strong&gt;&lt;font color="#ff0000"&gt;WARNING&lt;/font&gt;&lt;/strong&gt;! Remember that analogously to every other hotfix you can ask to Technical Support about whatever Microsoft’s product, you should install it only if you're sure it’s for the problem you're being affected by. This is because a hotfix is meant to address a specific issue and has been tested precisely for that: it didn't go through the whole regression testing that it's usually done when packaging many hotfixes into a Service Pack. So, you don’t have to install this hotfix if you’re not interested on Web Services over SSL (sending empty packets).&lt;/p&gt;  &lt;p&gt;Cheers,   &lt;br /&gt;~raffaele&lt;/p&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9632376" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/raffael/archive/tags/.NET+Compact+Framework/default.aspx">.NET Compact Framework</category><category domain="http://blogs.msdn.com/raffael/archive/tags/Technical+Support/default.aspx">Technical Support</category><category domain="http://blogs.msdn.com/raffael/archive/tags/HotFix/default.aspx">HotFix</category></item><item><title>O Service Request (about NETCF Memory Leak…), where art thoU?</title><link>http://blogs.msdn.com/raffael/archive/2009/05/20/o-service-request-about-netcf-memory-leak-where-art-thou.aspx</link><pubDate>Wed, 20 May 2009 10:45:56 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9631769</guid><dc:creator>Raffaele Limosani</dc:creator><slash:comments>1</slash:comments><comments>http://blogs.msdn.com/raffael/comments/9631769.aspx</comments><wfw:commentRss>http://blogs.msdn.com/raffael/commentrss.aspx?PostID=9631769</wfw:commentRss><description>&lt;p&gt;I’m losing my expertise on this!! &lt;img alt="smile_confused" src="http://spaces.live.com/rte/emoticons/smile_confused.gif" /&gt; After &lt;a href="http://blogs.msdn.com/raffael/archive/2008/02/21/netcf-memory-leak-now-what.aspx"&gt;blogging about it&lt;/a&gt; to spread out the usual suggestions I was used to give to ISVs with troubles around memory, I simply quitted handling this kind of cases! Either v3.5 addressed all known bugs, either NETCF developers are getting skilled about things to do to prevent memory leaks… and I hope I’ve been of some little help! &lt;img alt="smile_shades" src="http://spaces.live.com/rte/emoticons/smile_shades.gif" /&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;Cheers,   &lt;br /&gt;~raffaele&lt;/p&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9631769" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/raffael/archive/tags/Technical+Support/default.aspx">Technical Support</category><category domain="http://blogs.msdn.com/raffael/archive/tags/Scatter+Thoughts/default.aspx">Scatter Thoughts</category></item><item><title>Yet Another Technical Support’s added value: Engagement of Dev Teams</title><link>http://blogs.msdn.com/raffael/archive/2009/05/18/yet-another-technical-support-s-added-value-engagement-of-dev-teams.aspx</link><pubDate>Mon, 18 May 2009 09:55:26 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9624878</guid><dc:creator>Raffaele Limosani</dc:creator><slash:comments>1</slash:comments><comments>http://blogs.msdn.com/raffael/comments/9624878.aspx</comments><wfw:commentRss>http://blogs.msdn.com/raffael/commentrss.aspx?PostID=9624878</wfw:commentRss><description>&lt;ul&gt;   &lt;li&gt;&lt;em&gt;Some bloggers within Technical Support&lt;/em&gt; &lt;/li&gt;    &lt;li&gt;&lt;em&gt;Example of added value given by Technical Support: Devs’ engagement&lt;/em&gt;&amp;#160; &lt;/li&gt;    &lt;li&gt;&lt;em&gt;Comments about NETCF on ARMv6 and ARMv7&lt;/em&gt; &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;I often have to do some marketing for &lt;strong&gt;&lt;a href="http://blogs.msdn.com/raffael/archive/2008/05/14/get-what-you-paid-for.aspx"&gt;Microsoft Technical Support&lt;/a&gt;&lt;/strong&gt;, because it’s something everyone with questions or problems around Microsoft products must test out to understand its added value… Apart from myself &lt;img alt="smile_regular" src="http://spaces.live.com/rte/emoticons/smile_regular.gif" /&gt; we’re plenty of great people on all technologies: to name just a few, the following are representatives of the Technical Support – watch out their blogs, as they’re so plenty of “knowledge”! &lt;img alt="smile_nerd" src="http://spaces.live.com/rte/emoticons/smile_nerd.gif" /&gt;&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;&lt;a href="http://blogs.msdn.com/carloc"&gt;Carlo Cardella&lt;/a&gt; – Internet Development &lt;/li&gt;    &lt;li&gt;&lt;a href="http://blogs.msdn.com/andreal"&gt;Andrea Liberatore&lt;/a&gt; – WCF, Web Services &lt;/li&gt;    &lt;li&gt;&lt;a href="http://blogs.msdn.com/carlos"&gt;Carlo Colombo&lt;/a&gt; – WCF, COM+, Distributed &lt;/li&gt;    &lt;li&gt;&lt;a href="http://blogs.msdn.com/tess"&gt;Tess Ferrandez&lt;/a&gt; – Internet Development &lt;/li&gt;    &lt;li&gt;&lt;a href="http://blogs.msdn.com/alejacma"&gt;Alejandro Campos Magencio&lt;/a&gt; – Cryptography, Security &lt;/li&gt;    &lt;li&gt;&lt;a href="http://blogs.msdn.com/johnbreakwell"&gt;John Breakwell&lt;/a&gt; – MSMQ &lt;/li&gt;    &lt;li&gt;&lt;a href="http://blogs.msdn.com/andrekl"&gt;Andreas Klein&lt;/a&gt; – IIS &lt;/li&gt;    &lt;li&gt;&lt;a href="http://blogs.msdn.com/dougste"&gt;Doug Stewart&lt;/a&gt; – Internet Development &lt;/li&gt;    &lt;li&gt;… &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;There are many others I simply hadn’t yet the honor to work with, I simply couldn’t mention all of them!&lt;/p&gt;  &lt;p&gt;So, what is the added value I want to present today? This time I’d like to demonstrate that one of benefit of using Technical Support is that we may have a preferential engagement with the Product Groups, when necessary. This may differ in forms depending on the technology, but no doubt that we can engage the people who actually wrote the software. And an example of this happened to me some weeks ago…&lt;/p&gt;  &lt;p&gt;In that particular case who opened a Service Request was the OEM of a Windows CE 6.0-based device: you can say that I help ISVs, but this particular OEM was posing questions about developing a NETCF v3.5 application and wanted to receive support about Application Development rather than OS Customization through Platform Builder, therefore it fell in area of expertise. The device was based on a ARMv7 processor and was used as navigation system, hence it was heavily dependent on mathematical functions. On this processor, the OEM noticed that calling the same mathematical functions in a NETCF application required much more time than in a native application. The impression was that the native application leverages on the mathematical co-processor and asked if there’s any way to configure the NETCF Runtime to do the same either at application-layer or system-wide through an OS Customization. &lt;/p&gt;  &lt;p&gt;To make it short, in this case I had the pleasure to work directly with &lt;strong&gt;&lt;font color="#ff0000"&gt;Abhinaba Basu&lt;/font&gt;&lt;/strong&gt;, member of the NETCF Dev Team – see his blog posts as a result of this co-operation:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;&lt;a href="http://blogs.msdn.com/abhinaba/archive/2009/03/27/net-compact-framework-and-arm-fpu.aspx"&gt;.NET Compact Framework and ARM FPU&lt;/a&gt; &lt;/li&gt;    &lt;li&gt;&lt;a href="http://blogs.msdn.com/abhinaba/archive/2009/04/06/floating-point-operations-in-net-compact-framework-on-wince-arm.aspx"&gt;Floating point operations in .NET Compact Framework on WinCE+ARM&lt;/a&gt; &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;Apart from the deep explanations given by Abhinaba in his blog, questions and answers were:&lt;/p&gt;  &lt;p&gt;1- Is this an expected result?    &lt;br /&gt;&lt;em&gt;NetCF 3.5 lacks Armv6/v7 specific optimizations as it is based on Armv4i.&amp;#160; In particular we don’t leverage the FPU (Floating Point Unit), as NETCF does only floating point emulation.&amp;#160; Hence NetCF math functions will be much slower than doing the same in a native C++ program, which in contrast could be compiled to use the hardware FPU.&lt;/em&gt;&lt;/p&gt;  &lt;p&gt;2- Is ARMv7 a fully-supported architecture by the NETCF Runtime?    &lt;br /&gt;&lt;em&gt;NetCF 3.5 is based on Armv4i and Armv7 is backward compatible with Armv4i.&amp;#160; Hence all of the functionality of NetCF3.5 should work fine though may not yield optimal performance.&lt;/em&gt;&lt;/p&gt;  &lt;p&gt;3- Is there any possible way to achieve similar results with NETCF?    &lt;br /&gt;&lt;em&gt;Math routines could be written in native and the same could be PInvoked from managed code. Obviously you need to ensure that the cost of P/Invoke marshalling is not offsetting the saving in computation perf. A good idea to do that is to reduce the number of P/Invoke calls by bulking the computation.&lt;/em&gt;&lt;/p&gt;  &lt;p&gt;In particular, in that specific case the solution proposed was to develop a native DLL that internally invoked native math functions and exposes some “math expressions” to a .NET client. I mean a native DLL exposing f(a,b,c) which internally is like {[sin(a) x sin(b)] / cos(c)}. Moreover, if for example you know that you need to do 3 of these operations then create a buffer of inputs and outputs and push that to the native dll so that it can do all 3 in one go.&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;p&gt;Cheers,    &lt;br /&gt;~raffaele&lt;/p&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9624878" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/raffael/archive/tags/.NET+Compact+Framework/default.aspx">.NET Compact Framework</category><category domain="http://blogs.msdn.com/raffael/archive/tags/Technical+Support/default.aspx">Technical Support</category></item><item><title>MAPI GetOutgoingQueue not supported on Windows Mobile (so the Outbox?)</title><link>http://blogs.msdn.com/raffael/archive/2009/05/11/mapi-getoutgoingqueue-not-supported-on-windows-mobile-so-the-outbox.aspx</link><pubDate>Mon, 11 May 2009 17:00:23 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9602870</guid><dc:creator>Raffaele Limosani</dc:creator><slash:comments>1</slash:comments><comments>http://blogs.msdn.com/raffael/comments/9602870.aspx</comments><wfw:commentRss>http://blogs.msdn.com/raffael/commentrss.aspx?PostID=9602870</wfw:commentRss><description>&lt;p&gt;Recently I had to work on a sample code based on my previous post around MAPI that shows &lt;a href="http://blogs.msdn.com/raffael/archive/2008/09/08/mapi-on-windows-mobile-6-programmatically-retrieve-mail-body-sample-code.aspx"&gt;a possible way to extract the BODY of the mails in the Inbox folder of the ActiveSync account&lt;/a&gt;… this time I needed to grab a handle of the Outbox folder, and therefore I had to modify the function SaveMessagesFromStore of that post. Luckily the code was modularized enough… &lt;img alt="smile_regular" src="http://spaces.live.com/rte/emoticons/smile_regular.gif" /&gt; so, once I had the LPMAPIFOLDER pointer to the Outbox I could continue using basically the same code. I thought there was a MAPI Function similar to &lt;a href="http://msdn.microsoft.com/en-us/library/bb415653.aspx"&gt;IMsgStore::GetReceiveFolder&lt;/a&gt;, but found that quite many functions are not implemented in Windows Mobile 6 – see doc &lt;a href=" http://msdn.microsoft.com/en-us/library/bb159712.aspx"&gt;here&lt;/a&gt;. Luckily MAPI gives different ways to reach a goal, and in this particular case the code was based on the PR_IPM_OUTBOX_ENTRYID property of the MAPI store: &lt;/p&gt;  &lt;pre class="csharpcode"&gt;        &lt;span class="rem"&gt;// Get the Outbox folder&lt;/span&gt;
        ULONG rgTags[] = {1, PR_IPM_OUTBOX_ENTRYID};
        LPSPropValue rgprops = NULL;
        ULONG ulValues = 0;
        hr = pStore-&amp;gt;GetProps((LPSPropTagArray) rgTags, MAPI_UNICODE, &amp;amp;ulValues, &amp;amp;rgprops);
        CHR(hr);
        
        cbEntryId = rgprops[0].Value.bin.cb;
        pEntryId = (LPENTRYID)rgprops[0].Value.bin.lpb;
        
        &lt;span class="rem"&gt;// We have the entryid of the Outbox folder, let's get the folder &lt;/span&gt;
        hr = pStore-&amp;gt;OpenEntry(cbEntryId, pEntryId, NULL, 0, &amp;amp;ulObjType, (LPUNKNOWN*)&amp;amp;pFolder); 
        CHR(hr); 
        
        &lt;span class="rem"&gt;//check &lt;/span&gt;
        CBR(ulObjType == MAPI_FOLDER);&lt;/pre&gt;
&lt;style type="text/css"&gt;



.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }&lt;/style&gt;

&lt;pre class="csharpcode"&gt;&amp;#160;&lt;/pre&gt;

&lt;p&gt;&lt;style type="text/css"&gt;



.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }&lt;/style&gt;&lt;/p&gt;

&lt;p&gt;Cheers, 
  &lt;br /&gt;~raffaele&lt;/p&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9602870" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/raffael/archive/tags/Windows+Mobile/default.aspx">Windows Mobile</category><category domain="http://blogs.msdn.com/raffael/archive/tags/MAPI/default.aspx">MAPI</category></item><item><title>The wrong approach to get a Contact’s last communication (EDB)</title><link>http://blogs.msdn.com/raffael/archive/2009/05/04/the-wrong-approach-to-get-a-contact-s-last-communication-edb.aspx</link><pubDate>Mon, 04 May 2009 18:13:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9585950</guid><dc:creator>Raffaele Limosani</dc:creator><slash:comments>3</slash:comments><comments>http://blogs.msdn.com/raffael/comments/9585950.aspx</comments><wfw:commentRss>http://blogs.msdn.com/raffael/commentrss.aspx?PostID=9585950</wfw:commentRss><description>&lt;P&gt;Have you ever played with EDB? I hadn’t… till the moment when I thought that what I needed was not implemented by the POOM and therefore I had to play with the “Contacts Database” contained in pim.vol... Unfortunately I understood only later that I was wrong… &lt;IMG alt=smile_sad src="http://spaces.live.com/rte/emoticons/smile_sad.gif" mce_src="http://spaces.live.com/rte/emoticons/smile_sad.gif"&gt; And luckily this was precisely the same query raised by in the MSDN Forum ‘&lt;A href="http://social.msdn.microsoft.com/Forums/en-US/vssmartdevicesnative/thread/0686b076-0c07-4c2a-b060-f71ccba90f34" mce_href="http://social.msdn.microsoft.com/Forums/en-US/vssmartdevicesnative/thread/0686b076-0c07-4c2a-b060-f71ccba90f34"&gt;How to get the information of a selected phonecall number?&lt;/A&gt;’ which I answered having fresh mind on the topic. &lt;/P&gt;
&lt;P&gt;Basically when opening a Contact summary card, you can see 2 info:&lt;/P&gt;
&lt;OL&gt;
&lt;LI&gt;Firstly, what is the last time you called this contact by phone, and by using what phone# (mobile, work, home, etc): this is the item at the top, which is removed when user clears the Call Log history (&lt;EM&gt;off-topic:&lt;/EM&gt; &lt;EM&gt;have you ever tried to do programmatically clear the call log?&lt;/EM&gt;), and therefore no longer retrievable by the &lt;A href="http://msdn.microsoft.com/en-us/library/bb416387.aspx" mce_href="http://msdn.microsoft.com/en-us/library/bb416387.aspx"&gt;Phone Functions&lt;/A&gt; like PhoneOpenCallLog, PhoneGetCallLogEntry, etc -- masterly wrapped by the SDF's &lt;A href="http://www.opennetcf.com/library/sdf/html/ad0ec80e-3ebc-9402-7e30-9f1175bdecb7.htm" mce_href="http://www.opennetcf.com/library/sdf/html/ad0ec80e-3ebc-9402-7e30-9f1175bdecb7.htm"&gt;OpenNetcf.Phone.CallLog&lt;/A&gt; if you’re using a managed application. &lt;/LI&gt;
&lt;LI&gt;Secondly, what is the last &lt;EM&gt;way&lt;/EM&gt; user communicated with that contact: this is the selected item in the listview and can be phone\sms\mail etc, not necessarily phone. Well, this info is maintained also if user clears the call log history because it’s a property of the “Contacts Database” not of the “CLOG.EDB” database, and accordingly to what I wrote in the &lt;A href="http://social.msdn.microsoft.com/Forums/en-US/vssmartdevicesnative/thread/0686b076-0c07-4c2a-b060-f71ccba90f34" mce_href="http://social.msdn.microsoft.com/Forums/en-US/vssmartdevicesnative/thread/0686b076-0c07-4c2a-b060-f71ccba90f34"&gt;MSDN Forum post above&lt;/A&gt;, it's something you can retrieve by using &lt;STRONG&gt;POOM&lt;/STRONG&gt;, related to the &lt;STRONG&gt;PIMPR_SMARTPROP&lt;/STRONG&gt; property -- see doc &lt;A href="http://msdn.microsoft.com/en-us/library/bb415504.aspx" mce_href="http://msdn.microsoft.com/en-us/library/bb415504.aspx"&gt;here&lt;/A&gt;, ‘Remarks’ section: “&lt;EM&gt;The Smart Property (PIMPR_SMARTPROP) is the Contact property that contains the property ID of the default communication mode. This becomes the phone number or address displayed on the second line of the two-line display in the Contact list view, and highlighted in the Contact summary tab.&lt;/EM&gt;”. &lt;/LI&gt;&lt;/OL&gt;
&lt;P&gt;So why on the earth did I mess up with EDB Functions against the “Contacts Database”? Purely because I wasn’t aware of such ad-hoc property!! And I ended up with a code that I want to share in case anyone is approaching to &lt;STRONG&gt;&lt;A href="http://msdn.microsoft.com/en-us/library/aa912256.aspx" mce_href="http://msdn.microsoft.com/en-us/library/aa912256.aspx"&gt;EDB Functions on Windows Mobile&lt;/A&gt;&lt;/STRONG&gt; as it shows some basic functionalities… as usual it’s provided as-is for didactic purposes and doesn’t contain enough error-check for example. &lt;/P&gt;&lt;PRE class=csharpcode&gt;    DWORD dwError = ERROR_SUCCESS;
    CEGUID guid;
    DWORD dwBufSize, dwIndex;
    BOOL fOk = FALSE;
    HANDLE hSession, hDatabase; 
    WORD wNumProps;
    CEOID oid = 0, ceoid;
    TCHAR szBuffer[MAXBUFFERSIZE] = {0};
    PCEPROPVAL lpProp;

    &lt;SPAN class=rem&gt;//Used for CEVT_STREAM:&lt;/SPAN&gt;
    HANDLE hStream;
    DWORD cbStream;
    LPBYTE pBuffer;
    DWORD cbActualRead;

    &lt;SPAN class=rem&gt;//1- Mount DB&lt;/SPAN&gt;
    &lt;SPAN class=kwrd&gt;if&lt;/SPAN&gt; (!CeMountDBVolEx(&amp;amp;guid, TEXT(&lt;SPAN class=str&gt;"\\pim.vol"&lt;/SPAN&gt;), NULL, OPEN_ALWAYS)) 
    {
        dwError = GetLastError();
        &lt;SPAN class=kwrd&gt;goto&lt;/SPAN&gt; Exit;
    }

    &lt;SPAN class=rem&gt;//2- Open Session&lt;/SPAN&gt;
    hSession = CeCreateSession(&amp;amp;guid);
    &lt;SPAN class=kwrd&gt;if&lt;/SPAN&gt; (hSession == INVALID_HANDLE_VALUE) 
    {
        dwError = GetLastError();
        &lt;SPAN class=kwrd&gt;goto&lt;/SPAN&gt; Exit;
    }

    &lt;SPAN class=rem&gt;//3- Open Database&lt;/SPAN&gt;
    hDatabase = CeOpenDatabaseInSession(hSession, &amp;amp;guid, &amp;amp;oid, TEXT(&lt;SPAN class=str&gt;"Contacts Database"&lt;/SPAN&gt;), NULL, 0, NULL);
    &lt;SPAN class=kwrd&gt;if&lt;/SPAN&gt; (hDatabase == INVALID_HANDLE_VALUE) 
    {
        dwError = GetLastError();
        &lt;SPAN class=kwrd&gt;goto&lt;/SPAN&gt; Exit;
    }

    &lt;SPAN class=rem&gt;//4- Iterate through records (there are other ways apart from waiting for ERROR_SEEK...)&lt;/SPAN&gt;
    dwIndex = 0;
    BOOL bFound = FALSE;
    &lt;SPAN class=kwrd&gt;while&lt;/SPAN&gt; (!bFound) 
    {

        &lt;SPAN class=rem&gt;//4.1- Set index into db&lt;/SPAN&gt;
        ceoid = CeSeekDatabaseEx(hDatabase, CEDB_SEEK_BEGINNING, dwIndex, 0, NULL);
        &lt;SPAN class=kwrd&gt;if&lt;/SPAN&gt; (ceoid == 0) 
        {
            dwError = GetLastError();
            &lt;SPAN class=kwrd&gt;goto&lt;/SPAN&gt; Exit;
        }

        &lt;SPAN class=rem&gt;//4.2- Read records at index&lt;/SPAN&gt;
        wNumProps = 0;
        ceoid = CeReadRecordPropsEx(hDatabase, CEDB_ALLOWREALLOC, &amp;amp;wNumProps, NULL, (LPBYTE*)&amp;amp;lpProp, &amp;amp;dwBufSize, NULL);            
        &lt;SPAN class=kwrd&gt;if&lt;/SPAN&gt; (ceoid == 0) 
        {
            dwError = GetLastError();
            &lt;SPAN class=rem&gt;//if (dwError == 122) //ERR_INSUFFICIENT_BUFFER&lt;/SPAN&gt;
            &lt;SPAN class=rem&gt;//e.g. increase buffer and re-try&lt;/SPAN&gt;
            
            &lt;SPAN class=kwrd&gt;goto&lt;/SPAN&gt; Exit;
        }

        &lt;SPAN class=rem&gt;//4.3- Iterate through columns &lt;/SPAN&gt;
        &lt;SPAN class=kwrd&gt;for&lt;/SPAN&gt;( &lt;SPAN class=kwrd&gt;int&lt;/SPAN&gt; i = 0; i &amp;lt; wNumProps; i++ )
        {
            &lt;SPAN class=rem&gt;//4.4- switch based on datatype (http://msdn.microsoft.com/en-us/library/aa917573.aspx) &lt;/SPAN&gt;
            &lt;SPAN class=kwrd&gt;switch&lt;/SPAN&gt;( TypeFromPropID(lpProp[i].propid) )
            {
                &lt;SPAN class=kwrd&gt;case&lt;/SPAN&gt; CEVT_I2:
                    _stprintf(szBuffer, _T(&lt;SPAN class=str&gt;"%d\t %d\t %s: %s"&lt;/SPAN&gt;), dwIndex, i, _T(&lt;SPAN class=str&gt;"Data Type"&lt;/SPAN&gt;), _T(&lt;SPAN class=str&gt;"CEVT_I2"&lt;/SPAN&gt;) );
                    OutputDebugString(szBuffer);
                    _stprintf(szBuffer, _T(&lt;SPAN class=str&gt;"\t%d \r\n"&lt;/SPAN&gt;), lpProp[i].val.iVal );
                    OutputDebugString(szBuffer);
                    &lt;SPAN class=kwrd&gt;break&lt;/SPAN&gt;;

                &lt;SPAN class=kwrd&gt;case&lt;/SPAN&gt; CEVT_UI2:
                    _stprintf(szBuffer, _T(&lt;SPAN class=str&gt;"%d\t %d\t %s: %s"&lt;/SPAN&gt;), dwIndex, i, _T(&lt;SPAN class=str&gt;"Data Type"&lt;/SPAN&gt;), _T(&lt;SPAN class=str&gt;"CEVT_UI2"&lt;/SPAN&gt;) );
                    OutputDebugString(szBuffer);
                    _stprintf(szBuffer, _T(&lt;SPAN class=str&gt;"\t%d \r\n"&lt;/SPAN&gt;), lpProp[i].val.uiVal );
                    OutputDebugString(szBuffer);
                    &lt;SPAN class=kwrd&gt;break&lt;/SPAN&gt;;

                &lt;SPAN class=kwrd&gt;case&lt;/SPAN&gt; CEVT_I4:
                    _stprintf(szBuffer, _T(&lt;SPAN class=str&gt;"%d\t %d\t %s: %s"&lt;/SPAN&gt;), dwIndex, i, _T(&lt;SPAN class=str&gt;"Data Type"&lt;/SPAN&gt;), _T(&lt;SPAN class=str&gt;"CEVT_I4"&lt;/SPAN&gt;) );
                    OutputDebugString(szBuffer);
                    _stprintf(szBuffer, _T(&lt;SPAN class=str&gt;"\t%d \r\n"&lt;/SPAN&gt;), lpProp[i].val.lVal );
                    OutputDebugString(szBuffer);
                    &lt;SPAN class=kwrd&gt;break&lt;/SPAN&gt;;

                &lt;SPAN class=kwrd&gt;case&lt;/SPAN&gt; CEVT_UI4:
                    _stprintf(szBuffer, _T(&lt;SPAN class=str&gt;"%d\t %d\t %s: %s"&lt;/SPAN&gt;), dwIndex, i, _T(&lt;SPAN class=str&gt;"Data Type"&lt;/SPAN&gt;), _T(&lt;SPAN class=str&gt;"CEVT_UI4"&lt;/SPAN&gt;) );
                    OutputDebugString(szBuffer);
                    _stprintf(szBuffer, _T(&lt;SPAN class=str&gt;"\t%d \r\n"&lt;/SPAN&gt;), lpProp[i].val.ulVal );
                    OutputDebugString(szBuffer);
                    &lt;SPAN class=kwrd&gt;break&lt;/SPAN&gt;;

                &lt;SPAN class=kwrd&gt;case&lt;/SPAN&gt; CEVT_LPWSTR:
                    _stprintf(szBuffer, _T(&lt;SPAN class=str&gt;"%d\t %d\t %s: %s\t"&lt;/SPAN&gt;), dwIndex, i, _T(&lt;SPAN class=str&gt;"Data Type"&lt;/SPAN&gt;), _T(&lt;SPAN class=str&gt;"CEVT_LPWSTR"&lt;/SPAN&gt;) );
                    OutputDebugString(szBuffer);
                    OutputDebugString(lpProp[i].val.lpwstr);
                    OutputDebugString(_T(&lt;SPAN class=str&gt;"\r\n"&lt;/SPAN&gt;));
                    &lt;SPAN class=kwrd&gt;break&lt;/SPAN&gt;;

                &lt;SPAN class=kwrd&gt;case&lt;/SPAN&gt; CEVT_BLOB:
                    _stprintf(szBuffer, _T(&lt;SPAN class=str&gt;"%d\t %d\t %s: %s \r\n"&lt;/SPAN&gt;), dwIndex, i, _T(&lt;SPAN class=str&gt;"Data Type"&lt;/SPAN&gt;),_T(&lt;SPAN class=str&gt;"CEVT_BLOB"&lt;/SPAN&gt;) );
                    OutputDebugString(szBuffer);
                    _stprintf(szBuffer, _T(&lt;SPAN class=str&gt;"\t%s: %li \r\n"&lt;/SPAN&gt;), _T(&lt;SPAN class=str&gt;"Size in bytes"&lt;/SPAN&gt;), lpProp[i].val.blob.dwCount );
                    OutputDebugString(szBuffer);
                    _stprintf(szBuffer, _T(&lt;SPAN class=str&gt;"\t%s: 0x%x \r\n"&lt;/SPAN&gt;), _T(&lt;SPAN class=str&gt;"Buffer Address"&lt;/SPAN&gt;) ,lpProp[i].val.blob.lpb );
                    OutputDebugString(szBuffer);
                    &lt;SPAN class=kwrd&gt;break&lt;/SPAN&gt;;

                &lt;SPAN class=kwrd&gt;case&lt;/SPAN&gt; CEVT_BOOL:
                    _stprintf(szBuffer, _T(&lt;SPAN class=str&gt;"%d\t %d\t %s: %s \r\n"&lt;/SPAN&gt;), dwIndex, i, _T(&lt;SPAN class=str&gt;"Data Type"&lt;/SPAN&gt;),_T(&lt;SPAN class=str&gt;"CEVT_BOOL"&lt;/SPAN&gt;) );
                    OutputDebugString(szBuffer);
                    &lt;SPAN class=kwrd&gt;break&lt;/SPAN&gt;;

                &lt;SPAN class=kwrd&gt;case&lt;/SPAN&gt; CEVT_R8:
                    _stprintf(szBuffer, _T(&lt;SPAN class=str&gt;"%d\t %d\t %s: %s \r\n"&lt;/SPAN&gt;), dwIndex, i, _T(&lt;SPAN class=str&gt;"Data Type"&lt;/SPAN&gt;),_T(&lt;SPAN class=str&gt;"CEVT_R8"&lt;/SPAN&gt;) );
                    OutputDebugString(szBuffer);
                    &lt;SPAN class=kwrd&gt;break&lt;/SPAN&gt;;

                &lt;SPAN class=kwrd&gt;case&lt;/SPAN&gt; CEVT_STREAM:
                    _stprintf(szBuffer, _T(&lt;SPAN class=str&gt;"%d\t %d\t %s: %s \r\n"&lt;/SPAN&gt;), dwIndex, i, _T(&lt;SPAN class=str&gt;"Data Type"&lt;/SPAN&gt;),_T(&lt;SPAN class=str&gt;"CEVT_STREAM"&lt;/SPAN&gt;) );
                    OutputDebugString(szBuffer);

                    &lt;SPAN class=rem&gt;//OPEN STREAM&lt;/SPAN&gt;
                    hStream = CeOpenStream(hDatabase, lpProp[i].propid, GENERIC_READ);
                    cbStream = &lt;SPAN class=kwrd&gt;sizeof&lt;/SPAN&gt;(hStream);
                    
                    &lt;SPAN class=kwrd&gt;if&lt;/SPAN&gt; (hStream == INVALID_HANDLE_VALUE )
                    {
                        dwError = GetLastError();
                        &lt;SPAN class=kwrd&gt;goto&lt;/SPAN&gt; Exit;
                    }
                    
                    &lt;SPAN class=rem&gt;//SET SEEK POSITION AT BEGINNING&lt;/SPAN&gt;
                    &lt;SPAN class=kwrd&gt;if&lt;/SPAN&gt; (!CeStreamSeek(hStream, 0, STREAM_SEEK_SET, NULL))
                    {
                        dwError = GetLastError();
                        &lt;SPAN class=kwrd&gt;goto&lt;/SPAN&gt; Exit;
                    }

                    &lt;SPAN class=rem&gt;//READ STREAM&lt;/SPAN&gt;
                    pBuffer = &lt;SPAN class=kwrd&gt;new&lt;/SPAN&gt; BYTE[cbStream];
                    &lt;SPAN class=kwrd&gt;if&lt;/SPAN&gt; (!CeStreamRead(hStream, pBuffer, cbStream, &amp;amp;cbActualRead))
                    {
                        dwError = GetLastError();
                        delete [] pBuffer;
                        &lt;SPAN class=kwrd&gt;goto&lt;/SPAN&gt; Exit;
                    }

                    _stprintf(szBuffer, _T(&lt;SPAN class=str&gt;"\tSTREAM: %s\r\n"&lt;/SPAN&gt;), (LPTSTR)(pBuffer));
                    OutputDebugString(szBuffer);
                    &lt;SPAN class=kwrd&gt;break&lt;/SPAN&gt;;

                &lt;SPAN class=kwrd&gt;case&lt;/SPAN&gt; CEVT_RECID:
                    _stprintf(szBuffer, _T(&lt;SPAN class=str&gt;"%d\t %d\t %s: %s \r\n"&lt;/SPAN&gt;), dwIndex, i, _T(&lt;SPAN class=str&gt;"Data Type"&lt;/SPAN&gt;),_T(&lt;SPAN class=str&gt;"CEVT_RECID"&lt;/SPAN&gt;) );
                    OutputDebugString(szBuffer);
                    &lt;SPAN class=kwrd&gt;break&lt;/SPAN&gt;;

                &lt;SPAN class=kwrd&gt;case&lt;/SPAN&gt; CEVT_AUTO_I4:
                    _stprintf(szBuffer, _T(&lt;SPAN class=str&gt;"%d\t %d\t %s: %s"&lt;/SPAN&gt;), dwIndex, i, _T(&lt;SPAN class=str&gt;"Data Type"&lt;/SPAN&gt;),_T(&lt;SPAN class=str&gt;"CEVT_AUTO_I4"&lt;/SPAN&gt;) );
                    OutputDebugString(szBuffer);
                    _stprintf(szBuffer, _T(&lt;SPAN class=str&gt;"\t%d \r\n"&lt;/SPAN&gt;), lpProp[i].val.lVal );
                    OutputDebugString(szBuffer);
                    &lt;SPAN class=kwrd&gt;break&lt;/SPAN&gt;;

                &lt;SPAN class=kwrd&gt;case&lt;/SPAN&gt; CEVT_AUTO_I8:
                    _stprintf(szBuffer, _T(&lt;SPAN class=str&gt;"%d\t %d\t %s: %s"&lt;/SPAN&gt;), dwIndex, i, _T(&lt;SPAN class=str&gt;"Data Type"&lt;/SPAN&gt;),_T(&lt;SPAN class=str&gt;"CEVT_AUTO_I8"&lt;/SPAN&gt;) );
                    OutputDebugString(szBuffer);
                    _stprintf(szBuffer, _T(&lt;SPAN class=str&gt;"\t%d \r\n"&lt;/SPAN&gt;), lpProp[i].val.lVal );
                    OutputDebugString(szBuffer);
                    &lt;SPAN class=kwrd&gt;break&lt;/SPAN&gt;;

                &lt;SPAN class=kwrd&gt;default&lt;/SPAN&gt;:
                    _stprintf(szBuffer, _T(&lt;SPAN class=str&gt;"%d\t %d\t %s: %s \r\n"&lt;/SPAN&gt;), dwIndex, i, _T(&lt;SPAN class=str&gt;"Data Type"&lt;/SPAN&gt;),_T(&lt;SPAN class=str&gt;"Unknown"&lt;/SPAN&gt;) );
                    OutputDebugString(szBuffer);
                    &lt;SPAN class=rem&gt;//lpProp[i].val ??&lt;/SPAN&gt;
                    &lt;SPAN class=kwrd&gt;break&lt;/SPAN&gt;;
            } &lt;SPAN class=rem&gt;//switch&lt;/SPAN&gt;
        } &lt;SPAN class=rem&gt;//for&lt;/SPAN&gt;

        &lt;SPAN class=rem&gt;//move to next record&lt;/SPAN&gt;
        dwIndex++;
    } &lt;SPAN class=rem&gt;//while&lt;/SPAN&gt;


    &lt;SPAN class=rem&gt;//5- Unmount db&lt;/SPAN&gt;
    &lt;SPAN class=kwrd&gt;if&lt;/SPAN&gt; (!CeUnmountDBVol(&amp;amp;guid))
    {
        dwError = GetLastError();
        &lt;SPAN class=kwrd&gt;goto&lt;/SPAN&gt; Exit;
    }


Exit:
    &lt;SPAN class=kwrd&gt;if&lt;/SPAN&gt; (NULL != hDatabase) CloseHandle(hDatabase);
    &lt;SPAN class=kwrd&gt;if&lt;/SPAN&gt; (NULL != hSession) CloseHandle(hSession);
    &lt;SPAN class=kwrd&gt;if&lt;/SPAN&gt; (dwError == ERROR_SEEK) dwError = ERROR_SUCCESS; &lt;SPAN class=rem&gt;//ERROR_SEEK is expected to exit the while loop&lt;/SPAN&gt;

    &lt;SPAN class=kwrd&gt;return&lt;/SPAN&gt; dwError;&lt;/PRE&gt;
&lt;STYLE type=text/css&gt;

.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }&lt;/STYLE&gt;

&lt;P&gt;Cheers,&lt;/P&gt;
&lt;P&gt;~raffaele&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9585950" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/raffael/archive/tags/Windows+Mobile/default.aspx">Windows Mobile</category><category domain="http://blogs.msdn.com/raffael/archive/tags/POOM/default.aspx">POOM</category><category domain="http://blogs.msdn.com/raffael/archive/tags/EDB/default.aspx">EDB</category><category domain="http://blogs.msdn.com/raffael/archive/tags/PIMPR_5F00_SMARTPROP/default.aspx">PIMPR_SMARTPROP</category></item><item><title>FindWindowEx on Windows Mobile: not supported…</title><link>http://blogs.msdn.com/raffael/archive/2009/04/29/findwindowex-on-windows-mobile-not-supported.aspx</link><pubDate>Wed, 29 Apr 2009 11:45:15 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9575338</guid><dc:creator>Raffaele Limosani</dc:creator><slash:comments>1</slash:comments><comments>http://blogs.msdn.com/raffael/comments/9575338.aspx</comments><wfw:commentRss>http://blogs.msdn.com/raffael/commentrss.aspx?PostID=9575338</wfw:commentRss><description>&lt;p&gt;… so how can I grab the handle of a particular child window, considering that FindWindow retrieves all top-level windows? I worked on this when writing &lt;a href="http://blogs.msdn.com/raffael/archive/2009/01/08/disable-webbrowser-s-context-menu-in-netcf-applications.aspx"&gt;a previous post of mine&lt;/a&gt;, and got a wonderful comment from &lt;strong&gt;&lt;a href="http://www.paslatek.net"&gt;Lionel&lt;/a&gt;&lt;/strong&gt; (thanks again &lt;img alt="smile_regular" src="http://spaces.live.com/rte/emoticons/smile_regular.gif" /&gt;). Today I had to re-use that code, and found that something was missing and also the code required some enhancements… so here it is!&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;pre class="csharpcode"&gt;        &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; IntPtr FindChildWindow(&lt;span class="kwrd"&gt;string&lt;/span&gt; strChildClassName, &lt;span class="kwrd"&gt;string&lt;/span&gt; strChildWindowCaption, IntPtr hWndTopLevel)
        {
            IntPtr hwndCur = IntPtr.Zero;
            hwndCur = GetWindow(hWndTopLevel, (&lt;span class="kwrd"&gt;uint&lt;/span&gt;)GetWindowFlags.GW_CHILD);
            &lt;span class="kwrd"&gt;return&lt;/span&gt; RecurseFindWindow(strChildClassName, strChildWindowCaption, hwndCur);
        }

        &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;bool&lt;/span&gt; m_bFound = &lt;span class="kwrd"&gt;false&lt;/span&gt;;

        &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; IntPtr RecurseFindWindow(&lt;span class="kwrd"&gt;string&lt;/span&gt; strChildClassName, &lt;span class="kwrd"&gt;string&lt;/span&gt; strChildWindowCaption, IntPtr hWndParent)
        {
            &lt;span class="rem"&gt;//bool bFound = false;&lt;/span&gt;
            IntPtr hwndCur = IntPtr.Zero;
            &lt;span class="kwrd"&gt;char&lt;/span&gt;[] chArWindowClass = &lt;span class="kwrd"&gt;new&lt;/span&gt; &lt;span class="kwrd"&gt;char&lt;/span&gt;[32];
            &lt;span class="kwrd"&gt;if&lt;/span&gt; (hWndParent == IntPtr.Zero)
                &lt;span class="kwrd"&gt;return&lt;/span&gt; IntPtr.Zero;
            &lt;span class="kwrd"&gt;else&lt;/span&gt;
            {
                &lt;span class="rem"&gt;//check if we got the searched class name&lt;/span&gt;
                GetClassName(hWndParent, chArWindowClass, 256);
                &lt;span class="kwrd"&gt;string&lt;/span&gt; strWndClass = &lt;span class="kwrd"&gt;new&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt;(chArWindowClass);
                strWndClass = strWndClass.Substring(0, strWndClass.IndexOf(&lt;span class="str"&gt;'\0'&lt;/span&gt;));
                &lt;span class="kwrd"&gt;if&lt;/span&gt; (strWndClass.ToLower() == strChildClassName.ToLower())
                {
                    &lt;span class="rem"&gt;//check if we got the searched window name&lt;/span&gt;
                    &lt;span class="kwrd"&gt;int&lt;/span&gt; length = GetWindowTextLength(hWndParent);
                    StringBuilder sb = &lt;span class="kwrd"&gt;new&lt;/span&gt; StringBuilder(length + 1);
                    GetWindowText(hWndParent, sb, sb.Capacity);
                    m_bFound = (sb.ToString().ToLower() == strChildWindowCaption.ToLower());
                    &lt;span class="kwrd"&gt;if&lt;/span&gt; (m_bFound)
                        &lt;span class="kwrd"&gt;return&lt;/span&gt; hWndParent;
                }
                &lt;span class="kwrd"&gt;else&lt;/span&gt;
                {
                    &lt;span class="rem"&gt;//recurse into first child&lt;/span&gt;
                    IntPtr hwndChild = GetWindow(hWndParent, (&lt;span class="kwrd"&gt;uint&lt;/span&gt;)GetWindowFlags.GW_CHILD);
                    &lt;span class="kwrd"&gt;if&lt;/span&gt; (hwndChild != IntPtr.Zero)
                        hwndCur = RecurseFindWindow(strChildClassName, strChildWindowCaption, hwndChild);
                    &lt;span class="kwrd"&gt;if&lt;/span&gt; (!m_bFound)
                    {
                        IntPtr hwndBrother = IntPtr.Zero;
                        &lt;span class="rem"&gt;//enumerate each brother windows and recurse into&lt;/span&gt;
                        &lt;span class="kwrd"&gt;do&lt;/span&gt;
                        {
                            hwndBrother = GetWindow(hWndParent, (&lt;span class="kwrd"&gt;uint&lt;/span&gt;)GetWindowFlags.GW_HWNDNEXT);
                            hWndParent = hwndBrother;
                            &lt;span class="kwrd"&gt;if&lt;/span&gt; (hwndBrother != IntPtr.Zero)
                            {
                                hwndCur = RecurseFindWindow(strChildClassName, strChildWindowCaption, hwndBrother);
                                &lt;span class="kwrd"&gt;if&lt;/span&gt; (m_bFound)
                                    &lt;span class="kwrd"&gt;break&lt;/span&gt;;
                            }
                        }
                        &lt;span class="kwrd"&gt;while&lt;/span&gt; (hwndBrother != IntPtr.Zero);
                    }
                }
                &lt;span class="kwrd"&gt;return&lt;/span&gt; hwndCur;
            }
        }


        [DllImport(&lt;span class="str"&gt;&amp;quot;coredll.dll&amp;quot;&lt;/span&gt;, SetLastError = &lt;span class="kwrd"&gt;true&lt;/span&gt;)]
        &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;extern&lt;/span&gt; IntPtr FindWindow(&lt;span class="kwrd"&gt;string&lt;/span&gt; _ClassName, &lt;span class="kwrd"&gt;string&lt;/span&gt; _WindowName);

        [DllImport(&lt;span class="str"&gt;&amp;quot;coredll.dll&amp;quot;&lt;/span&gt;, SetLastError = &lt;span class="kwrd"&gt;true&lt;/span&gt;)]
        &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;extern&lt;/span&gt; IntPtr GetWindow(IntPtr hwnd, &lt;span class="kwrd"&gt;uint&lt;/span&gt; relationship);

        [DllImport(&lt;span class="str"&gt;&amp;quot;coredll.dll&amp;quot;&lt;/span&gt;, SetLastError = &lt;span class="kwrd"&gt;true&lt;/span&gt;)]
        &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;extern&lt;/span&gt; IntPtr SendMessage(IntPtr hWnd, &lt;span class="kwrd"&gt;int&lt;/span&gt; msg, &lt;span class="kwrd"&gt;int&lt;/span&gt; wParam, &lt;span class="kwrd"&gt;int&lt;/span&gt; lParam);

        [DllImport(&lt;span class="str"&gt;&amp;quot;coredll.dll&amp;quot;&lt;/span&gt;, SetLastError = &lt;span class="kwrd"&gt;true&lt;/span&gt;, CharSet = CharSet.Unicode)]
        &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;extern&lt;/span&gt; &lt;span class="kwrd"&gt;int&lt;/span&gt; GetClassName(IntPtr hwnd, &lt;span class="kwrd"&gt;char&lt;/span&gt;[] windowClass, &lt;span class="kwrd"&gt;int&lt;/span&gt; maxText);

        [DllImport(&lt;span class="str"&gt;&amp;quot;coredll.dll&amp;quot;&lt;/span&gt;, SetLastError = &lt;span class="kwrd"&gt;true&lt;/span&gt;, CharSet = CharSet.Unicode)]
        &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;extern&lt;/span&gt; &lt;span class="kwrd"&gt;int&lt;/span&gt; GetWindowTextLength(IntPtr hWnd);

        [DllImport(&lt;span class="str"&gt;&amp;quot;coredll.dll&amp;quot;&lt;/span&gt;, SetLastError = &lt;span class="kwrd"&gt;true&lt;/span&gt;, CharSet = CharSet.Unicode)]
        &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;extern&lt;/span&gt; &lt;span class="kwrd"&gt;int&lt;/span&gt; GetWindowText(IntPtr hWnd, StringBuilder lpString, &lt;span class="kwrd"&gt;int&lt;/span&gt; nMaxCount);

        [Flags]
        &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;enum&lt;/span&gt; GetWindowFlags
        {
            GW_HWNDFIRST = 0,
            GW_HWNDLAST = 1,
            GW_HWNDNEXT = 2,
            GW_HWNDPREV = 3,
            GW_OWNER = 4,
            GW_CHILD = 5,
        }&lt;/pre&gt;
&lt;style type="text/css"&gt;

.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }&lt;/style&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;p&gt;Cheers,&lt;/p&gt;

&lt;p&gt;~raffaele&lt;/p&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9575338" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/raffael/archive/tags/.NET+Compact+Framework/default.aspx">.NET Compact Framework</category><category domain="http://blogs.msdn.com/raffael/archive/tags/Windows+Mobile/default.aspx">Windows Mobile</category><category domain="http://blogs.msdn.com/raffael/archive/tags/Win32/default.aspx">Win32</category></item><item><title>Programmatically Discriminate between Upgrade or Uninstall of a CAB on Windows Mobile</title><link>http://blogs.msdn.com/raffael/archive/2009/04/22/programmatically-discriminate-between-upgrade-or-uninstall-of-a-cab-on-windows-mobile.aspx</link><pubDate>Wed, 22 Apr 2009 18:31:57 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9562504</guid><dc:creator>Raffaele Limosani</dc:creator><slash:comments>12</slash:comments><comments>http://blogs.msdn.com/raffael/comments/9562504.aspx</comments><wfw:commentRss>http://blogs.msdn.com/raffael/commentrss.aspx?PostID=9562504</wfw:commentRss><description>&lt;p&gt;Recently I've worked with a developer on an interesting issue I’ve not found any clue on the web about, and the solution is based on one of those details that you can &lt;em&gt;empirically&lt;/em&gt; retrieve but that there are not documented anywhere, therefore on future releases may change without any warning. This was for example what happened to the ClassName of NETCF applications... see Daniel Moth's post about this: &amp;quot;&lt;a href="http://www.danielmoth.com/Blog/2005/12/netcfagl.html" target="_blank"&gt;#NETCF_AGL_&lt;/a&gt;&amp;quot;. I’ve also discussed about this in a &lt;a href="http://social.msdn.microsoft.com/Forums/en-US/netfxcompact/thread/c251a7c7-d063-4414-9557-b5ece54df591"&gt;MSDN Forum post&lt;/a&gt; I found interesting, where the topic was something like “&lt;em&gt;how to prevent the CLR to not allow a second instance of the same NETCF application to run on Windows Mobile&lt;/em&gt;”. As I probably wrote elsewhere, “undocumented” doesn’t mean “technically not achievable”: it means that Product Group may change it as it doesn’t have to be backward-compatible.&lt;/p&gt;  &lt;p&gt;In this case we had an application that may have been updated at a later time: the ISV was wondering if there’s any way in the setup.dll of application’s CAB to specify, during uninstallation, if the uninstall is taking place during a version-upgrade or if it's a pure uninstallation. This is because, for example, the application's installation copies also some large files that user no longer needs after the uninstall and therefore are deleted: but it still needs them if the user is uninstalling a former version of the app in order to install a newer one. I hope I've been clear... &lt;img alt="smile_confused" src="http://spaces.live.com/rte/emoticons/smile_confused.gif" /&gt; Things can get more complicated by the fact that the when you do an “upgrade” of the same ap&lt;/p&gt;  &lt;p&gt;Well... we found out that there's no documented and standard way to achieve the goal, so we had to be creative - as usual... &lt;img alt="Nerd" src="http://messenger.msn.com/MMM2006-04-19_17.00/Resource/emoticons/49_49.gif" /&gt; To understand how to operate, we needed to understand the actual flow when installing\uninstalling\upgrading (=installing the CAB of a newer version of the app while a older one is installed); moreover, we had to take care a particular condition, i.e. when upgrading the user is prompted with the message “&lt;em&gt;The previous version of… Select Ok to continue or cancel to quit&lt;/em&gt;” -- and here it comes handy the “undocumented but empirically retrievable” info, that I'm going to show in a minute.&lt;/p&gt;  &lt;p&gt;The regular flow when installing and uninstalling is:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;&lt;strong&gt;Install:&lt;/strong&gt;       &lt;ol&gt;       &lt;li&gt;DLL_PROCESS_ATTACH – Setup.dll is loaded &lt;/li&gt;        &lt;li&gt;Install_Init &lt;/li&gt;        &lt;li&gt;Install_Exit &lt;/li&gt;        &lt;li&gt;DLL_PROCESS_DETACH – Setup.dll is unloaded &lt;/li&gt;     &lt;/ol&gt;   &lt;/li&gt;    &lt;li&gt;&lt;b&gt;Uninstall:&lt;/b&gt;       &lt;ol&gt;       &lt;li&gt;DLL_PROCESS_ATTACH – Setup.dll is loaded &lt;/li&gt;        &lt;li&gt;Uninstall_Init &lt;/li&gt;        &lt;li&gt;Uninstall_Exit &lt;/li&gt;        &lt;li&gt;DLL_PROCESS_DETACH – Setup.dll is unloaded &lt;/li&gt;     &lt;/ol&gt;   &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;When upgrading, the flow is as follows:&lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;DLL_PROCESS_ATTACH – SetupDLL.dll is loaded &lt;/li&gt;    &lt;li&gt;Install_Init &lt;/li&gt;    &lt;li&gt;DLL_PROCESS_DETACH – SetupDLL.dll is unloaded &lt;/li&gt;    &lt;li&gt;&lt;b&gt;Message prompt to the user to confirm uninstall of previous version&lt;/b&gt;&lt;b&gt;&lt;/b&gt;       &lt;ul&gt;       &lt;li&gt;&lt;strong&gt;Select Ok: &lt;/strong&gt;          &lt;ol&gt;           &lt;li&gt;DLL_PROCESS_ATTACH – SetupDLL.dll is loaded, *&lt;strong&gt;BUT&lt;/strong&gt;* &lt;em&gt;&lt;font color="#ff0000"&gt;the installer doesn’t know if we’re uninstalling because of a real uninstall or an upgrade&lt;/font&gt;&lt;/em&gt; &lt;/li&gt;            &lt;li&gt;Uninstall_Init &lt;/li&gt;            &lt;li&gt;Uninstall_Exit &lt;/li&gt;            &lt;li&gt;DLL_PROCESS_DETACH – SetupDLL.dll is unloaded &lt;/li&gt;            &lt;li&gt;DLL_PROCESS_ATTACH – SetupDLL.dll is loaded &lt;/li&gt;            &lt;li&gt;Install_Init &lt;/li&gt;            &lt;li&gt;Install_Exit &lt;/li&gt;            &lt;li&gt;running the exec &lt;/li&gt;            &lt;li&gt;DLL_PROCESS_DETACH – SetupDLL.dll is unloaded &lt;/li&gt;         &lt;/ol&gt;       &lt;/li&gt;        &lt;li&gt;&lt;b&gt;Select Cancel:&lt;/b&gt;           &lt;ol&gt;           &lt;li&gt;Nothing happens (setup.dll was already unloaded) &lt;/li&gt;         &lt;/ol&gt;       &lt;/li&gt;     &lt;/ul&gt;   &lt;/li&gt; &lt;/ol&gt;  &lt;p&gt;So the problem is how to let the installer know that it’s uninstalling or upgrading… the idea I had was to modify the flow this way, based on the fact that when “upgrading”, the flow involves firstly a Install_Init and secondly a Uninstall_Init; in contrast when “uninstalling” the flow doesn’t involve a first step through Install_Init:&lt;/p&gt;  &lt;p&gt;&lt;b&gt;a. &lt;/b&gt;&lt;b&gt;Install &lt;/b&gt;&lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;DLL_PROCESS_ATTACH – SetupDLL.dll is loaded &lt;/li&gt;    &lt;li&gt;&lt;strong&gt;&lt;font color="#008080"&gt;Install_Init&lt;/font&gt;&lt;/strong&gt; (&lt;em&gt;&lt;font color="#ff0000"&gt;query if the app is already installed (through the Uninstall CSP) and set a registry key or whatever, e.g.[HKLM\UpgradeKey]Upgrade=0 if it was not installed and 1 viceversa&lt;/font&gt;&lt;/em&gt;) –&amp;gt; now: &lt;strong&gt;Upgrade=0&lt;/strong&gt; &lt;/li&gt;    &lt;li&gt;Install_Exit &lt;/li&gt;    &lt;li&gt;DLL_PROCESS_DETACH – SetupDLL.dll is unloaded &lt;/li&gt; &lt;/ol&gt;  &lt;p&gt;&lt;strong&gt;b. Upgrade:&lt;/strong&gt;&lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;DLL_PROCESS_ATTACH – SetupDLL.dll is loaded &lt;/li&gt;    &lt;li&gt;&lt;strong&gt;&lt;font color="#008080"&gt;Install_Init&lt;/font&gt;&lt;/strong&gt; (&lt;em&gt;&lt;font color="#ff0000"&gt;query if the app is already installed (through the Uninstall CSP) and set a registry key or whatever, e.g.[HKLM\UpgradeKey]Upgrade=0 if it was not installed and 1 viceversa&lt;/font&gt;&lt;/em&gt;) –&amp;gt; now: &lt;strong&gt;Upgrade=1&lt;/strong&gt; &lt;/li&gt;    &lt;li&gt;DLL_PROCESS_DETACH – SetupDLL.dll is unloaded &lt;/li&gt;    &lt;li&gt;&lt;b&gt;Message prompt to the user to confirm uninstall of previous version&lt;/b&gt;       &lt;ul&gt;       &lt;li&gt;&lt;strong&gt;Select Ok: &lt;/strong&gt;          &lt;ol&gt;           &lt;li&gt;DLL_PROCESS_ATTACH – SetupDLL.dll is loaded &lt;/li&gt;            &lt;li&gt;&lt;strong&gt;&lt;font color="#0000ff"&gt;Uninstall_Init&lt;/font&gt;&lt;/strong&gt; (&lt;em&gt;&lt;font color="#ff0000"&gt;QUERY [HKLM\UpgradeKey]Upgrade and act accordingly&lt;/font&gt;&lt;/em&gt;) –&amp;gt; now: &lt;strong&gt;Upgrade=1&lt;/strong&gt; (was just set by Install_Init at point 2. of the Upgrade flow, and then it can be set back to 0) &lt;/li&gt;            &lt;li&gt;Uninstall_Exit &lt;/li&gt;            &lt;li&gt;DLL_PROCESS_DETACH – SetupDLL.dll is unloaded &lt;/li&gt;            &lt;li&gt;DLL_PROCESS_ATTACH – SetupDLL.dll is loaded &lt;/li&gt;            &lt;li&gt;Install_Init &lt;/li&gt;            &lt;li&gt;Install_Exit &lt;/li&gt;            &lt;li&gt;running the exec &lt;/li&gt;            &lt;li&gt;DLL_PROCESS_DETACH – SetupDLL.dll is unloaded &lt;/li&gt;         &lt;/ol&gt;       &lt;/li&gt;        &lt;li&gt;&lt;b&gt;Select Cancel:&lt;/b&gt;           &lt;ol&gt;           &lt;li&gt;Nothing happens (setup.dll was already unloaded) &lt;/li&gt;         &lt;/ol&gt;       &lt;/li&gt;     &lt;/ul&gt;   &lt;/li&gt; &lt;/ol&gt;  &lt;p&gt;&lt;strong&gt;c. Uninstall&lt;/strong&gt;&lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;DLL_PROCESS_ATTACH – SetupDLL.dll is loaded &lt;/li&gt;    &lt;li&gt;&lt;strong&gt;&lt;font color="#0000ff"&gt;Uninstall_Init&lt;/font&gt;&lt;/strong&gt; (&lt;em&gt;&lt;font color="#ff0000"&gt;query if we’re upgrading by looking at the registry key&lt;/font&gt;&lt;/em&gt;) –&amp;gt; now: &lt;strong&gt;Upgrade=0 &lt;/strong&gt;(it wasn’t changed by anyone) &lt;/li&gt;    &lt;li&gt;Uninstall_Exit &lt;/li&gt;    &lt;li&gt;DLL_PROCESS_DETACH – SetupDLL.dll is unloaded &lt;/li&gt; &lt;/ol&gt;  &lt;p&gt;To conclude, the idea was to:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;Install_Init creates the “Upgrade” registry key (or other info) and sets 0 if the application is NOT already installed and 1 viceversa. To check if an application is already installed I think I’ve already discussed once on the Uninstall Configuration Service Provider… yes, see &lt;a href="http://blogs.msdn.com/raffael/archive/2008/09/04/provisioning-the-uninstall-configuration-service-provider-fails-if-invoked-through-cab-or-cpf.aspx"&gt;this post&lt;/a&gt;. &lt;/li&gt;    &lt;li&gt;Uninstall_Init checks the value of the key and act accordingly (just as an example, if that’s an “uninstall” then remove some files that are no longer used) &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;p&gt;HOWEVER… &lt;img alt="smile_confused" src="http://spaces.live.com/rte/emoticons/smile_confused.gif" /&gt; this approach had a problem… what happens if user answers “Cancel” to the prompt “&lt;em&gt;The previous version of… Select Ok to continue or cancel to quit&lt;/em&gt;”? Nobody can restore [HKLM\UpgradeKey]Upgrade to 0 after that Install_Init set it to 1, and future possible “Uninstalls” are considered as “Upgrades”! So basically the problem is when user firstly doesn't accept to uninstall the previous version during upgrade and then secondly she uninstalls the previous version on her own: when doing this second action, the uninstall procedure would find that the Upgrade registry key is set to 1 and therefore would consider an upgrade even if in reality it's an uninstall. &lt;/p&gt;  &lt;p&gt;So, next question was: &lt;strong&gt;is there any programmatic way to know if user selects “Cancel” when prompted about uninstalling previous version? &lt;/strong&gt;The only way I could think at was to get ahold of the WCELOAD.EXE process and invoke GetExitCodeProcess() API to retrieve its return value: the assumption was that it was different when user hits “Cancel”… it turned out that this is true, but this approach involved an external application to be launched for example in setup.dll’s DLL_PROCESS_ATTACH, that can monitor WCELOAD.EXE and check its return value during Uninstall phase… Why an external process? Because the prompt comes up EVEN BEFORE the setup.dll can handle Install_Init. &lt;/p&gt;  &lt;p&gt;The “undocumented but empirically retrievable” info I was mentioning at the beginning is precisely the return value of WCELOAD.EXE when user hits Cancel. As I said, not being documented it may change on future releases without any notice..&lt;/p&gt;  &lt;p&gt;And now some code please!!&lt;/p&gt;  &lt;p&gt;I’m talking about the following in setup.dll: &lt;/p&gt;  &lt;blockquote&gt;   &lt;div class="csharpcode"&gt;     &lt;pre class="alt"&gt;&lt;span class="preproc"&gt;#define&lt;/span&gt; DELETE_STR(s) \&lt;/pre&gt;

    &lt;pre&gt;&lt;span class="kwrd"&gt;if&lt;/span&gt; (NULL != s) \&lt;/pre&gt;

    &lt;pre class="alt"&gt;delete [] s;&lt;/pre&gt;

    &lt;pre&gt;&amp;#160;&lt;/pre&gt;

    &lt;pre class="alt"&gt;&amp;#160;&lt;/pre&gt;

    &lt;pre&gt;HINSTANCE g_hinstModule;&lt;/pre&gt;

    &lt;pre class="alt"&gt;&amp;#160;&lt;/pre&gt;

    &lt;pre&gt;BOOL APIENTRY DllMain(&lt;/pre&gt;

    &lt;pre class="alt"&gt;    HANDLE hModule, &lt;/pre&gt;

    &lt;pre&gt;    DWORD  ul_reason_for_call, &lt;/pre&gt;

    &lt;pre class="alt"&gt;    LPVOID lpReserved&lt;/pre&gt;

    &lt;pre&gt;    )&lt;/pre&gt;

    &lt;pre class="alt"&gt;{&lt;/pre&gt;

    &lt;pre&gt;    &lt;span class="rem"&gt;//MessageBox(NULL, TEXT(&amp;quot;Now attach the debugger&amp;quot;), TEXT(&amp;quot;Test&amp;quot;), MB_OK);&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;&amp;#160;&lt;/pre&gt;

    &lt;pre&gt;    &lt;span class="kwrd"&gt;switch&lt;/span&gt; (ul_reason_for_call)&lt;/pre&gt;

    &lt;pre class="alt"&gt;    {&lt;/pre&gt;

    &lt;pre&gt;        &lt;span class="kwrd"&gt;case&lt;/span&gt; DLL_THREAD_ATTACH:&lt;/pre&gt;

    &lt;pre class="alt"&gt;        &lt;span class="kwrd"&gt;case&lt;/span&gt; DLL_THREAD_DETACH:&lt;/pre&gt;

    &lt;pre&gt;        &lt;span class="kwrd"&gt;case&lt;/span&gt; DLL_PROCESS_DETACH:&lt;/pre&gt;

    &lt;pre class="alt"&gt;            g_hinstModule = (HINSTANCE)hModule;&lt;/pre&gt;

    &lt;pre&gt;            &lt;span class="kwrd"&gt;break&lt;/span&gt;;&lt;/pre&gt;

    &lt;pre class="alt"&gt;&amp;#160;&lt;/pre&gt;

    &lt;pre&gt;        &lt;span class="kwrd"&gt;case&lt;/span&gt; DLL_PROCESS_ATTACH:&lt;/pre&gt;

    &lt;pre class="alt"&gt;              g_hinstModule = (HINSTANCE)hModule;&lt;/pre&gt;

    &lt;pre&gt;&amp;#160;&lt;/pre&gt;

    &lt;pre class="alt"&gt;              &lt;span class="rem"&gt;//check if UpgCheck.exe is already available on device (1st time it won't, but in any case we don't need it)&lt;/span&gt;&lt;/pre&gt;

    &lt;pre&gt;              LPCWSTR pszFileNameWithPath = &lt;span class="kwrd"&gt;new&lt;/span&gt; TCHAR[MAX_PATH];&lt;/pre&gt;

    &lt;pre class="alt"&gt;              pszFileNameWithPath = TEXT(&lt;span class="str"&gt;&amp;quot;\\Windows\\UpgCheck.exe&amp;quot;&lt;/span&gt;);&lt;/pre&gt;

    &lt;pre&gt;              WIN32_FIND_DATA wfdFindFileData;&lt;/pre&gt;

    &lt;pre class="alt"&gt;              HANDLE hFile = FindFirstFile(pszFileNameWithPath, &amp;amp;wfdFindFileData);&lt;/pre&gt;

    &lt;pre&gt;              &lt;span class="kwrd"&gt;if&lt;/span&gt;(hFile == INVALID_HANDLE_VALUE)&lt;/pre&gt;

    &lt;pre class="alt"&gt;              {&lt;/pre&gt;

    &lt;pre&gt;                            DELETE_STR(pszFileNameWithPath);&lt;/pre&gt;

    &lt;pre class="alt"&gt;                            &lt;span class="kwrd"&gt;break&lt;/span&gt;;&lt;/pre&gt;

    &lt;pre&gt;              }&lt;/pre&gt;

    &lt;pre class="alt"&gt;              FindClose(hFile);&lt;/pre&gt;

    &lt;pre&gt;&amp;#160;&lt;/pre&gt;

    &lt;pre class="alt"&gt;              &lt;span class="rem"&gt;//Launch external process that will monitor wceload.exe&lt;/span&gt;&lt;/pre&gt;

    &lt;pre&gt;              BOOL bRet;&lt;/pre&gt;

    &lt;pre class="alt"&gt;              SHELLEXECUTEINFO sei = {0};&lt;/pre&gt;

    &lt;pre&gt;&amp;#160;&lt;/pre&gt;

    &lt;pre class="alt"&gt;              sei.cbSize = &lt;span class="kwrd"&gt;sizeof&lt;/span&gt;(sei);&lt;/pre&gt;

    &lt;pre&gt;              sei.nShow = SW_SHOWNORMAL; &lt;/pre&gt;

    &lt;pre class="alt"&gt;              sei.lpFile = pszFileNameWithPath;&lt;/pre&gt;

    &lt;pre&gt;              sei.lpParameters = TEXT(&lt;span class="str"&gt;&amp;quot; &amp;quot;&lt;/span&gt;);&lt;/pre&gt;

    &lt;pre class="alt"&gt;              bRet = ShellExecuteEx(&amp;amp;sei);&lt;/pre&gt;

    &lt;pre&gt;&amp;#160;&lt;/pre&gt;

    &lt;pre class="alt"&gt;              &lt;span class="rem"&gt;//if (!bRet)&lt;/span&gt;&lt;/pre&gt;

    &lt;pre&gt;              &lt;span class="rem"&gt;//     MessageBox(NULL, TEXT(&amp;quot;Could not launch UpgCheck&amp;quot;), TEXT(&amp;quot;Test&amp;quot;), MB_OK);&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;&amp;#160;&lt;/pre&gt;

    &lt;pre&gt;              DELETE_STR(pszFileNameWithPath);&lt;/pre&gt;

    &lt;pre class="alt"&gt;              &lt;span class="kwrd"&gt;break&lt;/span&gt;;&lt;/pre&gt;

    &lt;pre&gt;    }&lt;/pre&gt;

    &lt;pre class="alt"&gt;&amp;#160;&lt;/pre&gt;

    &lt;pre&gt;&lt;span class="kwrd"&gt;return&lt;/span&gt; TRUE;&lt;/pre&gt;

    &lt;pre class="alt"&gt;}&lt;/pre&gt;
  &lt;/div&gt;
&lt;/blockquote&gt;
&lt;style type="text/css"&gt;

.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }&lt;/style&gt;

&lt;blockquote&gt;
  &lt;pre class="csharpcode"&gt;&amp;#160;&lt;/pre&gt;
&lt;/blockquote&gt;
&lt;style type="text/css"&gt;

.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }&lt;/style&gt;

&lt;p&gt;&lt;strong&gt;&lt;u&gt;&lt;/u&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;And I’m talking about something similar in the wceload-monitor:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;div class="csharpcode"&gt;
    &lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;int&lt;/span&gt; _tmain(&lt;span class="kwrd"&gt;int&lt;/span&gt; argc, _TCHAR* argv[])&lt;/pre&gt;

    &lt;pre&gt;{&lt;/pre&gt;

    &lt;pre class="alt"&gt;       &lt;span class="kwrd"&gt;int&lt;/span&gt; &lt;span class="kwrd"&gt;const&lt;/span&gt; MAXBUF = 32;&lt;/pre&gt;

    &lt;pre&gt;       HRESULT hr = E_FAIL;&lt;/pre&gt;

    &lt;pre class="alt"&gt;       HANDLE hProcess = NULL;&lt;/pre&gt;

    &lt;pre&gt;       BOOL bRes = FALSE;&lt;/pre&gt;

    &lt;pre class="alt"&gt;       DWORD dwRes = 0;&lt;/pre&gt;

    &lt;pre&gt;&amp;#160;&lt;/pre&gt;

    &lt;pre class="alt"&gt;       LPTSTR lpBuf = &lt;span class="kwrd"&gt;new&lt;/span&gt; TCHAR[MAXBUF];&lt;/pre&gt;

    &lt;pre&gt;       ZeroMemory(lpBuf, MAXBUF - 1);&lt;/pre&gt;

    &lt;pre class="alt"&gt;&amp;#160;&lt;/pre&gt;

    &lt;pre&gt;       &lt;span class="rem"&gt;//retrieve process handle of wceload.exe, until it's found&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;       &lt;span class="kwrd"&gt;do&lt;/span&gt;{&lt;/pre&gt;

    &lt;pre&gt;              hr = GetProcessHandleByName(TEXT(&lt;span class="str"&gt;&amp;quot;wceload.exe&amp;quot;&lt;/span&gt;), &amp;amp;hProcess);&lt;/pre&gt;

    &lt;pre class="alt"&gt;              CHR(hr);&lt;/pre&gt;

    &lt;pre&gt;              Sleep(1000);&lt;/pre&gt;

    &lt;pre class="alt"&gt;       } &lt;span class="kwrd"&gt;while&lt;/span&gt; (INVALID_HANDLE_VALUE == hProcess);&lt;/pre&gt;

    &lt;pre&gt;&amp;#160;&lt;/pre&gt;

    &lt;pre class="alt"&gt;       &lt;span class="rem"&gt;//hr = LogToFile(TEXT(&amp;quot;\r\nwceload found!\r\n&amp;quot;), g_pszFilename);&lt;/span&gt;&lt;/pre&gt;

    &lt;pre&gt;       &lt;span class="rem"&gt;//CHR(hr);&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;&amp;#160;&lt;/pre&gt;

    &lt;pre&gt;       &lt;span class="rem"&gt;//retrieve wceload.exe exit code, until it exits&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;       &lt;span class="kwrd"&gt;do&lt;/span&gt; {&lt;/pre&gt;

    &lt;pre&gt;              Sleep(1000);&lt;/pre&gt;

    &lt;pre class="alt"&gt;              bRes = GetExitCodeProcess(hProcess, &amp;amp;dwRes);&lt;/pre&gt;

    &lt;pre&gt;&amp;#160;&lt;/pre&gt;

    &lt;pre class="alt"&gt;              &lt;span class="kwrd"&gt;if&lt;/span&gt; ( !bRes )&lt;/pre&gt;

    &lt;pre&gt;              {&lt;/pre&gt;

    &lt;pre class="alt"&gt;                     &lt;span class="kwrd"&gt;goto&lt;/span&gt; Exit; &lt;span class="rem"&gt;//GetLastError&lt;/span&gt;&lt;/pre&gt;

    &lt;pre&gt;              }&lt;/pre&gt;

    &lt;pre class="alt"&gt;       } &lt;span class="kwrd"&gt;while&lt;/span&gt; (STILL_ACTIVE == dwRes); &lt;/pre&gt;

    &lt;pre&gt;       &lt;/pre&gt;

    &lt;pre class="alt"&gt;       hr = StringCchPrintf(lpBuf, &lt;/pre&gt;

    &lt;pre&gt;              LocalSize(lpBuf) / &lt;span class="kwrd"&gt;sizeof&lt;/span&gt;(TCHAR),&lt;/pre&gt;

    &lt;pre class="alt"&gt;              TEXT(&lt;span class="str"&gt;&amp;quot;ExitCode %d&amp;quot;&lt;/span&gt;),&lt;/pre&gt;

    &lt;pre&gt;              dwRes); &lt;span class="rem"&gt;//2147754005 when user select Cancel (0x80042015)&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;       CHR(hr);&lt;/pre&gt;

    &lt;pre&gt;&amp;#160;&lt;/pre&gt;

    &lt;pre class="alt"&gt;       hr = LogToFile(lpBuf, g_pszFilename);&lt;/pre&gt;

    &lt;pre&gt;       CHR(hr);      &lt;/pre&gt;

    &lt;pre class="alt"&gt;&amp;#160;&lt;/pre&gt;

    &lt;pre&gt;       &lt;span class="rem"&gt;//success&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;       hr = S_OK;&lt;/pre&gt;

    &lt;pre&gt;&amp;#160;&lt;/pre&gt;

    &lt;pre class="alt"&gt;Exit:&lt;/pre&gt;

    &lt;pre&gt;       DELETE_STR(lpBuf);&lt;/pre&gt;

    &lt;pre class="alt"&gt;&amp;#160;&lt;/pre&gt;

    &lt;pre&gt;       &lt;span class="kwrd"&gt;return&lt;/span&gt; 0;&lt;/pre&gt;

    &lt;pre class="alt"&gt;}&lt;/pre&gt;
  &lt;/div&gt;
&lt;/blockquote&gt;
&lt;style type="text/css"&gt;

.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }&lt;/style&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;p&gt;Where the helper functions are:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;div class="csharpcode"&gt;
    &lt;div class="csharpcode"&gt;
      &lt;pre class="alt"&gt;&lt;span class="rem"&gt;// **************************************************************************&lt;/span&gt;&lt;/pre&gt;

      &lt;pre&gt;&lt;span class="rem"&gt;// Function Name: GetProcessHandleByName&lt;/span&gt;&lt;/pre&gt;

      &lt;pre class="alt"&gt;HRESULT GetProcessHandleByName (LPCTSTR pszProcessName, LPHANDLE phProcessHandle)&lt;/pre&gt;

      &lt;pre&gt;{&lt;/pre&gt;

      &lt;pre class="alt"&gt;       HRESULT hr = E_FAIL;&lt;/pre&gt;

      &lt;pre&gt;&amp;#160;&lt;/pre&gt;

      &lt;pre class="alt"&gt;       &lt;span class="kwrd"&gt;if&lt;/span&gt; (pszProcessName == NULL)&lt;/pre&gt;

      &lt;pre&gt;              &lt;span class="kwrd"&gt;goto&lt;/span&gt; Exit;&lt;/pre&gt;

      &lt;pre class="alt"&gt;&amp;#160;&lt;/pre&gt;

      &lt;pre&gt;       HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);&lt;/pre&gt;

      &lt;pre class="alt"&gt;       &lt;span class="kwrd"&gt;if&lt;/span&gt; (hSnapshot == INVALID_HANDLE_VALUE)&lt;/pre&gt;

      &lt;pre&gt;              &lt;span class="kwrd"&gt;goto&lt;/span&gt; Exit;&lt;/pre&gt;

      &lt;pre class="alt"&gt;&amp;#160;&lt;/pre&gt;

      &lt;pre&gt;       *phProcessHandle = NULL;&lt;/pre&gt;

      &lt;pre class="alt"&gt;       PROCESSENTRY32 pe;&lt;/pre&gt;

      &lt;pre&gt;       pe.dwSize = &lt;span class="kwrd"&gt;sizeof&lt;/span&gt;(pe);&lt;/pre&gt;

      &lt;pre class="alt"&gt;&amp;#160;&lt;/pre&gt;

      &lt;pre&gt;       &lt;span class="kwrd"&gt;if&lt;/span&gt; (Process32First(hSnapshot, &amp;amp;pe))&lt;/pre&gt;

      &lt;pre class="alt"&gt;       {&lt;/pre&gt;

      &lt;pre&gt;              &lt;span class="kwrd"&gt;do&lt;/span&gt; {&lt;/pre&gt;

      &lt;pre class="alt"&gt;                     &lt;span class="rem"&gt;//log Exe name&lt;/span&gt;&lt;/pre&gt;

      &lt;pre&gt;                     hr = LogToFile(pe.szExeFile, g_pszFilename);&lt;/pre&gt;

      &lt;pre class="alt"&gt;                     CHR(hr);&lt;/pre&gt;

      &lt;pre&gt;                     hr = LogToFile(TEXT(&lt;span class="str"&gt;&amp;quot;\r\n&amp;quot;&lt;/span&gt;), g_pszFilename);&lt;/pre&gt;

      &lt;pre class="alt"&gt;                     CHR(hr);&lt;/pre&gt;

      &lt;pre&gt;                     &lt;/pre&gt;

      &lt;pre class="alt"&gt;                     &lt;span class="rem"&gt;//compare current Exe name with passed Process Name&lt;/span&gt;&lt;/pre&gt;

      &lt;pre&gt;                     &lt;span class="kwrd"&gt;if&lt;/span&gt; (lstrcmpi(pszProcessName, pe.szExeFile) == 0)&lt;/pre&gt;

      &lt;pre class="alt"&gt;                     {&lt;/pre&gt;

      &lt;pre&gt;                           &lt;span class="rem"&gt;//get the handle of the Exe name in case we reached the Exe we were looking for&lt;/span&gt;&lt;/pre&gt;

      &lt;pre class="alt"&gt;                           *phProcessHandle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pe.th32ProcessID);&lt;/pre&gt;

      &lt;pre&gt;&amp;#160;&lt;/pre&gt;

      &lt;pre class="alt"&gt;                           CloseHandle(hSnapshot);&lt;/pre&gt;

      &lt;pre&gt;                           &lt;span class="kwrd"&gt;return&lt;/span&gt; TRUE;&lt;/pre&gt;

      &lt;pre class="alt"&gt;                     }&lt;/pre&gt;

      &lt;pre&gt;              } &lt;span class="kwrd"&gt;while&lt;/span&gt; (Process32Next(hSnapshot, &amp;amp;pe));&lt;/pre&gt;

      &lt;pre class="alt"&gt;       }&lt;/pre&gt;

      &lt;pre&gt;&amp;#160;&lt;/pre&gt;

      &lt;pre class="alt"&gt;       &lt;span class="rem"&gt;//Success&lt;/span&gt;&lt;/pre&gt;

      &lt;pre&gt;       hr = S_OK;&lt;/pre&gt;

      &lt;pre class="alt"&gt;&amp;#160;&lt;/pre&gt;

      &lt;pre&gt;Exit:&lt;/pre&gt;

      &lt;pre class="alt"&gt;       &lt;span class="kwrd"&gt;if&lt;/span&gt; (NULL != hSnapshot)&lt;/pre&gt;

      &lt;pre&gt;              &lt;span class="rem"&gt;//UPDATE: thanks Vino!&lt;/span&gt;&lt;/pre&gt;

      &lt;pre class="alt"&gt;              &lt;span class="rem"&gt;//Contrarily to desktop Win32, don't invoke CloseHandle() to close the snapshot call.&lt;/span&gt;&lt;/pre&gt;

      &lt;pre&gt;              &lt;span class="rem"&gt;//Desktop (http://msdn.microsoft.com/en-us/library/ms682489(VS.85).aspx): &lt;/span&gt;&lt;/pre&gt;

      &lt;pre class="alt"&gt;              &lt;span class="rem"&gt;//       &amp;quot;[...] To destroy the snapshot, use the CloseHandle function.&amp;quot;.&lt;/span&gt;&lt;/pre&gt;

      &lt;pre&gt;              &lt;span class="rem"&gt;//Windows CE\Mobile (http://msdn.microsoft.com/en-us/library/aa911386.aspx): &lt;/span&gt;&lt;/pre&gt;

      &lt;pre class="alt"&gt;              &lt;span class="rem"&gt;//       &amp;quot;[...] To close a snapshot, call the CloseToolhelp32Snapshot function.&amp;quot;&lt;/span&gt;&lt;/pre&gt;

      &lt;pre&gt;              CloseToolhelp32Snapshot(hSnapshot);&lt;/pre&gt;

      &lt;pre class="alt"&gt;&amp;#160;&lt;/pre&gt;

      &lt;pre&gt;       &lt;span class="kwrd"&gt;return&lt;/span&gt; hr;&lt;/pre&gt;

      &lt;pre class="alt"&gt;}&lt;/pre&gt;

      &lt;pre&gt;&amp;#160;&lt;/pre&gt;

      &lt;pre class="alt"&gt;&amp;#160;&lt;/pre&gt;

      &lt;pre&gt;&lt;span class="rem"&gt;// **************************************************************************&lt;/span&gt;&lt;/pre&gt;

      &lt;pre class="alt"&gt;&lt;span class="rem"&gt;// Function Name: LogToFile &lt;/span&gt;&lt;/pre&gt;

      &lt;pre&gt;HRESULT LogToFile(LPTSTR szLog, LPCTSTR pszFilename)&lt;/pre&gt;

      &lt;pre class="alt"&gt;{&lt;/pre&gt;

      &lt;pre&gt;       HRESULT hr = E_FAIL;&lt;/pre&gt;

      &lt;pre class="alt"&gt;       &lt;/pre&gt;

      &lt;pre&gt;       &lt;span class="rem"&gt;//Open the handle to the file (and create it if it doesn't exist&lt;/span&gt;&lt;/pre&gt;

      &lt;pre class="alt"&gt;       HANDLE hFile = CreateFile(pszFilename, GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);&lt;/pre&gt;

      &lt;pre&gt;       &lt;span class="kwrd"&gt;if&lt;/span&gt; (INVALID_HANDLE_VALUE == hFile)&lt;/pre&gt;

      &lt;pre class="alt"&gt;              &lt;span class="kwrd"&gt;goto&lt;/span&gt; Exit;&lt;/pre&gt;

      &lt;pre&gt;&amp;#160;&lt;/pre&gt;

      &lt;pre class="alt"&gt;       &lt;span class="rem"&gt;//Set the pointer at the end so that we can append szLog&lt;/span&gt;&lt;/pre&gt;

      &lt;pre&gt;       DWORD dwFilePointer = SetFilePointer(hFile, 0, NULL, FILE_END);&lt;/pre&gt;

      &lt;pre class="alt"&gt;       &lt;span class="kwrd"&gt;if&lt;/span&gt; (0xFFFFFFFF == dwFilePointer)&lt;/pre&gt;

      &lt;pre&gt;              &lt;span class="kwrd"&gt;goto&lt;/span&gt; Exit;&lt;/pre&gt;

      &lt;pre class="alt"&gt;&amp;#160;&lt;/pre&gt;

      &lt;pre&gt;       &lt;span class="rem"&gt;//Write to the file&lt;/span&gt;&lt;/pre&gt;

      &lt;pre class="alt"&gt;       DWORD dwBytesWritten = 0;&lt;/pre&gt;

      &lt;pre&gt;       BOOL bWriteFileRet = WriteFile(hFile, szLog, wcslen(szLog) * 2, &amp;amp;dwBytesWritten, NULL);&lt;/pre&gt;

      &lt;pre class="alt"&gt;       &lt;span class="kwrd"&gt;if&lt;/span&gt; (!bWriteFileRet)&lt;/pre&gt;

      &lt;pre&gt;              &lt;span class="kwrd"&gt;goto&lt;/span&gt; Exit;&lt;/pre&gt;

      &lt;pre class="alt"&gt;&amp;#160;&lt;/pre&gt;

      &lt;pre&gt;       &lt;span class="rem"&gt;//Flush the buffer&lt;/span&gt;&lt;/pre&gt;

      &lt;pre class="alt"&gt;       BOOL bFlushFileBuffersRet = FlushFileBuffers(hFile);&lt;/pre&gt;

      &lt;pre&gt;       &lt;span class="kwrd"&gt;if&lt;/span&gt; (!bFlushFileBuffersRet)&lt;/pre&gt;

      &lt;pre class="alt"&gt;              &lt;span class="kwrd"&gt;goto&lt;/span&gt; Exit;&lt;/pre&gt;

      &lt;pre&gt;&amp;#160;&lt;/pre&gt;

      &lt;pre class="alt"&gt;       &lt;span class="rem"&gt;//Success&lt;/span&gt;&lt;/pre&gt;

      &lt;pre&gt;       hr = S_OK;&lt;/pre&gt;

      &lt;pre class="alt"&gt;&amp;#160;&lt;/pre&gt;

      &lt;pre&gt;Exit:&lt;/pre&gt;

      &lt;pre class="alt"&gt;       &lt;span class="kwrd"&gt;if&lt;/span&gt; (NULL != hFile)&lt;/pre&gt;

      &lt;pre&gt;              CloseHandle(hFile);&lt;/pre&gt;

      &lt;pre class="alt"&gt;&amp;#160;&lt;/pre&gt;

      &lt;pre&gt;       &lt;span class="kwrd"&gt;return&lt;/span&gt; hr;&lt;/pre&gt;

      &lt;pre class="alt"&gt;}&lt;/pre&gt;
    &lt;/div&gt;
    &lt;style type="text/css"&gt;
.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }&lt;/style&gt;&lt;/div&gt;
  &lt;style type="text/css"&gt;
.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }&lt;/style&gt;&lt;/blockquote&gt;
&lt;style type="text/css"&gt;

.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }&lt;/style&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;p&gt;Hope this can help someone that absolutely has to distinguish if the application needs to be uninstalled or upgraded… but maybe the code above can find other meaningful usage! &lt;img alt="smile_nerd" src="http://spaces.live.com/rte/emoticons/smile_nerd.gif" /&gt;&lt;/p&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;p&gt;Cheers,&lt;/p&gt;

&lt;p&gt;~raffaele&lt;/p&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9562504" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/raffael/archive/tags/Windows+Mobile/default.aspx">Windows Mobile</category><category domain="http://blogs.msdn.com/raffael/archive/tags/CAB/default.aspx">CAB</category><category domain="http://blogs.msdn.com/raffael/archive/tags/Win32/default.aspx">Win32</category></item></channel></rss>