Saturday, February 23, 2008

What's wrong with this picture?  (I wish I had found this during RC0)

 

Saturday, February 23, 2008 9:49:08 AM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [0]  |  Trackback
 Thursday, February 14, 2008

After being a one man shop for far too long, my new cohort and myself have experienced the joy of actually validating that the Compact Framework projects in Subversion are acually correct.  The Solution has a Lib solution folder which contains all of the external dependencies needed for the project to build and run.  On a clean machine it appears that the Compact Framework 2.0 is not installed when you install VS2008.  This led me to put mscorlib, System.Windows.Forms, etc. into the Lib folder to save Dan from needing to install VS 2005 (which he has blogged about) in order to get the assemblies we need.  Oddly enough, all UserControl and Form classes in the solution do not appear to have designer support when the solution is checked out, getting a clean local copy shows the same behavior for me.  Controls just display all their designer-added children (Label, Button, etc) in a giant Control tray.

The only thing that seemed to resolve this issue for us is removing our Lib assembly references and re-adding the fundamental dependencies from the GAC.  This makes one wonder: what bizarre implementation detail of the designer support causes this issue?

Thursday, February 14, 2008 12:58:51 PM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [0]  |  Trackback
 Friday, January 11, 2008

I saw this over at Peter Foot's blog and the first thing I thought was "Maybe they are using Exception handling to control program flow?"; by this I mean just trying to use a Proxy without first checking to see if it's valid, and handling this situation in a try/catch block.  I have the utmost repect for the CF team, so maybe this is not what they're doing, or maybe they have a good reason for doing so. 

Regardless of what the CF team is doing, this re-opened a barely healed wound.  I recently inherited a codebase which I am modifying to help a friend.  This code is riddled with the age-old no no of "Using exception handling blocks to control program flow".  I think I first saw this best practice in Bjarne Stroustroup's "The C++ Programming Language" at least ten years ago.  The code has things like catching NullReferenceException rather than checking for null first, and catching ClassCastException rather than checking a column's DBNull status.  Logic that should be the "if" or "else" of a condition statement is then executed in the catch{} block. Not only is this ugly practice making the code hard to read, but considering the frequency of these conditions the code is being slowed down quite a bit while the exception is handled. 

Friday, January 11, 2008 11:59:02 AM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [0]  |  Trackback
 Tuesday, November 13, 2007

I got the AT&T tilt today.  I have done the Smartphone thing for a few years but this is my first full PDA phone.  I ported a stripped down version of one of our data collection apps to run on the phone, man do I love the compact framework.  I'm going to see about getting CF 3.5 on here tonight and maybe port my incomplete Asteroids clone to the phone.

Tuesday, November 13, 2007 4:21:38 PM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [0]  |  Trackback
 Friday, October 05, 2007

This is my 1st new toy today, The Rocket.  This is a mobile wifi hotspot and router with a cellular card, running some kind of Linux distribution.  I think I shall plug this into my car adapter and go work from the lakefront later.

Friday, October 05, 2007 9:33:09 AM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [0]  |  Trackback
 Thursday, August 30, 2007

One of our OEMs provides an FTP server that is built in C and compiled against Windows CE 4.2.  The new version of a another device that connects to this server via its own FTP client no longer works for some reason, this 2nd OEM claims that some timeout or tolerance in the device is too touchy and that it simply cannot speak to this FTP server.  Doing some searching I found a partial FTP RFC implementation originally posted on gotdotnet and authored by a gentleman by the name of joel@collude.com.au.   There doesn't appear to be any open source license present so I got the source, hacked it to run on the CF, removed a cumbersome custom logging interface to replace it with the CF version of log4net, and cleaned up deprecated code warnings for CF2.0.  The idea was I would send the OEM a log of FTP server sessions to determine which tolerences needed to be increased, but the device in question talks fine to my new custom FTP server running on CE.  I continue to be a big fan of the performance of .NET.

Up to this point I usually don't make full source available with articles but I'm thinking I should change that policy once I've chosen an appropriate open source license.  Would anyone like an FTP implementation in C#?

Thursday, August 30, 2007 10:45:39 AM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [3]  |  Trackback
 Monday, July 16, 2007

You may try to open an SQL Mobile database with the query manager tool, or you may get error messages trying to compact, repair, or shrink an SQL Mobile database.  The solution is to install the SQL Mobile replication CAB appropriate for your device platform.  If you installed Visual Studio to the default folder you will find this in C:\Program Files\Microsoft Visual Studio 8\SmartDevices\SDK\SQL Server\Mobile\v3.0\wceX00 and sqlce30.repl.phone.wce5.armv4i.CAB is the file you're looking for, or the appropriate version for your platform.  You may not have installed this file if you are not using replication, but it contains a DLL (sqlcecompact30.dll) that the managed SQLMobile code will be looking for if one of the aforementioned operations is attempted.  It also seems that deploying from Visual Studio will not install this CAB file when you are using code that depends on it. 

Monday, July 16, 2007 1:57:17 PM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [0]  |  Trackback
 Tuesday, April 03, 2007

I looked into getting a new laptop for work, and I'd really like to run Vista on it since VS2005 seems to be working fine now, however, one of the applications I have to support is my good old friend the Windows CE 4.2/Compact Framework application.  Mobile Device Center only works for Windows Mobile 2003 and later systems.  Active Sync does not install or work on Vista.  Just like when CF2 came out without CE4.2 support (thankfully patched later) I'm left in the lurch.  Curse you, Microsoft, for leaving a large number of people high and dry once again.

Luckily it seems Dell can offer Windows XP if you order from the business division, which I've never thought they were able to do before.  I could always get it w/Vista and wipe it right away but what fun is that?  Maybe w/Virtualizaiton I could create an XP install for working on this one product, but  I'm not sure how much hardware Virtual PC gives you access to though.  I guess I'll be trying it on my vista desktop.

{edit: USB is explicitly not supported for performance reasons.  Guess I'm running XP until my products sunset 5 years from now?  Give me a break, Microsoft}

Tuesday, April 03, 2007 11:55:39 AM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [0]  |  Trackback
 Wednesday, February 07, 2007

After the huge user uproar that happened when the Compact Framework 2.0 initially did not support CE 4.2 devices, one would think MSFT would have taken the point, instead, today I get another fun Vista Fact.

ActiveSync 4.2 and before will not run on Vista.  It's blocked, and tells you so when you try to run it;  Nice of them to let me install it first though.  The Vista solution is the Windows Mobile Device Center, which sounds very swell.  However it explicitly does not support CE 4.2.  Old version won't run, new version won't talk to my devices.  Of course I tried anyway and on my hardware any attempt to connect reliably crashes the Service Host over and over again.  So, for now, we can't sell our most expensive product on Vista.  Granted, I mostly blame this on the OEM who has refused to upgrade to CE 5 for over two years now.

 

Wednesday, February 07, 2007 4:04:00 PM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [0]  |  Trackback
 Friday, October 27, 2006

This is, officially, not supported.  VS2005 is required to debug CF2, and VS2005 does not target CE.net 4.2 devices.  It was a good step forward when the CF2 service pack one came out with runtime support for CF2 and SqlMobile 3 on CE.net 4.2 devices but as someone who loves the debugger, lack of debug suport was a cruel omission.  Often things that are not officially supported will still work in many cases though, so when SP2 came out I tried debugging on my DAP ce4.2 devices.  "A file cannot be created when it already exists", an obscure error with hardly a mention on Google groups or MSDN forums, so I gave up.

Today I was debugging on a CE 5 device from this vendor.  Somehow it got set to "limited user" mode, a proprietery feature of theirs.  Limited user does not have access to read or write most things, including whatever VS2005 needs to start managed debugging on the device.  Lo, I get the same error on my CE5 device which had previously been working for a week "A file cannot be created when it already exists".  Changing back to "supervisor" mode on the device alleviated the issue.  On a whim, I tried the first CE 4.2 device I came across in the office and I get the error. 

Enabling "supervisor", and slowly but surely (much slower than CE5) it deploys to the device.  Starting debugging fails though and I get an error saying it cannot find a version of the CLR compatible with my application, "Some devices do not support automatic CLR upgrade".  Manually upgrading with NETCFv2.wce4.ARMV4.cab, System_SR_ENU.CAB, sqlce30.ppc.wce4.armv4.CAB, sqlce30.dev.ENU.ppc.wce4.armv4.CAB and I'm in business on CE 4.2.  If anyone else has this problem I would encourage experimentation, it might work.

Edit: I should note that my target platform in VS2005 was "Windows CE 5.0 Device".

Friday, October 27, 2006 1:36:04 PM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [0]  |  Trackback
 Monday, May 22, 2006

Here is my bug from Friday.  I have code something like the following that works in SQL CE 2.0:

string sql = "select field1, field2 from Table";
string conStr = @"Data Source=\Stuff.sdf";
SqlCeConnection con = new SqlCeConnection(conStr);
con.Open();
SqlCeCommand command = new SqlCeCommand(sql, con);
SqlCeDataReader reader = command.ExecuteReader();
SqlCeCommand updateCommand = null;
StringBuilder message = new StringBuilder();
while (reader.Read())
{
object[] vals = new object[reader.FieldCount];
reader.GetValues(vals);
if (null == updateCommand)
{
//... if first record, build update command
DataTable dt = reader.GetSchemaTable();
foreach (DataRow row in dt.Rows)
{

string colName = (string)row["ColumnName"];
message.Append(colName);
message.Append("=");
message.Append(row["ColumnSize"]);


}
}
}

This code merges data from "temp database" into permanent database.  Due to the # of tables merging the commands are built by reading the schema of the tables in the to-be-merged database.  Some of this code I inherited from someone else, and it works, or I might see about using  SqlCeCommandBuilder, but that is a post for another day.  This code reads all records from a merge table, and if it is the first record, build update and insert commands using the Schema Table.  In SqlCE 2 this works fine.  In SQL Mobile, if you call GetSchemaTable() after you have read the first record from the reader then the ColumnSizes contained in the schema table will be incorrect, reflecting the data in the current record rather than the schema of the table.  This results in things like truncated data errors if the first record has 5 chars in a varchar(20) field, etc.  The code works as expected if the GetSchemaTable() method is called before you begin reading records.

I can't find anything in the doc describing this as expected behavior, so its submitted as a bug.

Monday, May 22, 2006 8:19:04 AM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [0]  |  Trackback
 Friday, May 19, 2006
I found a great SQL Mobile bug with ColumnSize today which I can reliably reproduce.  I am going to go find out where I submit this bug and scheck to see if its already been submitted, and then post an exaple here of how to reproduce it.
Friday, May 19, 2006 4:17:28 PM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [2]  |  Trackback
 Tuesday, May 16, 2006
Tomorrow night I will be speaking at the Fox Valley .NET User's group, giving a presentation of the Compact Framework version 2.  If you're in the Appleton area, stop by and say hi.
Tuesday, May 16, 2006 1:53:47 PM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [3]  |  Trackback
 Friday, April 21, 2006

The compact framework team has released a beta version of Service Pack 1 for the compact framework version 2.  You can download the packages here: http://www.microsoft.com/downloads/thankyou.aspx?familyId=6548dd53-a418-42d9-a481-19ba3ceca1a6&displayLang=en&oRef=http%3a%2f%2fblogs.msdn.com%2fnetcfteam%2f.  You can read the details here http://blogs.msdn.com/netcfteam/archive/2006/04/21/580901.aspx ; one of the highly anticipated features of this release is the ability to run CF2 applications on CE.net 4.2.  I have one client who has been waiting on this feature for a long time due to a hardware investment that won't allow their converting to CE 5. 

The package contains a Visual Studio patch as well as the standard device updater application.

 

Friday, April 21, 2006 2:43:48 PM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [2]  |  Trackback
 Wednesday, April 05, 2006

RDA, sometimes so good, sometimes so bad.  I post about data synchronization to mobile systems a lot because its one of those interesting problems to me.  There are many ways to do it, Merge Replication is one.  Merg Rep comes with so many drawbacks I could write a decent sized essay about it.  For now I'll just say that if you are considering merge replication you should try to talk to someone with experience implementing it and make sure you want to go down that path.  Synchronizing a read-only database is easy with merg rep or without using custom code.  Synchronizing a read-write database with custom code is a non-trivial endeavor.

Having written and re-written such things several times I have tried various methods.  After my first attempts at remote rebuilding a 100 meg database on a 200mhz strong arm over the internet using web services I decided that RDA needs to be a part of any solution.  RDA allows one to pull down SQL Sever data in a nice binary format that automagically turns into an SQLCE table schema and table data as it streams down to a mobile device.  You can push SQL data using RDA as well, but I don't like doing so for various reasons.  Since RDA is streaming data over HTTP it also gets you around some ugly memory issues.  Consider your woe when your XML message containing 10,000 rows of data is easily spit out by your server but runs the mobile systems out of memory every time.  Segmenting large messages using many XML calls quite frankly feels dirty as well.  As far as rebuilding that 100meg database over the internet, RDA is great.

On my current project we do frequent data synchronization over an AirLink modem.  These things are truly great but they have data rates that are woefully slow in a world that has become accustomed to cable modems and burstable ethernet.  We were having situations where in-office testing would have a sync time of say a minute and a half for a good amount of data.  However in the field some locations were so bad (-110 db signal strength or worse) that this same data packet was taking 20 minutes to process.  This is unacceptable.  Since I happen to have a method to FTP the handheld log files to myself I started doing some log file forensics.

In addition to low data rate, these CDMA modems have high latency, 500ms ping and such.  Every additional trip to the server was incurring large overhead in just making the request.  My data sync that was making an RDA.Pull("select blah blah from blah blah where DateLastChanged > myLastSync") for each table that was fine in our office (where the connection SUCKS butt apparently not as suck as some of our remote locations) but not fine over a low data rate, high latency, in-a-black-hole parking lot where our trucks must operate.  In testing with the SQL server DBA we have noticed an inexplicable overhead for each RDA operation that is about six seconds over a good connection and skyrockets exponentially on a bad one.  While we work out issues with other modem providers (Sprint, Verizon, and Cingular are the big players, Sprint is currently working but connectivity sucks in many areas) a solution was needed.  In the process of making my remote operationgs more "transactional" (after studying F# and what it's all about a tiny bit I dislike the common usage of the term idempotent, which I will explain in a future post) I ended up building multiple code paths for the data sync based on how much data was to be exchanged.  A full rebuild or "very large messages" will still use RDA and execute one pull per table, but in many cases the data package can be sent and received as one large XML message.  I had avoided this approach as long as possible due to the bloat of encoding everything as XML and the potential for memory problems on the clients.  I've found that an "average" XML message is about 179kb which makes me nervous given the CF 1.0 max stack size of 640k and my assumption that the webservice client must load the entire message into memory before it can deserialize it.  If this does become an issue I will do some column mapping such that <FuelDeliveryTransaction><FuelDeliveryTransactionId>12345</FuelDeliveryTransactionId><TotalPricePerGallon>$2.78</TotalPricePerGallon></FuelDeliveryTransaction> in a message becomes <FuelDeliveryTransaction><0>12345</0><1>$2.78</1></FuelDeliveryTransaction> and thereby saves many bytes of data over hundreds or thousands of rows.

I would say "Bring on the high speed wireless connection to every corner of the globe", but Johnny Mneumonic had a traumatizing effect on me.

Wednesday, April 05, 2006 8:56:49 PM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [0]  |  Trackback
 Friday, March 31, 2006

I usually do not post my unqualified ramblings on here but a thought occurred to me today regarding a problem I'm having with on of my mobile systems.  There is a great deal of data exchange and I have taken pains to ensure that no data is ever "lost" in the process.  If a network connection dies at the wrong time the worst thing that happens is that the data exchanged did not complete and the PDA OR server (never both) each have an incomplete picture of the data in question.  When this occurs, I recover the complete picture from a transaction log and go on with my life.

However, I was thinking that it would sure be great to be able to treat the whole data synchronization process as one great big distrubuted transaction.  A distributed transaction involved a wifi network, an over-the-air CDMA connection, web services and SQL server.  There are a hundred sticky little issues that would go along with that strategy and at least a hundred very good reasons not to pursue the idea but it certainly has some allure in my mind as well.  The way my data sync is set up, unfortunately, the transaction cannot be just on the server nor just on the client, they must both agree to commit or roll back if the agreement cannot be procured in a reasonable amount of time; it would be much easier if I could just "make sure the handheld was done", etc.

If anyone out there has mused before on distrubuted transactions involving compact framwork applications I'd be very interested in where your thoughts led.

Friday, March 31, 2006 1:21:59 PM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [2]  |  Trackback
 Thursday, March 23, 2006

This is a follow up to my previous post.  After today, I have a small distant idea of how NASA must feel when a "trivial" item causes a big problem.  My trucks in Detroit were having issues today, and long support calls were getting me nowhere.  I finally came around to thinking that our data synchronization is time-based (rather than GUID based like Merge Replication) and wondered if I had not setup the Detroit units properly.  All times are convered to UTC on the units so there is no hoo-ha for trucks outside of good ole  GMT - 6 where the server lives, and on my checklist for building new handhelds is a bullet point "Verify time zone".  I did this however forgot to verify Time as well so my units had GMT -5 but the hour set to the same hour as current local time.  A small thing caused a very big SNAFU today.  Obviously I can't trust truck drivers (nor myself, clearly) to not screw up the time on the units and I should automate the system time from the backend.  Things like time-zones for nation-wide deployments will play a larger role in my testing strategy in the future...

 

Thursday, March 23, 2006 6:12:48 PM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [0]  |  Trackback
 Tuesday, March 21, 2006

One of the cool aspects of doing Mobile systems is that you often get to do a different kind of programming.  There are plenty of business problems to solve with ASP.NET and SQL but I've recently had a very cool opportunity.

A local company is in the fleet fueling business, this means if you are, say, FedEx in Atlanta, they bring fuel trucks around to your lot at night and re-fuel all your Coca Cola delivery trucks.  The fuel is dispensed using control systems in the truck comprised of fuel meters, printers, and other devices.  As you can imagine with oil-based products being very expensive right now, there are a lot of fraud-prevention mechanisms and business rules related to fuel pricing.  I recently completed, and am now supporting in Production, a new Compact Framework based application that controls the control systems on the truck.  There were many cool-yet-annoying requirements on this effort that forced me to defend-or-change some of my software engineering practices: they system has to talk to several different brands of fuel meters to record gallons, meter totalizers, preset delivery amounts, etc.  Each manufacturer has its own protocol and there are no well published APIs or Web Services: binary hex instead.  We also could not be tied to any specific make/model for any of our other hardware: PDAs, wireless to serial bridges, port replicators, CDMA modems, mobile printers.  Supporting Windows Mobile 2003 and raw CE.NET 4.2 on the same codebase along with 4 different flavors of different OEMs' barcode scanners, cold boot procedures, and WiFi registry settings was also a "Lesson in configurability".

 

Here's a shot of my oh-so-clean and ergonomic development environment with various handheld units:

 

The most excellent part of this system was interacting with the hardware on a real truck once everything was working.  One great thing about being a developer is changing code and then seeing it dance on the screen; pressing a button to calibrate a Fuel Meter, writing exception handling code that tells hardware to reboot itself, scanning a barcode and then watching Low Sulpher Diesel flow out of a real truck at a pre-determined flow rate, now that's fun, and realy damn cool. I recall a conversation with one great architect who was telling me about his experiences with writing warehouse control code many years ago.  He said words to the effect of "Design and testing take on new meaning when a 'bug' results in boxes piling up somewhere or flying off the end of a conveyor belt with nothing there to catch them."  Working in the hardware world occasionally helps make code and the things the code does more real.  If you ever get a chance to work with a hardware system, don't pass it up, you'll probably be thinking and talking about it for a long time.  I'll never forget my first hardware control system experience working for a local manufacturer.  We had a large "test bench" setup so that we could watch lights blink.  One aspect of the software we wrote was the notion of an Alarm that would occur on a client application if hardware operating parameters were outside norms.  The canonical alarm example was that a processor could overheat.  While we stood around deciding how we could accurately test a real alarm situation, one of the testers pried the heatsync off of said processor with a pocketknife to create the alarm state.  Contrast that with the types of testing we normally see on projects, "If I leave this field blank, it doesn't save" and things like that.

Speaking of test benches, here is a shot of some of my test hardware:

All in all, this is one of the coolest projects I've gotten to work on.  I'll ask for permission to post pictures of the actual fuel trucks. Now I just have to convince them to upgrade to CF2 and SQL Mobile...

Tuesday, March 21, 2006 1:44:50 PM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [1]  |  Trackback
 Thursday, March 02, 2006

I personally feel that a good debugger and ability to debug is one of a programmer's best friends.  This includes debugging onto Windows Mobile devices via ActiveSync.

Recently one of my clients got Windows Mobile 2005 on some devices we ordered.  I set about making sure our application would run properly on it. This application happens to communicate over a wireless network with several different pieces of hardware using various proprietery protocols.  I have gotten used to cradling the device, starting a new debug session in Visual Studio and watching bytes flow back and forth over sockets with the wireless connection.  This new gem we received (A Symbol MC9090 with 625mhz Xscale) insisted on shutting down the wireless card whenever the device was cradled.  This makes it hard to communicate with my hardware, which is seperated from the corporate network and on its own WLAN for very good reasons.  Assuming this was a setting I could change, I contacted their support and got the following disheartening response:

  • Microsoft will not allow us to change this functionality.  In short, they will not allow an AS (Activesync) connection simultaneously with a WLAN connection.
  • Also, please note: This cannot be corrected by a GRIP request (custom product request) or any other mechanism.  At the present time if we change this functionality we will fail Logo Certification and therefore not be able to sell the resulting device.
  • I also found some MSDN articles alluding to Microsoft's claims that "some of their Enterprise customers" had asked for this feature for security reasons.  I have trouble imagining what type of customer asked for this change, but so be it.  It seems ludicrous that this is not a developer-overridable item.  There do look to be some hoops one can jump through (if one is very nimble) to get debugging over WiFi to work on CE5 based devices.  I could also ruin my test environment by putting it on the corporate network, or get cozy with platform bulider and try to make an OS image that does what I want just for testing.

    The developer story for Mobile and Embedded systems could still use some work.

    Thursday, March 02, 2006 11:20:42 AM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [0]  |  Trackback
     Saturday, February 04, 2006

    A lot of developers working with these great modern garbage collected single-inheritance object oriented programming languages on big powerful servers may go their whole career without actually seeing an OutOfMemoryException.  This will happen from time to time on the compact framework and I'm happy to say I typically pay attention to what I'm doing and my hard to track down bug from yesterday is my first OOME.  I have a sync process that merges data into SQL CE 2.  To try to squeeze blood (performance) out of a rock (SQLCE 2.0) it prepares and caches update and insert commands.  Here's a small piece of that code:

    ...            

                System.Data.DataTable schemaTable = dr.GetSchemaTable();

                dbCommand = DataHub.Database.GetCommand(GetUpdateTemplate(ref schemaTable, pk, changeColumn), DataAccessObject.CONNECTION_STRING);
                string columnName;

                SqlCeParameter dbParameter;

                foreach (System.Data.DataRow row in schemaTable.Rows)
                {
                    columnName = (string)row["ColumnName"];
                    int columnSize = (int)row["ColumnSize"];
                    dbParameter = new SqlCeParameter(
                        "@" + columnName,
                        GetSqlDbType(row["ProviderType"].ToString()),
                        columnSize);

                    if (!row.IsNull("NumericPrecision"))
                    {
                        dbParameter.Precision = Convert.ToByte((short)row["NumericPrecision"]);
                    }
                    if (!row.IsNull("NumericScale"))
                    {
                        dbParameter.Scale = Convert.ToByte((short)row["NumericScale"]);
                    }
                    int columnOrdinal = (int)row["ColumnOrdinal"];
                    object pVal = DBNull.Value;
                    try
                    {
                        pVal = dr.GetValue(columnOrdinal);
                        dbParameter.Value = pVal;

    ...

    This worked for a long time until someone decided that a column of type ntext  should be replicated.  The column size for a field of type ntext happens to return something like 580million bytes.   When the code tries to set the parameter value, it finds it can't allocate that much space.  The maximum stack size in the compact framework v1 is 640k (reminds me of MS-DOS low memory, no one will ever need more than 640k); 640kb * 1024b/kb = 655,360bytes, or "not enough" and the OutOfMemoryException is thrown. 

    I feel a little sorry for anyone building a custom sync process using SQL CE.  SQL Mobile is much nicer but does not remove the potential for things like this to happen.  I have a project I'm working on which I'll open-source IF I get it done.  I say if becuase I have occasionally announced some wacky plan here only to be distracted by a shiny object and said project dies on the vine.

    Speaking of stack size optionsScalper was telling me about F# and how .... look, a penny!

    Saturday, February 04, 2006 11:59:35 AM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [16]  |  Trackback
     Wednesday, January 11, 2006

    My presentation at the user group last night went ok.  A big part of my example was to show both multi-threading and mobile data synchronization with a mobile device talking wirelessly to my laptop.  The Wifi connection in the room was weak sauce though and I didn't have the foresight to bring an access point as a backup plan despite owning 2 or 3.  Seeing a progress bar tick off across the screen often makes things click for people, so that's too bad.  I have not presented in this building before either and wasn't quite prepared for how difficult it was to see what was on the screens.  Oh well, live and learn, I will definately scope out the Venue more before I do this again.

    As soon as I get a moment I'll make the code and slides available here as well as from the Wineta site.

    Wednesday, January 11, 2006 10:05:04 AM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [0]  |  Trackback
     Wednesday, December 14, 2005

    .NET Architect, gourmet cook, and all-around good guy Matt Terski confided in me once that the great hurdle in getting peolpe to understand SOA was not teaching them transport protocols and such but getting them to Think Asynchronously.  I have posted before about how the Cage Builder culture in some organizations tells developers to "Never use threads".  This is a barrier to responsive apps, great performance, and adoption of SOA.

    For my current client I built another custom data synchronization process for a mobile device.  We are not using Merge Replication for any number of reasons, mostly because of the constraints it puts on your database schema.  This sync process runs over a Sprint Airlink modem mounted on a truck; the speed of the modem is entirely dependent upon the quality of the connection it has at any given time.  Since the trucks could be in the middle of nowhere or surrounded by power lines I'm lucky to get 4k/s on some days.  A normal sync was taking about 3 and a half minutes and I was asked to optimize it.  We are moving to SQL Mobile in Q2 2006 but that doesn't help us today so I sat down to see what I could do to make this faster.

    Long story short, I have it to just under one minute now.  They are pleased.

    Most of the Performance talk you see going around deals with things like "avoid boxing", "use StringBuilder", "stored procedure", etc.  Those are the last things I look at, the first things are improving the efficiency of data stores and Asynchronous processing. 

    Improving the efficiency of your database is a huge topic and one that I am only now becoming more familiar with.  My current sync process is largely based on DateLastChanged fields on various tables, and some of those are large for SQL CE, say 20,000 rows.  Adding an Index on the DateLastChanged fields of some large tables changed the operation from Table Scan to Bookmark seek, and took many seconds off of my times.  There is no execution plan viewer on SQL CE 2 to prove that statement, but the proof is in the performance. 

    The larger part of my 300% improvement was "Processing Item A while waiting on Item B to be done". I am going to write three articles as I get time about some very simple Practices I use to keep me honest and reap the benefits of Thinking Asynchronously.  My 3-part intro to threading will consist of:

    1. Control.Invoke practices for the CF and Delegates in ASP.NET
    2. Practices for Work Item constructs
    3. Thread Signaling
    Wednesday, December 14, 2005 11:27:57 AM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [0]  |  Trackback
     Tuesday, November 15, 2005

    During the visual studio 2005 beta I did some testing with CF v2 and was very excited by the results.  The tests were done on one of my CE.net 4.2 devices.  I was told by numerous Microsoft people that when the final version came out it would require CE 5 to run, which is a serious kick in the junk.  There are some very serious issues with the CF version 1, most notably working with SQLCE 2.0.  By forcing the CE 5 issue, any future hope for people who don't have the ability to upgrade to CE 5 is crushed.  Did I say it was a hard kick in the throat?  Just to tease me, creating a Smart Device CAB project in VS 2005 shows "OSMin" as 4.00, this is clearly just thrown in to confuse and annoy since OSMin is really 5.0.

    On well known compact framework usenet guy Daniel Moth's blog (link is not working for me) he states that there is a chance that a service pack for the Compact Framework v2 will include "runtime only" support for ce.net 4.2;  I would assume this will allow SQL Mobile to run as well.  I would encourage you to go to http://lab.msdn.microsoft.com/productfeedback/ and do a search for compact framework 2 on CE.net 4.2 and vote for it.

    Tuesday, November 15, 2005 12:03:59 PM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [2]  |  Trackback
     Thursday, October 13, 2005

    This is by no means new:

    Palm/Microsoft are going to port WindowsMobile to run on Palm hardware.  Microsoft makes very little money off of licensing for WindowsMobile/CE so this move must be an effort to sell more of the things that go along with mobile systems: back end integration, lock people into the WindowsPlatform, etc.  Does this mean we may see ActiveSync get some more attention and maybe get ported to more platforms?

    Palm has always had great hardware in my opinion and was absolutely an innovator in this field.  I believe having their own OS has contributed greatly to their downfall.  With Windows CE we have had eVB, eVC, the .NET CF for years.   They weren't always great but they were all VERY usable small device development environments.  With Palm you have had C++ using CodeWarrior and J2ME using the KVM.  I have not looked at J2ME in a couple of years, but I have seen some big names post about it: it's not very good.  Maybe I am out of touch with the community, but I've never heard of a big app being written on PalmOS the way I do about windowsmobile stuff.  I run into mobile apps all over the place: at the airport, in Kohls or Target, at the rental-car place; every one I've gotten a chance to look at was undoubtedly a  Windows CE based device.  Big apps being written on these things means companies like DAP, TDS, Symbol, Intermec get orders for hundreds of units at a time, meanwhile Palm has been (as far as I know) relying on individual purchasers to upgrade their units to be able to view their calendar faster or store that extra million contacts they were missing. 

    Since I may end up evaluating palm units on a future project I'm curious: can anyone else tell of their experience developing for Palm over the past several years?

    Thursday, October 13, 2005 3:19:23 PM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [0]  |  Trackback
     Wednesday, September 14, 2005

    Due to the Visual Studio 2005 launch event in November my presentation of the Compact Framework version 2 to the Wisconsin .NET user's group has been pushed back to January 2006.  Considering how cool VS 2005 is I think its safe to say this launch event will be better than anything I could have possibly presented.

    The CF 2.0 release is very near and dear to me due to the amount of pain I have experienced in the CompactFramework 1.0 and SqlCE 2.0, and conversely the joy I have found in porting one of my mobile apps to the new platform.  There are so many different things I could discuss related to the state of mobile development, I'd welcome anyone's ideas for specific things they'd like to see covered.  Some of the points I planned to touch on:

    • Important API differences
    • Important CLR differences
    • Important Visual Studio differences
    • SQL Mobile: this is a big one, especially from a performance perspective
    • COM interop on the CompactFramework
    • Data Sync processes
    • Discussion of Active Sync and Emulators
    • Discussions of Smartphone vs. Windows CE builds vs. WindowsMobile builds

    I'd welcome any comments at damon@damonpayne.com ;see you in January.

    Wednesday, September 14, 2005 1:55:24 PM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [0]  |  Trackback
     Wednesday, July 20, 2005

    So, I hear there are a lot of programs out there that check for newer versions when you run them.  As an end user I find this feature annoying more often than not: how many Windows Media updates are there per week anyway?  As a writer of software it is very nice to have an update feature built into anything you wish to distribute to more than 2 people.  There is a nice Updater Application Block, extensible and easy, and I think there are some partial ports to the compact framework or MSDN CAB-downloader examples out there.  From what I've seen these either don't suit my needs or would require some serious shoe-horning to make them fit my needs.  One of my favorite clients, with their non-Microsoft backend systems now needs Updater functionality, so I set out to design something flexible.

    • There is a custom sync process that runs while the system is connected, so I want to query a backend system for what updates might be available for the unit
    • I want to be able to download CAB files containing new versions of the main system (of course)
    • Download arbitrary files for that matter
    • I want to be able to Execute these CABs, and any other arbitrary shell executable
    • I want to be able to modify the local databases, they are huge so just rebuilding is not an option
    • I want to be able to have the unit upload arbitrary files

    The reasons for these should be apparent but I'll explain anyway.  Suppose you have a change you need to make to a system that 100 people in the field are using:

    1. A new user enterable field is added to a table
    2. New software is needed to collect this data
    3. You need to alter the local data sources to contain this field

    Based on this idea and others, I came up with a list of "Action types" I might want to do during an update.  I query the server for a list of updates passing things like the serial number of the device, and the server returns a list of these Actions sorted by order of execution.  Each action has its own attributes and method of execution so the updater program can kill the main application and polymorphicly go about doing what it needs to do with things like DownloadAction, SqlAction, ShellExAction, UploadAction.

    Obviously there is some work to be done on the server, essentially this will be a webservice that returns a message with the ordered set of Actions in it.  This is more work than a file-based solution but also gives us the flexibility of being able to configure different updates for different devices.  You probably don't want too many different versions of your software running, but the actions can be used to assist technically challenged users with deleting temp files, distribute customer-specific content, delete troublesome SqlCE data, etc.  Due to various other aspects of our software its easy to set up a nag feature where the user can choose to skip the update a certain # of times and other useful stuff.  The upload actions can be either FTP or HTTP PUT.

    Since I mentioned it, I'll have to post about custom data synchronization processes in the future as well, since I think I've got a pretty good one and as one respected member of the Compact Framework newsgroups says "It is not trivial to go that route".  Sometimes Merge Replication just makes you want to shove salt-covered icepicks through your intestines though, and I think a lot of people would use a custom sync processes if there was a proven one out there.

     

    Wednesday, July 20, 2005 3:22:42 PM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [6]  |  Trackback
     Thursday, June 23, 2005

    Suppose for some reason you need to use the HTTP PUT verb from the compact framework.  Depending on whether you zig before zagging for vice versa, you may expience some unexpected behavior.  I'm posting this here in case anyone else has this issue, Google should lead you here and help you out.  You may get an uncatchable InvalidOperationException from HttpWebRequest when setting the ContentLength of your request, not on every request just once in a while.  The exception is uncatchable because it happens on a worker thread you do not have access to.  You can "continue" through it in the debugger but it will otherwise crash your application.  The error is as follows:

    System.dll!System.Net.HttpWebR­equest.set_ContentLength(long value = 108863) + 0xe bytes
    System.dll!BufferConnectStream­.WritingSucceeds() + 0x12 bytes
    System.dll!System.Net.HttpWrit­eStream.doClose() + 0x4b bytes
    System.dll!System.Net.HttpWrit­eStream.Finalize() + 0x6 bytes

    My working Http PUT code:

    public bool HttpPut(string path)
            {
                bool success = false;


                string fileName = Image.ImageNameHelper.GetLastPathPart(path);
                Uri uri = new Uri("http://bigfatlaptop/put/" + fileName            ;

    HttpWebRequest req = (HttpWebRequest)HttpWebRequest.Create( uri );
                req.AllowWriteStreamBuffering = true;
                req.Method