GPSID: Problem & workaround on recent WM6 release

Background
A number of customers on a recent WM6 versions have run into a problem where GPSGetPosition returns ERROR_INVALID_PARAMETER always, even on apps that worked fine in the past.  The newsgroup thread is here.

The device I've reproed and tested on was an HTC P3300, but based on newsgroup thread I think other devices may have been affected also.

I have determined the cause and a workaround for the problem.  It'll take a while to get a real fix, but we're working on that too.

Underlying Cause
In a future Windows Mobile, we're exposing extensions to the GPS_POSITION and GPS_DEVICE structures.  GPSID is actually aware of the extended structure already - in WM6 AKU0.4 & above, also known as 18120+ builds.  The reason being that GPS chips can do some "magic" with this stuff even before we actually expose the structures to app developers.  (It's a very long story, if you're not a GPS OEM you don't care.)  Because the structure is larger, it means the sizeof() checks on it have changed but sizeof(GPS_POSITION) that you're passing in has not changed because you're using the same GPS_POSITION as always.  The MS GPSID allows the old struct size for legacy.

What complicates things is that OEMs are allowed to replace GPSID on their device, because they may want to tweak it in order to work with their GPS chips.  I don't have the source, but I'm almost positive what's happening is that an OEM GPSID is checking only against the extended GPS_POSITION size and hence is failing when it gets the original GPS_POSITION.

Workaround
Your application can lie about how big a structure it is passing in to worakround this.  So if your application gets ERROR_INVALID_PARAMETER, it can pass in the sizes of the new struct.  Here's code below.  I tested this with an HTC 3300 and was successfully able to get my lat/long using this.  GPSGetDeviceState has similar issue so I'm including code for it, too.

// Retrieves GPS location data and prints it to the screen.
void GetLocationAndPrint(HANDLE hGPS) {
    BYTE gpsPositionRaw[376];
    GPS_POSITION *pGpsLocation = (GPS_POSITION*)gpsPositionRaw;
   
    pGpsLocation->dwVersion = GPS_VERSION_1;
    pGpsLocation->dwSize    = sizeof(gpsPositionRaw);
 
    DWORD dw = GPSGetPosition(hGPS,pGpsLocation,1000,0);
    if (dw != ERROR_SUCCESS) {
        wprintf(L"GPSGetPosition() fails, GLE = 0x%08x\r\n",dw);
        DebugBreak();
        return;
    }

    PrintGPSPosition(pGpsLocation);
}

void GetDeviceStateAndPrint(void) {
    BYTE gpsDeviceRaw[332];

    GPS_DEVICE *pGpsDevice = (GPS_DEVICE *)gpsDeviceRaw;
    pGpsDevice->dwVersion = GPS_VERSION_1;
    pGpsDevice->dwSize = sizeof(gpsDeviceRaw);
 
    DWORD dw = GPSGetDeviceState(pGpsDevice);
    if (dw != ERROR_SUCCESS) {
        wprintf(L"GPSGetDeviceState() fails, GLE = 0x%08x\r\n",dw);
        DebugBreak();
        return;
    }
    PrintGPSDeviceState(pGpsDevice);
}

Going Forward
This is clearly a stop-gag solution.  There's no way that we expect our customers to recompile existing apps for a new WM release, especially considering how hard it is to get applications signed/tested/deployed.  I have alerted the OEM to the problem and am coordinating with them on rolling out a fix.  I'll provide an update when I can.

Once again I apologize for the pain that this has caused and the delay.

John