GPS Programming Tips for Windows Mobile - Part 1
NETCF: Memory leak... now what??
Supporting Kiosk-Applications on Windows Mobile (Technically achievable vs. supported)
Wireless Programming on Windows Mobile: supported or not supported?
Establishing GPRS Connection on Windows CE and Windows Mobile: Sample Codes
Disable WebBrowser's Context-Menu in NETCF applications
MAPI on Windows Mobile 6: Programmatically retrieve mail BODY (sample code)
Microsoft released a HotFix for NETCF v3.5 on Windows Mobile 6.1.4 onwards, to address basic functionalities of WebBrowser control
The right approach to get a Contact’s last communication (IItem’s PIMPR_SMARTPROP)
Remote Desktop Mobile (RDP Client) disconnects after 10 minutes of inactivity
Support Boundaries for Windows Mobile Programming (Developing Drivers, for example... Or even WiFi Programming)
Miei post in italiano sul team-blog del Supporto Tecnico agli Sviluppatori
A few weeks ago I’ve started handling a Service Request coming from a ISV whose NETCF v3.5 Application relied on the WebBrowser control to display a HTML FORM with some links on it… Imagine simply the following form’s code:
private string m_Html = "<html><body>" + "<a href=\"http://www.msn.com\">MSN</a><BR>" + "<a href=\"http://www.msn.com\">MSN</a><BR>" + "<a href=\"http://www.msn.com\">MSN </a><a href=\"http://www.msn.com\">MSN </a><BR>" + "<a href=\"http://www.msn.com\">MSN </a><a href=\"http://www.msn.com\">MSN </a><a href=\"http://www.msn.com\">MSN</a><BR>" + "<a href=\"http://www.msn.com\">MSN</a><BR>" + "</body></html>"; private void menuItem2_Click(object sender, EventArgs e) { this.webBrowser1.DocumentText = m_Html; }
Problem is that, after the HTML is loaded, when using navigation “buttons” (up\down\left\right):
The problem is easily reproduced on the Emulators as well, thus demonstrating that the issue is not OEM-ish…
I also found at least 2 other developers reporting the problem through Microsoft Connect:
Troubleshooting steps included verifying which native control is wrapped by the NETCF v3.5’s WebBrowser: I noticed that when using the NATIVE code Mike Francis provided in his blog post (code sample available here), then I get the desired behavior on all the 3 Emulators. Mike’s code is based on the WM6’s SDK Sample named “Browse” (\Samples\CPP\Win32\Browse\browse) and explains how to add gesture- and selection-support to a native application hosting the NATIVE web-browser control.
So, the problem was just with the NETCF v3.5’s WebBrowser here! And interestingly it’ NOT reproduced with NETCF v2 SP2 that ships in-ROM on WM6.x. So… what are the loaded DLLs (i.e. what is the native control wrapped by the NETCF v3.5’s WebBrowser)? And which Windows? [I was intereseted on Windows’ ClassNames due to a possible technique to customize the WebBrowser’s context-menu, which I discussed here]
WM6
WM6.1.4
WM6.5
To recap: the issues are due to the NETCF v3.5’s WebBrowser control loading the new native IE6on6 (shdocvw.dll) instead of relying on the native webview.dll + htmlview.dll, and this makes impossible for the user to (a) click a href link and (b) to navigate through them by using the up\down\left\right pad. Also, (c) on 6.5 the scrollbars are not created. When loading the same HTML by the same NETCF application on a WM6, the behavior is as expected. There’s NO problem on WM6.1.4 and 6.5 when using the native control directly (htmlview.dll and webview.dll), for example through the WM6 SDK Sample \Samples\CPP\Win32\Browse\browse.
What happened at this point? As I mentioned other times (for example here), one of the added values provided by Technical Support is that we have a channel to the Dev Teams which we can use to advocate final users’ needs. You can imagine how many customers the Technical Support reaches every single day: we’re basically one of the ears of the Product Groups. And also this time I received an impressive collaboration from the NETCF Dev Team, which firstly accepted to package the FIX, and then did it in a very few days: this is not the usual way it works, so if you’ll ever request a fix then don’t expect this in general. As you can imagine this depends on the code that needs to be modified, in terms of both the complexity and the possible regression risks that a modification introduces, compared to the risks of application usability and other factors if the fix is not provided. For example, many times developers and users can accept a “workaround” while waiting for next version of the product or the possible next Service Pack – I’ve discussed about an example of this here.
To conclude: a FIX is ready to be asked to the Technical Support. KB Article is:
FIX: You cannot scroll through a Web page or browse to a link by using a .NET Compact Framework 3.5-based application that hosts a WebBrowser control in Windows Mobile 6.1.4 and 6.5
For the time being it’s a separate hotfix, maybe the Dev team will consider packaging it within a Service Pack – this is not yet decided. This is another demonstration of a kind of historical change, as this is just the second separate hotfix provided for NETCF on Windows Mobile-based OSs. First one was release few months ago and I blogged about it here.
A question may arise: can ISVs distribute the FIX? I mean, imagine I’m an ISV and developed a NETCF v3.5 app based on the WebBrowser control: if I want to make my app usable on WM6.1.4 and 6.5 devices of my clients, do I need to ask each of them to open a Service Request to Microsoft asking for the hotfix? The answer is: ISVs can distribute also the “patched” NETCF’s CAB.
<UPDATE date=”February 4, 2010” topic=”redist of the fix”>At the time I wrote this post, Marketplace was not yet opened so I didn’t mention an interesting detail regarding the distribution of the fixed NETCF v3.5 CAB: well, if you use Marketplace to distribute your application, then you don’t need to worry about the fixed CAB of the NETCF, because Marketplace will distribute the most updated Build of the NETCF runtime your application targets, accordingly also to the Application Submission Requirements for Windows® Marketplace for Mobile whose point “7.4. Restriction on .NET Compact Framework Redistribution” states:
Application providers should not include the .NET Compact Framework (.NET CF) redistributable package with their applications. The Windows Marketplace installation process will ensure that either the .NET CF 2.0 or .NET CF 3.5 runtime is installed on the device as required.
I did a quick test with a freeware application I knew was built for NETCF v3.5, on a WM6.5 Emulator (so just hard-reset with only NETCF v2 “in-ROM”) – note the user-friendly process (I grayed the portions naming the application becasue I’m sure there are many others out there based on NETCF v3.5 ):
When the download\install finished, just to verify which exact Build of the NETCF v3.5 was installed, I’ve run \Windows\cgacutil.exe and could see that, at today, the Build is 3.5.9198, which is precisely the one mentioned in the KB Article I’ve mentioned above:
</UPDATE>
WARNING! Remember that analogously to every other hotfix you can ask to Technical Support about whatever Microsoft’s product, you should install it only if you're sure it’s for the problem you're being affected by. This is because a hotfix is meant to address a specific issue and has been tested precisely for that: it didn't go through the whole regression testing that it's usually done when packaging many hotfixes into a Service Pack. In this precise case, you don’t have to install this hotfix if your NETCF v3.5 applications doesn’t use the WebBrowser control.
Cheers, ~raffaele
Unfortunately I had to put GPS-Programming in stand-by mode… but finally some days ago I was reading one of the posts I wrote about GPS roughly one year ago, and tried to navigate to a company’s webpage I remembered containing a lot of interesting info and controls about GPS, i.e. GeoFrameworks: well, I realized that GeoFrameworks is now closed! Luckily their Mastering GPS Programming is still available, but, much better… the founder of GeoFrameworks, Jon Person, “[…] decided to release the full source code of GPS.NET to the public domain for the benefit of the open source development community”. If you’re interested on GPS-Programming, you must visit http://gps3.codeplex.com!
Yesterday my Italian colleagues in Developer Support and I officially inaugurated our new team blog: if you can read Italian then join us at http://blogs.msdn.com/itasupport.
CIAO! ~raffaele
[UPDATE 10/9/2009: Source-Code and CAB are now available at http://mobilerdpnotimeout.codeplex.com/] [UPDATE 9/2/2010: v2 of the sample app is available at http://mobilerdpnotimeout.codeplex.com/: it takes care of the battery-life impacted by application continuing to emulate mouse-move even after user closed RDP session – see details below]
This issue should be somehow well known by the Community, but I couldn’t easily find a solution so I had to think one by myself… :-) After 10 minutes of inactivity of a Terminal Server session on Windows Mobile devices, the Remote Desktop Mobile application needs you to logon again stating that a timeout “set by the server administrator or by network policy” occurred. Unfortunately it’s not really a good error message, since many times the server is correctly set and the problem is just client-side... Anyway, probably it was not very frustrating since in the most of the cases one is logged via RDP only to actively work on the server. But this is not always true, so I’d guess either I wasn’t able to find someone with a possible solution, either simply people accepted to live with it…
Remote Desktop Mobile on WM6.x (and, before this, the TSC client on WM5) is a component that OEMs are not required to include to have their OSs pass the Windows Mobile Logo Test Kit, and this is basically why you may find devices with it in-ROM and others where you need to find alternative solutions. In any case, regarding the inactivity timeout issue, luckily Windows Mobile 6.5 _should_ now have an updated version of the Remote Desktop Mobile application that OEMs can include in their images, easier to use on the field as it allows, for example, to finally customize an idle timeout!! Unfortunately it’s not included in the emulators coming with the Windows Mobile 6.5 Developer Tool Kit.
Back to the problem… after some researches I understood that the timer is reset only when the Remote Desktop Mobile’s application window receives mouse or keyboard input. Refreshing the window, or sending exotic WM_xx messages wasn’t enough. So, I came to thinking what was a possible keypress or mouseevent that can be programmatically simulated (through keybd_event() or mouse_event()) that wouldn’t impact application at all?? After some tests I’ve realized that MOUSEEVENTF_MOVE, which is the event of user “moving the mouse”, has no effect on current Windows Mobile-based devices: that event is maintained as codebase with Windows CE, where an OEM may also include a non-touch screen where you really have a mouse to move... but its only effect on Windows Mobile device is for example to modify display’s brightness, in case the display entered a sort of power-safe state (well, obviously the mouse-pointer is moved on the remote server)
So, the idea was to develop a Win32 Console application that simply launches the Remote Desktop Mobile application and every X minutes (5? 9?) simulates a mouse-movement of some pixels and after a short time another one to place the mouse on the previous position.
This is NOT elegant code at all, absolutely, but it does what was meant to run a specific task…
Obviously this watch-dog application would “waste” one of the 30 process slots… is it acceptable? As you can see the application doesn’t do anything special or unsupported: it’s simply a monitor-console application with no particularly elegant code. As usual, I would strongly encourage on adding some error-checking!!
int _tmain(int argc, _TCHAR* argv[]) { int const FIVEMINUTES = 1000*60*5; HWND hWndRDM = NULL; //Firstly launch RDP Client SHELLEXECUTEINFO sei = {0}; sei.cbSize = sizeof(sei); sei.nShow = SW_SHOWNORMAL; sei.lpFile = TEXT("\\Windows\\wpctsc.exe"); sei.lpParameters = TEXT(" "); if (!ShellExecuteEx(&sei)) { MessageBox(NULL, TEXT("Couldn't launch RDP Client"), TEXT("Remote Desktop Launcher"), MB_OK); goto Exit; } //Now every X minutes check if it's still running and if so "refresh" its window //if it's no longer running, exit do { //check if RDP Client is running, otherwise exit hWndRDM = FindWindow(_T("TSSHELLWND"), NULL); if (NULL != hWndRDM) { ////Get foreground window -- this is not needed if RDM is launched Full-Screen as it was in this case //hWndForeground = GetForegroundWindow(); //Sleep(500); //Give focus to the RDP Client window (even if the logon screen, in case user logged out in the meantime) SetForegroundWindow(hWndRDM); //The timer is reset when the rdp window receives mouse or keyboard input //with no MOUSEEVENTF_ABSOLUTE the move is relative mouse_event(MOUSEEVENTF_MOVE, 100, 0, 0, 0); Sleep(250); mouse_event(MOUSEEVENTF_MOVE, -100, 0, 0, 0); ////Give focus back to previous foreground window //SetForegroundWindow(hWndForeground); //Sleep Sleep(FIVEMINUTES); } else { //RDP Client is not running - let's exit goto Exit; } } while (TRUE); //The check (NULL != hWndRDM) is already done inside the loop Exit: if (NULL != hWndRDM) CloseHandle(hWndRDM); return 0; }
I can imagine that this problem affects more the WinMo Users rather than the WinMo “Devs”, therefore I had in mind to distribute directly the CAB of the application, if anyone else doesn’t want to do it for the Community. I’m wondering if CodePlex would be a good place, I’ll see and update this post. In any case, remember that it’s up to the OEMs to decide if including RDM (\Windows\wpctsc.exe) in their OSs based on Windows Mobile platform!
Cheers! ~raffaele
EDIT 9/2/2010:
After interacting with some users of the sample application and tested a v2 build on some scenarios, I’d like to share it now – note that the CodePlex project page will continue containing both versions. The issue was that MyRDM continued to emulate mouse-move even after user closed session, and this impacted on battery-life: this was not a bug, but simply a well known limitation of the tiny sample application… so we wanted a code that acted on the following possible conditions after every sleep-interval:
So the main portion of the code is the following (the same disclaimers apply as before):
do { //Sleep Sleep(FIVEMINUTES); //check if RDP Client is still running, otherwise exit hWndRDM = FindWindow(_T("TSSHELLWND"), NULL); if (NULL != hWndRDM) { hWndForeground = GetForegroundWindow(); if (hWndRDM == hWndForeground) { //The timer is reset when the rdp window receives mouse or keyboard input //with no MOUSEEVENTF_ABSOLUTE the move is relative mouse_event(MOUSEEVENTF_MOVE, 100, 0, 0, 0); Sleep(250); mouse_event(MOUSEEVENTF_MOVE, -100, 0, 0, 0); } else //this means that RDM main windows is no longer foreground, however it may be that the RDP logon page is active { pid = NULL; threadId = GetWindowThreadProcessId(hWndForeground, &pid); //only if the foreground window is not the RDP logon page, then kill wpctsc.exe and exit if (pid != GetProcessIdByName(TEXT("wpctsc.exe"))) { KillProcessByName(TEXT("wpstsc.exe")); goto Exit; } } } else //hWndRDM == NULL: RDP Client is not running - let's exit { goto Exit; } } while (TRUE);
HTH, ciao! ~raffaele