Windows CE Networking Team WebLog

Windows CE Networking - from NDIS to TCP to SOAP to VOIP and everything in between.

  • Kerberos cannot resolve netapi32.dll in CE5.0 after QFE updates

    If you install the recent CE 5.0 QFE's AND try to build Kerberos.dll, you will run into a bug that unfortunately was introduced in this QFE.  Check out customer thread alerting us to it here.

    Short summary is that customer is seeing:

    "Warning: Unable to do imports from kerberos.dll to NETAPI32.dll - will late bind"

    Root cause:

    To fix a problem with how Kerberos resolves domain names (basically turning REDMOND domain into a DC controller mydomain-controllername.redmond.microsoft.com), Kerberos was changed to call into the official NetApi32 DsGetDcName instead of using a private interface.  This meant that kerberos has a dependency on Netapi32.dll being in the image which previously it did not.  Customers never think about dependency logic (or hardly ever) because Microsoft runs a large suite of tests to make sure that if component A relies on component B being in the image it explicitly sets it (Kerberos needing Netapi32 in this case) and we fix these issues before releasing the product.

    In this case, because it was a QFE we don't usually add dependencies like this, so we didn't catch the dependency prior to QFE release.

    The customer workaround is straightforward.  Basically set SYSGEN_NETAPI32=1 (I'm not sure what exactly this translates to in the IDE catalog, probably something like "Domain Discovery").  You only need to do this if you include Kerberos component, which most devices do not.  As near as I can tell, the only way you get kerberos is of course if you manually include it, or if you bring in the voipPhone local authentication plugin (SYSGEN_VOIPPHONE_LAP).

    We apologize for the inconvenience.  We're going to be releasing the same QFE effectively in CE6.0 and we will fixup the dependencies prior to releasing that QFE.

    John

  • Inspect incoming SIP headers in RTC CE 6.0 R2 release

    There are many scenarios where inspecting incoming SIP messages for custom headers is useful.  Many servers add their custom headers for custom functionalities like custom ring tones, shared line functionality, privacy, etc. and hence having the ability to inspect incoming SIP messages is very useful. In CE 6.0 R2 release, RTC supports the capability of inspecting incoming SIP messages.  

    The incoming SIP messages that can be inspected are those that generate an RTC EVENT. All Event interfaces can now be queried for the interface: IRTCSIPEvent, which exposes the following g API:

        HRESULT GetSIPMessage(

            [out] IRTCSIPMessage **  ppMessage

            );

    If the event indeed was generated because of an incoming SIP message, then the above API will return a valid IRTCSIPMessage interface, else the error RTC_E_NO_SIP_MESSAGE will be returned and the incoming pointer will be set to NULL in that case.

    Interfaces that can be queried for IRTCSIPEvent are:

    IRTCRegistrationStateChangeEvent

    IRTCSessionStateChangeEvent

    IRTCSessionOperationCompleteEvent

    IRTCMessagingEvent

    IRTCInfoEvent

    IRTCReInviteEvent

    IRTCSessionReferStatusEvent

    IRTCSessionReferredEvent

    IRTCSubscriptionStateChangeEvent

    IRTCSubscriptionNotificationEvent

    IRTCUnsolicitedNotificationEvent

    IRTCSessionConsultantReferredEvent

    IRTCSessionNotificationEvent

     

    A few examples of cases where RTC events are generated due to incoming SIP messages and for which, those incoming SIP messages can be inspected are:

    1.       REGISTRATION success, registration failure response from the server, etc.

    2.       Incoming INVITEs for different types of RTC sessions, incoming INFO, MESSAGE types

    3.       Incoming PRACK messages

    4.       Incoming notifications for subscriptions

    5.       Etc.

     

  • Adding custom SIP headers using RTC, in CE 6.0 R2 release.

    Adding custom SIP headers using RTC, in CE 6.0 R2 release.

     

    In CE 6.0 R2, RTC now supports the capability of adding custom headers to outgoing REQUEST messages, for RTC sessions and RTC subscriptions. Here is how once can do it.

    After CE 6.0 R2 release, IRTCSession interface and IRTCSubscription can now be queried for the interface: IRTCSIPObject. This interface supports the following 2 functions:

        HRESULT SetAdditionalHeaderValues(

            [in]    BSTR    bstrHeaderValuePairs

            );

        HRESULT GetAdditionalHeaderValues(

            [out]   BSTR*   pbstrHeaderValuePairs

            );

    SetAdditionalHeaderValues function can be used to add additional custom headers to outgoing REQUEST style messages, of the IRTCSession and IRTCSubscription, on which it gets called.

    So, in case of IRTCSession, those messages would be:

    INVITE, PRACK(in case PRACK is supported) and final ACK during session setup or mid –session(for cases like Hold).

    CANCEL or BYE message when the session is cancelled or terminated.

    In case of IRTCSubscription, the message will be SUBCRIBE.

    To stop sending custom headers, SetAdditionalHeaderValues can be called again with a NULL value.

    GetAdditionalHeaderValues API can be used to get back the header pair value string that is set by the SetAdditionalHeaderValues API.

    Note: These APIs give direct control in modifying outgoing SIP messages and hence should be used with “extreme” caution. RTC does not validate the contents of the custom headers added, nor does it check the format of these custom headers. Adding improper custom header values can cause the remote side of the RTC session or subscription to reject SIP messages, which can lead to unexpected application behavior.

     

  • Old Man Spaith is out of ideas

    I just checked out the blog and realized it's been ~1.5 months since the last post, which is lame.  I have a dilemna since I've run out of tricks/advice that I think are useful, for now at least.  I can either write nothing or do something random, like put up a picture of my dog, Daisy.  It never would've occurred to me to do this, even in desperation for posts, on what I think of as a work-blog until I checked out the main feed at blogs.msdn.com.  I was amazed at the number of personal, totally random, stuff up there.

    My compromise is that I'll just link to pictures of Daisy rather than wasting bandwidth for people here for work.  So check out Daisy Spaith on my Toastmasters blog, www.mySpaith.com.  (I guess given MS investment in Facebook I should've named SpaithBook, but I put it up before that and mySpaith is better anyway.)

    I wish I could say we had made CE networking technologies so easy and awesome for our developers that we could turn the CENet blog into the "dogs of the CE Networking team" site.  We know we're not there yet.  Please keep the questions coming in the newsgroups and we'll do our best to help.  Thanks for your continued support through the years.  I'll try to come up with better stuff so we can avoid the self-indulgent posts like this I promise.

    -- Old Man Spaith (just turned 31, it's down hill from here)

  • Problems building svsutil.hxx in Windows Mobile SDK

    If you try to build svsutil.hxx on certain versions of the Windows Mobile SDK, you may run into build errors.  I know it's on WM5 SDK at a minimum, I don't know about WM6 SDK. 

    The error you'll see will complain about the methods int operator==(int iBit) and int operator==(SVSBitField &bf) in the class SVSBitField in particular.  What happened is that the compiler got a bit more picky at some point but the SDK headers weren't updated to reflect this in the given SDK version.  We have fixed this in latest & greatest svsutil.hxx.

    If you run into this, what you'll need to do is change the initial
      for (int i = 0 ; i < m_iWLength - 1 ; ++i) {

    So that the 'int i' is outside the for loop, namely:

      int i;
      for (i = 0 ; i < m_iWLength - 1 ; ++i) {

    Our apologies to anyone who hits this.

    John

  • Controlling VOIP interfaces on Windows Mobile devices

    RTC 1.5 can be restricted to use only certain types of interfaces (Wifi, Ethernet, etc.) on Windows Mobile devices. Same restriction cannot be applied on Windows CE, as RTC uses connection manager functionality to do that, which is not available on Windows CE.

     

    RTC can be restricted using the following reg keys. These reg keys need to be set before RTC gets initialized.

     

    HKLM\Comm\RTC\AdapterTypes

     

    One can list all the allowed interfaces as numerical keys:

     

    e.g.        1

                  2

                  3

                  ETC.

     

    The value of each key should be an ORed value of the connection manager interface type and sub-type

     

    e.g. If one wants to allow Ethernet interface only.

    The connection manager interface type to use will be CM_CONNTYPE_NIC (0x2)

    The connection manager sub-interface type to use will be CM_CONNSUBTYPE_NIC_ETHERNET (0x1)

     

    The Ored value = (0x2 << 16) | 0x1 = 0x20001

     

    So the reg key will look like:

                  

    HKLM\Comm\RTC\AdapterTypes\1 (DWORD with value 0x2001)

     

    Similarly, if Wifi is also desired,

    The connection manager interface type to use will be CM_CONNTYPE_NIC (0x2)

    The connection manager sub-interface type to use will be CM_CONNSUBTYPE_NIC_WIFI (0x2)

     

    The ored value  = 0x2 << 16 | 0x2 = 0x20002

     

    So the reg keys will look like:

                  

    HKLM\Comm\RTC\AdapterTypes\1 (DWORD with value 0x2001) ß for Ethernet

                                                                     2(DWORD with value 0x2002) ß For Wifi

     

  • Pluggable video codec for RTC 1.5 stack

    RTC 1.5 (CE 6.0 R 2 release) supports Point to Point Video calling. However, the stack does not ship any built-in video codecs. Instead it supports a pluggable video codec architecture through which, one can add their own video codecs.

    Below are the steps one needs to take to plug-in a video codec into the RTC stack.

    1.      Implement your video codec in form of a DShow filter. Here is a MSDN link that explains How to write a DShow filter.

    2.      On the device, set the following reg keys before RTC is initialized:

    HKEY_LOCAL_MACHINE\Comm\RTC\Video\Codecs\<key set#>

     

    *Note: <key set#> can be any name (e.g. 1,2,3 or codec name itself)

    *Note: For latest and up to date pluggable video codec reg keys listed below, please visit the MSDN link here .

    Name

    Type

    Description

    EncoderFilter

    REG_SZ

    Specifies the COM CLSID of the encoding IBaseFilter.

    DecoderFilter

    REG_SZ

    Specifies the COM CLSID of the decoding IBaseFilter.

    DecoderMediaSubtype

    REG_SZ

    Specifies the media subtype GUID of the format of the incoming data. Examples of incoming data format include H263 and H264.

    CodecType

    REG_SZ

    Specifies the codec type. Always set the data to Filter. There is no default value.

    CodecRank

    REG_DWORD

    Sets the relative priority of the codec. The data is an integer between 0 and 100. The highest priority is 0 and the lowest is 100.

    CodecName

    REG_SZ

    Specifies the name of the codec sent in the Session Description Protocol (SDP) payload. For example, the codec name could be H263-1998. The name must contain fewer than 32 characters.

    PayloadType

    REG_DWORD

    Specifies the RTP payload type associated with the codec. For example …

    ClockRate

    REG_DWORD

    Indicates the clock rate of the codec as it appears in the a=rtpmap line of the SDP . For many codecs the correct data is 90,000.

     

    Note: If a codec needs to be represented by multiple payload types (as some codec do), then a separate key set needs to be added for each payload type. RTC supports plugging in a maximum of 7 such key sets (7 separate payload types).

    3.      If your codec supports custom codec properties, which needs to be negotiated through SDP using FMTP lines, then the codec can put its FMTP string in the following reg key:

    HKEY_LOCAL_MACHINE\Comm\RTC\Video\Codecs\<key set#>

    Name

    Type

    Description

    SDPFmtp

    REG_SZ

    Indicates the format specific parameters FMTP of the codec as it appears in the SDP a=fmtp line of the SDP. If SDPFmtp is not set, no FMTP lines will be sent.

    This data indicates only the parameters themselves. SDP automatically fills in the following text:a=fmtp:<RTP Payload Type #>

     

    RTC will read the reg key during initialization, and will add it to the outgoing SDP as is, as FMTP properties of the codec. If no reg key is specified, no FMTP lines will get published in SDP for the codec.

    4.      RTC also supports passing of incoming FMTP property string to the plugged in codec, so that the codec can make a decision if it supports those properties or not. The pluggable codec needs to implement the following interface: IRTCSDPValidator to accept incoming FMTP strings from the SDP. The following reg keys needs to be set for the codec, to let RTC know of the interface:

    HKEY_LOCAL_MACHINE\Comm\RTC\Video\SdpValidators

    Name

    Type

    Description

    <Codec Name>

    REG_SZ

    Specifies the CLSID that implements this object.

    e.g.

    Name

    Description

    H263-1998

    {D018239F-4022-4c15-BC87-03CCADC1A4E3}

    Note: An IRTCSDPValidator registry value is not required. If a codec does not implement this registry key, the codec accepts all SDP.

    5.      Implement interfaces that allow adding and removing custom RTP headers.

    RTC uses RTP as the media transport protocol for video. RTP allows adding codec specific headers for each RTP payload. Since this header is codec specific, RTC provides a mechanism so that pluggable codecs can add/remove these custom RTP headers during the encode/decode process.

    Implement the interface IRTCPluggableVideoEncoder to add custom RTP header and the interface IRTCPluggableVideoDecoder to remove custom RTP headers. Publish these interfaces in the reg key:

    HKEY_LOCAL_MACHINE\Comm\RTC\Video\Codecs\<key set#>

    Name

    Type

    Description

    EncoderPlugin

    REG_SZ

    Specifies the COM CLSID of the IRTCPluggableVideoEncoder interface. Set H.263 to {A7D8A6EF-575B-4750-A727-04234A70D9DE} to use the Microsoft provided implementation of this interface. Set H.264 to {92A200F8-0981-11DC-813E-B77255D89593} to use the Microsoft provided implementation of this interface.

    DecoderPlugin

    REG_SZ

    Specifies the COM CLSID of the IRTCPluggableVideoDecoder interface. Set H.263 to {0CE193DF-27F0-48c7-92F7-75CA7A5965E6} to use the Microsoft provided implementation of this interface. Set H.264 to {86546C00-0981-11DC-88BE-AE7255D89593} to use the Microsoft provided implementation of this interface.

    *Note: The Microsoft implementation of the above interfaces for H263 and H264 video codecs can be found at CE OS installation location: public\fp_voip\oak\codecs\H263Parse and public\fp_voip\oak\codecs\H264Parse respectively.

    Now that we know how to write a pluggable video codec and add it to RTC, let’s see how RTC will use the codec and all other interfaces by the codec module:

    1.      As soon as RTCClient object is initialized, RTC goes through the all reg keys defined above to check for any pluggable video codecs. If the reg keys are set, RTC will check, verify and load the codec for future use.

    2.      When a user makes an outgoing video using RTC, then:

    a.      All pluggable video codecs that are successfully loaded by RTC, will get published in the outgoing SDP.

    b.      If the codec has set the SDPFmtp reg key to specify its FMTP properties, then RTC will add that string in the outgoing SDP for the respective video codec.

    3.      When an incoming video call is received by RTC, then:

    a.      For each video codec published in the incoming SDP, RTC will try to match it with its plugged in codecs. If any of the codec name matches, then RTC checks to see if the codec implements IRTCSDPValidator interface. If it does, then RTC will call the CheckAcceptableFmtp function of the interface with the incoming FMTP string, to let the codec check if it can support those properties. If the function returns S_OK, RTC considers that codec is capable of handling the incoming FMTP properties, and it proceeds with the call as usual. Any other return value is considered a failure. If there is no codec match, RTC will reject the call.

    b.      If the codec does not implement IRTCSDPValidator, then RTC assumes that the codec is capable of handling any incoming FMTP property, and will proceed with the call as usual (generally by triggering an event of an incoming video call)

    4.      Once the call has been established:

    a.      During the encode process, RTC will call the appropriate filter APIs to encode the raw video frames. After that, RTC will call the IRTCPluggableVideoEncoder interface API to let the codec generate custom RTP header for the encoded frame. Please see the MSDN page for more details on the interface.

    b.      During the decode process, RTC will first call the IRTCPluggableVideoDecoder interface API to let the interface extract the encoded frame from RTP payload. Once an entire encoded frame is extracted, RTC will then call the filter APIs to decode the raw video frames. Please see the MSDN page for more details on the interface.

     

  • Sample Code for Local Audio Mixing using RTC 1.5 (CE 6.0 R2 Release)

    Sample code for local audio mixing to achieve 3 way/N way calling.

    In CE 6.0 R2 release, RTC 1.5 started supporting local audio mixing. Local audio mixing can be enabled by using the flag RTCIF_ENABLE_GLOBAL_MEDIA_MIXING during RTCClient object initialization. Here is the code example (ignoring error handling):

    Initialize RTC to enable local media mixing:

        hr =  CoInitializeEx(NULL, COINIT_MULTITHREADED);

        hr = CoCreateInstance(CLSID_RTCClient,

     NULL,

     CLSCTX_INPROC_SERVER,

     IID_IRTCClient,

     (LPVOID *)&gpRTCClient );

            IRTCClient2 *piRTC2 = NULL;

           

            hr = gpRTCClient->QueryInterface(IID_IRTCClient2, (void**)&piRTC2);

            hr = piRTC2->InitializeEx(RTCIF_ENABLE_GLOBAL_MEDIA_MIXING);

     

     Once media mixing is enabled, audio for all calls will be locally mixed. Consider the following example to see how 3-way /N way calling can be achieved:

    Consider two audio calls between a caller (Endpoint 1) and two other callers (Endpoint 2 and 3). Without local media mixing, 2 and 3 can talk to 1, but not to each other on the existing calls. When local audio mixing is enabled on endpoint 1, endpoint 1 mixes the audio stream as described below, which will enable 3-way conferencing, and all three can talk to each other.

    ·        Endpoint 1 mixes its own audio (1) with the audio that it receives from endpoint 3 (3) and sends it to endpoint 2. Similarly,

    ·        Endpoint 1 mixes its own audio (1) with the audio that it receives from endpoint 2 (2) and send it to endpoint 3.

    This way, endpoint 2 can listen to endpoint 3, and endpoint 3 can also listen to endpoint 2.

    Since Endpoint 1 is the mixer, the conferencing is dependent on endpoint 1. If endpoint 1 disconnects any of the calls, then Endpoint 2& 3 won’t be able to talk to each other.

    Here is a code example (ignoring error conditions for simplicity)

    Establishing a 3 way call:

    Step 1: Endpoint 1 Calling Endpoint 2

        hr = gpRTCClient->CreateSession(RTCST_PC_TO_PC, NULL, NULL, 0, &pSessionEndpoint2);

        if (SUCCEEDED(hr))

        {

     

                hr = pSessionEndpoint2->AddParticipant(bstrEndpoint2URI, bstrEndpoint2Name, NULL);

       }

    After this, RTC will post a session connected event, once the call has been established between endpoin1 and endpoint 3.

    Step 2: Endpoint 1 putting Endpoint 2 on Hold, before calling Endpoint 3

        IRTCSessionCallControl* pSessionEndpoint2CallCtrl = NULL;

     

        // Query for the IRTCSessionCallControl interface.

        HRESULT hr = pSessionEndpoint2->QueryInterface (IID_IRTCSessionCallControl,

                                       (void**) & pSessionEndpoint2CallCtrl);

     

        hr = pSessionEndpoint2->get_State(&enState);

     

            if(enState != RTCSS_CONNECTED)

            {

                ASSERT(0);

               // Handle error!!

            }

            

        pSessionEndpoint2CallCtrl->Hold(lCookie);

    Step 3: Endpoint 1 Calling Endpoint 3

        hr = gpRTCClient->CreateSession(RTCST_PC_TO_PC, NULL, NULL, 0, &pSessionEndpoint3);

        if (SUCCEEDED(hr))

        {

     

                hr = pSessionEndpoint3->AddParticipant(bstrEndpoint3URI, bstrEndpoint3Name, NULL);

       }

    Step 4: Endpoint 1 Unholds Endpoint 2 to establish 3 way conference

        IRTCSessionCallControl* pSessionEndpoint2CallCtrl = NULL;

     

        // Query for the IRTCSessionCallControl interface.

        HRESULT hr = pSessionEndpoint2->QueryInterface (IID_IRTCSessionCallControl,

                                       (void**) & pSessionEndpoint2CallCtrl);

     

        hr = pSessionEndpoint2->get_State(&enState);

     

            if(enState != RTCSS_HOLD)

            {

                ASSERT(0);

               // Handle error!!

            }

            

        pSessionEndpoint2CallCtrl->UnHold(lCookie);

     

    After Step 4, all 3 endpoints can talk to each other. Please note that Step 2 and Step 4 (putting Endpoint 1 call on Hold and then UnHold) are optional steps. RTC 1.5 will allow making call to Endpoint 3 while call to Endpoint 2 is active. But this kind of calling is not normal in the telephony world.

     

    If Endpoint 1 wants to talk to Endpoint 2 exclusively, it can simply put Endpoint 3 call on Hold, and similarly it can put Endpoint 1 call on Hold if it wants to talk to Endpoint 3 exclusively.

     

    Also note that even though media is mixed for both calls, All APIs related to each call (like RTCSession and RTCParticipant APIs) will only act on the respective individual calls. For e.g.

    Example 1: pSessionEndpoint2->Terminate(RTC_TERMINATE_REASON) will just disconnect Endpoint 2 and not Endpoint 3.

    Example 2: pPartEndpoint2->SendDTMF(RTC_DTMF) will send DTMF tones only to Endpoint 2, and not to Endpoint 3,

    etc.

     

    However, APIs like CRTCClient::put_Volume(RTC_AUDIO_DEVICE enDevice, long lVolume) will affect both calls.

     

    Thanks and happy coding!!

  • What is new in RTC 6.0 R2 release?

    Following are the new features in RTC 6.0 R2 release:

    1. Local audio mixing capability (enabling 3 way VOIP calling)
    2. Point to Point Video Calls
    3. Pluggable Video Codec capability
    4. Ability to inspect SIP headers for certain SIP messages
    5. Ability to add custom headers to certain outgoing SIP Messages
    6. Attended Call Transfer facility
    7. Call Park/Pickup facility

    All the above features, except video, are available through VOIP default sysgen, i.e. SYSGEN_VOIP. Point to Point Video

    feature is selectable using SYSGEN_VOIP_VIDEO sysgen.

    As time permits, I and my team will blog out each feature in more details.

    For now, you can get some details about local audio mixing through the following link:
    http://download.microsoft.com/download/0/7/4/0748b074-ed6c-461f-bcd0-e35d047bc1f8/Windows%20Embedded%20CE%206.0%20R2%20Release%20Notes.htm#WN7

    Thanks and happy new year to all!!
    Rajesh

  • The History of the DCOM Remoting Addon Pack

    I recently wrote about the recent DCOM Remoting Addon pack being available.

    Since I'm running out of things to write about, I'll explain the geeky details of how the DCOM addon pack came to be.  This post is for the very bored only or those who are intrigued by the Windows CE Build Process.  There are no profound insights on COM or any other subject, for that matter.

    First we had to figure out what to do with DCOM remoting.  We had to either re-port Windows Vista COM or else remove DCOM remoting from the product.  Even though CE is componentized and we could have warned that this component was insecure & should be avoided almost always, NT4 vintage DCOM was *so* insecure that this wasn't enough.  After all, how often do you click through the obnoxious warnings that software pops up?

    This was a no win situation.  Even if we wanted to spend the effort to re-port COM, the amount of time needed to do the work and then get it stable (think about how key COM is to the system) didn't allow us to go down this path.  At the same time we knew we had some OEMs who desperately needed DCOM remoting.

    So the Group Program Manager, who makes a lot more money than I do for good reason, helped push through the idea of an addon pack.  DCOM remoting would be available only in CE6 if you downloaded a separate product.  The addon pack made our security people happy.  Since you have to go to a website to get the bits, you can't accidentally click on some buttons and end up with it.  It also lets us warn you point blank on the download site what you're getting into in a way less likely to be missed than warning popup box #73.

    From the website:

    <
    "the component contains known MSRC class critical bulletins. Installing the supplemental pack ... is discouraged, and Microsoft assumes no liability if this pack is deployed."
    >

    How does the DCOM addon pack work?  Ironically for all the time I spent in meetings discussing various aspects of it from biz/legal/security, the actual dev work was straightforward.  On NT4, DCOM has the concept of loadable transport DLL's to actually do the heavy lifting of talking to the transport layer.  rpcltscm.dll & rpcltscm.dll. 

    The way PB builds MS doesn't ship these DLL's but instead rpcltscm.lib and rpcltscm.lib, and under the covers OEMs are building the DLL themselves.  We have config files that allow us to specify which files (in this case in public\dcom\oak\lib\<CPU>\...) are shipped out to customers.  So I changed the logic in them so that rpcltscm.lib & rpcltscm.lib were no longer shipped, even though they were still building.  I also changed a few configuration files to add some comments should some geek poke around the build and try to add the DLLs manually.  Check out public\dcom\oak\lib\(dcom.reg & dcom.bib) if you want to see Spaith's warnings.

    There was the extra step here of making sure that DCOM didn't have any direct calls to Winsock or other networking layer technology to do an end-round the transport DLL layer.  It doesn't.  I was impressed with the cleanliness of the design.  I anticipated whacking out winsock calls thrown all over the place and had given myself a lot more time on the schedule than I actually needed.  Of course a lot of other work that I underestimated ended up filling the free time I had!

    So the addon pack is basically just an MSI installer, various EULA's (the most important piece from a biz perspective), and the libraries. 

    At the time of shipping this I joked about trying to get a ship-it award, which would be riduculous given that I hardly spent a few weeks on this.  (Other ship-its have taken me +1 year of work).  The Group PM said in all seriousness he'd try to make it happen, but I think it's best to let it drop.

    John

  • DCOM Remoting on Windows CE 6.0

    As I wrote here, in Windows CE 6.0 we removed DCOM remoting - that is the ability to create and host COM objects across a network.  We did this due to security.  Our DCOM is built on NT4 vintage code and there was no way we could patch up our implementation to meet security requirements.  The desktop faced a similar problem post-NT4 and also came to the conclusion they couldn't do a patch up, so they had to redo lots of their DCOM.

    Note this is all embedded CE only - Windows Mobile doesn't even have cross-proc COM objects, much less remoting.

    I'm happy to announce that an add on kit to CE6 is available here that will allow OEMs to get DCOM remoting in their image.

    As the docs call out but I will emphasize here, this is ONLY for completely closed networks.  I'm thinking of a factory floor as the main example (and they're the main ones who want this).  This is not safe for the Internet of course or anywhere that untrusted machines may get on a network due to security worries.

    While we can't make any official statements about future products on the blog, I'll say unofficially that we are most likely not going to be doing another remoting addon pack for Windows CE 7.0.  We wanted to provide some sort of stop gag solution as Web Services for Devices for instance (available in CE 6.0 R2) or other technologies become available.

  • UTF-8 in ASP pages on Windows CE

    My "stuff to blog about" well has pretty much run dry, as anyone who follows this blog knows.  Fortunately there's always a customer running into something that I've never thought about something to inspire me.  Bad for the poor customer hitting the issue, but good for the rest of us.

    A customer wasn't able to make ASP pages from CE Web Server work when the pages were UTF-8.  The same page had worked fine as ANSI.  The error they got was when setting <% Response.Expires = -1 %> in their page.

    -----------------START

     

    The HTTP headers are already written to the client. HTTP header

    modifications must be made before writing page content

     

    ASP scripting compilation error: '80020009'

     

    Description:

     

    In file: /Test/default.asp

    On line: 1

     

    -----------------END

    ASP aficionados, can you guess what was happening?

    --

    What happens is UTF-8 puts special characters in the first bytes of a file indicating to an editor that it is UTF-8.  When our ASP interpreter parses out a page, it sees those UTF-8 characters and (unfortunately) doesn't know about UTF-8 and assumes its ASP body that needs to be sent out.  Once ASP body has been sent, you're not allowed to send HTTP headers anymore, which is why the Expires=-1 wasn't working.

    I had the customer remove the special bytes and also look into the Response.Charset() to make sure the browser knew the encoding of the file (always a good idea with non-ANSI anyway).

  • 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

  • Memory Corruption, Compiler Bug, Or Not?

    While tracking down some memory corruption issues, I noticed in one function that a parameter on the stack was always getting set to the value 2, even though it was a pointer. I could see it turn red in the memory view window as its value changed. I thought I had identified a compiler bug. But no, it was not a compiler bug. It was actually a mismatch between the optimizing compiler and the debugger. The x86 optimizer knew that the memory for the stack variable was referenced only one time and then was enregistered, so its stack memory could be used for another local variable. The debugger’s local variable display did not realize this and continued to display the memory value for the local variable – confusing.

    On ARM, a similar situation can arise since the first 4 registers (R0, R1, R2 and R3) are used as function parameters. The debugger doesn’t track when a function parameter gets moved to a “permanent” register (R6 for instance) and continues to display the function parameter register’s value as the local variable’s value.

     

  • About Harish

    Hi, my name is Harish Srinivasan. I work in the Windows CE Core Networking team. I own IPsec, IKE and several other networking components.

More Posts Next page »

© 2009 Microsoft Corporation. All rights reserved. Terms of Use  |  Trademarks  |  Privacy Statement
Microsoft
Page view tracker