Some time ago I blogged that I was going to post about my last project.. and now, after three re-writes (*sigh*), here’s the post..
The location and schedule:
Started off in New Jersey in June 2004; after a few months we moved down to D.C. to be with the server team. The schedule was, um, challenging (to say the least).
The business:
Uh… government stuff (can’t say any more than that)
My role:
Architect / Technical Lead / Mobile Fix Team Lead (so it says on my PCF )
The technology:
Custom device running Windows CE .NET (WinCE 4.2); the device featured a 320x240 screen, Bluetooth, and 802.11b. The application is written in C# on the .NET Compact Framework 1.0 [1]. The OEM provided us with native APIs for all the radios (802.11b, BT), keyboard, screen, cradle, and scanning. Yep, native APIs. When we first met with the technical folks from the OEM in July, they were surprised to hear that we were developing with .NET CF (they were expecting us to use eVC++).
Most of the APIs we could P/Invoke to; however, for the special cases, we handled the native bits using two methods: 1) we wrote a thunking layer in eVC++ [that we hit via P/Invoke] and 2) we used unsafe code. We also leveraged a native DLL (via P/Invoke) to handle pinging. Speaking of libraries (and third party items), we used OpenNETCF’s Smart Device Framework v1.2 and Resco’s AdvancedList .NET. OpenNETCF == Goodness.
SQL CE 2.0 was leveraged as a local data store. To get around some concurrency issues with SQL CE, we looked at using message queueing on the device, but due the complexities involved here[2], we chose another route (whilst remembering the K.I.S.S. principle).
Data was brought to the device on a regular basis (i.e. outside of normal app usage) via the synchronization engine[3] I wrote. It consumed web services hosted in WAS (IBM Web Sphere) (eek!) for not only the initial data synchronization, but all communications to and from the server. The web services, of course, were called over a secure connection. To make matters worse (joke), WAS went to Oracle to get it’s data (interestingly enough, both of these products were running on Windows Server 2003). We also had a nifty thing called a notification service, but that would be difficult to explain (aside from what you can glean by the name) without going into a [legally] questionable amount of detail.
Development Infrastructure:
VS.NET 2003 / VSS 6.0d (ugh!). In my many years, I have used VSS more often than not [4], and it proves (with proper care and maintenance) to be an OK source control system. This engagement found us on a very s l o w network, which made using VSS (and pulling things down from the Internet) a rather large frustration. For example, opening a seven project solution (350+ files) took eight minutes (VS.NET/VSS integration); performing a GetLatest on the solution from within the IDE – twenty-eight minutes. During my tenure on the project, and upon my departure, I suggested that they explore an alternative source control system. I suggested SourceGear’s Vault.
Well, they listened to me – after I left. Instead of the eight and twenty-eight minutes we experienced before, they are now seeing thirty-five seconds and ninety seconds respectively!!! To quote [the initial reaction of] the developer who stepped into my role when I left: “Vault f-ing rocks!”. I asked him again this week, it being a few weeks into the switch to Vault, and his response was “Life is a dream [with Vault]”. I will note that they have experienced a minor issue with date/time stamps on keyword expansion – SourceGear support has said that this will be fixed in Vault 4.0.
I wrote a build process from scratch which leveraged NAnt (and NAntContrib) [5]. It not only build our .NET CF app, but also our helper eVC++ DLLs, the setup DLLs for the CABs, and the CABs themselves. For deployment, I built three CABs: CAB1 contained our app, CAB2 was the OpenNETCF SDF, and CAB3 was a ‘master’ CAB that contained them both (for debug builds, I also included the SQL CE Query Analyzer CAB).
A one CAB solution was needed because of desire to, well, only have a one CAB to deploy. Note: Microsoft does not officially support nested CABs (someone correct me here if need be..), so the docs would be no help here; with some assistance I got this working how I needed. (Thank you again, Reed!) Some of you may be asking what about the SQL CE engine CAB? No need for that; the OEM has SQL CE embedded in the ROM. I’m sure some of you are also wondering why I needed to rebuild the OpenNETCF SDF CAB (personal thanks to Neil C). The customer required that the device have a Trusted Environment…so, I had to execute signfile.exe against every assembly [prior to building the CABs]. After the CAB was built, I would transfer it to the SMS server (using an FTP Task) to be pushed to the product testers. SMS what? Enter the SMS 2003 Device Management Feature Pack. Goodness.
I need to give thanks to Neil Cowburn for his excellent NAnt CabWiz task and to the guy that wrote the FTP task (can’t remember where I got it from and he didn’t put his name in the code).
Almost forgot..deployment numbers. A secret again, but suffice to say it is the largest mobile app deployment I have worked on. Ever.
Hmm… and that’s all I can say about that. I certainly learned a lot on this project (and not just in the technical domain). It was my first WinCE project (all others have been PPC / Smartphone / WM), and we had a ton of interesting technical challenges to address…so all in all, mobile goodness! :-) I’m guessing that some folks are thinking “WTF?” about a few things I have said, or are curious about more detail. I am sorry to say that I cannot oblige your requests unless I wish be on the pointy end of legal action.
-Nino
[1] Yes, it is .NET Compact Framework 1.0, *not* 1.1 as many people think. The version of the .NET Compact Framework is only 1.0, despite it shipping along with the .NET Framework 1.1.
[2] We explored some options in creating our own System.Messaging (that namespace does not exist in CF v1.0), but some of the marshaling was not possible without a lot of work, and, quite frankly, we did not have time for that in our schedule. Additionally, we looked at writing a thunking layer and hitting the COM interfaces into message queueing, but decided against that as well.
[3] This customer not being a “Microsoft shop”, there were no SQL Servers to be found; SQL Server <> SQL CE replication is out of the question. So we looked at Oracle Lite <> Oracle replication. This option was rejected as well, although I got a chance to work with Oracle 9i Lite for the first time.
[4] My experiences have been with VSS, Vault, StarTeam (pre-Borland), CVS, and PVCS (pre-Serena)
[5] I had to punt (damn!) and exec devenv.exe instead of being ‘pure’ and using csc.exe (which is where Neil is getting to). Given that I had a limited timeframe to create the build scripts and some issues with web services, this was the way to go – unfortuantely.
Now playing: Jeff Buckley - Dream Brother