tag:blogger.com,1999:blog-219993782024-03-07T00:28:39.955-08:00Windows Mobile Pocket PC Smartphone Programming<p><a href="http://windowsmobilepro.blogspot.com/2005/08/windows-mobile-pocket-pc-smartphone.html">==>Click here for the SiteMap<==</a>. Original contents with decent amount of source codes. </p>Lao Khttp://www.blogger.com/profile/13748590324739892436noreply@blogger.comBlogger45125tag:blogger.com,1999:blog-21999378.post-1148109022862829442006-05-11T00:09:00.000-07:002006-05-20T00:10:22.883-07:00Pocket PC Power Management Series 11: Play sound (for example, wav file) when a Pocket PC is suspended<p><b>Pocket PC Power Management Series 11: Play sound (for example, wav file) when a Pocket PC is suspended</b></p> <p>I am going to write a new series on Pocket PC Power Management topic: How to play sound when Pocket PC is sleeping or suspended. Let me use a simple API to achieve this purpose: PlaySound. </p> <h3>Why care? </h3> <p>If you read my previous series on the Power Management topic, you may ask why we care. If the Pocket PC sleeps, no thread can run, so PlaySound won't even be called. If the PPC is not sleeping, PlaySound is called, so why the hassle? The answer is: Yes, PlaySound will be called, but you may not hear the sound! So the title of this blog is sort of misleading. It should be changed to something like "How to make sure there is a sound when the device is suspended".</p> <p>Let us say, you write the code to request the PPC to play a wav file, even when it is suspended. A good example is the Alarm program. It might need to play a warning or ringtone at 8PM. This piece of code can be executed at 8PM, guaranteed by Windows CE OS. However, you may be disappointed not hearing any sound. Below I will explain why and how to solve the problem.</p> <h3>Why no Sound?</h3> <p>Ultimately a peripheral device needs to emit the sound. This peripheral must be powered or put into certain state so as to vibrate to produce sound waves. A good chance is: When PlaySound() is called, the Pocket PC is in such a "System Power State" that the sound peripheral is not supposed to work; or in Microsoft terms, the sound peripheral is in such a "Device Power State" mapped from the current "System Power State", that the sound peripheral might have no power, have low power or in standby mode.</p> <p>For our specific alarm example, the Pocket PC might be in a "System Power State" called "Unattended". The sound peripheral is called "wav1:", which is put into a "D4 Device Power State", mapped from "Unattended" state. "D4" means "No Power", so you won't be able to hear any sound.</p> <p>To above explanation might be too abstract. If you really need to understand those terms, please read Microsoft Platform Builder documentation on "Power Management".</p> <h3>A Possible Solution</h3> <p>A possible solution to the problem is to change the mapping, so as to change the power state of "wav1:" device. The following code snippet is doing this job:</p> <p><span style="font-family:Courier;font-size:85%;">HRESULT ChangeWav1Mapping()<br />{<br /> LRESULT lr = E_FAIL;<br /><br /> HKEY hKey = NULL;<br /> DWORD dwSubKeys = 0;<br /> DWORD dwMaxSubkeyLen = 0;<br /> TCHAR szSubkeyName[MAX_PATH];<br /><br /> lr = RegOpenKeyEx(HKEY_LOCAL_MACHINE, TEXT("\\System\\CurrentControlSet\\Control\\Power\\State"), 0, 0, &hKey);<br /> if (ERROR_SUCCESS != lr) goto FuncExit;<br /><br /> lr = RegQueryInfoKey(hKey, NULL, 0, 0, &dwSubKeys, &dwMaxSubkeyLen, NULL, NULL, NULL, NULL, NULL, NULL);<br /> if (ERROR_SUCCESS != lr) goto FuncExit;<br /><br /> for (int i=0; i<dwSubKeys; i++) {<br /> DWORD dwSubkeyNameLen = MAX_PATH-1;<br /> memset(szSubkeyName, 0, MAX_PATH*sizeof(TCHAR));<br /> lr = RegEnumKeyEx(hKey, i, szSubkeyName, &dwSubkeyNameLen, NULL, NULL, NULL, NULL);<br /> if (ERROR_SUCCESS != lr) continue;<br /> <br /> //ALERT(szSubkeyName);<br /><br /> HKEY hSubkey = NULL;<br /> lr = RegOpenKeyEx(hKey, szSubkeyName, 0, 0, &hSubkey);<br /> if (ERROR_SUCCESS != lr) continue;<br /><br /> // any wav1: ?<br /> DWORD dwValueType = 0;<br /> DWORD dwValueData = 0;<br /> DWORD dwValueDataLen = sizeof(DWORD);<br /> lr = RegQueryValueEx(hSubkey, TEXT("wav1:"), NULL, &dwValueType, (LPBYTE)&dwValueData, &dwValueDataLen);<br /> if (ERROR_SUCCESS == lr && 0 != dwValueData) {<br /> dwValueData = 0;<br /> RegSetValueEx(hSubkey, TEXT("wav1:"), NULL, REG_DWORD, (LPBYTE)&dwValueData, sizeof(DWORD));<br /> }<br /> RegCloseKey(hSubkey);<br /> }<br /><br /> RegFlushKey(hKey);<br /><br />FuncExit:<br /> if (hKey) {<br /> RegCloseKey(hKey);<br /> }<br /><br /> return S_OK;<br />}</span></p> <p>Notice this is a piece of bad code. It forces the "wav1:" device to be always powered, no matter what state the Pocket PC is in. Looks like that is the case for most Pocket PC 2003 devices, but probably not true for Pocket PC 5.0 device. So the above code effectively changes the sound behavior of PPC 5.0 device.</p> <p>The recommended API to use to <b>SetPowerRequirement</b> and <b>ReleasePowerRequirement</b>. I will talk about them in a later post.</p> <h3>Wrap Up</h3> <p>Pocket PC sleeps. Read the following two posts for basis:</p> <ul><li><a title="Pocket PC Power Management Series 3: When is My Device Sleeping, and when is it Running?" href="http://windowsmobilepro.blogspot.com/2005/10/pocket-pc-power-management-series-3.html">Pocket PC Power Management Series 3: When is My Device Sleeping, and when is it Running?</a></li><li><a title="Pocket PC Power Management Series 8: Why Pocket PC's Battery Life so Notorious?" href="http://windowsmobilepro.blogspot.com/2006/01/pocket-pc-power-management-series-8.html">Pocket PC Power Management Series 8: Why Pocket PC's Battery Life so Notorious?</a></li></ul> <p>There are ways to force the device not to sleep, or request it to run a program at certain time or upon certain event:</p> <ul><li><a title="Pocket PC Power Management Series 5: Force the Device not to Sleep: a Brutal Way?" href="http://windowsmobilepro.blogspot.com/2005/12/pocket-pc-power-management-series-5.html">Pocket PC Power Management Series 5: Force the Device not to Sleep: a Brutal Way?</a></li><li><a title="Pocket PC Power Management Series 6: Request the Device to Run: a Gentle Way" href="http://windowsmobilepro.blogspot.com/2005/12/pocket-pc-power-management-series-6.html">Pocket PC Power Management Series 6: Request the Device to Run: a Gentle Way</a></li></ul> <p>The above techniques force the CPU to run, but not necessarily other peripheral devices. In this post we talked about "wav1:" and a possible hacky way to override the power mapping.</p><div class="blogger-post-footer"><script type="text/javascript"><!--
google_ad_client = "pub-8510650669347560";
google_ad_width = 728;
google_ad_height = 90;
google_ad_format = "728x90_as";
google_ad_type = "text_image";
google_ad_channel ="";
//--></script>
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script></div>Lao Khttp://www.blogger.com/profile/13748590324739892436noreply@blogger.com9tag:blogger.com,1999:blog-21999378.post-1147417769236326652006-05-08T00:08:00.000-07:002006-05-12T00:09:29.253-07:00XXX.exe is not a valid Pocket PC Application: Troubleshooting guidelines<p><b>XXX.exe is not a valid Pocket PC Application: Troubleshooting guidelines</b></p> <p>It is not uncommon for a developer to see his/her program cannot run in the emulator or physical device, after struggling with code development, compilation error and build issues. Most typical error is like "<b>XXX.exe is not a valid Pocket PC application</b>", like the following screen cut. Hereby I am trying to write simple guidelines for troubleshooting such issue.</p> <p align="center"><img src="http://photos1.blogger.com/blogger/5783/1371/1600/PPC2003WrongSubsystemcannotrun.jpg" border="0" height="552" width="346" /></p> <h3>1. Check the Platform</h3> <p>The executable might be built for a platform that does not match the target device. For example, an executable built for x86 emulator cannot run in any physical device, which supports ARM instruction sets.</p> <p>In WM5.0, Microsoft introduces a build target called "THUMB", which is a subset of ARM instruction sets. An executable built for "THUMB" can only run in WM5.0 device or emulator. You'll get the above error message if running such executable in Pocket PC 2003 or Smartphone 2003 device.</p> <p>The way to check the platform is to use "<i>dumpbin /header <exe_file></i>", and take a look at the line exposing the "<i>machine</i>" information.</p> <p>The way to fix platform issue is to change project settings in your IDE (EVC4 or Visual Studio 2005). Both IDEs allow you to manually modify the command line option <i>/MACHINE</i>.</p> <h3>2. Check the SubSystem</h3> <p>An executable built for a lower subsystem (for example, 4.20) can run in a WM5.0 device, but not vice versa. If you try to start a program built for 5.0, you will get the warning "<b>XXX is not a valid Pocket PC application</b>".</p> <p>The way to check the subsystem is to use "<i>dumpbin /header <exe_file></i>", and take a look at the line exposing the "<i>subsystem</i>" information.</p> <p>The way to fix subsystem issue is to change project settings in your IDE (EVC4 or Visual Studio 2005). Both IDEs allow you to manually modify the command line option <i>/SUBSYSTEM</i>.</p> <h3>3. DLL HELL</h3> <p>The previous two issues are easy to identify and fix, but the third one is very concealing and hard to troubleshoot. In general, if a program needs DLLs (who does not?), the DLL must either be present in the system, or already loaded into memory. If a required DLL is not available, the warning is clear and to the point: "<b>Cannot find 'XXX.exe' (or one of its components). Make sure the path and file name are correct and all the required libraries are available."</b></p> <p>However, if the DLL is available or already loaded into memory, but the DLL does not export the required functions, CE OS could not verify that linker time dependencies are met. It shows a super-misleading warning "<b>XXX.exe is not a valid Pocket PC application</b>".</p> <p>It is hard to find which DLL causes the issue, and even harder to solve the issue. On the desktop, you can isolate yourself to certain extent by ensuring that the DLL you built and tested is the one that is loaded by the OS; one way putting the DLL in the same directory as your application. On Windows CE, to save memory, only a single copy of DLL is loaded into physical memory, and multiple processes share the single copy if all requiring such DLL.</p> <p>To confirm whether the DLL HELL causes the dreaded message, you can try to find what other processes are using the same DLL, then terminate those processes and start your first. If your program works, then definitely your issue is caused by the DLL loaded by other processes. MFC is a good suspect, since there is so many versions of MFC DLLs (although Microsoft has taken extra mile to name the MFC DLLs with version number, debug/retail, ...)</p> <h3>Wrap Up</h3> <p>Machine or SubSystem mismatch is easy to detect and fix. Please read "<a href="http://windowsmobilepro.blogspot.com/2006/04/trap-of-copying-project-settings-in.html" title="Trap of Copying Project Settings in Visual Studio 2005 (/Machine: ARM vs. Thumb, /subsystem: windowsce, 4.02 vs 5.01)">Trap of Copying Project Settings in Visual Studio 2005 (/Machine: ARM vs. Thumb, /subsystem: windowsce, 4.02 vs 5.01)</a>" for more details.</p> <p>Issue caused by DLL-mismatch is much harder to detect. If you run into the issue, and you are use MFC, there is a high possibility that multiple versions of MFC DLLs are the culprit.</p><div class="blogger-post-footer"><script type="text/javascript"><!--
google_ad_client = "pub-8510650669347560";
google_ad_width = 728;
google_ad_height = 90;
google_ad_format = "728x90_as";
google_ad_type = "text_image";
google_ad_channel ="";
//--></script>
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script></div>Lao Khttp://www.blogger.com/profile/13748590324739892436noreply@blogger.com3tag:blogger.com,1999:blog-21999378.post-1146985653602685792006-05-05T00:06:00.000-07:002006-05-07T00:07:33.616-07:00Emulator Troubleshooting/Tip 03: Quickly Establish ActiveSync Connection<p><b>Emulator Troubleshooting/Tip 03: Quickly Establish ActiveSync Connection</b></p> <p>As talked in "<a href="http://windowsmobilepro.blogspot.com/2006/04/emulator-troubleshootingtip-01-to.html" title="Emulator Troubleshooting/Tip 01: To Cradle or Not to Cradle?">Emulator Troubleshooting/Tip 01: To Cradle or Not to Cradle?</a>", when an emulator is cradled, ActiveSync uses DMA to communicate with the emulator, eliminating the error-prone TCP/TP transport. </p> <p>DMA is generally very reliable. However, quite a few times, an emulator might have difficulty to be ActiveSync'ed, after cradled. Typically a dialog like below is displayed. </p> <p align="center"><img src="http://photos1.blogger.com/blogger/5783/1371/1600/EmulatorCannotConnectAfterConnectionChange.jpg" border="0" height="295" width="486" /><br /></p> <p>I was not able to generalize under what circumstances ActiveSync did not work. It might happen if ActiveSync's "Connection Setting" is changed, or the Device Emulator Manager runs several emulators and one of which is already cradled.</p> <p>At first, I did not know any good way to fix the problem. Restart the emulator does not help at all. Killing ActiveSync or <i>wcescomm.exe</i> might worsen the issue. A lot of times I had to restart the machine.</p> <p>Accidentally I found a very quick and very reliable way to make ActiveSync connect to the emulator:</p> <p>1. Go to ActiveSync's "Connect Setting" dialog, and clear the check box "<b>Allow connections to one of the following</b>". Click OK to dismiss the dialog.</p> <p align="center"><img src="http://photos1.blogger.com/blogger/5783/1371/1600/ActiveSyncDMADisabled.jpg" border="0" height="312" width="454" /></p> <p>2. Again, go to ActiveSync's "Connect Setting" dialog, and check the check box "<b>Allow connections to one of the following</b>". Make sure DMA is chosen. Click OK to dismiss the dialog.</p> <p align="center"><img src="http://photos1.blogger.com/blogger/5783/1371/1600/ActiveSyncDMAEnabled.jpg" border="0" height="312" width="454" /></p> <p>In my cases, a cradled-emulator will be successfully ActiveSync'ed, guaranteed!</p> <p><span style="font-style: italic; font-weight: bold;">A little off-topic</span>: When ActiveSync 4.0 were released, there were so many issues that Microsoft had to publish a special memo to partners, listing all possible workarounds and promising a quick release of ActiveSync 4.1. Actually when I got a PPC6700 device from Sprint before it was released to mass-market, I had so many troubles making ActiveSync 4 work with the device, that the Sprint support recommended me to format and install a new machine, without installing any other software and without enabling any firewall, and dedicate the machine to ActiveSync 4 and the device. What a nice workaround!</p><div class="blogger-post-footer"><script type="text/javascript"><!--
google_ad_client = "pub-8510650669347560";
google_ad_width = 728;
google_ad_height = 90;
google_ad_format = "728x90_as";
google_ad_type = "text_image";
google_ad_channel ="";
//--></script>
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script></div>Lao Khttp://www.blogger.com/profile/13748590324739892436noreply@blogger.com1tag:blogger.com,1999:blog-21999378.post-1146901518747061962006-05-03T00:44:00.000-07:002006-05-06T00:45:18.763-07:00Pocket PC Console for standard input and standard output: A convenient tool for lazy debugging and tracing in Pocket PC 2003 devices<p><b>Pocket PC Console for standard input and standard output: </b><b>A convenient tool for lazy debugging and tracing in Pocket PC 2003 devices<br /></b></p> <p>Debugging and tracing sometimes can be a tricky business, especially for a multi-threaded program. </p> <ul><li>Log file is used most commonly. </li><li><i>OutputDebugString</i> is also nice, and there is no need to write any code to deal with a log file. However, you do need to attach the debugger to receive the debugging message. </li></ul> <p>Probably the simplest approach, requiring neither a log file nor a debugger, is the famous <i>printf </i>(or the C# equivalent <i>Console.Write</i>, or the Java equivalent <i>System.out.println</i>). The simplicity of using <i>printf</i>, and the beautify of showing messages on a console in real time, make <i>printf</i> a very nice tool for lazy programmers :) </p> <h3>Pocket PC Shell</h3> <p>Unfortunately there is no built-in console (therefore no standard input and standard output) in Windows Mobile devices. Even if your code compiles and builds correctly, there is no way you can see the messages.</p> <p>One tool coming for rescue is PPC Command Shell, part of Microsoft <a href="http://www.microsoft.com/downloads/details.aspx?FamilyID=74473fd6-1dcc-47aa-ab28-6a2b006edfe9&DisplayLang=en">Windows Mobile Developer Power Toys</a>. See my article "<a href="http://windowsmobilepro.blogspot.com/2006/04/how-to-launch-program-via-command-line.html" title="How to launch a program via command line in Pocket PC 2003 device and Pocket PC 5.0 device?">How to launch a program via command line in Pocket PC 2003 device and Pocket PC 5.0 device?</a>" for a brief introduction on those nice little tools.</p> <ul><li><b><i>PPC Command Shell </i></b>- Command shell for the Pocket PC 2003 device.</li></ul> <p>Once installed, three files can be found in the desktop PC's destination folder:</p> <ul><li><i>console.dll</i>: copying it to the device's \Windows folder</li><li><i>shell.exe</i>: copying it to any folder in the device</li><li><i>cmd.exe</i>: copying it to any folder in the device</li></ul> <p>The only files needed for <i>printf </i>to work are <i>console.dll </i>and <i>shell.exe</i>. These two provide the console, supporting standard input and standard output. Once invoked, <i>shell.exe </i>stays in the memory. In fact, upon running, <i>shell.exe </i>put an entry under registry <i>HKLM\Init</i>,<i> </i>so as to make sure itself is always up and running (even before the OS kernel components, like <i>device.exe</i>, <i>gwes.exe</i>, and etc.)</p> <blockquote> <pre>[HKEY_LOCAL_MACHINE\init]<br />"Launch10"="shell.exe"</pre> </blockquote> <p>The executable <i>cmd.exe </i>is not needed. It solely provide implementations of some commonly used DOS prompt commands, for example, dir, cd.</p> <p>Below is a simple testing program:</p> <blockquote> <pre>printf("This is a test");<br />MessageBox(NULL, TEXT("Console Test!"), TEXT("Demo"),<br /> MB_ICONINFORMATION|MB_OK|MB_SETFOREGROUND|MB_OK);</pre> </blockquote> <p>And here is the screen cut when the program runs:</p> <p><img src="http://photos1.blogger.com/blogger/5783/1371/1600/ConsoleTestingPPC2003.0.jpg" border="0" height="324" width="239" /></p> <p>Warning: This tool does not work in Pocket PC 5.0 device, nor does it work in any Smartphone device. In fact, the following warning is popped up if running in Smartphone 2003 device:</p> <p><img src="http://photos1.blogger.com/blogger/5783/1371/320/ConsoleNotWorkingSP2003.jpg" border="0" height="224" width="179" /></p> <p> </p> <h3>Wrap Up</h3> <p>Pocket PC Shell is a simple yet powerful tool for debugging or tracing in real time. However, the one packaged in Microsoft's Mobile Power Toy can only work in Pocket PC 2003 device (inclduing 2003 SE).</p> <p>There is <a href="http://www.symbolictools.de/public/pocketconsole/index.htm">another free tool</a> but I've never tested it. Looks like it has not been updated for quite a while.</p> <p>Notice: Never compile <i>printf</i> into your release build! The <i>printf </i>and console processing code are not simple thus sort of eating the CPU!</p> <p> </p> <p> </p> <p> </p> <p> </p> <p> </p><div class="blogger-post-footer"><script type="text/javascript"><!--
google_ad_client = "pub-8510650669347560";
google_ad_width = 728;
google_ad_height = 90;
google_ad_format = "728x90_as";
google_ad_type = "text_image";
google_ad_channel ="";
//--></script>
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script></div>Lao Khttp://www.blogger.com/profile/13748590324739892436noreply@blogger.com4tag:blogger.com,1999:blog-21999378.post-1146468692230160242006-04-30T00:30:00.000-07:002006-05-04T23:27:59.906-07:00Trap of Copying Project Settings in Visual Studio 2005 (/Machine: ARM vs. Thumb, /subsystem: windowsce, 4.02 vs 5.01)<p><b>Trap of Copying Project Settings in Visual Studio 2005 (/Machine:ARM vs. Thumb, /subsystem:windowsce,4.02 vs 5.01)</b></p> <p>Visual Studio 2005 offers developers with a nice option when a new project platform needs to be created: to copy project settings for one platform to the new platform.</p> <h3>How Copying Project Setting works?</h3> <p>Typical use case is that you already have a project for Pocket PC 2003, and you want to create a new project targeting Pocket PC 5.0 device. You can bring up "<b>Project Settings</b>" dialog, and click "<b>Configuration Manager</b>" button to "<b>New</b>" the project for 5.0 platform, and opt to copy from the project setting for 2003 platform.</p> <p>Visual Studio takes care quite a few changes automatically, for example, output directory, windows CE version, and PPC/Smartphone platform. The mechanism to cover the changes is using Macros extensively. Below are two typical macros:</p> <ul><li>Windows CE version difference:<b> $(CEVer)</b>. 4.20 for 2003 platform, and 5.01 for 5.0 plaform.</li><li>Platform difference: <b>$(CEPlatform) / $(CePlatform) / $(PLATFORMDEFINES)</b>. <b>WIN32_PLATFORM_WFSP</b> for Smartphone, and <b>WIN32_PLATFORM_PSPC</b> for Pocket PC.</li></ul> <h3>Issue of Blindly Copying Project Settings from Newer Platform to Older Platform</h3> <p>It is worthy noting that VS2005 does not adjust two important options for its linker while copying project settings: </p> <ul><li><b>/SUBSYSTEM </b>option, which tells the targeting OS how to run the .exe file, and affects the entry point symbol (or entry point function) that the linker will choose. </li><li><b>/MACHINE </b>option, which specifies the target platform for the program, for example, X86, X64, IA64, MIPS, SH4, and etc.</li></ul> <p>If you create a new Smart Device project, possibly <b>/MACHINE </b>is not set explicitly, and <b>/SUBSYSTEM </b>is hard coded to be the number most suitable for the project. For example, if you create a project for Pocket PC 5.0 platform, <b>/MACHINE </b>is not set (so default to <b>THUMB</b>), and <b>/SUBSYSTEM </b>is set to 5.01.</p> <p>If such settings are blindly copied to another project for older platform (in this case, Pocket PC 2003), the final binary won't be executed by PPC2003 device.</p> <h3>Walkthrough of the issue</h3> <p>1. A new solution is created, and a new Smart Device project targeting Pocket PC 5.0 platform is created. </p> <ul><li>"Project Setting"=>"Linker"=>"System"=>"SubSystem" is not set. </li><li>"Project Setting"=>"Linker"=>"Advanced"=>"Target Machine" is not set either. </li></ul> <p>Command line option will be like "<b> /subsystem:windowsce,5.01"</b></p> <p>Do a "<b>dumpbin /all</b>" on the executable generated by VS2005, you'll see something like this, meaning the binary is for Thumb machine and CE version should be 5.01 or higher.</p> <blockquote> <pre>FILE HEADER VALUES<br /> 1C2 machine (Thumb)<br />OPTIONAL HEADER VALUES<br /> 5.01 subsystem version</pre> </blockquote> <p>2. The executable for Pocket PC 5.0 runs great in a 5.0 device. Now you want propagate its success to Pocket PC 2003 devices, so a new project targeting PPC2003 platform is created using Configuration Manager. In its "Active solution platform" dropdown list, you select "New", and "Copy settings from" the Pocket PC 5.0 platform.</p> <p><img src="http://photos1.blogger.com/blogger/5783/1371/1600/PPC2003CopiedFromPPC5.jpg" border="0" height="234" width="339" /></p> <p>3. For the new project to build, <a href="http://windowsmobilepro.blogspot.com/2005/08/manually-migrate-embedded-visual-c.html">you may need to add "secchk.lib" to lib dependency list if you have at least one function call, and add "ccrtrtti.lib" to lib dependency list if you have at least one C++ source file</a>. However, if you run the executable, you'll get the infamous error dialog:</p> <p><img src="http://photos1.blogger.com/blogger/5783/1371/1600/PPC2003WrongSubsystemcannotrun.jpg" border="0" height="552" width="346" /></p> <p>4. Do a "<b>dumpbin /all</b>" on the executable for PPC2003 platform, you'll see that the executable is for THUMB machine and CE OS must be 5.01 or higher, exactly the same as the one for PPC5.0 device. To fix it, you need to change the linker option to something like "<b> /subsystem:windowsce,4.20 /machine:ARM</b>".</p> <p>Rebuild and you'll get a good executable with the following header values:</p> <blockquote> <pre>FILE HEADER VALUES<br /> 1C0 machine (ARM)<br />OPTIONAL HEADER VALUES<br /> 4.20 subsystem version</pre> </blockquote> <p>Notice you must change both <b>/subsystem</b> and <b>/machine</b>, otherwise it won't work!</p> <h3>Wrap Up</h3> <p>VS2005 seems to copy the project setting literally. It resolves the fundamental differences (OS, PPC or Smartphone, directories) by expanding Macros, for example, <b>$(CEVer) </b>and <b>$(CEPlatform)</b>. However, <b>/MACHINE</b> and <b>/SUBSYSTEM </b>are either not specified, or hard-code to be a number, resulting in wrong values to be used in the newly-created project. Such mismatch probably is not a big issue if the new project is for newer platform (for example, copying PPC2003 settings to PPC5.0 project), but definitely causes headache is the new project is for an older platform (for example, copying PPC5.0 settings to PPC2003 project).</p> <p><i>A Side Topic</i>: The THUMB instruction set consists of 16-bit instructions that act as a compact shorthand for a subset of the 32-bit instructions of the standard ARM. The binary built for THUMB is typically with the size roughly 70-80% that of ARM. Unfortunately binary compiled for THUMB cannot be executed in Windows Mobile 2003 devices.</p><div class="blogger-post-footer"><script type="text/javascript"><!--
google_ad_client = "pub-8510650669347560";
google_ad_width = 728;
google_ad_height = 90;
google_ad_format = "728x90_as";
google_ad_type = "text_image";
google_ad_channel ="";
//--></script>
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script></div>Lao Khttp://www.blogger.com/profile/13748590324739892436noreply@blogger.com2tag:blogger.com,1999:blog-21999378.post-1146381159700715012006-04-28T00:11:00.000-07:002006-04-30T18:07:41.800-07:00/etc/hosts file equivalent in Windows Mobile device<p><b>/etc/hosts file equivalent in Windows Mobile device</b></p> <p>As you know, the "hosts" file in Windows and other operating systems is used to associate host names with IP addresses. When TCP/IP networking stack tries to resolve a host name to its IP address, it first consults the local hosts file to see whether such mapping is already available. If not, domain name (DNS) server is then consulted. For example, all machines' hosts file might contain the following line:</p> <blockquote> <p><span style="font-family:Courier New;">127.0.0.1 localhost</span></p> </blockquote> <p>It maps "localhost" to the loopback address. There is no magic; the TCP/IP stack won't treat "localhost" differently from "<a href="http://www.mit.edu/">www.mit.edu</a>" when it tries to resolve the string name. (For curious mind, the difference comes when IP stack realizes that the IP's first number is 127, a special number.)</p> <h3>Why hosts-like functionality is needed for Windows Mobile device?</h3> <p>Windows Mobile devices does not have the concept of HOSTS file. <a href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/wcetcpip/html/cmconhostnameresolution.asp">DNS or WINS is always used</a>. However, a hosts-file-like capability might be useful in certain cases. Below I listed a few possible cases:</p> <ul><li><b>Corporate intranet</b>: In a corporate intranet environment, quite possibly a large number of Windows Mobile devices are used. Unlike desktop PCs or Linux/Solaris servers, handheld device does not have a good way for naming, thus typically give IT department more management overhead. Distributed a common hosts file to all Windows Mobile devices is one way to manage.</li><li><b>Some special APIs</b>: A typical example is <a href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/mobilesdk5/html/mob5oriMessageQueuing.asp">MSMQ for Windows Mobile devices</a>. In MSMQ, a message queue can be referenced by its path name in the form of "MachineName\QueueName". So able to resolve machine name is essential for MSMQ application to work.</li><li><b>Home or Home Office</b>: At your home you may have a wireless router, several PCs and Windows Mobile devices, all having static-assigned IPs or DHCP-ed IPs. And, you need to sync a device with a home PC over wireless. The trouble is that ActiveSync in the device side needs the name of the desktop PC where ActiveSync is also running, and there is no way for the device to resolve the desktop PC's name (unless you really want to run a WINS service in one desktop PC and configure your device to use the WINS service for name resolution.)</li></ul> <h3>How to make "hosts" in Windows Mobile devices for name resolution?</h3> <p>Although there is no hosts file in Pocket PC or Smartphone's file-system, registry is the place to put such name-IP mappings. To achieve this, add a subkey to <b>HKEY_LOCAL_MACHINE\Comm\Tcpip\Hosts</b> for each machine name that must be resolved, then add binary values for the IP address (value name "ipaddr") and expiration time (value name "<b>expiretime</b>"). The following shows the export of a key entry that resolves the name "hello" to IP address 161.163.165.169. <b>Expiretime</b> is a huge number, indicating no expiration. For the sole purpose of name resolution, <b>expiretime</b> is not strictly needed.</p> <blockquote> <pre class="clsCode">[HKEY_LOCAL_MACHINE\Comm\Tcpip\Hosts\hello]<br />"ipaddr"=hex:a1,a3,a5,a9<br />"ExpireTime"=hex:99,99,99,99,99,99,99</pre> </blockquote> <p>Below are the screen shots how to manually add the entry using Remote Registry Editor.</p> <p align="left"><img src="http://photos1.blogger.com/blogger/5783/1371/1600/HostsRegistrySettings.jpg" border="0" height="238" width="640" /></p> <p>Below is the screen cut shows testing name resolution in the device. The following simple code is used:</p> <pre>C++:<br />HOSTENT* pHostent = gethostbyname(pchHostName)<br />or C#:<br />System.Net.Dns.Resolve(hostName)</pre> <div align="left"> <pre><img src="http://photos1.blogger.com/blogger/5783/1371/1600/HostsResolved.jpg" border="0" height="475" width="350" /></pre> </div> <h3 align="left">Wrap Up</h3> <p align="left">If you only need to take care of one or two name-IP mappings, manually adding them to the registry is do-able. For large number of names, Pocket Hosts is an ideal free utility for such task.</p> <p align="left">People with good eyesight might notice a subkey called "<b>ppp_peer</b>" in one of screen shots. </p> <blockquote> <pre>[HKEY_LOCAL_MACHINE\Comm\Tcpip\Hosts\ppp_peer]<br />"aliases"=hex(7): 00<br />"ipaddr"=hex: c0,a8,37,64</pre> </blockquote> <p align="left">"<b>ppp_peer</b>" is the name the device gives to the desktop PC during ActiveSync. It maps to IP "c0,a8,37,64" ("192.168.55.100"). In the device side itself, the IP is "192.168.55.101". </p> <h3 align="left">Update on the Wrap Up</h3> <p align="left">In Windows Mobile 5.0 devices, ActiveSync in the device gives desktop PC a new name: "<b>dtpt_peer</b>", which maps to IP "A9,FE,02,02" (169.254.2.2). In the device side itself, the IP is "169.254.2.1". </p> <p align="left">Looks like in Windows Mobile 5.0 emulators (and Windows Mobile 2003 devices), "<b>ppp_peer</b>" is still used.</p> <p align="left"><i>A little bit on why "<b>ppp_peer</b>" or "<b>dtpt_peer</b>" is needed for ActiveSync</i>: When a windows mobile device plus in a desktop PC, a new network interface is created in the desktop PC. This NIC is named like "Windows Mobile-based Device #n", and its IP is hard coded to be "169.254.2.2". New entries are also added to the PC's routing table, so as to route IP packets destined to 169.254.2.X to only the Window Mobile device. </p> <p align="left">You may notice when your device is cradled, a small tray icon like networking icon, with a plus sign turning left and right, trying to acquire a network address. You can also try typing "ipconfig /all" and "route print" in a command prompt to play with the this NIC.</p> <p align="left">As far as I know, you cannot explicitly bind to this specific NIC (disclaimer: Never tried myself.)</p><div class="blogger-post-footer"><script type="text/javascript"><!--
google_ad_client = "pub-8510650669347560";
google_ad_width = 728;
google_ad_height = 90;
google_ad_format = "728x90_as";
google_ad_type = "text_image";
google_ad_channel ="";
//--></script>
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script></div>Lao Khttp://www.blogger.com/profile/13748590324739892436noreply@blogger.com14tag:blogger.com,1999:blog-21999378.post-1146206383505893182006-04-26T23:38:00.000-07:002006-04-30T11:34:49.623-07:00Pocket Outlook Woe 02: Domain name is truncated to the same size as password after calling IMailSyncCallBack :: RequestCredentials<p><b>Pocket Outlook Woe 02: Domain name is truncated to the same size as password after calling IMailSyncCallBack::RequestCredentials</b></p> <p>In "<a href="http://windowsmobilepro.blogspot.com/2006/04/pocket-outlook-woe-01-incoming-server.html" title="Pocket Outlook Woe 01: incoming server and outgoing server are passed as two NULL pointers from Outlook to Transport">Pocket Outlook Woe 01</a>", I talked about one issue regarding the latest version of Pocket Outlook (installed with Windows Mobile 5.0 devices, and newer version of Pocket PC 2003 SE devices), that Pocket Outlook passes two NULL pointers as incoming mail server and outgoing mail server to a customized Transport. Today I am focusing on the second woe: domain name is truncated to the same size as that of password after <b>IMailSyncCallBack::RequestCredentials</b> is returned.</p> <h3>IMailSyncCallback: Pocket Outlook itself</h3> <p>The method involved here is called <b>IMailSyncCallBack::RequestCredentials</b>. <b>IMailSyncCallback</b> can be understood as Outlook itself, which provides Transport with methods to interact with Outlook. For example, Transport can:</p> <ul><li>request memory in tmail.exe's address space</li><li>request Outlook to synchronize an account</li><li>request Outlook to display a message box</li></ul> <p>The method giving headache here is <span style="font-weight: bold;">RequestCredentials</span>, which is used by Transport to request new credentials from the user. </p> <blockquote> <b>HRESULT RequestCredentials (</b> <b>LPCWSTR </b><i>pszProfile</i><b>,</b> <b>SYNCCREDENTIALS * </b><i>ppcredsSource</i><b>,</b> <b>SYNCCREDENTIALS ** </b><i>ppcreds</i> <b>);</b> </blockquote> <p>This is a blocking call. Once called, Outlook shows a dialog to the user asking username, password and domain name. Results won't be returned to Transport until after the user clicks "OK" or "Cancel" in the dialog.</p> <h3>Domain name is truncated!</h3> <p>This simple API works greatly in previous version of Pocket Outlook. However, in the newer version, domain name is always truncated to the same size as that of password. Below are some screen cuts with illustrations:</p> <p>Screen 1: <b>RequestCredentials</b>() is called. Domain name is "aa.com" (6 characters), password is "12345"</p> <p align="center"><img src="http://photos1.blogger.com/blogger/5783/1371/320/TransportDemoPasswd12345.jpg" border="0" height="320" width="240" /></p> <p>Screen 2: <b>RequestCredentials</b>() returns with a new credential (in parameter <i>ppcreds</i>). Notice domain name is truncated to "aa.co". </p> <p align="center"><img src="http://photos1.blogger.com/blogger/5783/1371/320/TransportDemoDomainTruncated.jpg" border="0" height="320" width="240" /></p> <p>Screen 3: <b>RequestCredentials</b>() is called again. Now parameter <i>ppcreds</i> is copied to <i>ppcredsSource.</i></p> <p align="center"><img src="http://photos1.blogger.com/blogger/5783/1371/320/TransportDemoDomainTruncatedReAsk.jpg" border="0" height="320" width="240" /></p> <p>Screen 4: Let us revert the domain name back to "aa.com", but type "123" as the password.</p> <p align="center"><img src="http://photos1.blogger.com/blogger/5783/1371/1600/TransportDemoPasswd123DomainFull.jpg" border="0" height="320" width="240" /></p> <p>Screen 5: <b>RequestCredentials</b>() returns with another new credential. Now the domain name is truncated to "aa."</p> <p align="center"><img src="http://photos1.blogger.com/blogger/5783/1371/1600/TransportDemoDomainTruncatedMore.jpg" border="0" height="320" width="240" /></p> <h3>Source code used</h3> <p>The source code is adapted from TransportDemo, really seemingly simple and innocent code.</p> <p><span style=";font-family:Courier New;font-size:85%;" >HRESULT CTransportSyncHandler::Connect(<br /> DWORD dwReserved,<br /> SYNCCREDENTIALS* pCredentials<br />)<br />{<br /> HRESULT hr = S_OK;<br /> SYNCCREDENTIALS * pCurrentCreds = pCredentials;<br /> ULONG cTries = 0;<br /><br /> // The transport is no longer shut down<br /> ASSERT(m_hEventShutdown != NULL);<br /> m_fShutDown = FALSE;<br /> ResetEvent(m_hEventShutdown);<br /><br /> //while(TRUE)<br /> while(cTries <= 4) {<br /> // Do we need to prompt for account info?<br /> if(cTries || *pCurrentCreds->pszPassword == L'\0') {<br /> SYNCCREDENTIALS * pNewCreds = NULL;<br /> <br /> // Make a request to the Inbox for logon credentials.<br /> hr = m_pCallback->RequestCredentials(m_pszProfile, pCurrentCreds, &pNewCreds);<br /> if(FAILED(hr)) {<br /> // Log an error...<br /> if (!m_fShutDown) {<br /> LogErrorEvent(CEMAPI_E_NO_ACCOUNT_INFO, 0);<br /> }<br /> break;<br /> }<br /> <br /> // pNewCreds now contains the new info from the user.<br /> ASSERT(pNewCreds != NULL);<br /> <br /> // Check to see if 'pCurrentCreds' is *not* the ones passed in.<br /> // If they are not, then we need to free them. This will happen<br /> // if the user has been asked more than once for the password.<br /> if(pCurrentCreds != pCredentials) {<br /> m_pCallback->FreeMem(pCurrentCreds);<br /> }<br /><br /> // what is the new credential<br /> {<br /> TCHAR szInfo[1024];<br /> swprintf(szInfo, TEXT("After RequestCredentials>>\nUserName: %s\nPassword: %s\nDomain: %s"), pNewCreds->pszUsername, pNewCreds->pszPassword, pNewCreds->pszDomain);<br /> ALERT(szInfo);<br /> }<br /> <br /> pCurrentCreds = pNewCreds;<br /> }<br /> <br /> // Now try to connect to the mail server<br /> // [ Omitted ]<br /> hr = E_ACCESSDENIED;<br /> <br /> // [ Assumed to return hr ]<br /> if(FAILED(hr)) {<br /> if (!m_fShutDown) {<br /> LogErrorEvent(hr, 0);<br /> }<br /> <br /> //break;<br /> // retry instead<br /> }<br /> <br /> if(m_fShutDown) {<br /> hr = E_FAIL;<br /> break;<br /> }<br /> <br /> // Log in to the mail server<br /> SetStatusText(0/*IDS_TRANSPORT_CONNECTING*/); // TODO: Use an appropriate string resource<br /> // [ Omitted ]<br /> // [ Assumed to return hr ]<br /> <br /> // If the logon succeeded, we're done<br /> if(SUCCEEDED(hr)) {<br /> break;<br /> }<br /> <br /> // If we failed due to anything but authentication errors,<br /> // log the error and bail out<br /> if(hr != E_ACCESSDENIED) {<br /> // Log an error back to the application if user didn't himself ask for shutdown<br /> if (!m_fShutDown) {<br /> LogErrorEvent(hr, 0);<br /> }<br /> break;<br /> }<br /> <br /> // No success! Need to hang up and ask the user for new<br /> // credentials.<br /> ++cTries;<br /><br /> // Disconnect from the mail server<br /> // [ Omitted ]<br /> // [ Assumed to return hr ]<br /> } // while(TRUE)<br /><br /> if(FAILED(hr)) {<br /> // Disconnect from the mail server<br /> // [ Omitted ]<br /> // [ Assumed to return hr ]<br /> }<br /><br /> return hr;<br />}<br /></span></p> <h3 align="left">Wrap Up</h3> <p align="left">Similar to <a href="http://windowsmobilepro.blogspot.com/2006/04/pocket-outlook-woe-01-incoming-server.html">Outlook Woe 1</a>, I tried to disable the device security, or sign the transport DLL using a certificate, but the problem persists.</p> <p align="left">This seems affecting not only Windows Mobile 5.0 device, but also newer version of Pocket PC 2003 SE device, where the newer version of Outlook is shipped. The old version of Pocket Outlook actually does NOT show domain-name input box in the credential request dialog.</p> <p align="left">As a workaround, the user might be required to have a password with the size not shorter than the domain name. For example, "microsoft.com" employee must have a password with at least 13 characters. This sounds like a ridiculous requirement. So again the burden lies on the shoulder of transport developers, who might remember the "original" domain name in a place, and ignore the one passed by <b>IMailSyncCallback</b>. Hereby "original" domain name refers to the one passed by <b>IMailSyncCallback</b> the first time <b>RequestCredentials</b>() is called. Alternatively, registry can be used to store the domain information, rather than relying on Outlook. However, this means that the user cannot change the domain settings via Outlook.</p> <p align="left">Also similar to <a href="http://windowsmobilepro.blogspot.com/2006/04/pocket-outlook-woe-01-incoming-server.html">Outlook Woe 1</a>, the POP3 transport and IMAP4 transport shipped along with Pocket Outlook seem immune to the issue. Could it because the TransportDemo code is not doing the correct thing in its <b>Connect</b>() method?</p><div class="blogger-post-footer"><script type="text/javascript"><!--
google_ad_client = "pub-8510650669347560";
google_ad_width = 728;
google_ad_height = 90;
google_ad_format = "728x90_as";
google_ad_type = "text_image";
google_ad_channel ="";
//--></script>
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script></div>Lao Khttp://www.blogger.com/profile/13748590324739892436noreply@blogger.com0tag:blogger.com,1999:blog-21999378.post-1146115197462206172006-04-24T22:18:00.000-07:002006-04-26T23:55:06.150-07:00Emulator Troubleshooting/Tip 02: Emulator Connecting to Internet (Internet Pass-through Connectivity) Issue<p><b>Emulator Troubleshooting/Tip 02: Emulator Connecting to Internet (Internet Pass-through Connectivity) Issue</b></p> <p>The post "<a href="http://windowsmobilepro.blogspot.com/2006/04/emulator-troubleshootingtip-01-to.html" title="Emulator Troubleshooting/Tip 01: To Cradle or Not to Cradle?">Emulator Troubleshooting/Tip 01: To Cradle or Not to Cradle?</a>" is mainly regarding basic knowledge of the new Emulators. Essentially DMA channel is used by Visual Studio and Remote Tools to communicate with the Emulator. It is really NOT that necessary to always ActiveSync an emulator. </p> <h3>Internet Pass-through Connectivity</h3> <p>However, in a lot of cases, the emulator needs to be cradled and ActiveSync'ed. One common requirement is that the emulator wants to use host PC's networking capability, as if it were its own. You can use this feature to perform tasks such as downloading POP3 or IMAP4 email messages, to connect directly with a remote server, or to browse the Internet. This feature is called "Internet Pass-Through". <a href="file:///E:/Wireless/Docs/Leisure/windowsmobilepro.blogspot.com/2006/04/emulator-troubleshootingtip-01-to.html">My post</a> briefly talks about how to make it. <a href="http://blogs.msdn.com/akhune/archive/2005/11/16/493329.aspx">An excellent post</a> from a Microsoft employee shows much detailed steps with screen cuts.</p> <p>However, the Microsoft post and a lot of other similar articles only mention what to do in the emulator side. I want to emphasize here that you also need to take care of the ActiveSync side. <b>ActiveSync needs to be instructed whether the host computer is connected to "Work Network" or "The Internet"</b>. See below for a screen cut and how to do it:</p> <ol type="1"><li>Click <b>Connection Settings</b>. </li><li>Select <b>Open ActiveSync when my device connects</b>. </li><li>In the <b>This computer is connected to</b> list, select a connection to which this computer should connected when passing through ActiveSync.</li></ol> <p align="center"><img src="http://photos1.blogger.com/blogger/5783/1371/1600/ActiveSyncInternetPassthrough.jpg" border="0" height="312" width="454" /> </p> <p align="left">If you are not sure what network to use, choose "Automatic". Hopefully ActiveSync can automatically find out which network the host PC is connected and adjust emulator's setting accordingly. </p> <h3>My Use Case</h3> <p>I am not the lucky one that ActiveSync magically finds out the network to use. It took me 30 minutes to figure out why all of a sudden the emulator in my home PC could not browse internet. Basically the ActiveSync setting is somewhat mysteriously changed to either "Work Network" or "The Internet". Here is my story:</p> <p>I am using Comcast cable for internet access at home. Occasionally, when I work from home, I run a VPN software in my home PC to place it into the company's intranet. Once in the intranet, any external web site can only be accessed via a proxy server.</p> <p>Therefore, the emulator in my home PC needs to have internet access in two distinct cases:</p> <ul><li>My home PC is inside the corporate intranet. In the emulator side, a proxy server must be configured. In ActiveSync side, "Work Network" or "Automatic" must be used. The emulator cannot browse internet if "The Internet" is chosen in ActiveSync.</li><li>After business hour, my home PC is directly connected to the public internet. In the emulator side, no special action needs to be taken. In ActiveSync side, "The Internet" or "Automatic" must be chosen. Again, the emulator won't connect if "Work Network" is chosen in ActiveSync.</li></ul> <h3>Wrap Up</h3> <p>Next time when you fight with your emulator that cannot browse a public site, not only check whether the emulator is cradled and ActiveSync'ed successfully, but also check whether ActiveSync side is setup properly!</p><div class="blogger-post-footer"><script type="text/javascript"><!--
google_ad_client = "pub-8510650669347560";
google_ad_width = 728;
google_ad_height = 90;
google_ad_format = "728x90_as";
google_ad_type = "text_image";
google_ad_channel ="";
//--></script>
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script></div>Lao Khttp://www.blogger.com/profile/13748590324739892436noreply@blogger.com3tag:blogger.com,1999:blog-21999378.post-1146036950892242272006-04-23T00:34:00.000-07:002006-04-26T23:52:54.053-07:00Pocket Outlook Woe 01: incoming server and outgoing server are passed as two NULL pointers from Outlook to Transport<p><b>Pocket Outlook Woe 01: incoming server and outgoing server are passed as two NULL pointers from Outlook to Transport</b></p> <p>I've briefly mentioned how to write a transport plugin for Pocket Outlook in two of my previous posts:</p> <ul><li><a href="http://windowsmobilepro.blogspot.com/2006/02/transportdemo-sample-in-pocket-pc-50.html" title="TransportDemo sample in Pocket PC 5.0 SDK does not work? Check the solution here...">TransportDemo sample in Pocket PC 5.0 SDK does not work? Check the solution here...</a></li><li><a href="http://windowsmobilepro.blogspot.com/2006/02/how-to-programmatically-query-mail.html" title="How to programmatically query mail account information in Windows Mobile devices, for example, incoming server and username?">How to programmatically query mail account information in Windows Mobile devices, for example, incoming server and username?</a></li></ul> <p>In Pocket Outlook, each mail account is associated with a MAPI store, and a transport. A store is a store, for storing email folders and email messages. The transport is responsible for synchronizing a mail account by talking to the remote server. The main reference on CEMAPI can be found in MSDN's <a href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/mobilesdk5/html/mob5oriMessagingAPIMAPI.asp">Windows Mobile SDK Messaging section</a>, and the main interface a transport must implement is called <a href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/mobilesdk5/html/mob5lrfimailsynchandler.asp">IMailSyncHandler</a>.</p> <p>In Windows Mobile 5.0 devices (and some newer version of Pocket PC 2003 SE devices), a newer version of Pocket Outlook is shipped. This updated version seems bringing a couple of woes to transport developers. Today I am focusing on the first one: Incoming server and outgoing server are passed by Outlook as two NULL pointers to the transport.</p> <p>The method involved is <b>Install</b>, which is called by Outlook to install the transport and then passes the configuration information to the transport.</p> <blockquote> <b>HRESULT Install (</b> <b>LPCWSTR </b><i>pszProfileName</i><b>,</b> <b>LPCWSTR </b><i>pszIncomingServer</i><b>,</b> <b>LPCWSTR </b><i>pszOutgoingServer</i><b>,</b> <b>GUID * </b><i>pidNetwork</i> <b>);</b> </blockquote> <dl><dt><i>pszProfileName</i> </dt><dd>[in] Profile name of the transport instance, which is also the account name. </dd><dt><i>pszIncomingServer</i> </dt><dd>[in] Incoming server name that the transport should use to synchronize the e-mail into the device. </dd><dt><i>pszOutgoingServer</i> </dt><dd>[in] Outgoing server name that the transport should use to send outgoing e-mails.</dd></dl> <p>Incoming server and outgoing server can be either specified by the user who create the account via Outlook's New Account Setup wizard, or created by the developer using <b>DMProcessConfigXML</b> and <b>EMAIL2 </b>CSP. </p> <p>I tested both cases, and found that two NULL pointers are always passed from Outlook to the transport. The testing transport is the TransportDemo sample in Windows Mobile SDK. In its <b>Install </b>method, a dialog is used to display two server strings passed by Outlook</p> <h3>Case 1: TransportDemo1 is created by the user using Outlook's wizard</h3> <p>In New Account Setup Wizard, typing the incoming mail server name and outgoing mail server name.</p> <p align="center"><img src="http://photos1.blogger.com/blogger/5783/1371/1600/TransportDemo1SetupServers.jpg" border="0" height="320" width="240" /></p> <p>When the transport (TransportDemo) is loaded, two NULL pointers are passed from Outlook.</p> <p align="center"><img src="http://photos1.blogger.com/blogger/5783/1371/1600/TransportDemo1InstallNULL.jpg" border="0" height="320" width="240" /></p> <h3>Case 2: TransportDemo2 is programmatically created using DMProcessConfigXML</h3> <p>The account information can be queried back successfully, showing the two server names correctly. Refer here for <a href="http://windowsmobilepro.blogspot.com/2006/02/how-to-programmatically-query-mail.html" title="How to programmatically query mail account information in Windows Mobile devices, for example, incoming server and username?">how to programmatically query mail account information in Windows Mobile devices, for example, incoming server and username.</a></p> <p align="center"><img src="http://photos1.blogger.com/blogger/5783/1371/1600/TransportDemo2QueryBack.jpg" border="0" height="320" width="240" /></p> <p align="left">Unfortunately, you'll still get two NULL pointers.</p> <p align="center"><img src="http://photos1.blogger.com/blogger/5783/1371/1600/TransportDemo2InstallNULL.jpg" border="0" height="320" width="240" /></p> <h3 align="left">Wrap Up</h3> <p align="left">I tried to disable the device security, or sign the transport DLL using a certificate, but the problem persists.</p> <p align="left">This seems affecting not only Windows Mobile 5.0 device, but also newer version of Pocket PC 2003 SE device, where the newer version of Outlook is shipped.</p> <p align="left">As a workaround, the transport developer might use registry to store the sever information, rather than relying on Outlook. However, this means that the user cannot change the server settings via Outlook.</p> <p align="left">The POP3 transport and IMAP4 transport shipped along with Pocket Outlook seem immune to the issue. Could it because the TransportDemo code is too simple and not implement necessary methods??</p><div class="blogger-post-footer"><script type="text/javascript"><!--
google_ad_client = "pub-8510650669347560";
google_ad_width = 728;
google_ad_height = 90;
google_ad_format = "728x90_as";
google_ad_type = "text_image";
google_ad_channel ="";
//--></script>
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script></div>Lao Khttp://www.blogger.com/profile/13748590324739892436noreply@blogger.com0tag:blogger.com,1999:blog-21999378.post-1145950304130027412006-04-21T00:30:00.000-07:002006-04-25T00:33:33.510-07:00Emulator Troubleshooting/Tip 01: To Cradle or Not to Cradle?<p><b>Emulator Troubleshooting/Tip 01: To Cradle or Not to Cradle?</b></p> <p>Firstly, a quick introduction to the emulators shipped with Visual Studio 2005 (VS2005, and/or Windows Mobile 5.0 SDK). </p> <h3>What is New in the emulators shipped with VS2005</h3> <p>The 2005 emulator runs applications compiled for the ARM instruction set (same as the physical device) and runs as a user-mode process. The emulators work much faster than the previous generations that deal with X86 instruction sets. Also the emulator loading and shutdown time reduce significantly.</p> <p>The other big change is that VS2005 now provides a Direct Memory Access (DMA) transport to communicate with the emulator. Surpassing the traditional TCP/IP transport, the DMA transport is faster, does not rely on network connectivity or other external factors, and provides deterministic connection and disconnection. </p> <h3>Connect and Cradle Emulator</h3> <p>The centralized place to interact with the emulators is the Device Emulator Manager. To launch the Device Emulator using the Device Emulator Manager in VS2005:</p> <ul><li>On the Visual Studio <b>Tools</b> menu, click <b>Device Emulator Manager</b>.</li><li>In the <b>Device Emulator Manager</b> window, right-click the emulator you want to launch.</li><li>On the shortcut menu, click <b>Connect</b>.</li></ul> <p>The following screen cut show that Pocket PC 2003 SE Emulator is connected. Now VS2005 is able to deploy your program to the emulator and debug your program as well. The Remote Tools (like remote registry editor, remote spy, remote file explorer, and etc) can also work with the emulator. No, in such case, you do not need to establish an ActiveSync connection to use the remote tools.</p> <p align="center"><img src="http://photos1.blogger.com/blogger/5783/1371/1600/DEMConnect.jpg" border="0" height="300" width="420" /></p> <p>Sometimes you may need to ActiveSync with an emulator, for example, you want to use the "Mobile Device" shell namespace in your desktop PC's explorer to access the emulator's file system, or you want to make the emulator use the host PC's network connection. The way to establish an ActiveSync connection changed significantly compared to the the previous development environment (Visual Studio 2003/VS2003, Embedded Visual C++ 4/EVC4, and Pocket PC 2003 SDK or Smartphone 2003 SDK). </p> <ul><li>Right click the already-connected emulator, then click <b>Cradle </b>in the popup menu. </li><li>Make sure ActiveSync is configured to allow <b>DMA </b>connections via its <b>Connection Setting</b> dialog's "<b>Allow connections to one of the following</b>" option.</li><li>ActiveSync should then start as the emulator makes a connection to your desktop computer. </li></ul> <p>The following screen cut shows that the Pocket PC 2003 SE emulator is ActiveSync'ed.</p> <p align="center"><img src="http://photos1.blogger.com/blogger/5783/1371/1600/DEMtoCradle.jpg" border="0" height="300" width="420" /></p> <p align="center"><img src="http://photos1.blogger.com/blogger/5783/1371/1600/DEMCradled.jpg" border="0" height="300" width="420" /></p> <h3>To Cradle or Not to Cradle </h3> <p>If an emulator is successfully cradled, VS2005 and Remote Tools can either treat the emulator as an Emulator, or as a Physical Device. For example, in above screen cuts, Pocket PC 2003 SE Emulator is ActiveSync'ed. Now in VS2005 or in Remote Tool's "Select a Windows CE Device" dialog, you can either choose the Emulator as is, or choose "Pocket PC 2003 Device". Either way, the emulator will be connected.</p> <p>However, you'll see certain degree of performance penalty if the emulator is cradled, compared to a non-cradled emulator. As mentioned above, VS2005 and Remote Tools do not really need the emulator to be ActiveSync'ed. In case that the emulator is not cradled, DMA transport is used. As the named implies, VS2005 or Remote Tool is directly accessing the emulator process' memory, much faster and reliable. Using ActiveSync as the transport adds an unnecessary extra layer.</p> <p>The other advantage to realize no-need-to-cradle-clarification is that you can connect a Remote Tool to multiple Emulators simultaneously. ActiveSync actually does not support connecting to multiple devices or emulators.</p> <h3>Wrap Up</h3> <p>"<b>To Cradle or Not to Cradle</b>" only applies to Emulators. For a physical device, you do need to cradle and ActiveSync it for VS2005 and Remote Tools to work. Reason is simple. There is no such thing like "DMA" in such a scenario, because the desktop PC and the pocket PC are living in two worlds. </p><div class="blogger-post-footer"><script type="text/javascript"><!--
google_ad_client = "pub-8510650669347560";
google_ad_width = 728;
google_ad_height = 90;
google_ad_format = "728x90_as";
google_ad_type = "text_image";
google_ad_channel ="";
//--></script>
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script></div>Lao Khttp://www.blogger.com/profile/13748590324739892436noreply@blogger.com2tag:blogger.com,1999:blog-21999378.post-1145251078836388272006-04-19T22:16:00.000-07:002006-04-20T23:31:10.453-07:00Internal Use Spy: A nice hidden debugging tool for Pocket PC 2003 device and Pocket PC 5.0 device<p><b>Internal Use Spy: A nice hidden debugging tool for Pocket PC 2003 device and Pocket PC 5.0 device</b></p> <p>On Apr. 13, 2006, I talked about <a href="http://windowsmobilepro.blogspot.com/2006/04/remote-ce-spy-shipped-with-visual.html">the usage of Remote CE Spy and how to overcome the broken Remote CE Spy shipped with Visual Studio 2005</a>. Specifically, the Remote Spy displays a list of the windows that are open on a target device. In a separate window, the tool displays information about the messages in the message queue for the selected window.</p> <p>Remote CE Spy is a very powerful tool for any UI-related programming job. However, the tool requires the target device must be ActiveSync'ed with the desktop PC. What if you do not have access to a PC? With only the physical device, can you discover similar information on the fly, like the window handle, class, style, size, and etc?</p> <p>Recently when I was playing with my PPC6601 (2003 SE) device, I found such a hidden tool called "Internal Use Spy". The way to bring it up is like this:</p> <ul><li>Press (and Hold) the Action key</li><li>Tap the top title bar where nothing is displayed (to the right of title string, and to the left of notification icon)</li></ul> <p>A dialog will popup, listing the current window's handle, style, title, client area position and size. Further, it shows the handle of the parent window, and offers a choice to further dump the properties of the parent window. The following screen cut is for "Microphone AGC" applet in the Control Panel Settings:</p> <p align="center"><img src="http://photos1.blogger.com/blogger/5783/1371/320/InternalUseSpy.jpg" alt="Internal Use Spy Screen dump" border="0" height="320" width="240" /></p> <h3 align="left">Wrap Up</h3> <p align="left">I tested in my PPC6700 device, a Windows Mobile 5.0 device. It also works. It seems both Pocket PC 2003 device and Pocket PC 5.0 device have the hidden tool built-in.</p> <p align="left">The emulator does not expose the same. In the emulator, supposedly one can press and hold the PC's CTRL key to simulate the behavior of pressing and holding Action key in real devices. However, the Internal Use Spy dialog simply does not show up.</p> <p align="left">For a related post on the hidden trick without connecting the device to a desktop PC, read "<a href="http://windowsmobilepro.blogspot.com/2006/04/how-to-launch-program-via-command-line.html">how to launch a program via command line in Pocket PC 2003 device and Pocket PC 5.0 device</a>".</p><div class="blogger-post-footer"><script type="text/javascript"><!--
google_ad_client = "pub-8510650669347560";
google_ad_width = 728;
google_ad_height = 90;
google_ad_format = "728x90_as";
google_ad_type = "text_image";
google_ad_channel ="";
//--></script>
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script></div>Lao Khttp://www.blogger.com/profile/13748590324739892436noreply@blogger.com4tag:blogger.com,1999:blog-21999378.post-1145583329172706822006-04-17T18:34:00.000-07:002006-04-30T10:56:40.243-07:00Using Camera API with only Embedded Visual C++ 4.0 (evc4): Sample code and EVC4 workspace download<p><b>Using Camera API with only Embedded Visual C++ 4.0 (evc4): Sample code and EVC4 workspace download</b></p> <p align="left">In my previous post, I talked about <a href="http://windowsmobilepro.blogspot.com/2006/04/how-to-use-new-camera-api-in-windows.html">how to use the new Camera API in Windows Mobile 5.0 SDK with only Embedded Visual C++ 4.0 (evc4)</a>. </p> <p align="left">You can <a href="http://windowsmobilepro.home.comcast.net/CameraDemo.zip">download the EVC4 workspace here</a>. The source code is written based on the <a href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/mobilesdk5/html/mob5lrfSHCameraCaptureFn.asp">MSDN documentation on SHCameraCapture</a>, which states:</p> <blockquote> <p align="left">Application writers should be aware that <b>SHCameraCapture</b> function can cause the calling application to stop responding in cases where the calling application is minimized and then reactivated while the call to <b>SHCameraCapture</b> function is still blocking.</p> </blockquote> <p align="left">The sample code is written by copying the snippets in that MSDN documentation, although I do not really find such "stop responding" mischief using the "possible sequence of events". The program shows "Capture" and "Exit" in the bottom menu bar. Clicking the left soft key launches the camera capture dialog. After clicking the Action key, the program captures videos for 15 seconds then ask for a place to save the video file.</p> <p align="left">Two gotchas:</p> <ul><li> <p align="left">The MSDN documentation says the window class of camera capture dialog is "Camera View". In my Sprint PPC6700 device, the class name is actually "WCE_IA_Camera_Main" (read the source code for a comment). </p></li><li> <p align="left">The camera capture dialog still shows even after the program is closed. The function "<i>CloseCameraDialog</i>" is used to close it before the program shuts down (read the source code for details) </p></li></ul> <p align="left">BTW, the tool to find out the window class is Remote CE Spy. The default Remote CE Spy shipped with VS2005 does not work well with Windows Mobile 5.0 device. Read "<a href="http://windowsmobilepro.blogspot.com/2006/04/remote-ce-spy-shipped-with-visual.html">Remote CE Spy shipped with Visual Studio 2005 fails to intercept windows messages</a>" for a possible solution.</p><div class="blogger-post-footer"><script type="text/javascript"><!--
google_ad_client = "pub-8510650669347560";
google_ad_width = 728;
google_ad_height = 90;
google_ad_format = "728x90_as";
google_ad_type = "text_image";
google_ad_channel ="";
//--></script>
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script></div>Lao Khttp://www.blogger.com/profile/13748590324739892436noreply@blogger.com2tag:blogger.com,1999:blog-21999378.post-1145515557137427882006-04-16T23:45:00.000-07:002006-04-30T10:54:39.833-07:00How to use the new Camera API in Windows Mobile 5.0 SDK with only Embedded Visual C++ 4.0 (evc4)?<p><b>How to use the new Camera API in Windows Mobile 5.0 SDK with only Embedded Visual C++ 4.0 (evc4)?</b></p> <p align="left">Almost all up-to-date phones, PDAs, or handheld gadgets have an embedded camera, allow users to snap pictures or capture videos. Microsoft releases <a href="http://msdn.microsoft.com/mobility/windowsmobile/howto/windowsmobile5/api/default.aspx#native">new APIs in Windows Mobile 5.0 SDK to help developers controlling the camera</a>.</p> <blockquote> <p align="left"><span style="color: rgb(0, 0, 0);"><b>Camera Capture API</b><br /> Camera enabled devices are extremely popular. With these devices being so widely available, application developers now have the opportunity to substantially enhance the user experience by integrating the capture of both still and video images directly into their applications. To enable application developers to easily provide this functionality, Windows Mobile 5.0 provides the camera capture dialog. The unmanaged API is called <a href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/mobilesdk5/html/mob5lrfSHCameraCaptureFn.asp">SHCameraCapture</a>.</span></p> </blockquote> <p align="left">The problem is that the only Visual Studio 2005 can work with Windows Mobile 5.0 SDK. What if you are still using the free Embedded Visual C++ 4 (EVC4), and you do not want to shed a cool $800 to get a copy of VS2005?</p> <p align="left">The solution is to use <i>LoadLibrary</i> to load <i>aygshell.dll</i>, get the entry point to <i>SHCameraCapture</i>, then call that function by jumping to the entry point. The API anticipates a structure as the parameter, so you need to instruct EVC4 compiler to generate the parameter correctly by defining it yourself. Luckily all the members in the structure are primitive types or character arrays, so there is really not much hassle.</p> <p align="left">Below is the source code that you can copy and paste into your EVC4 source code. It uses <i>#ifdef _WIN32_WCE </i>to make sure the code gets compiled for Pocket PC 2003 project or Smartphone 2003 project. The final executable can then be copied to a Pocket PC 5.0 device or Smartphone 5.0 device.</p> <p align="left"><span style="font-family:Courier New;font-size:85%;">#include <aygshell.h><br />#if _WIN32_WCE < 0x0500<br /><br />//////////////////////////////////////////////////////////////////////////////<br />//<br />// Flags for camera capture UI<br /><br />typedef enum {<br /> CAMERACAPTURE_MODE_STILL = 0,<br /> CAMERACAPTURE_MODE_VIDEOONLY,<br /> CAMERACAPTURE_MODE_VIDEOWITHAUDIO,<br />} CAMERACAPTURE_MODE;<br /><br />typedef enum {<br /> CAMERACAPTURE_STILLQUALITY_DEFAULT = 0,<br /> CAMERACAPTURE_STILLQUALITY_LOW,<br /> CAMERACAPTURE_STILLQUALITY_NORMAL,<br /> CAMERACAPTURE_STILLQUALITY_HIGH,<br />} CAMERACAPTURE_STILLQUALITY;<br /><br />typedef enum {<br /> CAMERACAPTURE_VIDEOTYPE_ALL = 0xFFFF,<br /> CAMERACAPTURE_VIDEOTYPE_STANDARD = 1,<br /> CAMERACAPTURE_VIDEOTYPE_MESSAGING = 2,<br />} CAMERACAPTURE_VIDEOTYPES;<br /><br />typedef struct tagSHCAMERACAPTURE<br />{<br /> DWORD cbSize;<br /> HWND hwndOwner;<br /> TCHAR szFile[MAX_PATH]; <br /> LPCTSTR pszInitialDir;<br /> LPCTSTR pszDefaultFileName;<br /> LPCTSTR pszTitle;<br /> CAMERACAPTURE_STILLQUALITY StillQuality;<br /> CAMERACAPTURE_VIDEOTYPES VideoTypes;<br /> DWORD nResolutionWidth;<br /> DWORD nResolutionHeight;<br /> DWORD nVideoTimeLimit;<br /> CAMERACAPTURE_MODE Mode;<br />} SHCAMERACAPTURE, *PSHCAMERACAPTURE;<br /><br /><br />HRESULT SHCameraCapture(PSHCAMERACAPTURE pshcc);<br /><br />typedef HRESULT (*fnSHCameraCapture)(PSHCAMERACAPTURE pshcc);<br /><br />HRESULT SHCameraCapture(PSHCAMERACAPTURE pshcc)<br />{<br /> HRESULT hr = S_OK;<br /> HINSTANCE hAygShell = LoadLibrary(TEXT("aygshell.dll"));<br /> fnSHCameraCapture funcSHCameraCapture = NULL;<br /><br /> if (!hAygShell) {<br /> hr = HRESULT_FROM_WIN32(GetLastError());<br /> goto FuncExit;<br /> }<br /> funcSHCameraCapture = (fnSHCameraCapture)GetProcAddress(hAygShell, TEXT("SHCameraCapture"));<br /> if (!funcSHCameraCapture) {<br /> hr = HRESULT_FROM_WIN32(GetLastError());<br /> goto FuncExit;<br /> }<br /><br /> // call the API now<br /> hr = funcSHCameraCapture(pshcc);<br /><br />FuncExit:<br /> if (hAygShell) {<br /> FreeLibrary(hAygShell);<br /> }<br /> return hr;<br />}<br /><br />#endif // faked one in 4.20/4.21 platform<br /><br /></span></p> <h3 align="left">Wrap Up</h3> <p>You may use similar approach to access other new 5.0 APIs from within EVC4. You need to find out which DLL exports the API, and more importantly, you need to let EVC4 compiler correctly generate parameters to feed into those APIs, so inevitably you have to copy some header definitions from Windows Mobile 5.0 SDKs.</p><div class="blogger-post-footer"><script type="text/javascript"><!--
google_ad_client = "pub-8510650669347560";
google_ad_width = 728;
google_ad_height = 90;
google_ad_format = "728x90_as";
google_ad_type = "text_image";
google_ad_channel ="";
//--></script>
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script></div>Lao Khttp://www.blogger.com/profile/13748590324739892436noreply@blogger.com3tag:blogger.com,1999:blog-21999378.post-1145429482492079592006-04-13T23:42:00.000-07:002006-04-19T00:06:37.133-07:00Remote CE Spy shipped with Visual Studio 2005 fails to intercept windows messages: Check the solution here!<p><b>Remote CE Spy shipped with Visual Studio 2005 fails to intercept windows messages: Check the solution here!</b></p> <p>Remote CE Spy is Windows Mobile programmer's buddy if there is a need to inspect the windows currently opened in a Windows Mobile device, or intercept the messages sent to a particular window in real-time. It might not be useful if you are writing simple UI and know for sure what messages to process. However, if you need to find out what is going on with a program written by other people, need to inject messages into the message queue of a program (or to be technically right, a window), or want to find the ID of a window control, Remote CE Spy is an indispensable tool.</p> <p>CE Spy shipped with Embedded Visual Tools 4 (along with Pocket PC 2003 SDK and Smartphone 2003 SDK) works perfectly, always able to list all the windows, and reliably capture the messages of any window's message queue. However, the one shipped with Visual Studio 2005 is broken. It might list all the windows, but sometimes it doesn't. Worse, when capturing messages sent to a particular window, it grossly misses messages.</p> <p>Quite some users reported various issues and Microsoft acknowledged it:</p> <ul><li><a href="http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=58908&SiteID=1">http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=58908&SiteID=1</a></li><li><a href="http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=17401&SiteID=1">http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=17401&SiteID=1</a></li><li><a href="http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=12630&SiteID=1">http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=12630&SiteID=1</a></li><li><a href="http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=319056&SiteID=1">http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=319056&SiteID=1</a></li><li><a href="http://groups.google.com/group/microsoft.public.pocketpc.developer/browse_thread/thread/13dc59c942299c34/2c31c0c768f21722">http://groups.google.com/group/microsoft.public.pocketpc.developer/browse_thread<br /> /thread/13dc59c942299c34/2c31c0c768f21722</a></li><li><a href="http://groups.google.com/group/microsoft.public.pocketpc.developer/browse_thread/thread/2ca5adc86877ca3a/c4e504353719e397">http://groups.google.com/group/microsoft.public.pocketpc.developer/browse_thread/<br /> thread/2ca5adc86877ca3a/c4e504353719e397</a></li><li><a href="http://groups.google.com/group/microsoft.public.pocketpc.developer/browse_thread/thread/3eabee13724fe80d/0f9e22d7c69e0b16">http://groups.google.com/group/microsoft.public.pocketpc.developer/browse_thread/<br /> thread/3eabee13724fe80d/0f9e22d7c69e0b16</a></li><li><a href="http://groups.google.com/group/microsoft.public.pocketpc.developer/browse_thread/thread/6705c8793e6f4e51/340654e349c75a6f">http://groups.google.com/group/microsoft.public.pocketpc.developer/browse_thread/<br /> thread/6705c8793e6f4e51/340654e349c75a6f</a></li><li><a href="http://groups.google.com/group/microsoft.public.dotnet.framework.compactframework/browse_thread/thread/3b51d271fa8c7583/b07ff4a4696d8185">http://groups.google.com/group/microsoft.public.dotnet.framework.compactframework/<br /> browse_thread/thread/3b51d271fa8c7583/b07ff4a4696d8185</a></li></ul> <p>Basically those posts are saying that CE Spy is broken in Visual Studio Beta 2. I also found it out when I was using Beta 2. The real trouble is that I am using the RTM version of Visual Studio 2005 (8.0.50727.42, see below). CE Spy still missed capturing messages.</p> <p align="center"><img src="http://photos1.blogger.com/blogger/5783/1371/1600/VS2005Version.jpg" border="0" height="95" width="288" /></p> <p>I did a search on my hard drive, and found three version of cespy under "<i>\Program Files</i>". Looks like one of them can work with Windows Mobile 5.0 device. </p> <h3>Version 5.0.1.1400 works!</h3> <p>The following one works without any issue:</p> <p><i>C:\Program Files\Common Files\Microsoft Shared\Windows CE Tools\Platman\bin\wce500\cespy.exe</i></p> <p> The catch is: After 5.0 device is ActiveSync'ed, this tool won't list Pocket PC 5.0 as a target platform. Just simply choose Pocket PC 2003, the tool can make the connection, list windows and intercept messages correctly!</p> <p align="center"><img src="http://photos1.blogger.com/blogger/5783/1371/1600/CESpy5.0.1.jpg" border="0" height="502" width="454" /></p> <p align="center">Version 5.0.1.1400</p> <p align="center"><img src="http://photos1.blogger.com/blogger/5783/1371/1600/CESpy5.0.1_Connect2003.jpg" border="0" height="424" width="382" /></p> <p align="left">The window below shows the messages capture by ceSpy.exe 5.0.1.1400 when I clicked the "Send/Receive" menu item of Pocket Outlook. It reports 12 messages. Keep reading on, and you'll be surprised how many messages the "broken" spy is reporting.</p> <p align="center"><img src="http://photos1.blogger.com/blogger/5783/1371/1600/CESpy5.0.1_AllMessages.jpg" border="0" height="294" width="639" /></p> <h3>Version 5.1.1651.0 (shipped with Visual Studio 2005 RTM and appearing under the start menu "<i>Visual Studio Remote Tools => Remote Spy</i>" does not work</h3> <p>Version 5.1.1651.0 seems to be the on shipped with Visual Studio 2005 and is put under start menu "<i>Visual Studio Remote Tools => Remote Spy</i>":</p> <p><i>C:\Program Files\CE Remote Tools\5.01\bin\ccspy.exe (Notice the name is called ccspy.exe, not cespy.exe)</i></p> <p> It has no problem connecting to 5.0 device, but messages are grossly missing. Do not use it!</p> <p align="center"><img src="http://photos1.blogger.com/blogger/5783/1371/1600/CESpy5.1.1651.0.jpg" border="0" height="502" width="454" /></p> <p align="center"><img src="http://photos1.blogger.com/blogger/5783/1371/1600/CESpy5.1.1651.0_Connect5.0.jpg" border="0" height="424" width="382" /></p> <p align="left">The window below shows the messages capture by ccSpy.exe when I clicked the "Send/Receive" menu item of Pocket Outlook. Only two messages are captured. Compared to the messages intercepted by the good version 5.0.1.1400. This guy fails to report 10 messages!</p> <p align="center"><img src="http://photos1.blogger.com/blogger/5783/1371/1600/CESpy5.1.1651.0_MissingMessages.jpg" border="0" height="142" width="609" /></p> <h3>Version 4.10.1.908 (shipped with Embedded Visual Tools) does not work with 5.0 device, but is the ideal choice to work with 2003 device</h3> <p>The one installed with Embedded Visual Tools does not work against Windows Mobile 5.0 device:</p> <p><i>C:\Program Files\Common Files\Microsoft Shared\Windows CE Tools\Platman\bin</i></p> <p> This is anticipated, as it is supposed to work with Pocket PC 2003 device and Smartphone 2003 device.</p> <p align="center"><img src="http://photos1.blogger.com/blogger/5783/1371/1600/CESpy4.10.1.jpg" border="0" height="502" width="454" /></p> <p>If you ActiveSync'ed a device and try connect, you will get the following error message.</p> <p align="center"><img src="http://photos1.blogger.com/blogger/5783/1371/1600/CESpy4.10.1_CannotConnect.jpg" border="0" height="128" width="358" /></p> <p align="center"> </p> <h3 align="left">Wrap Up</h3> <p>When you need to use Remote CE Spy to watch windows or messages in a Pocket PC 5.0 device or Smartphone 5.0 device, do not use the one put into the start menu by Visual Studio 2005. Instead, search your hard drive, and locate the one with version 5.0.1.1400.</p> <p>Please do not ask me why if you cannot find the good guy in your hard drive. I have no idea why I have two different 5.0 versions of them.</p><div class="blogger-post-footer"><script type="text/javascript"><!--
google_ad_client = "pub-8510650669347560";
google_ad_width = 728;
google_ad_height = 90;
google_ad_format = "728x90_as";
google_ad_type = "text_image";
google_ad_channel ="";
//--></script>
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script></div>Lao Khttp://www.blogger.com/profile/13748590324739892436noreply@blogger.com1tag:blogger.com,1999:blog-21999378.post-1145153115592472282006-04-11T18:55:00.000-07:002006-04-16T12:44:42.523-07:00How to launch a program via command line in Pocket PC 2003 device and Pocket PC 5.0 device?<p><b>How to launch a program via command line in Pocket PC 2003 device and Pocket PC 5.0 device?</b></p> <p>As you may have already known, Pocket PC does not have a shell (unless you want to install one), so there is no easy way to launch a program by typing in command line. Daily average user may not have such requirement. A developer, especially a Java developer, may consider it a nice-to-have feature. Java program is normally launched in the following format:</p> <blockquote> <p><span style=";font-family:Courier New;font-size:85%;" ><jvm_executable> [jvm_argument|jvm_argument] <main_class_name> [program_argument|program_argument]</span></p> </blockquote> <p>The command line is usually long. Worse, for debugging purpose, you may need to feed different arguments into your program.</p> <h3>If the device is connected to desktop PC via ActiveSync</h3> <p>If you have setup your development environment and connect the device to your desktop via ActiveSync, the IDE will take care the steps to remote launch a program. </p> <p>You can also install <a href="http://www.microsoft.com/downloads/details.aspx?FamilyID=74473fd6-1dcc-47aa-ab28-6a2b006edfe9&DisplayLang=en">Windows Mobile Developer Power Toys</a>, which packages a few useful tools for developers:</p> <ul><li><b><i>Emulator ActiveSync Connection Tool </i></b> - Allows Activesync to connect to your Emulator session from Visual Studio .NET 2003.</li><li><b><i> ActiveSync Remote Display </i></b> - Display Pocket PC applications on your desktop or laptop without needing any device side configuration.</li><li><b><i> CECopy </i></b> - Command line tool for copying files to the device currently connected to desktop ActiveSync.</li><li><b><i> Convert PPC DAT to SP XML </i></b> - Command line tool for generating Smartphone CABWizSP XML docs from existing Pocket PC CAB files.</li><li><b><i> Hopper </i></b> - User input stress simulator.</li><li><b><i> JShell </i></b> - UI version of the Platform Builder Target Control Window.</li><li><b><i> PPC Command Shell </i></b> - Command shell for the Pocket PC 2003 device.</li><li><b><i> RAPI Debug </i></b> - Displays detailed information about currently running processes.</li><li><b><i> RAPI Start </i></b> - Command line tool to remotely start an application on your Pocket PC from your desktop.</li><li><b><i> TypeIt </i></b> - Send characters/strings to the Smartphone 2003 Emulator via ActiveSync.</li></ul> <p>Among them, <b><i>RAPIStart</i></b> and <b><i>PPC Command Shell </i></b>can be used for remotely launching an application via command line.</p> <h3>What if the device is not connected to desktop PC, for example, I am outside my office</h3> <p>The above tools requires the Pocket PC to be connected to a desktop PC via ActiveSync. What if you do not have access to a PC? You can try the following: </p> <ul><li>Go to Today screen (the home screen)</li><li>Press (and Hold) the Action key</li><li>Tap the position where the current time is displayed in the title bar</li></ul> <p>A menu pops up with two items: <i>Run </i>and <i>Clock</i>. Click <i>Run</i>, you will get a dialog asking for the program name and arguments. </p> <p align="center"><img src="http://photos1.blogger.com/blogger/5783/1371/1600/RunClock.jpg" border="0" height="320" width="240" /> <img src="http://photos1.blogger.com/blogger/5783/1371/1600/runPIE.jpg" border="0" height="320" width="240" /></p> <p align="left">It is for sure a painful experience to type a long command line in the Pocket PC. You can first write down the command line in a Word Mobile file, then do a copy and paste into the <i>Run </i>dialog. For varying arguments, just do copy and paste then make minor modifications.</p> <p align="left">In the emulator you can achieve the same, but you need to press and hold your PC's CTRL key to simulate the behvaior of pressing and holding Action key in real devices. See <a href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/guide_ppc/html/ppc_intro_to_the_ce_emulator_jfcm.asp">Emulator Keyboard Shortcuts</a> for details.</p><div class="blogger-post-footer"><script type="text/javascript"><!--
google_ad_client = "pub-8510650669347560";
google_ad_width = 728;
google_ad_height = 90;
google_ad_format = "728x90_as";
google_ad_type = "text_image";
google_ad_channel ="";
//--></script>
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script></div>Lao Khttp://www.blogger.com/profile/13748590324739892436noreply@blogger.com1tag:blogger.com,1999:blog-21999378.post-1145083734409122952006-04-09T23:46:00.000-07:002006-04-16T22:39:10.663-07:00Pocket PC Power Management Series 10: A Better Way to Catch when the Device Wakes Up - Multi-Thread Code with Visual Studio 2005 Solution Download<p><b>Pocket PC Power Management Series 10: A Better Way to Catch when the Device Wakes Up - Multi-Thread Code with Visual Studio 2005 Solution Download</b></p> <p>In <a href="http://windowsmobilepro.blogspot.com/2005/11/pocket-pc-power-management-series-4.html">Pocket PC Power Management Series 4: A Better Way to Catch when the Device Wakes Up</a>, I present a nice way to catch when the device wakes up. The sample code use <i>CeSetUserNotificationEx</i> to register a named event; when Windows CE OS wakes up, OS fires the event. The code has only one thread, calling <i>MsgWaitForMultipleObjectsEx</i> to both listen to the wakeup event, and process windows message queue. As warned at the end of that post, the single thread might be busy thus missing wakeup events. </p> <p>Some readers mailed me wondering whether I can provide a fully-functional sample code with two threads such that wakeup event can be always reliably caught. A reader also left a comment asking for the two-thread code. Here I am :)</p> <ul><li><a href="http://windowsmobilepro.home.comcast.net/WakeupDemo2.zip">Visual Studio 2005 solution download</a></li><li><a href="http://windowsmobilepro.home.comcast.net/wakeupdemo2.exe">Pocket PC executable file download</a></li></ul> <p>The VS2005 solution is a Zip file. Extracting it you'll get .sln, .vcproj and source code. Project settings cover Pocket PC 2003 platform and Pocket PC 5.0 platform. For PPC2003 platform, <a href="http://windowsmobilepro.blogspot.com/2005/08/manually-migrate-embedded-visual-c.html">secchk.lib and ccrtrtti.lib</a> are added.</p> <p>The executable can be run on both Pocket PC 2003 device and Pocket PC 5.0 device. You can use your Pocket IE to download the executable file directly into your device, then run it there. </p> <p>This is a screen cut when the program runs. All windows messages posted to the main windows (along with the timestamp) are logged to the screen. Besides, any wakeup event (along with the timestamp when the event is fired) are also logged to the screen.</p> <p align="center"><img src="http://photos1.blogger.com/blogger/5783/1371/1600/wakeupdemo2.jpg" border="0" height="525" width="340" /></p> <p>Below is a quick walkthrough of the source code:</p> <p><b>The thread that is dedicated to listening to the wakeup signal. </b>Notice it calls <i>WaitForMultipleObjects </i>to actually listen to two events, the other one being the shutdown signal. This also demonstrates how to gracefully shutdown a thread without relying on a global boolean that the thread periodically polling against.</p> <p><span style=";font-family:Courier New;font-size:85%;" ><br />static DWORD WakeupEventListener(LPVOID lpData)<br />{<br /> TCHAR szBuf[256];<br /> PEVENTHANDLES pEventHandles = (PEVENTHANDLES)lpData;<br /><br /> while (TRUE) {<br /> ResetEvent(pEventHandles->hWakeupEvent);<br /> DWORD dwResult = WaitForMultipleObjects(2, (HANDLE*)pEventHandles, FALSE, INFINITE);<br /> if (WAIT_OBJECT_0 == dwResult) {<br /> _tcscpy(szBuf, TEXT("Wakeup at "));<br /> FormatCurrentTime(szBuf+_tcslen(szBuf));<br /> _tcscat(szBuf, TEXT("\r\n\r\n"));<br /> OutputString(szBuf);<br /> } else if (WAIT_OBJECT_0+1 == dwResult) {<br /> break;<br /> } else { <br /> // WAIT_ABANDONED and WAIT_FAILED<br /> // Abondoned is not possible, failed most probably means the Handle is closed<br /> if (WAIT_FAILED == dwResult) {<br /> // ... do something error processing<br /> }<br /> } <br /> }<br /><br /> return S_OK;<br />}<br /></span></p> <p><b>Start and stop the wakeup event listener thread.</b></p> <p><span style=";font-family:Courier New;font-size:85%;" ><br />static HRESULT StartWakeupEventListener(const PEVENTHANDLES pEventHandles, HANDLE& hThread)<br />{<br /> DWORD dwDummy = 0;<br /> hThread = CreateThread(NULL, 0, WakeupEventListener, (LPVOID)pEventHandles, 0, &dwDummy);<br /> // need to error handling if thread creation failed<br /><br /> return S_OK;<br />}<br /><br />static HRESULT StopWakeupEventListener(const PEVENTHANDLES pEventHandles, HANDLE& hThread)<br />{<br /> DWORD dwMilliSec = 2000;<br /> if (hThread) {<br /> PulseEvent(pEventHandles->hThreadStop);<br /> DWORD dwResult = WaitForSingleObject(hThread, dwMilliSec);<br /> if (WAIT_OBJECT_0 != dwResult) {<br /> // error or timeout. terminate the thread anyway<br /> TerminateThread(hThread, -1);<br /> }<br /><br /> CloseHandle(hThread);<br /> hThread = NULL;<br /> }<br /><br /> return S_OK;<br />}<br /></span></p> <p><b>Main logic during program starts up:</b></p> <ul><li>to create the wakeup event</li><li>to create shutdown signal</li><li>to start the wakeup event listener thread</li></ul> <p><b>and before the program quits:</b></p> <ul><li>to stop the wakeup event listener thread,</li><li>to destroy the wakeup event</li><li>to destroy the shutdown signal</li></ul> <p><span style=";font-family:Courier New;font-size:85%;" ><br />{<br /> HRESULT hr = ClearWakeupNotification(g_szEventName);<br /> hr = AddWakeupNotification(g_szEventName);<br /> HANDLE hWakeupEvent = CreateEvent(NULL, TRUE, FALSE, g_szEventName);<br /> HANDLE hThreadStopEvent = CreateEvent(NULL, TRUE, FALSE, TEXT("ThreadStop"));<br /> EVENTHANDLES eventHandles = {hWakeupEvent, hThreadStopEvent};<br /> HANDLE hWakeupEventListenerThread = NULL;<br /> hr = StartWakeupEventListener(&eventHandles, hWakeupEventListenerThread);<br /><br /><br /> // ..........<br /><br /> hr = StopWakeupEventListener(&eventHandles, hWakeupEventListenerThread);<br /> // thread handle already closed<br /> hr = ClearWakeupNotification(g_szEventName);<br /> CloseHandle(hWakeupEvent);<br /> CloseHandle(hThreadStopEvent);<br />}</span></p> <p> </p> <p> </p><br /><br /><span style="font-size:100%;"><span style="font-weight: bold;">Category: </span><a style="font-weight: bold;" href="http://search.blogger.com/?ie=UTF-8&ui=blg&bl_url=windowsmobilepro.blogspot.com&x=0&y=0&scoring=d&as_q=%22%5BPower%20Management%5D%22">[Power Management]</a></span><div class="blogger-post-footer"><script type="text/javascript"><!--
google_ad_client = "pub-8510650669347560";
google_ad_width = 728;
google_ad_height = 90;
google_ad_format = "728x90_as";
google_ad_type = "text_image";
google_ad_channel ="";
//--></script>
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script></div>Lao Khttp://www.blogger.com/profile/13748590324739892436noreply@blogger.com6tag:blogger.com,1999:blog-21999378.post-1144999757652499742006-04-06T00:27:00.000-07:002006-04-14T00:29:17.666-07:00Extreme Makeover - How to rescue a Pocket PC with partially-damaged display screen<p><b>Extreme Makeover - How to rescue a Pocket PC with partially-damaged display screen</b></p> <p>Pocket PC is a fragile device. Display screen is Achilles' heel, susceptible to scratches. Worse, if the device is dropped on the floor or ground, the screen may be partially damaged (or completely broken, if that day is really not your day). My officemate actually successfully destroyed the screen of an iPAQ 4155 device.</p> <p>Besides the obvious choice of trashing the device, or sending it for repair, can we somewhat DIY and still make use of it? I actually do not have the chance myself, but being able to help an unlucky guy who posted a question in a newsgroup:</p> <blockquote> <p>My touchscreen is a little damaged. After an accidental hard reset it is not possible to go successfully the adjust routine through. I can't start windows mobile (2003). Is there a possibility to start windows and avoid the adjust procedure?</p> </blockquote> <p>His screen was not completely broken, but he could not use the device, because there was no way he could pass the "screen align" procedure after a hard-reset. My first thought was like: If he could not pass the procedure, why not forcibly kill it? The calibration data is stored under a predefine registry key, then he could manually populate the registry himself. </p> <h3>What tools?</h3> <p>The tools are not hard to find, just remote process viewer and remote regeditor, which are shipped along with Microsoft Embedded Tools (free) or Visual Studio (common). The catch is ActiveSync must be up and running for the remote tools to be able to connect to the device. This should not the a problem, as the ActiveSync components should be more close to OS than the calibration process.</p> <h3>What registry key?</h3> <p>The registry key is not publicly documented, and I do not think either Microsoft or OEMs have any reason to document it. So the correct way to locate the registry key is to find another device with the same model, do a search, then copy the values and names. In my Sprint PPC6601 device, the key is <i>HKLM\HARDWARE\DEVICEMAP\TOUCH</i>, and value name is<br /><i>CalibrationData</i>, with value data "<i>507,497 150,763 153,230 886,241 871,767</i>".</p> <p>The guy followed my suggestion, managed to kill the calibration program and populated the registry key. He also contributed another interesting value under that key:</p> <blockquote> <p><i>"MaxCalError"=dword:50</i> - for less sensibility and it works.</p> </blockquote> <h3>Which process to kill?</h3> <p>The final question is how to know which process is showing the "screen align" window. You can guess from the processes listed by remote process viewer. A more rational approach needs another remote tool: the remote spy, which shows all windows in the device. You can easily locate the "screen align" window from the windows captured by remote spy, find which process ID owns the window, then switch to remote process viwer to locate the process.</p> <p><a href="http://http//groups.google.com/group/microsoft.public.pocketpc.developer/browse_thread/thread/d0731581389da268/b4e4fa96504794fd">Read the whole story here</a>.</p> <h3>Wrap Up</h3> <p>There must be a way for Shell to decide not to show the touch screen calibration window upon rebooting. Most probably such information is stored under a predefined registry key. If so, there is really no need to kill the "align screen" window. Instead, using remote regeditor to populate some values is sufficient to rescue your device.</p> <p><br /></p><div class="blogger-post-footer"><script type="text/javascript"><!--
google_ad_client = "pub-8510650669347560";
google_ad_width = 728;
google_ad_height = 90;
google_ad_format = "728x90_as";
google_ad_type = "text_image";
google_ad_channel ="";
//--></script>
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script></div>Lao Khttp://www.blogger.com/profile/13748590324739892436noreply@blogger.com1tag:blogger.com,1999:blog-21999378.post-1144827294593819042006-04-03T00:33:00.000-07:002006-04-12T00:36:37.346-07:00Windows Mobile 5.0 New MAPI Functions Linker Error LNK2019 / LNK2001<p><b>Windows Mobile 5.0 New MAPI Functions Linker Error LNK2019 / LNK2001<br /></b></p> <p>In Windows Mobile 5.0, a few new MAPI functions are exposed, namely:</p> <ul><li><i>MailComposeMessage</i></li><li><i>MailDisplayMessage</i></li><li><i>MailSwitchToAccount</i></li><li><i>MailSwitchToFolder</i></li><li><i>MailSyncMessages</i></li></ul> <p>If you have worked on MAPI, you may notice these functions are not really that much MAPI related. They are more like Outlook oriented, to facilitate developers to better control Outlooks' UI and built in forms. For example, <i>MailComposeMessage</i> brings up the form to compose an outgoing message, and <i>MailDisplayMessage</i> brings up the form to view a message. I guess the reason that Microsoft exposes these APIs is to help developers make use of Outlook in a very high level, not in the low level of MAPI coding.</p> <p>I do like the two functions: <i>MailSwitchToAccount</i> and <i>MailSyncMessages</i>, as I need them for my customized transport. However, as soon as I add them to my code, I get a very puzzling linker error:</p> <blockquote> <p><i>error LNK2019: unresolved external symbol "long __cdecl MailSwitchToAccount(wchar_t const *,unsigned long)" (?MailSwitchToAccount@@YAJPB_WK@Z) referenced in function _Sync</i></p> </blockquote> <p>The lib file "<i>cemapi.lib</i>" is already added to the project's Additional Dependencies, otherwise other MAPI-related code won't even link. So the only reason is because mangled function name generated by the compiler does not match the one in the lib.</p> <p>The function is declared as:</p> <blockquote> <p><b>HRESULT MailSwitchToAccount(</b> <b>LPCTSTR </b><i><a class="synParam" onclick="showTip(this)" href="http://www.blogger.com/post-create.do">pszAccount</a></i><b>, DWORD </b><i><a class="synParam" onclick="showTip(this)" href="http://www.blogger.com/post-create.do">dwFlags</a></i> <b>);</b></p> </blockquote> <p>I decided to trace down to the root, so I did a "<i>dumpbin /exports cemapi.lib</i>" to see what name and signature should the compiler generate to appease the linker:</p> <blockquote> <p><i>?MailSwitchToAccount@@YAJPBGK@Z (long __cdecl MailSwitchToAccount(unsigned short const *,unsigned long))</i></p> </blockquote> <p>Aha! Do you, the reader, find the difference? Yes the mangled function names do not match, which is why the linker is not happy. But pay closer attention to the first parameter. In the source code, it is declared as <i>LCPTSTR</i>. My compiler compiles it to "<i>wchar_t const *</i>", but the compiler building the <i>cemapi.lib</i> makes it to "<i>unsigned short const *</i>"!</p> <p>So here involves a change: <b>Treat wchar_t as built-in type</b>. VS2005 compiler changed the behavior how wchar_t is handled. The previous versions treats <i>wchar_t</i> as <i>unsgined short </i>(via Macro include), but the new compiler in VS2005 treats <i>wchar_t</i> as a built-in type, which is, of course, just <i>wchar_t </i>itself. </p> <p>Apparently the people who built <i>cemapi.lib </i>turned the option off, which IMHO, was not a wise thing to do, as these APIs will be shipped as part of Windows Mobile 5.0 SDK, and will be used only in Visual Studio 2005 environment anyway.</p> <p>To fix the issue is easy:</p> <ul><li>Open the project's <b>Property Pages </b>dialog box. </li><li>Click the <b>C/C++</b> folder.</li><li>Click the <b>Language </b>property page.</li><li>Modify the <b>Treat wchar_t as Built-in Type </b>property.</li></ul> <p>There is also a very <a href="http://blogs.msdn.com/vsdteam/archive/2005/11/16/linker_error_lnk2019_lnk2001.aspx">good blog post</a> from Microsoft employees on the problem. The author summarized a few cases you may encounter such linker error:</p> <ul><li>You have created a new C++ MFC smart device project and changed the Project -> Properties -> C/C++ -> Language -> "Treat wchar_t as built in type" to "No (/Zc:wchar_t-)"</li><li>You have migrated an eVC project to visual Studio 2005, which links to some dependent ATL/MFC DLLs which are compiled using previous versions (like eVC3.0, eVC 4.0 or Visual Studio 2003).</li><li>You have migrated you eVC ATL/MFC project to Visual Studio 2005 that has no dependent DLLs, but the Project -> Properties -> C/C++ -> Language -> "Treat wchar_t as built in type" is set to "No (/Zc:wchar_t-)"</li></ul> <p>My case is exactly the second case, as I've migrated all my projects from Embedded Visual C++ 4 to Visual Studio 2005. <a href="http://windowsmobilepro.blogspot.com/2005/08/manually-migrate-embedded-visual-c.html">Read my migration lessons here...</a></p> <p>And at the end, he said "Microsoft are looking at fixing this issue". I certainly hope so!</p><br /><p><span style="font-size:100%;"><span style="font-weight: bold;">Category: </span><a style="font-weight: bold;" href="http://search.blogger.com/?ie=UTF-8&ui=blg&bl_url=windowsmobilepro.blogspot.com&x=0&y=0&scoring=d&as_q=%22%5BOutlook%20Transport%20MAPI%5D%22">[Outlook / Transport / MAPI]</a></span></p><div class="blogger-post-footer"><script type="text/javascript"><!--
google_ad_client = "pub-8510650669347560";
google_ad_width = 728;
google_ad_height = 90;
google_ad_format = "728x90_as";
google_ad_type = "text_image";
google_ad_channel ="";
//--></script>
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script></div>Lao Khttp://www.blogger.com/profile/13748590324739892436noreply@blogger.com2tag:blogger.com,1999:blog-21999378.post-1144566310841135112006-03-31T00:03:00.000-08:002006-04-09T00:06:38.580-07:00Windows Mobile Secure Socket Implementation Series 4: Changes in Windows Mobile 5.0 platform<p><b>Windows Mobile Secure Socket Implementation Series 4: Changes in Windows Mobile 5.0 platform</b></p> <p>In previous three posts on Windows Mobile secure socket implementation, I talked about:</p> <ul><li><a href="http://windowsmobilepro.blogspot.com/2006/03/windows-mobile-secure-socket.html">general ideas</a></li><li><a href="http://windowsmobilepro.blogspot.com/2006/03/windows-mobile-secure-socket_25.html">source code to prepare a socket for secure connection, to crack a BLOB into a X.509 Certificate, and the callback to validate a X.509 certificate</a></li><li><a href="http://windowsmobilepro.blogspot.com/2006/03/windows-mobile-secure-socket_28.html">subject and CN in X.509 Certificate, and the approach to support wildcard certificate</a></li></ul> <p>In this post I will list the changes of secure socket implementation from Windows Mobile 2003 devices (based on Windows CE 4.2 .NET) to Windows Mobile 5.0 devices (based on Windows CE 5.0 device). </p> <h3>Newly added: remote host name verification</h3> <p>In 5.0 platform, Microsoft adds a new control code <i>SO_SSL_SET_PEERNAME</i>. With such control code, the remote host name is verified by Winsock against the server certificate after a successful SSL handshake. The verification results are then indicated in the certificate validation callback function via the <i>dwFlags </i>parameter. If the specified host name does not match the one indicated in the certificate chain of the SSL Handshake, <i>SSL_CERT_FLAG_ISSUER_UNKNOWN</i> is set in the <i>dwFlags </i>parameter.</p> <p>It is simple to use the control code:</p> <p><span style="font-family:Courier New;font-size:85%;">char* pchHostName = "www.example.com"; // passing somewhere<br />sockerror = WSAIoctl(in_socket, SO_SSL_SET_PEERNAME,<br /> pchHostName, strlen(pchHostName)+1, NULL, 0, NULL, NULL, NULL);<br /></span></p> <p>Notice you need to use <i>strlen(hostname)+1</i> as the input buffer length (to include the NULL terminator).</p> <p>If you go through all my previous three posts, you will immediately find that my code actually is doing the same thing in the certificate validation callback function, but I need <i>SslCrackCertificate</i> to crack the BLOB into a X.509 structure. I think the reason why Microsoft adds this new control code is because <i>SslCrackCertificate</i> and <i>SslFreeCertificate</i> are not publicly documented. </p> <p>My own test reveals that <i>SO_SSL_SET_PEERNAME</i> does not recognize wildcard certificate. Microsoft code possibly just did a literal match between the desired host name and the CN from the subject, like what I did in my <a href="file:///E:/Wireless/Docs/Leisure/windowsmobilepro.blogspot.com/2006/03/windows-mobile-secure-socket_25.html">sample code</a>.</p> <p><b><i>Warning: If you need to support wildcard certificate, do not use SO_SSL_SET_PEERNAME.</i></b></p> <h3>More subtle changes during SSL handshake phase</h3> <p>My experiences dealing with Windows Mobile users tells me: A lot of users forgot to set up their devices' time after a hard-reset. It is not a big deal for smartphones, as the phone can synchronize the time via air. For Pocket PCs, the time is reset to the factory-default one. For example, in my Sprint PPC6600 device (Windows Mobile 2003 SE), the time is reset to some day in 2004.</p> <p>Why the time matters to secure socket programming? Remember we need to validate the lifetime of a server certificate. If the certificate is already expired, there is no reason we should trust the server, but we may present a dialog to the user, and let the user to decide whether to connect or not. However, in the case of a hard-reset device, the certificate's starting time actually is later than the device's current time. Take PPC6600 device as an example, the current time returned by <i>GetLocalTime()</i> is year 2004, but the server certificate is valid from year 2005 to year 2006. What gives? </p> <p>You may simply ignore the "post-dated" certificate and continue to establish a secure connection. Better, as a programmer with good sense, you may present a dialog reminding the user to set up the time correctly. The above logic is natural to implement in Windows Mobile 2003 platform; in which, the server certificate is passed into the validation callback function as "normal" by Winsock, so you have the chance to test the lifetime of the certificate.</p> <p>However, the behavior changed in 5.0 plaform. If the current time of the device is earlier than the starting time of the certificate, <i>dwFlags</i> now contains <i>SSL_CERT_FLAG_ISSUER_UNKNOWN</i>, . IMHO this is a very misleading flag. Now the programmer has no idea whether the server certificate is really a bad one, or the certificate is good but the device's time is bad.</p> <h3>Wrap-Up</h3> <p align="left">You do not really need to change source code in 5.0 platforms, if you do not plan to use the newly added <i>SO_SSL_SET_PEERNAME</i> feature. And, you should not use it at all, if wildcard certificate needs to be supported.</p> <p align="left">In 5.0 platforms, you lose the capability to gracefully handle a device which has a bad time setting.</p> <br /><br /><br /><br /><span style="font-size:100%;"><span style="font-weight: bold;">Category: </span><a style="font-weight: bold;" href="http://search.blogger.com/?ie=UTF-8&ui=blg&bl_url=windowsmobilepro.blogspot.com&x=0&y=0&as_q=%22%5BSSL%20Socket%20Networking%20Connection%20Manager%5D%22">[SSL / Socket / Networking / Connection Manager]</a></span><div class="blogger-post-footer"><script type="text/javascript"><!--
google_ad_client = "pub-8510650669347560";
google_ad_width = 728;
google_ad_height = 90;
google_ad_format = "728x90_as";
google_ad_type = "text_image";
google_ad_channel ="";
//--></script>
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script></div>Lao Khttp://www.blogger.com/profile/13748590324739892436noreply@blogger.com1tag:blogger.com,1999:blog-21999378.post-1144479007092197332006-03-28T23:48:00.000-08:002006-04-08T00:02:43.250-07:00Windows Mobile Secure Socket Implementation Series 3: X.509 Certificate and Wildcard Certificate<p><b>Windows Mobile Secure Socket Implementation Series 3: X.509 Certificate and Wildcard Certificate</b></p> <p>In previous two posts on Windows Mobile secure socket implementation, I talked about <a href="http://windowsmobilepro.blogspot.com/2006/03/windows-mobile-secure-socket.html">general ideas</a>, and the <a href="http://windowsmobilepro.blogspot.com/2006/03/windows-mobile-secure-socket_25.html">source code to prepare a socket for secure connection, to crack a BLOB into a X.509 Certificate, and the callback to validate a X.509 certificate</a>. </p> <h3>More on X.509 Certificate, Subject and CN (Common Name)</h3> <p>The function parsing a subject name to retrieve the CN, ParseCN(), is intentionally left out in the source code in <a href="http://windowsmobilepro.blogspot.com/2006/03/windows-mobile-secure-socket_25.html">previous post</a>. What is a subject, what is CN, and why do we care the subject and CN when we need to validate a certificate?</p> <p>To answer the above questions, some basic knowledge of X.509 certificate is required. Below are two good and quick readings:</p> <ul><li><a href="http://en.wikipedia.org/wiki/X.509">X.509 from Wikipedia, the free encyclopedia</a></li><li><a href="http://java.sun.com/j2se/1.5.0/docs/guide/security/cert3.html">X.509 Certificates and Certificate Revocation Lists (CRLs)</a></li></ul> <p>Subject can be roughly understood as the name of an entity, who can be identified by the certificate. CN refers to common name, and in the internet, most probably a host name. Below is Amazon.com's server certificate. Notice the subject line and CN.</p> <blockquote> <p><i>CN = www.amazon.com, O = Amazon.com Inc., L = Seattle, ST = Washington, C = US</i></p> <p align="center"><img border="0" src="http://photos1.blogger.com/blogger/5783/1371/1600/AmazonCertificate.jpg" width="475" height="468"></p><br /> </blockquote> <p>Now we can answer the question why we need to care subject and CN, because we need to compare CN to the remote host name, to see whether they match. Below is the function to extract CN from the subject line:</p> <p><span style="font-family:Courier New;font-size:85%;"><br />char* ParseCN(char* pchSubjLine)<br />{<br /> char* pchCommonName = NULL;<br /> char* pchEnd = NULL;<br /><br /> if (!pchSubjLine) return NULL;<br /><br /> pchSubjLine = _strlwr(pchSubjLine);<br /> pchCommonName = strstr(pchSubjLine, "cn=");<br /> if (!pchCommonName) {<br /> return NULL;<br /> } <br /><br /> pchCommonName += 3;<br /> pchEnd = pchCommonName;<br /> // find the next separator: , or \t or space, or apos<br /> while ('\0' != *pchEnd && ',' != *pchEnd && ' ' != *pchEnd<br /> && '\t' != *pchEnd && '\'' != *pchEnd) {<br /> pchEnd++;<br /> }<br /> if ('\0' != pchEnd) pchEnd = '\0';<br /><br /> return pchCommonName;<br />}<br /></span></p> <h3>Wildcard Certificate</h3> <p>If you go back to the source code in my <a href="http://windowsmobilepro.blogspot.com/2006/03/windows-mobile-secure-socket_25.html">previous post</a>, you may notice that I did a literal match between CN and the remote host name by simply using <i>_stricmp()</i>. This simple literal match should work for most sites, but recently there is an industry trend to use a wildcard certificate, and literal match won't work against such certificate.</p> <p>What is a wildcard certificate? Let us say a company "<i>example.com</i>" wants to expose 10 web servers to the public internet, all supporting HTTPS:</p> <ul><li><i>https://www.example.com</i></li><li><i>https://www01.example.com</i></li><li><i>...</i></li><li><i>https://www09.example.com</i></li></ul> <p>The company can buy 10 certificates from CA , each using the fully qualified host name as the CN. Alternatively, the company can buy ONE certificate from CA, using "<i>*.example.com</i>" as the CN. The price of a wildcard certificate is definitely higher than a "normal" certificate, but if the company has a lot of web servers, wildcard certificate can save big. A little bit more information regarding wildcard certificate can be found in "<a href="http://www.microsoft.com/technet/prodtechnol/isa/2004/maintain/wildcard.mspx">Publishing Multiple Web Sites using a Wildcard Certificate in ISA Server 2004</a>".</p> <p>Modern browsers like Firefox and IE have no difficulty supporting wildcard certificate and do not complain. Interestingly enough, I found that Pocket IE in both Windows Mobile 2003 devices and Windows Mobile 5.0 devices complains that a wildcard certificate is not a good match to the remote host.</p> <p>Back to our code. We need to modify the simple literal match to a slightly more advanced one:</p> <p><span style="font-family:Courier New;font-size:85%;">if ('*' == *pchCN && '.' == *(pchCN+1)) {<br /> while ('\0' != *pchRemoteHost && '.' != *pchRemoteHost) <br /> pchRemoteHost++;<br /> if ('.' == *pchRemoteHost) {<br /> bMatched = !(_stricmp(pchRemoteHost+1, pchCN+2));<br /> }<br /> // if there is no dot, bMatch remains FALSE<br />} else {<br /> bMatched = !(_stricmp(pchRemoteHost, pchCN));<br />}<br /></span></p> <p> </p> <br /><br /><br /><span style="font-size:100%;"><span style="font-weight: bold;">Category: </span><a style="font-weight: bold;" href="http://search.blogger.com/?ie=UTF-8&ui=blg&bl_url=windowsmobilepro.blogspot.com&x=0&y=0&as_q=%22%5BSSL%20Socket%20Networking%20Connection%20Manager%5D%22">[SSL / Socket / Networking / Connection Manager]</a></span><div class="blogger-post-footer"><script type="text/javascript"><!--
google_ad_client = "pub-8510650669347560";
google_ad_width = 728;
google_ad_height = 90;
google_ad_format = "728x90_as";
google_ad_type = "text_image";
google_ad_channel ="";
//--></script>
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script></div>Lao Khttp://www.blogger.com/profile/13748590324739892436noreply@blogger.com0tag:blogger.com,1999:blog-21999378.post-1144454444259311852006-03-25T16:46:00.000-08:002006-04-07T23:53:17.233-07:00Windows Mobile Secure Socket Implementation Series 2: Sample Source Code<p style="font-weight: bold;">Windows Mobile Secure Socket Implementation Series 2: Sample Source Code</p> <p>In previous post, I talked about <a href="http://windowsmobilepro.blogspot.com/2006/03/windows-mobile-secure-socket.html">general ideas to write secure socket applications in Windows Mobile device (or actually on Windows CE platforms)</a>. The current post has the source code and simple explanations on the code.</p><br /><br /><h3>Function: Establish a secure socket connection to a remote host:port</h3> <p>Notice the remote host name is passed as certificate validation function's <i>pvArg</i>, which will be given back to us by Winsock when the validation function is called.</p> <p> </p> <font face="Courier" size="2"><br />int SecureConnect(int in_socket, <br /> const struct sockaddr * in_pHostInetAddr, <br /> int in_port )<br />{<br /> struct sockaddr_in theInetAddr;<br /> int sockerror = 0;<br /><br /> /* initialize the address structures */<br /> memset (&theInetAddr, 0, sizeof(theInetAddr));<br /><br /> theInetAddr.sin_family = AF_INET;<br /> theInetAddr.sin_addr.s_addr = htonl(INADDR_ANY);<br /> theInetAddr.sin_port = htons(in_port);<br /><br /> // make it secure<br /> {<br /> DWORD dwOptVal = SO_SEC_SSL;<br /> DWORD dwBytes = 0;<br /> SSLVALIDATECERTHOOK sslValidateFunc;<br /><br /> sockerror = setsockopt(in_socket, SOL_SOCKET, <br /> SO_SECURE, (LPSTR)&dwOptVal, sizeof(dwOptVal));<br /><br /> if (SOCKET_ERROR == sockerror){<br /> // error logging<br /> return 0;<br /> }<br /><br /> // register certificate validation callback <br /> sslValidateFunc.HookFunc = certificateValidationCallback;<br /> sslValidateFunc.pvArg = "www.sample.com"; // ... passing server name from your context<br /><br /> sockerror = WSAIoctl(in_socket, SO_SSL_SET_VALIDATE_CERT_HOOK,<br /> &sslValidateFunc, sizeof(sslValidateFunc), NULL, 0, &dwBytes, NULL, NULL);<br /><br /> if (SOCKET_ERROR == sockerror){<br /> // error logging<br /> return 0;<br /> }<br /> }<br /><br /><br /> // connect<br /> sockerror = connect(in_socket, <br /> (struct sockaddr *)in_pHostInetAddr, sizeof (*in_pHostInetAddr));<br /> if (sockerror == SOCKET_ERROR) {<br /> // error logging<br /> return 0;<br /> }<br /><br /> {<br /> // show SSLCONNECTIONINFO<br /> SSLCONNECTIONINFO SSLConnectionInfo;<br /> DWORD dwBytes = 0;<br /> sockerror = WSAIoctl(in_socket, SO_SSL_GET_CONNECTION_INFO,<br /> NULL, 0, &SSLConnectionInfo, sizeof(SSLConnectionInfo), &dwBytes, NULL,NULL);<br /> if (sockerror == SOCKET_ERROR) {<br /> // error logging<br /> return 0;<br /> }<br /> ShowConnectionInfo(&SSLConnectionInfo);<br /> }<br /><br /> return 1;<br />}<br /></font><br /><br /><h3>Function: Load the functions from <i>schannel.dll</i>, to crack a BLOB into X.509 certificate </h3> <p>The two functions pointers are defined as global variables so that they do not need to be dynamically loaded or unloaded during each SSL handshake phase. </p> <font face="Courier" size="2"><br /><br />#include <wincrypt.h><br />#include <schnlsp.h><br /><br />// load SslCrackCertificate and SslFreeCertificate<br />#define SSL_CRACK_CERTIFICATE_NAME TEXT("SslCrackCertificate")<br />#define SSL_FREE_CERTIFICATE_NAME TEXT("SslFreeCertificate")<br /><br />HRESULT LoadSSL()<br />{<br /> // already loaded?<br /> if (gSslCrackCertificate && gSslFreeCertificate) return S_OK;<br /><br /> hSchannelDLL = LoadLibrary(TEXT("schannel.dll"));<br /> if (!hSchannelDLL) {<br /> // error logging<br /> return E_FAIL;<br /> }<br /><br /> gSslCrackCertificate = (SSL_CRACK_CERTIFICATE_FN)GetProcAddress(hSchannelDLL, SSL_CRACK_CERTIFICATE_NAME);<br /> gSslFreeCertificate = (SSL_FREE_CERTIFICATE_FN)GetProcAddress(hSchannelDLL, SSL_FREE_CERTIFICATE_NAME);<br /><br /> if (!gSslCrackCertificate || !gSslFreeCertificate) {<br /> // error logging<br /> gSslCrackCertificate = NULL;<br /> gSslFreeCertificate = NULL;<br /> FreeLibrary(hSchannelDLL);<br /> hSchannelDLL = NULL;<br /> return E_FAIL;<br /> } else {<br /> return S_OK;<br /> }<br />}<br /><br />HRESULT FreeSSL()<br />{<br /> if (hSchannelDLL) {<br /> FreeLibrary(hSchannelDLL);<br /> hSchannelDLL = NULL;<br /> }<br /> return S_OK;<br />}<br /></font><br /><br /><h3>Function: Show SSL connection information for debugging or learning purpose</h3> <p> Do not put it into your release build. </p> <font face="Courier" size="2"><br /><br />void ShowConnectionInfo(SSLCONNECTIONINFO *pConnectionInfo)<br />{<br /> TCHAR szTemp[1028];<br /> memset(szTemp, 0, 1028*sizeof(TCHAR));<br /><br /> switch(pConnectionInfo->dwProtocol)<br /> {<br /> case SSL_PROTOCOL_SSL3:<br /> swprintf(szTemp+wcslen(szTemp), TEXT("Protocol: SSL3"));<br /> break;<br /><br /> case SSL_PROTOCOL_PCT1:<br /> swprintf(szTemp+wcslen(szTemp), TEXT("Protocol: PCT"));<br /> break;<br /><br /> case SSL_PROTOCOL_SSL2:<br /> swprintf(szTemp+wcslen(szTemp), TEXT("Protocol: SSL2"));<br /> break;<br /><br /> default:<br /> swprintf(szTemp+wcslen(szTemp), TEXT("Protocol: 0x%08x"), pConnectionInfo->dwProtocol);<br /> }<br /> wcscat(szTemp, TEXT("\n"));<br /><br /> switch(pConnectionInfo->aiCipher)<br /> {<br /> case CALG_RC4: <br /> swprintf(szTemp+wcslen(szTemp), TEXT("Cipher: RC4"));<br /> break;<br /><br /> case CALG_3DES: <br /> swprintf(szTemp+wcslen(szTemp), TEXT("Cipher: Triple DES"));<br /> break;<br /><br /> case CALG_RC2: <br /> swprintf(szTemp+wcslen(szTemp), TEXT("Cipher: RC2"));<br /> break;<br /><br /> case CALG_DES: <br /> swprintf(szTemp+wcslen(szTemp), TEXT("Cipher: DES"));<br /> break;<br /><br /> case CALG_SKIPJACK: <br /> swprintf(szTemp+wcslen(szTemp), TEXT("Cipher: Skipjack"));<br /> break;<br /><br /> default: <br /> swprintf(szTemp+wcslen(szTemp), szTemp, TEXT("Cipher: 0x%08x"), pConnectionInfo->aiCipher);<br /> }<br /> wcscat(szTemp, TEXT("\n"));<br /><br /> swprintf(szTemp+wcslen(szTemp), TEXT("Cipher strength: %d"), pConnectionInfo->dwCipherStrength);<br /> wcscat(szTemp, TEXT("\n"));<br /><br /> switch(pConnectionInfo->aiHash)<br /> {<br /> case CALG_MD5: <br /> swprintf(szTemp+wcslen(szTemp), TEXT("Hash: MD5"));<br /> break;<br /><br /> case CALG_SHA: <br /> swprintf(szTemp+wcslen(szTemp), TEXT("Hash: SHA"));<br /> break;<br /><br /> default: <br /> swprintf(szTemp+wcslen(szTemp), szTemp, TEXT("Hash: 0x%08x"), pConnectionInfo->aiHash);<br /> }<br /> wcscat(szTemp, TEXT("\n"));<br /><br /> swprintf(szTemp+wcslen(szTemp), TEXT("Hash strength: %d"), pConnectionInfo->dwHashStrength);<br /> wcscat(szTemp, TEXT("\n"));<br /><br /> switch(pConnectionInfo->aiExch)<br /> {<br /> case CALG_RSA_KEYX: <br /> case CALG_RSA_SIGN: <br /> swprintf(szTemp+wcslen(szTemp), TEXT("Key exchange: RSA"));<br /> break;<br /><br /> case CALG_KEA_KEYX: <br /> swprintf(szTemp+wcslen(szTemp), TEXT("Key exchange: KEA"));<br /> break;<br /><br /> default: <br /> swprintf(szTemp+wcslen(szTemp), TEXT("Key exchange: 0x%08x"), pConnectionInfo->aiExch);<br /> }<br /> wcscat(szTemp, TEXT("\n"));<br /><br /> swprintf(szTemp+wcslen(szTemp), TEXT("Key exchange strength: %d"), pConnectionInfo->dwExchStrength);<br /> MessageBox(NULL, szTemp, NULL, NULL);<br />}<br /></font><br /><br /><h3>Function: Certificate validation callback</h3> <p>Notice the order how it checks the certificate and other parameters. Sometimes Winsock passes false alarms in <i>dwFlags</i>. The way how Winsock internally handles the certificate in Windows Mobile 5.0 devices (Windows CE 5.0 based) is also changed from Windows Mobile 2003 devices (CE 4.2 based). This will be discussed in my later post.</p> <br /><font face="Courier" size="2"><br />// the certificate validattion for SSL<br />int certificateValidationCallback(<br /> DWORD dwType,<br /> LPVOID pvArg,<br /> DWORD dwChainLen,<br /> LPBLOB pCertChain,<br /> DWORD dwFlags)<br />{<br /> X509Certificate* pCert = NULL; <br /> int nRet = SSL_ERR_CERT_UNKNOWN;<br /><br /> // dwType must be SSL_CERT_X.509<br /> if (dwType != SSL_CERT_X509) {<br /> // error logging<br /> return nRet;<br /> }<br /><br /> if (dwFlags & SSL_CERT_FLAG_ISSUER_UNKNOWN) {<br /> // error logging<br /> return nRet;<br /> }<br /><br /> if (pCertChain == NULL) return nRet;<br /> ASSERT(dwChainLen == 1);<br /><br /> if (!gSslCrackCertificate || !gSslFreeCertificate) {<br /> // error logging<br /> return nRet; // unable to crack<br /> }<br /><br /> // crack X.509 Certificate<br /> if (!gSslCrackCertificate(pCertChain->pBlobData, pCertChain->cbSize, TRUE, &pCert)) {<br /> // error logging<br /> return SSL_ERR_BAD_DATA;<br /> }<br /><br /> // Site check<br /> {<br /> char* pchSubject = NULL;<br /> char* pchCN = NULL;<br /> BOOL bMatched = FALSE;<br /> char* pchRemoteHost = (char*)pvArg;<br /><br /> pchSubject = pCert->pszSubject;<br /> <br /> // here you need to parse the subjec to retrieve the CN name <br /> pchCN = ParseCN(pchSubject);<br /> if (!pchCN) {<br /> goto FuncExit;<br /> } <br /><br /> // CN comparison<br /> bMatched = !(_stricmp(pchRemoteHost, pchCN));<br /> if (!bMatched) {<br /> // error logging<br /> goto FuncExit;<br /> }<br /> }<br /><br /> // validFrom, validUntil check<br /> {<br /> SYSTEMTIME stNow;<br /> FILETIME ftNow;<br /> FILETIME ftValidFrom = pCert->ValidFrom;<br /> FILETIME ftValidUntil = pCert->ValidUntil;<br /><br /> GetSystemTime(&stNow);<br /> SystemTimeToFileTime(&stNow, &ftNow);<br /><br /> if (!(IsEarlierThan(&ftValidFrom, &ftNow) && IsEarlierThan(&ftNow, &ftValidUntil))) {<br /> // give user an option to continue or not<br /> // a little more lenient than Subject check<br /> }<br /> }<br /><br /> nRet = SSL_ERR_OKAY;<br /><br />FuncExit:<br /> gSslFreeCertificate(pCert);<br /><br /> return nRet;<br />}<br /> </font> <br /><p></p><br /><span style="font-size:100%;"><span style="font-weight: bold;">Category: </span><a style="font-weight: bold;" href="http://search.blogger.com/?ie=UTF-8&ui=blg&bl_url=windowsmobilepro.blogspot.com&x=0&y=0&as_q=%22%5BSSL%20Socket%20Networking%20Connection%20Manager%5D%22">[SSL / Socket / Networking / Connection Manager]</a></span><div class="blogger-post-footer"><script type="text/javascript"><!--
google_ad_client = "pub-8510650669347560";
google_ad_width = 728;
google_ad_height = 90;
google_ad_format = "728x90_as";
google_ad_type = "text_image";
google_ad_channel ="";
//--></script>
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script></div>Lao Khttp://www.blogger.com/profile/13748590324739892436noreply@blogger.com8tag:blogger.com,1999:blog-21999378.post-1144394821459882192006-03-22T00:24:00.000-08:002006-04-07T23:47:43.163-07:00Windows Mobile Secure Socket Implementation Series 1: General Idea<p style="font-weight: bold;">Windows Mobile Secure Socket Implementation Series 1: General Idea</p> <p>Whenever you need to write socket-based programs, very possibly you need to implement a secure socket. For example, if you develop your own mini-http client, you have to deal with HTTPS; if you write an IMAP4 client, you may need to support STARTTLS command. Or, you are writing both the server in the desktop and the client for Windows Mobile device, and need to support a secure communication channel.</p> <p>I plan to write four articles on the series of secure socket implementation:</p> <ul><li>General idea</li><li>Sample source code</li><li>X.509 Certificate and how to deal with wildcard certificate<br /></li><li>Changes in Windows Mobile 5.0 platform (vs. 2003 devices on 4.2 platform)</li></ul> <p>Different from Windows desktop environment, Windows CE platform exposes a very nice way to write secure socket program. Adding a security infrastructure requires few code changes to "normal non-secure" socket-based applications. Once a secure socket is connected, the application may send and receive data on that socket unaware that the data over the wire is encoded. You can just write the boilerplate socket code and functions: socket(), connect(), read(), recv(), closesocket(). </p> <p>The procedure to establish a secure socket connection is well documented by Microsoft, ever since 3.0:</p> <ul><li><a href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/wcecomm/html/_wcesdk_Implementing_a_Secure_Socket.asp">Microsoft Windows CE 3.0/ .NET 4.2 Implementing a Secure Socket</a></li><li><a href="http://http//msdn.microsoft.com/library/default.asp?url=/library/en-us/wcecomm5/html/wce50conimplementingasecuresocket.asp">Microsoft Windows CE .NET 5.0 Implementing a Secure Socket</a></li></ul> <p>Below are the two critical steps:</p> <ul><li>Set the socket in secure mode with the <a href="http://msdn.microsoft.com/library/en-us/wcecomm5/html/wce50lrfsetsockoptwindowssockets.asp">setsockopt</a> function. Set <i>level</i> to SOL_SOCKET, <i>optname</i> to SO_SECURE, and <i>optval</i> to a <b>DWORD</b> set to SO_SEC_SSL. </li><li>Specify the certificate validation callback function by calling <a href="http://msdn.microsoft.com/library/en-us/wcecomm5/html/wce50lrfwsaioctl.asp">WSAIoctl</a> with the SO_SSL_SET_VALIDATE_CERT_HOOK control code.</li></ul> <p>Notice the certificate validation callback function: </p> <pre>int SslValidate (<br /> DWORD dwType<br /> LPVOID pvArg<br /> DWORD dwChainLen<br /> LPBLOB pCertChain<br /> DWORD dwFlags<br />);</pre> <p>Below are explanations of some important parameters: </p><ul type="disc"><li>The <i>dwType</i> parameter specifies the data type pointed to by <i>pCertChain</i>. It must be SSL_CERT_X.509. </li><li>The <i>pvArg</i> parameter is the application-defined context. It is a nice place to pass information against which you want to verify, for example, remote host name. </li><li>The <i>pCertChain</i> parameter is a pointer to a BLOB struct, which contains a X.509 certificate (ISO standard). The certificate is the server certificate. You can parse the certificate to extract the pertinent data like the subject and life cycle.</li><li><i>dwFlags</i> parameter will contain SSL_CERT_FLAG_ISSUER_UNKNOWN, if the root issuer of the certificate could not be found in the client device's CA database. <b>Notice WinSock sometimes passes false alarms in this parameter.</b></li></ul> <p>If you simply return SSL_ERR_OKEY in your certificate validation callback, then any faked or invalid SSL certificate is deemed valid. This obviously defeats the purpose of establishing a trusted secure communication channel. You need to do your due diligence by testing at least three things:</p> <ul><li>to test the <i>dwFlags</i> passed to you by WinSock, </li><li>to test the server certificate to see whether the certificate subject name matches the remote host name, </li><li>and, to test whether the server certificate is already expired.</li></ul> <p>Most probably you do not need to test the issuer, since Winsock already did the job by checking the server certificate against the root CA store in the device.</p> <p>One tricky business of how to parse the <i>pCertChain</i> Blob to get the following structure:</p> <pre>typedef struct _X509Certificate {<br /> DWORD Version;<br /> DWORD SerialNumber[4];<br /> ALG_ID SignatureAlgorithm;<br /> FILETIME ValidFrom;<br /> FILETIME ValidUntil;<br /> PSTR pszIssuer;<br /> PSTR pszSubject;<br /> PctPublicKey *pPublicKey;<br />} X509Certificate, * PX509Certificate;</pre> <p>The way to crack the Blob is not documented by Microsoft, but it it not difficult to find out by searching in major search engines: to use <i>SslCrackCertificate</i> and <i>SslFreeCertificate</i> that are exported from <i>schannel.dll</i>. Once you have the X.509 structure, you can easily validate it against the remote host name (by checking <i>pszSubject</i>), and life cycle (by checking <i>ValidFrom </i>and <i>ValidUtil</i>).</p> <p>I'll post ready-to-compile source code in my next post.</p><br /><br /><span style="font-size:100%;"><span style="font-weight: bold;">Category: </span><a style="font-weight: bold;" href="http://search.blogger.com/?ie=UTF-8&ui=blg&bl_url=windowsmobilepro.blogspot.com&x=0&y=0&as_q=%22%5BSSL%20Socket%20Networking%20Connection%20Manager%5D%22">[SSL / Socket / Networking / Connection Manager]</a></span><div class="blogger-post-footer"><script type="text/javascript"><!--
google_ad_client = "pub-8510650669347560";
google_ad_width = 728;
google_ad_height = 90;
google_ad_format = "728x90_as";
google_ad_type = "text_image";
google_ad_channel ="";
//--></script>
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script></div>Lao Khttp://www.blogger.com/profile/13748590324739892436noreply@blogger.com2tag:blogger.com,1999:blog-21999378.post-1143962119700353332006-03-18T18:45:00.000-08:002006-04-05T00:11:15.026-07:001.1 .NET Framework is Needed for Smart Device Projects targeting 1.0 NET CF (Compact Framework) in Visual Studio 2005 (VS2005)<p style="font-weight: bold;">1.1 .NET Framework is Needed for Smart Device Projects targeting 1.0 NET CF (Compact Framework) in Visual Studio 2005 (VS2005)</p> <p>Our new team member was opening a SDK sample C# solution in Visual Studio 2005, and could not build it. I took a look at the output window. The output was huge with 700+ lines, considering how tiny the sample project is. The following error message was shown there:</p> <blockquote> <p>C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\Microsoft.CSharp.Targets(147,9): error VSD6000: Projects targeting .NET Compact Framework 1.0 require version 1.1 of the .NET Framework, which is not detected on this machine.</p> </blockquote> <p>This sounds strange and interesting, as I never seen this error message in my own PC. A quick search results in the following MSDN2 library documentation:</p> <blockquote> <p><a href="http://msdn2.microsoft.com/en-us/library/ms184406.aspx">Version 1.1 of .NET Framework required</a></p> </blockquote> <p>Looks like the team member just installed a fresh PC with VS2005 and Windows Mobile SDKs, and apparently Visual Studio 2005 installed .NET Framework 2.0, but not 1.1. To solve the problem is easy, just downloading .NET Framework 1.1 and installing it in the team member's PC.</p> <p>I did not see this problem in my own PC, because several versions of .NET Framework already reside in my PC. Such weird requirement actually puzzled me. Why cannot .NET 2.0 Framework do the job, if .NET 1.1 can do? I am not familiar with what happens under the hood, but just wondering how confusing it is. I myself did a lot of java coding (ever since JDK 1.1), and I've never seen such a weird requirement that old JDK or JRE has to be present for some stuff to work. Kudos to Sun Microsystem guys!</p> <p>Another thing worth mentioning is one statement in that MSDN2 documentation page:</p> <blockquote> <p>Smartphone 2003 projects fall into this category (.NET Compact Framework version 1.0)</p> </blockquote> <p>Sometimes I saw people posted questions to certain forums wondering how to develop .NET CF 2.0 applications for Smartphone 2003 platforms. Unfortunately this is not supported. The root reason is that Smartphone 2003 does not persist "\Windows" folder (the one it persists is "\Storage\Windows"). Rather funny, huh? It is not because certain APIs are not available in Smartphone 2003, nor because Smartphone 2003 is "too small"...</p> <p>The following .NET CF team blog presents an excellent table on what platforms can support .NET CF 2.0:</p> <blockquote> <p><a href="http://blogs.msdn.com/netcfteam/archive/2005/10/11/479793.aspx">.NET Compact Framework Version 2 .CAB Files Explained</a> </p> </blockquote> <p>In short, .NET CF 2.0 is supported on:</p> <ul><li>Pocket PC 2003 and 2003 SE</li><li>Windows Mobile 5.0 PPC</li><li>Windows Mobile 5.0 Smartphone</li></ul> <p>You even cannot find an installation .NETCFv2 CAB package for Smartphone 2003 platform.</p> <p>Out of curiosity, I checked what .NET CF version are stored out of box for the following devices:</p> <ul><li>Sprint PPC6700: 1.0.4292.00 (Windows Mobile 5.0 Pocket PC, OS Version 5.1.1700, Build 14352.0.1.0)</li><li>Sprint PPC6601: 1.0.3316.00 (Windows Mobile 2003 SE Pocket PC, OS Version 4.21.1088, Build 14132)</li><li>I-Mate SP3i: 1.0.3316.00 (Windows Mobile 2003 Smartphone)</li></ul><br /><br /><br /><span style="font-size:100%;"><span style="font-weight: bold;">Category: </span><a style="font-weight: bold;" href="http://search.blogger.com/?ie=UTF-8&ui=blg&bl_url=windowsmobilepro.blogspot.com&x=0&y=0&scoring=d&as_q=%22%5BDevelopment%20Environment%5D%22">[Development Environment]</a></span><div class="blogger-post-footer"><script type="text/javascript"><!--
google_ad_client = "pub-8510650669347560";
google_ad_width = 728;
google_ad_height = 90;
google_ad_format = "728x90_as";
google_ad_type = "text_image";
google_ad_channel ="";
//--></script>
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script></div>Lao Khttp://www.blogger.com/profile/13748590324739892436noreply@blogger.com0tag:blogger.com,1999:blog-21999378.post-1143965379800501672006-03-15T00:08:00.000-08:002006-04-03T17:45:21.520-07:00Source code to find out all the programs that are installed in a Windows Mobile device and that can be un-Installed<p style="font-weight: bold;">Source code to find out all the programs that are installed in a Windows Mobile device and that can be un-Installed</p> <p>In the post "<a href="http://windowsmobilepro.blogspot.com/2006/03/programmatically-find-out-all-programs.html">Programmatically find out all the programs that can be unInstalled in Windows Mobile devices</a>", I showed how to locate a list of programs installed in a Windows Mobile device. Pocket PC 2003 and other newer platforms (Smartphone 2003, Pocket PC 5.0, and Smartphone 5.0) have to be handled differently. </p> <p> A reader actually sent me an email for the source code. Oh well this is an easy one so I am posting here:</p><font face="Courier" size="2"><br />#include "cfgmgrapi.h"<br />HRESULT QueryAllInstalled_DM()<br />{<br /> LPTSTR szProvXMLOut = NULL;<br /> TCHAR szProvXMLIn[512];<br /><br /> memset(szProvXMLIn, 0, 512*sizeof(TCHAR));<br /> wcscat(szProvXMLIn, TEXT("<wap-provisioningdoc><characteristic-query type=\"UnInstall\">"));<br /> wcscat(szProvXMLIn, TEXT("</characteristic-query></wap-provisioningdoc>"));<br /><br /> HRESULT hr = DMProcessConfigXML(szProvXMLIn, CFGFLAG_PROCESS, &szProvXMLOut);<br /> if (!FAILED(hr)) {<br /> ALERT2(TEXT("SUCCESS"), TEXT("DM"));<br /> } else {<br /> ALERT2(TEXT("FAILED"), TEXT("DM"));<br /> }<br /> ALERT2(szProvXMLOut, TEXT("DM"));<br /><br /> DELETE_STR(szProvXMLOut);<br /><br /> return hr;<br />}<br /><br /><br />#define APPS_REGHOME TEXT("\\Software\\Apps")<br />static HRESULT QueryAllInstalled_Registry()<br />{<br /> HRESULT hr = E_FAIL;<br /> LRESULT lr = E_FAIL;<br /> HKEY hKey = NULL;<br /><br /> DWORD dwcSubKeys = 0; // Number of sub keys<br /> DWORD dwcMaxSubKeyName = 0; // Longest sub key name<br /> TCHAR* szSubKeyName = NULL; // subkey names<br /> DWORD j = 0;<br /><br /> // Open the predefined registry<br /> lr = RegOpenKeyEx(HKEY_LOCAL_MACHINE, APPS_REGHOME, 0, 0, &hKey);<br /> if (ERROR_SUCCESS != lr) {<br /> goto FuncExit;<br /> }<br /> <br /> // Get Value count.<br /> lr = RegQueryInfoKey(hKey, // Key handle.<br /> NULL, // Buffer for class name.<br /> NULL, // Length of class string.<br /> NULL, // Reserved.<br /> &dwcSubKeys, // Number of sub keys.<br /> &dwcMaxSubKeyName, // Longest sub key size.<br /> NULL, // Longest class string.<br /> NULL, // Number of values for this key.<br /> NULL, // Longest Value name.<br /> NULL, // Longest Value data.<br /> NULL, // Security descriptor.<br /> NULL); // Last write time.<br /> <br /> // Enumerate the sub keys<br /> if (!dwcSubKeys || dwcMaxSubKeyName <= 0) {<br /> goto FuncExit;<br /> }<br /> szSubKeyName = new TCHAR[dwcMaxSubKeyName+1];<br /> if (NULL == szSubKeyName) {<br /> goto FuncExit;<br /> }<br /><br /> for (j = 0, lr = ERROR_SUCCESS; j < dwcSubKeys; j++)<br /> {<br /> DWORD dwcSubKeyName = dwcMaxSubKeyName;<br /> memset(szSubKeyName, 0, sizeof(TCHAR)*(dwcMaxSubKeyName+1));<br /> HKEY hSubKey = NULL;<br /><br /> lr = RegEnumKeyEx(<br /> hKey, <br /> j,<br /> szSubKeyName, <br /> &dwcSubKeyName,<br /> NULL,<br /> NULL,<br /> NULL,<br /> NULL);<br /><br /> if (ERROR_SUCCESS != lr) {<br /> continue;<br /> }<br /><br /> // now we have the key name. let us open it.<br /> lr = RegOpenKeyEx(hKey, szSubKeyName, 0, 0, &hSubKey);<br /> if (ERROR_SUCCESS != lr) {<br /> continue;<br /> }<br /><br /> DWORD dwInstl = 0;<br /> DWORD dwValueType = REG_DWORD;<br /> DWORD dwValueLen = sizeof(DWORD);<br /> lr = RegQueryValueEx(hSubKey, TEXT("Instl"), NULL, &dwValueType, (LPBYTE)&dwInstl, &dwValueLen);<br /> if (ERROR_SUCCESS == lr) {<br /> if (dwInstl == 1) {<br /> ALERT2(szSubKeyName, TEXT("From Registry"));<br /> }<br /> }<br /><br /> RegCloseKey(hSubKey);<br /> }<br /><br />FuncExit:<br /> if (szSubKeyName) {<br /> delete []szSubKeyName;<br /> }<br /> if (hKey) {<br /> RegCloseKey(hKey);<br /> }<br /><br /> return hr;<br />}<br /><br /></font><br /><br /><span style="font-size:100%;"><span style="font-weight: bold;">Category: </span><a style="font-weight: bold;" href="http://search.blogger.com/?ie=UTF-8&ui=blg&bl_url=windowsmobilepro.blogspot.com&x=0&y=0&as_q=%22[Setup%20Install%20unInstall%20Upgrade]%22">[Setup / Install / unInstall / Upgrade]</a></span><div class="blogger-post-footer"><script type="text/javascript"><!--
google_ad_client = "pub-8510650669347560";
google_ad_width = 728;
google_ad_height = 90;
google_ad_format = "728x90_as";
google_ad_type = "text_image";
google_ad_channel ="";
//--></script>
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script></div>Lao Khttp://www.blogger.com/profile/13748590324739892436noreply@blogger.com0tag:blogger.com,1999:blog-21999378.post-1144128895773752202006-03-12T22:34:00.000-08:002006-04-07T00:30:16.486-07:00Programmatically find out all the programs that can be unInstalled in Windows Mobile devices<p><b>Programmatically find out all the programs that can be unInstalled in Windows Mobile devices</b></p> <p>In my previous post, I talked about how to <a href="http://windowsmobilepro.blogspot.com/2006/03/programmatically-uninstallremovedelete.html">programmatically unInstall/remove/delete one program in Windows Mobile devices</a>. Notice that is only for one program. In this post, I am going to talk about how to find out all the programs that can be un-installed in a Windows Mobile device. With such a list, we can programmatically un-install all those programs. To enterprise customers, such functionality is a very welcome one, who deem the ability to remote-destroying lost or stolen devices a MUST-Have feature.</p> <p>Like what I did in the previous post on <a href="http://windowsmobilepro.blogspot.com/2006/03/programmatically-uninstallremovedelete.html">programmatically unInstall/remove/delete one program in Windows Mobile devices</a>, I have to treat Pocket PC 2003 differently from other newer platforms to locate a list of un-installable programs</p> <h3>Pocket PC 2003 platform</h3> <p>Information about what programs are installed in a Pocket PC 2003 device can be found under registry key "\HKLM\SOFTWARE\Apps\". Each program is listed as a sub-key, with program name as the sub-key name. For each program, the value "CabFile" stores what is the original CAB file (the installation package), and value "InstallDir" is where (in which directory) the program is installed to.</p> <p>Notice not all the programs listed there can be unInstalled, but only the sub-key with value "Instl" = dword:1. So to find a list of programs that can be uninstalled in a Pocket PC 2003 device, you can simply iterate through all sub-keys under registry hive "\HKLM\SOFTWARE\Apps\" with value "Instl" = dword:1. The APIs to use are RegOpenKeyEx, RegQueryInfoKey, RegQueryValueEx, and mainly RegEnumKeyEx. </p> <h3>Other newer platforms (Smartphone 2003, Pocket PC 5.0, Smartphone 5.0)</h3> <p>As I put in my previous post, Microsoft wants to move anything regarding mobile device management and configuration to its CSP (<a href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/mobilesdk5/html/wce51conconfigurationserviceproviderreferenceforwindowsmobiledevices.asp">Configuration Service Provider</a>) architecture. UnInstallation is one CSP. UnInstall Configuration Service Provider not only uninstalls applications from the device, but also returns information like what programs can be unInstalled. Below is the exact XML to feed into DMProcessConfigXML to get the list of un-installable programs in a Smartphone 2003 device, Pocket PC 5.0 device, or Smartphone 5.0 device:</p> <p><span style="font-family:Courier;font-size:85%;"> <wap-provisioningdoc><br /> <characteristic-query type="UnInstall"><br /> </characteristic-query> </wap-provisioningdoc></span></p><br /><br /><br /><span style="font-size:100%;"><span style="font-weight: bold;">Category: </span><a style="font-weight: bold;" href="http://search.blogger.com/?ie=UTF-8&ui=blg&bl_url=windowsmobilepro.blogspot.com&x=0&y=0&as_q=%22%5BSetup%20Install%20unInstall%20Upgrade%5D%22">[Setup / Install / unInstall / Upgrade]</a></span><div class="blogger-post-footer"><script type="text/javascript"><!--
google_ad_client = "pub-8510650669347560";
google_ad_width = 728;
google_ad_height = 90;
google_ad_format = "728x90_as";
google_ad_type = "text_image";
google_ad_channel ="";
//--></script>
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script></div>Lao Khttp://www.blogger.com/profile/13748590324739892436noreply@blogger.com0