MapPoint and the Dreaded Incorrect Parameter

I’m working on an application to map data in Microsoft MapPoint and ran into a very generic COM subsystem error message of “The parameter is incorrect”. This beautifully nondescript error message seems to be a big thorn in the side of MapPoint developers everywhere, including myself. The function I was trying to use was DisplayDataMap, which is the only API call that MapPoint exposes to map imported data. I was calling this function from within a C++ application, and no matter what I tried, I always seemed to get the error message when mapping data using the geoDataMapTypeMultipleSymbol map type. This error message doesn’t indicate which parameter is incorrect, which made troubleshooting it that much more frustrating, since the function has 13 (ironic?) different parameters.

I’ve been working with Eric Frost of mp2kmag fame over the last few weeks, and he was able to supply me with a C# snippit of code that worked. I trimmed it down to the bare essentials and figured out the main parameter that I was having problems with was ArrayOfCustomValues. This seemed to be rather straight forward in that I just needed to pass in an array of numbers. But Eric’s code was a bit different.

object[] customValues = { 1, 2, 3, 4, 5 };

The array was defined as an object array, not an int or long array as I would have expected. Sure enough, changing the declaration to the following caused MapPoint to throw the error.

long[] customValues = { 1, 2, 3, 4, 5 };

So now that I knew what caused the error message I was seeing, I went about figuring out how to fix it in the Visual C++ world. Variants and variant arrays (safearrays) are a crude beast to get your mind around, and there are quite a few code samples scattered across the internet that deal with them. When it came right down to it, the difference between these two code segments lies in how the .Net framework packages up the values to pass as a variant parameter. The long array is packaged up as a variant safearray containing type VT_I4, whereas the object array is packaged up as a variant safearray of variants, with each variant set to a type VT_I4. This additional level of indirection makes all the difference in the world.

I changed my code to create the array of type VT_VARIANT instead of VT_I4, then added variant records containing the values to the array, and MapPoint happily plotted the data as expected.