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 very quick post: if you’re using devices powered with HTC or Samsung drivers (such as also the Sony-Ericsson Xperia X1, for example) and noticed periodic slowdowns of the UI, then you may benefit of the following fix: Some GUI interactions no longer work correctly on Windows Mobile 6.1 devices and Windows Mobile 6.5 devices. This is not strictly required, so make sure to read the Symptoms section. And please remember to fill out the feedback at the bottom of the page!
Cheers, ~raffaele
Part of my job as Support Engineer is to handle requests coming from ISVs developing applications for Windows CE: this is not always an easy task because contrarily to Windows Mobile, for which OEMs must stick to some specifications (otherwise their OS would fail the “Windows Mobile Logo Test Kit”), when it comes to Windows CE (or “Windows Embedded CE”, you know what I mean…) the OEMs have the complete freedom of developing whatever module or driver to be included in their OS, so in some cases the only option to understand a problem’s cause or to reach a specific goal programmatically, is to engage the OEM. I surely have already talked about this in the past…
So, requests from ISVs targeting Windows CE are rare compared to the ones for Windows Mobile, but after the release of Windows Embedded CE 6.0 R3 (“Cashmere”) Microsoft did on late September 2009, I’ve started handling some very interesting cases about Silverlight for Windows Embedded (“SWE” from now on). During past months many have discussed about this topic and how “particular” it seems to be programming for Silverlight in C++ instead that in .NET… so I’d like to share some info and sample code that I’ve personally been using so far.
Before doing that, even just because this is the very first post about SWE I’m writing, let me digress a bit so that we can all be on the same page. Above all, if you have no idea what SWE is at all about, then I think that nothing else than watching it in action would help on describing it, and apart from some other videos from latest conferences we may benefit of a 15' minutes-long demo recorded by Mike Hall back in June 2009 together with Jeff MacDuff and Todd Segal, available thru his post Creating compelling user interfaces for embedded devices (even if Jeff and Todd paid attention not to disclose the “name” of the underlying technology, we now know it’s SWE! ).
So, the idea is very simple: just divide the job done by designers and by developers and let everyone do what is good at. Designers have their tools to develop the UI (for example, Expression Blend) and developers have theirs to develop the Business Logic (for example, Visual Studio). Developers won’t even need to know how the UI looks like in fact (my sample code below are an example for that). More about this idea is available through the document Introduction to Application Development with Silverlight for Windows Embedded.
The important thing is that those out-of-browser applications are possible through a powerful engine, i.e. the XAML Runtime, that takes care of glueing the UI to the code-behind by supporting a subset of Silverlight 2 XAML. The object model to programmaticaly interact with such runtime is native.
Now: imagine you’re a Windows Mobile developer or in any case not a CE6.0 OEM – this means you don’t have the tools to even start investigating how programming for SWE looks like. If that’s the case, remember that precisely as it was for its predecessors, also Windows Embedded CE 6.0 R3 has its own evaluation edition that you can freely download and that is fully functional for 6 months. Note that this is no longer a separate IDE as it was for Windows CE 5.0: it’s an addin that integrates with VS2005 SP1 – follow all the steps here. The evaluation copy includes the software tool for interaction design, Expression Blend 2.0 and gives you the ability to create a so-called “Private SDK” related to the XAML Runtime-powered CE image (the required component is SYSGEN_XAML_RUNTIME) and containing a Device Emulator image targetable from VS2008 directly.
Still about tools, Olivier Bloch explained here why there’s a lack of really tied integration between the UI and the code-behind: “[…] Well here is the answer: there has been some decisions made to make this technology available as is because our customers were in urgent need of this technology.”. I’ve not yet personally tested it, but this missing functionality seems to be provided by the (Italian! ) Microsoft MVP Walter Minute through his XAML2CPP tool.
So, after this quick intro, what I’d like to share here is:
The sample is very easy to read and I used it as starting poing to run specific tests, for example about automating resources-stressing. The code is based on the documentation Create a Silverlight for Windows Embedded Application:
//global vars
IXRStackPanelPtr m_pStackPanel;
IXRApplicationPtr m_pApp;
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow)
{
int exitCode = 0;
HRESULT hr = S_FALSE;
IXRVisualHostPtr vhost = NULL;
IXRFrameworkElementPtr root = NULL;
//Initialize Xaml Runtime
if (!XamlRuntimeInitialize())
return -1;
//Get XRAppInstance
hr = GetXRApplicationInstance(&m_pApp);
CHR(hr);
XRWindowCreateParams wp;
ZeroMemory(&wp, sizeof(XRWindowCreateParams));
wp.Style = WS_OVERLAPPED | WS_SYSMENU;
wp.pTitle = L"SWE Testing";
wp.Left = 0;
wp.Top = 0;
//Retrieve resource associated to the PAGE.XAML file
XRXamlSource xamlsrc;
xamlsrc.SetResource(hInstance,TEXT("XAML"), MAKEINTRESOURCE(IDR_XAML_PAGE));
//Create host
hr = m_pApp->CreateHostFromXaml(&xamlsrc, &wp, &vhost);
//Get Root Element of the XAML
hr = vhost->GetRootElement(&root);
//Get the Stack Panel
hr = root->FindName(TEXT("LayoutRoot"), &m_pStackPanel); //Grid = StackPanel
//TODO: Add test code here
//For automation purposes, create a Timer
//Automation testing code in TimerProc function
Timer = SetTimer(0, 0, 250, TimerProc);
UINT exitcode;
hr = vhost->StartDialog(&exitcode);
Exit:
XamlRuntimeUninitialize();
return (int)hr;
}
void CALLBACK TimerProc(HWND hwnd, UINT, UINT, DWORD dwTime)
//TODO: Automation code here
//...
//Just to see the UI refreshed
InvalidateRect(GetActiveWindow(), NULL, TRUE);
In another case the ISV was interested on maintaining main application (or main page) separate from the control DLLs, so that he could re-use the control separately by other applications. Also, he was interested on having multiple instances of the same control within the same application.
What I could learn through this Service Request is that the XAML Runtime takes care of (quite) everything for you! I left many comments in the sample code (for me at least!) but probably the most important bit here is that a control class is derived from XRCustomUserControlImpl<Class [,Interface]>, therefore it’s an abstract class hence can’t be instantiated and needs to have static functions only. This means that you can’t really talk about “visual controls hosted in an application” – what happens instead is that the XAML Runtime executes and renders different bits of XAML code. So, look at “controls” as “chunks of XAML” (this is not really object-oriented…). This also means that before using the control, you need to initialize it becasue before calling IXRApplication::CreateHostFromXaml from the application EXE code (note closely where CreateHostFromXaml is called in WinMain), the XAML Runtime must know all the associations between Classes and XAML Namespaces.
In other words, the “initialization” of a control should be done in2 steps:
//CONTROL CLASS DECLARATION
class __declspec(uuid("{1F8F37C1-CA69-4894-A6AA-8667F9387E2E}")) //Change GUID!
MyControl : public XRCustomUserControlImpl<MyControl>
public:
static HRESULT GetXamlSource(XRXamlSource* pXamlSource);
static HRESULT Register(HINSTANCE hInstance);
//Added these functions so that they can be exported through a .LIB (created by adding a .DEF to the project)
//Any exe application using this control will need to link the .LIB
static HRESULT MyControlInitialize(IXRFrameworkElementPtr root, LPCTSTR pszControlClassName);
static HRESULT MyControlPreInitialize(HINSTANCE hInstance);
};
//*************************************************************************************
//Standard implementation of XRCustomUserControlImpl<>.GetXamlSource
HRESULT MyControl::GetXamlSource(XRXamlSource* pXamlSource)
//Retrieve the resource (the XAML file) from the DLL Module
pXamlSource->SetResource((HINSTANCE)GetModuleHandle(lpThisModule), TEXT("XAML"), MAKEINTRESOURCE(IDR_XAML_MYCTRL));
return S_OK;
//Standard implementation of XRCustomUserControlImpl<>.Register
HRESULT MyControl::Register(HINSTANCE hInstance)
hr = XRCustomUserControlImpl::Register(__uuidof(MyControl), L"MyControl", L"clr-namespace:SLForEmbedded");
return hr;
// Setup the global var for the application instance and invoke .Register on the control.
HRESULT MyControl::MyControlPreInitialize(HINSTANCE hInstance)
s_appInstance = hInstance;
/*LEFT FOR COMMENTING PURPOSES, IN CASE THE .XAML WILL CONTAIN IMAGE or FONT <Application.Resources>
////Initialize Xaml Runtime --> If needed, then add MyControl::UnInitialize
//if (!XamlRuntimeInitialize())
// return -1;
////1. Get XRAppInstance
//IXRApplicationPtr app;
//hr = GetXRApplicationInstance(&app);
//CHR(hr);
//2. Add control resource
/*This is needed when there are resources within the XAML of type XAML_RESOURCE
//hr = app->AddResourceModule(hInstance);
// ONLY IF <Application.Resources> IN THE APPLICATION's XAML:
//The following code shows an example of XAML markup that must be parsed
//into a resource dictionary:
//<Application.Resources>
// <SolidColorBrush x:Key="Text_DefaultColor" Color="#FF292F33"/>
//</Application.Resources>
//
//IXRResourceDictionary* pResourceDictionary;
//XRXamlSource Source;
//Source.SetFile(MAKEINTRESOURCE(IDR_XAML_MYCONTROL));
//hr = app->LoadResourceDictionary(&Source, &pResourceDictionary);
//hr = app->GetResourceDictionary(&pResourceDictionary);
*/
//3. Register control's Namespace
hr = MyControl::Register(hInstance);
//Initialize the control and event handlers
HRESULT MyControl::MyControlInitialize(IXRFrameworkElementPtr root, LPCTSTR pszControlClassName)
IXRControlPtr m_myUserControl;
BtnEventHandler m_btnUserControlHandler;
IXRDelegate<XRMouseButtonEventArgs>* m_btnUserControlDelegate;
IXRButtonBasePtr m_btnUserControl;
//hr = root->FindName(TEXT("MyUserControl"), &m_myUserControl);
hr = root->FindName(pszControlClassName, &m_myUserControl);
//m_btnUserControlHandler.m_StoryboardPaused = FALSE;
//BtnEventHandler::m_StoryboardPaused = FALSE;
m_StoryboardPaused = FALSE;
hr = m_myUserControl->FindName(TEXT("btnUserControl"), &m_btnUserControl);
hr = CreateDelegate(&m_btnUserControlHandler, &BtnEventHandler::btnUserControlOnClick,&m_btnUserControlDelegate);
hr = m_btnUserControl->AddClickEventHandler(m_btnUserControlDelegate);
//TODO: Add event handler code
class BtnEventHandler
HRESULT btnUserControlOnClick(IXRDependencyObject* pSender, XRMouseButtonEventArgs* pArgs)
MessageBox(GetActiveWindow(), L"User Control button clicked.", L"Event Handler", MB_OK | MB_ICONINFORMATION);
For the application:
//Application's MAIN Entry Pointint WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow)
IXRApplicationPtr app = NULL;
//(let's keep it simple here...)This is not needed when the XAML has not <Application.Resources>
//IXRResourceManager* pResourceMgr = NULL;
IXRButtonBasePtr btn = NULL;
//showing a page with its own button control
//<Button Margin="200,200,200,200" Content="Button" x:Name="MyButton"/>
IXRDelegate<XRMouseButtonEventArgs>* clickdelegate = NULL;
PageBtnEventHandler btnHandler;
hr = GetXRApplicationInstance(&app);
////An application should register an IXRResourceManager object for Silverlight
////before the application executes any functionality related to loading resources.
////<Image Source=foo.jpg" />
////<TextBlock x:Name="GridTextBlock10" Grid.Row="1" Grid.Column="0" FontSize="14" FontFamily="castelar.ttf#Castellar" FontStyle='Italic' Text='Hello'/>
// -->
////IXRResourceManager* pResourceMgr;
//hr = app->RegisterResourceManager(pResourceMgr);
//This is needed when there are resources within the XAML of type XAML_RESOURCE
//Register control with application instance
//This method added so that the control code can do init and call Register on the control
//so that the control's class is tied to the XAML Runtime's namespace
//and this is done in control's DLL code
hr = MyControl::MyControlPreInitialize(hInstance);
hr = app->CreateHostFromXaml(&xamlsrc, &wp, &vhost);
//MyButton is a control directly defined and used by the application
//defined in PAGE.XAML, look at x.Name of the <Button> element
//left here just to show a control example inside the same application
hr = root->FindName(TEXT("MyButton"), &btn);
hr = CreateDelegate(&btnHandler,&PageBtnEventHandler::OnClick,&clickdelegate);
hr = btn->AddClickEventHandler(clickdelegate);
//MyControl is the control exported by SilverlightControl DLL project
//deriving from XRCustomUserControlImpl<MyControl>, it's an abstract class
//i.e. can't be instantiated and needs to have STATIC functions only
hr = MyControl::MyControlInitialize(root, TEXT("MyUserControl"));
hr = MyControl::MyControlInitialize(root, TEXT("MyUserControl2"));
RELEASE_OBJ(clickdelegate);
//Handler of a button included directly in the EXE
class PageBtnEventHandler
HRESULT OnClick(IXRDependencyObject* source,XRMouseButtonEventArgs* args)
MessageBox(NULL,TEXT("Click!"),TEXT("Button"),MB_OK);
Note how straightforward the XAML for the page (main application) is – quite intuitively, it just contains one line for each control:
<UserControl
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="SLForEmbedded.Page"
xmlns:SLForEmbedded="clr-namespace:SLForEmbedded"
Width="640" Height="480">
<Grid x:Name="LayoutRoot" Background="White">
<Button Margin="200,200,200,200" Content="Button" x:Name="MyButton"/>
<SLForEmbedded:MyControl HorizontalAlignment="Left" VerticalAlignment="Top" x:Name="MyUserControl"/>
<SLForEmbedded:MyControl HorizontalAlignment="Right" VerticalAlignment="Top" x:Name="MyUserControl2"/>
</Grid>
</UserControl>
The XAML for the control may be useless for this post, however for the sake of completeness:
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
x:Class="SLForEmbedded.MyControl">
<Grid x:Name="LayoutRoot">
<Button Height="25" Width="125" HorizontalAlignment="Left" VerticalAlignment="Top" Margin="10,10,0,0" Content="Click User Control" x:Name="btnUserControl"/>
As usual, macros were:
#pragma once
#ifndef MACROS
#define MACROS
#define _ExitLabel Exit
#define _ExitCode exitCode
#define CHR(hResult) \
if(S_OK != hResult) { hr = (hResult); goto _ExitLabel;}
#define RELEASE_OBJ(s) \
if (NULL != s) \
{ \
s->Release(); \
s = NULL; \
#endif
Hope this may help out developers learning SWE (like myself… )
I recently worked with some ISVs asking support about this, then also answered to a MSDN Forum thread about the same, so I’d say it may be worth to mention it here as well for Community reference. This happens to be one of those common questions that fall under the umbrella of the “not supported as OEM-dependent” or “not supported as it’s not meant to work that way”. I’ve talked about this some times on my blog, for example regarding Wireless programming, Drivers, Kiosk applications, Hooks…
The issue is about “intercepting” incoming phone calls and prevent the native UI dialog provided by OS application cprog.exe to take care of it: there are some OEMs that customized the user interface for this phone application, so ISVs may think this could be a common task to achieve? One could say: “Wouldn’t be sufficient to kill cprog.exe?”. Or, in any case, is there a way for ISV Application Developers to programmatically control incoming and outgoing calls *before* or *instead* the Operating System itself?
The answer is no, but you may possibly find “creative” ways to achieve the same visual effect your application’s final users may look for. The main point is that interfering with the OS Native Phone application (cprog.exe) is not supported for ISV Application Developers, contrarily to Device Manufacturers (OEMs) who actually build their own OS based on the Windows Mobile platform and therefore can develop and include whatever they want on their Operating Systems, as long as they fulfill the “Windows Mobile Logo Test Kit” (so that their OS is certified as “Windows Mobile”).
As an example, a thing that the Windows Mobile platform doesn’t test or even consider is killing cprog.exe, which is the process underlying the Phone UI Application. Once the device is booted, cprog.exe executes and even when there is a Out-Of-Memory condition (so that the Shell starts asking every application to shut down, accordingly to this old post from WinMo Dev Team), cprog.exe is not terminated. So the current OS design does not expect it to be killed forcefully.
In some cases, to meet this requirement you would need to cooperate with the Device OEM\OEMs so that he\they can sponsor you as their “Windows Mobile In-ROM ISV”. By doing so, you would have access to all the tools a Device Manufacturer has, including the knowledge on the RIL Driver (Radio Interface Layer), developed by the OEM, that is responsible to handle every radio-related communication of the device (phone call, GPRS data session, …). So, to intercept phone calls before cprog.exe does it, you should do it at RIL Driver level, and Microsoft has no idea about how the OEM implemented it.
In other cases, you can let cprog.exe do its work, and play with Windows APIs to hide its window and take control of the phone call via TAPI (Telephony API): that is the “supported” way.
You may ask: then how does Microsoft’s Communicator Mobile 2007 R2 implement "Work Phone calls”? How can it intercept phone calls, if this is OEM-dependent? Well, actually it doesn’t. CoMo is not working with the RIL to intercept phone-voice calls. Documentation is available through the following Microsoft Office Communications Server 2007 R2 – Technical Reference (section “Outside Voice Control”):
[…] For inbound calls, Office Communications Server 2007 R2 sends a SIP Invite to all registered SIP endpoints of the user including the user’s Communicator Mobile (2007 R2 release) client running on the phone, over the data channel. Office Communications Server 2007 R2 subsequently initiates an outbound PSTN/mobile network call through Office Communications Server 2007 R2 Mediation Server to the user’s mobile phone number.
So as you can see, when dealing with “Communicator phone-calls” we’re not precisely working with “Voice-Phone calls”: it’s about SIP requests sent over the Data Channel, not the Voice-one.
Among the “supported” ways to deal with phone calls, developers can rely on the State&Notification Broker states like PhoneCallTalking and PhoneIncomingCall: a state that may be missing is about the last call being ignored. Here it is a managed sample code showing a possible way to achieve this (to be tested… as usual! ):
public Form1()
InitializeComponent();
_PhoneIncomingCall.Changed += new ChangeEventHandler(_PhoneIncomingCall_Changed);
bool bTalking = false;
bool bIncoming = false;
bool bIgnoring = false;
SystemState _PhoneCallTalking = new SystemState(SystemProperty.PhoneCallTalking);
SystemState _PhoneIncomingCall = new SystemState(SystemProperty.PhoneIncomingCall);
void _PhoneCallTalking_Changed(object sender, ChangeEventArgs args)
bTalking = (0 != (int)args.NewValue);
//_PhoneIncomingCall.Changed += new ChangeEventHandler(_PhoneIncomingCall_Changed);
_PhoneCallTalking.Changed -= _PhoneCallTalking_Changed;
void _PhoneIncomingCall_Changed(object sender, ChangeEventArgs args)
bIncoming = (0 != (int)args.NewValue);
if (bIncoming)
//_PhoneIncomingCall.Changed -= _PhoneIncomingCall_Changed;
_PhoneCallTalking.Changed += new ChangeEventHandler(_PhoneCallTalking_Changed);
else
//answered: bTalking = true
//ignored: bTalking = false
bIgnoring = !bTalking;
MessageBox.Show(string.Format("IgnoredCall: {0}", bIgnoring.ToString()));
//reset vars
bIncoming = false;
bIgnoring = false;
bTalking = false;