Microsoft has finally declared the NNTP newsgroups dead. It’s where I’ve done my “community service” for the past decade or so, so I’m a bit sorry to see them go. They have started a set of new online Forums (which are live now) to replace these groups.
In one of the mailing lists I’m on today, someone noted that on their Windows Mobile device the performance of GDI is much better in portrait mode than it is in landscape mode and was wondering why. The reason is actually pretty simple. Think of the image on the screen as just a contiguous stream of bytes (which is probably is). The physical display needs to get that data and “paint” it. Displays are engineered to essentially take in the data in a linear fashion, left to right, top to bottom. So it’s a pretty simple operation to just send out the framebuffer data to the display.
Now consider what happens if you want the display rotated 90 degrees. Remember, the display requires the data top to bottom, left to right, as it will show on the screen. To get it into that state you have 2 options. You can either A) rotate the data as you take it out of the frame buffer and send it to the display or B) rotate all calls to draw into the framebuffer. In either case you have to do a matrix transform, which is expensive and gets worse the larger your display gets (so a VGA device will be more affected than a QVGA device).
Of course some devices have hardware acceleration that can greatly improve things by having matrix functions right in the silicon, but that still requires that the OEM actually modifies the driver to use that function (you’d be surprised how many don’t).
So how bad is the performance penalty? Well, since I like to actually quantify stuff I decided to resurrect an old GDI test app I had and rework it for this. The results of my testing, as well as tests sent in from other people (if you want to add a test to the table, send me your results):
|Axim x51||PXA270||WinMo 5||188 ops/s||77 ops/s||59%|
|Asus P750||PXA270 520MHz||WinMo 6 Pro||241 ops/s||55 ops/s||77%|
As you can see, there’s a significant price to running rotated.
The test application (source and ARMv4I binary) is available here
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:
“Depend90″=hex:1e,00 ; depend on GWES, which is at 30
“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);
int i = 0;
while((! IsAPIReady(SH_WMGR)) && (i++ < 50))
success = (i < 50);
int launchCode = _ttoi(argv);
RETAILMSG(TRUE, (_T(“CFInitGate timed out – SH_WMGR was not ready after 5 secondsrn”)));
If you just got the latest release of the IE8 Beta, your C++ Smart Device wizard will now fail. When you try to create a project you’ll get a few screen flashes and then an unhelpful “project creation failed” message in teh status bar of Studio. The fix is outlined here (and worked on my XP box).
OpenNETCF used to have a product that provided RAS capabilities. Well Microsoft deprecated RAS in WindowsMobile – starting with WinMo 5.0 as near as I can figure – in favor of Connection Manager. That depracation actually broke RAS in some scenarios. FOr example, if you create a RAS connection and then try to use a managed TcpClient, it will try to create it’s own connection through the Connection Manager instead of using the connection you created through RAS.
What this did was skyrocket our support incidents for something that we sold very, very few licenses for. In the interest of keeping our sanity, yet allowing people using plain of Windows CE to still use RAS, we made the decision to just make it a shared source project. It’s now out on CodePlex. If you need support for it, we still offer consulting services, but everything is there to get you going.
I realize we’re a bit late in releasing a version for Studio ’08. Now you might say to yourself “how hard can it be? Just open the solution in Studio ’08, let it upgrade, recompile and release.” Sure, it could be that simple if we wer content with just tossing it out there, but we’re not. With the move to Studio ’08 we decided to take advantage of some of the new tools we have. First we migrated the entire SDF source tree from Vault to TFS. Vault worked just fine, but we wanted to take advantage of TFS and integrate both continuous integration, automated testing and test-driven development into the product.
That mean rearchitecting the solution and projecy layouts and then writing tests. Lots of tests. Of course writing tests leads to finding bugs, which then leads to fixing bugs. We started by looking at reported bugs but also looking at some use cases and testing classes we know get the most use. We have no delusion that we’re going to have even close to full code coverage (or even 50%) by our next release, but we want to get off on the right foot and at least have some coverage for the next release.
Of course we’ve also added some new features like the OpenNETCF.Net.Mail namespace and all of this takes time. As of right now we have less than 40 hours of test writing left to hit our release milestone. Once we hit that, we then have to build the Help and installation package and release. My hope is to have something ready in early September, but that’s not a guarantee. We know you want the release – we do – we just want to make sure it’s right.
An ancillary question that also comes up is “when will we be releasing a version compiled for CF 3.5?” As of right now we have no plans to release a CF 3.5-targeted version of the SDF. Yes, you read that right. We have no plan for a CF 3.5 release. “Why is that?” you might ask, after all CF 3.5 is the latest and greatest, right? Sure, it is, and we think that when possible you should use it. However the SDF has historically been used by developers using older versions of the CF and is already rolled out in a *lot* of CF 2.0 projects. If we moved to 3.5, none of those 2.0 project would be able to use the SDF without recompiling themselves. If we moved to 3.5, then we’d also be tempted to use 3.5 features, which would then even make the source incompatible with 2.0 and a recompile wouldn’t even be an option. I, for one, don’t really want to leave all of those CF 2.0 developer’s high and dry.
Since CF 3.5 assemblies are unusable in CF 2.0 projects, but CF 2.0 assemblies can be used without a problem in CF 3.5 applications it makes the decision pretty simple. If we stay with CF 2.0 as a target, then far more people can use the library. If you absolutely must have it built targeting CF 3.5, you can always recompile the source yourself.