If you’ve ever needed to automatically launch an application under Windows CE then you probably know that one of the most common ways is to put an entry into the device registry under HKLMInit. This works great for native applications, but for CF applications success is hit or miss. The reason is that CF applications require certain system APIs to be up and running before they can run. For a native app that has this requirement, the solution is simple: you call either IsApiReady or WaitForAPIReady (depending on the OS version) and then continue when you’re satisfied. For CF apps it won’t work. The APIs need to be ready long before Main is entered and any of your managed code is running.
Of course the “right” solution is that the CF team should have put that check into the loader so we could launch this way, but they didn’t so we have to work around it.
So how do we get around this? Well we leverage the initialization process itself. When an app is launched from HKLMInit, it is responsible for calling SignalStarted once it is running. This allows any other items launching from HKLMInit to set up dependencies, for example if item 60 depends on item 50, item 60 won’t launch until item 50 has called SignalStarted. What we can do is create a native application that acts as a launch gate. This gate app will call the appropriate wait function, and only after the APIs we need are available does it call SignalStarted. We can then launch any CF application using HKLMInit by simply having the gate application launch first, and then having the CF app depend on the gate.
So in the registry, it would look like this:
[HKEY_LOCAL_MACHINEInit]
“Launch90″=”gateapp.exe”
“Depend90″=hex:1e,00 ; depend on GWES, which is at 30
“Launch91″=”MyCFApp.exe”
“Depend91″=hex:5a,00 ; depend on gateapp
And here’s the source code for a basic gate app:
extern “C” DWORD WaitForAPIReady(DWORD, DWORD);
extern “C” BOOL IsAPIReady(DWORD hAPI);
int _tmain(int argc, _TCHAR* argv[])
{
// quick sanity check – HKLMInit will send in our order number
if(argc == 0) return 0;
BOOL success = FALSE;
// wait for window manager – that should be enough for us
#if _WIN32_WCE > 0x500
success = (WaitForAPIReady(SH_WMGR, 5000) == WAIT_OBJECT_0);
#else
int i = 0;
while((! IsAPIReady(SH_WMGR)) && (i++ < 50))
{
Sleep(100);
}
success = (i < 50);
#endif
if(success)
{
int launchCode = _ttoi(argv[1]);
SignalStarted(launchCode);
}
else
{
RETAILMSG(TRUE, (_T(“CFInitGate timed out – SH_WMGR was not ready after 5 secondsrn”)));
}
return 0;
}
Just wanted to thank you for this article. If only MSDN could be this clear and concise…..
LikeLike
An excellent code snippet.
Should the line
#if _WIN32_WCE > 0x500
not be
#if _WIN32_WCE >= 0x600
otherwise minor versions of Windows CE 5 try to compile
the WaitForAPIReady block of code.
LikeLike
The _WIN32_WCE define, I *think* is not that closely tied to the minor version. I think all versions of 5.0 (including all minor versions) still are at 0x500. Of course I could be wrong, so it’s worth checking.
LikeLike
Thank you, it worked with 0x500 for me, running Windows Mobile 6.5.5 (CE 5.2.24635)
No more random exception error message! 🙂
I have a question, I am using it to load HARET and boot linux and I would like to not load the GUI / Today screen, is that possible?
LikeLike
@m4f1050: I really don’t know. I’ve never used HaRET, and I don’t know really anything about how it boots.
LikeLike