# Wednesday, September 12, 2012

Yes, VS 2012 will support CE development, including Compact Framework 3.9.  Support is scheduled to be released in Q1 of next year.  See this video for more details.

Wednesday, September 12, 2012 6:23:08 PM (Central Daylight Time, UTC-05:00)  #     | 
# Friday, June 15, 2012

It was easy to miss, but Microsoft publicly announced that Smart Device development projects will, in fact, be released in Visual Studio 2012 in Q1 of 2013.  It’s not news to me, but it is to most, and it’s way, way past due.

Friday, June 15, 2012 9:50:07 AM (Central Daylight Time, UTC-05:00)  #     | 
# Friday, March 30, 2012

Ages ago I created an SDK that allows you to extract device CAB files and create a replacement for wceload if you wanted (we used this on a couple customer applications).  We also tried to sell it as an experiment in "value-based pricing".  Well the experiment showed, largely, that people would pay the minimum and very, very rarely come back and pay anything more so either it was of low value, or people are just cheap.

At any rate, I don't feel like maintaining it internally any longer so it has become yet another project that I've open sourced for the community at large.  The full download is now available over on Codeplex.

Friday, March 30, 2012 10:55:07 AM (Central Standard Time, UTC-06:00)  #     | 
# Tuesday, March 06, 2012

I just got an email in the Support inbox over at OpenNETCF asking about the libraries support (or really lack thereof) for Wireless Networking in Windows Embedded Compact 7 (rolls off the tongue, doesn’t it?).  While this is a question about a specific feature of the SDF, it really opens up the broader question of what our plans are for the future of the whole product.  In fact you could say it really opens up the question on what our general company plans and philosophy are.

First, let’s address this specific issue, as it deserves answering and has a little bit of a back story leading to a minor rant which is always fun. 

The SDF supports an object model for wireless networks that is based around the Wireless Zero Config (WZC) API.  Microsoft introduced WZC in CE 5.0 (IIRC) in an attempt to “standardize” the way the platform and apps would communicate with the wireless drivers, since NDIS doesn’t really have any specification for a lot of the wireless properties.  While I applaud the spirit, WZC is convoluted at best, and was definitely not designed to make the life of someone who has to use P/Invoke to communicate with it any easier.  Still, it was some sort of standardization so we rolled up our sleeves and created a managed interface for it. 

I’ll readily admit that what we ended with isn’t ideal, but I’m a fierce self critic and I rarely think what we do is as good as it could be.  Still it provided a programmatic interface for something that a *lot* of people wanted and that Microsoft had not implemented in managed code.

Well with Compact 7 (I’ll just call it CE7) Microsoft decided that WZC wasn’t the way to go, but instead Native WiFi was.  Painfully they didn’t follow a sensible “deprecated but supported” track for WZC and support side-by-side, they just dropped WZC support altogether.  That meant that we could not interface with a wireless adapter under CE7 using our existing code base at all – it was a flat-out break.

To make things worse, Microsoft went radio-silent for about 2 years (and still counting – yes I’m looking at you Redmond!) on what, if any, future the Compact Framework, or CE for that matter, might have.  The original WZC work was probably 4-6 weeks of development and it required that we buy several devices for testing.  Believe me, it was a real pain in the ass.  Do we (more specifically do *I*) really feel like doing that all again for the Native WiFi interfaces?  If I do, where do I get a CE7 device with WiFi support?  If I do all of that work, what’s the ROI if Microsoft kills the Compact Framework?  What’s the ROI if they revive it and implement Wireless themselves?

It’s really difficult to answer those questions, and we’re not the only ones who are wondering these things.  I can say, though, that we’ve very recently decided that yes, we will continue to do both support and new development for the SDF.  What that new development will entail I can’t say.  Not because it’s some big secret, but because I can’t make those plans until Microsoft tells us their plans (and they haven’t).  If they decide to release a new version of the Compact Framework, I’d like to not have a load of functionality duplication between it and the SDF.

So, is the SDF a dead product?  No.  We will continue to support it and have plans for feature additions.  We just don’t know exactly what those features will be or when they will be written (confidence inspiring, I know). 

Will we provide Wireless support for CE7?  If Microsoft does not, then yes, we will.  Again, we don’t know if they will or not.  If they did, we don’t know when that would be.  Ideally, though, programming for WZC and Native WiFi should be the same, so if they don’t do it, we’ll add support that looks and feels just like what’s in the SDF today.  If they do add it, I’d be inclined to update our object model to match theirs (keeping the old stuff for compatibility though).

Don’t read too much into this.  Yes, I’m optimistic about the Compact Framework and Windows CE Windows Embedded Compact but I’ve been using them for over a decade and I’ve based a whole lot of my knowledge, business and life on them.  I almost have to be optimistic.  But let’s face it, CE and the CF are still great tools for delivering products.  We’re still shipping products based on them.  Still doing new development and new installs.  Still writing proposals for them. 

Yes, we’ve tested the waters with Android and iOS.  We’ve even delivered finished products for them both, but using those tolls only reinforced my feelings about the strength and possibilities of the CF and CE and we’re still committed to using and supporting them.

Tuesday, March 06, 2012 5:25:57 PM (Central Standard Time, UTC-06:00)  #     | 
# Monday, November 14, 2011

There has been rampant speculation for some time that Windows CE was dead and that Microsoft was abandoning it.  The announcement that Windows 8 will run on ARM only added fuel to it, despite the fact that Win8 is undoubtedly going to have a large, desktop-style footprint and no capability for real-time operation.  Well, Microsoft finally decided to tell us what many of us suspected for some time.  Windows Embedded Compact (i.e. Windows CE) is still on their product roadmap.  It will have a v Next, and it will be supported in newer versions of Visual Studio (well native development will be anyway).  Read the full press release here.

Monday, November 14, 2011 1:41:15 PM (Central Standard Time, UTC-06:00)  #     | 
# Friday, March 04, 2011

In case you missed the pretty quiet announcement this week, Windows CE Windows Embedded Compact (love those marketers) 7.0 was released to manufacturers this week.  You can download the eval as well.

There are some nice new features in this release, but what's more important is that it's actually been released.  There seems to have been a lot of speculation lately about the demise of CE, and this concretely says "no, CE is not dead".  This release means that it is officially a supported product for the next 5 years with extended support for another 5 after that.

I spent most of this week in Redmond talking with some of the teams and I came away with a pretty positive impression about the future of CE Compact.  Microsoft has failed lately to provide information about the future and direction of Compact, and that lack of communication has led to a lot of people making implicit assumptions that we've been reassured are not true.

I don't have any specifics that I can share right now, but I can say that I personally would have no qualms about recommending CE 7 Embedded Compact 7 and the Compact Framework as a base for new products that you intend to ship for the next decade. 

I'll share more news as I get it.

Friday, March 04, 2011 12:46:38 PM (Central Standard Time, UTC-06:00)  #     | 
# Thursday, December 09, 2010

The MTConnect Agent SDK I published last week is really only useful if you implement a Host to actually serve up the data.  The IHost interface isn't complex, but if you don't have an example, it's a bit difficult to understand my intent.  I've published a desktop implementation that uses Padarn as the web server.  In theory the same code should work under Windows CE as well, but I've not yet tested it to be certain.

Thursday, December 09, 2010 11:30:59 AM (Central Standard Time, UTC-06:00)  #     | 
# Tuesday, June 01, 2010

Microsoft has finally announced the next vesion of Windows CE - renamed (because their marketing team needs something to do I guess) Windows Embedded Compact 7Get the CTP here.

Tuesday, June 01, 2010 8:08:36 AM (Central Daylight Time, UTC-05:00)  #     | 
# Monday, May 17, 2010

Microsoft has finally declared the NNTP newsgroups dead.  It's where I've done my "community  service" for the past decade or so, so I'm a bit sorry to see them go.  They have started a set of new online Forums (which are live now) to replace these groups.

Monday, May 17, 2010 5:44:34 PM (Central Daylight Time, UTC-05:00)  #     | 
# Friday, April 17, 2009

In one of the mailing lists I'm on today, someone noted that on their Windows Mobile device the performance of GDI is much better in portrait mode than it is in landscape mode and was wondering why.  The reason is actually pretty simple.  Think of the image on the screen as just a contiguous stream of bytes (which is probably is).  The physical display needs to get that data and "paint" it.  Displays are engineered to essentially take in the data in a linear fashion, left to right, top to bottom.  So it's a pretty simple operation to just send out the framebuffer data to the display.

Now consider what happens if you want the display rotated 90 degrees. Remember, the display requires the data top to bottom, left to right, as it will show on the screen.  To get it into that state you have 2 options.  You can either A) rotate the data as you take it out of the frame buffer and send it to the display or B) rotate all calls to draw into the framebuffer.  In either case you have to do a matrix transform, which is expensive and gets worse the larger your display gets (so a VGA device will be more affected than a QVGA device).

Of course some devices have hardware acceleration that can greatly improve things by having matrix functions right in the silicon, but that still requires that the OEM actually modifies the driver to use that function (you'd be surprised how many don't).

So how bad is the performance penalty?  Well, since I like to actually quantify stuff I decided to resurrect an old GDI test app I had and rework it for this.  The results of my testing, as well as tests sent in from other people (if you want to add a test to the table, send me your results):

Device Processor OS Portrait Landscape Penalty
Axim x51 PXA270 WinMo 5 188 ops/s 77 ops/s 59%
Asus P750 PXA270 520MHz WinMo 6 Pro 241 ops/s 55 ops/s 77%

As you can see, there's a significant price to running rotated.

The test application (source and ARMv4I binary) is available here

GDIPerf.zip (10.46 KB)

 

Friday, April 17, 2009 1:32:33 PM (Central Daylight Time, UTC-05:00)  #     | 
# Wednesday, April 15, 2009

If you've ever needed to automatically launch an application under Windows CE then you probably know that one of the most common ways is to put an entry into the device registry under HKLM\Init.  This works great for native applications, but for CF applications success is hit or miss.  The reason is that CF applications require certain system APIs to be up and running before they can run.  For a native app that has this requirement, the solution is simple: you call either IsApiReady or WaitForAPIReady (depending on the OS version) and then continue when you're satisfied.  For CF apps it won't work.  The APIs need to be ready long before Main is entered and any of your managed code is running.

Of course the "right" solution is that the CF team should have put that check into the loader so we could launch this way, but they didn't so we have to work around it.

So how do we get around this?  Well we leverage the initialization process itself.  When an app is launched from HKLM\Init, it is responsible for calling SignalStarted once it is running.  This allows any other items launching from HKLM\Init to set up dependencies, for example if item 60 depends on item 50, item 60 won't launch until item 50 has called SignalStarted.  What we can do is create a native application that acts as a launch gate.  This gate app will call the appropriate wait function, and only after the APIs we need are available does it call SignalStarted.  We can then launch any CF application using HKLM\Init by simply having the gate application launch first, and then having the CF app depend on the gate.

So in the registry, it would look like this:

[HKEY_LOCAL_MACHINE\Init]
    "Launch90"="gateapp.exe"
    "Depend90"=hex:1e,00 ; depend on GWES, which is at 30
    "Launch91"="MyCFApp.exe"
    "Depend91"=hex:5a,00 ; depend on gateapp

And here's the source code for a basic gate app:

extern "C" DWORD WaitForAPIReady(DWORD, DWORD);
extern "C" BOOL IsAPIReady(DWORD hAPI);

int _tmain(int argc, _TCHAR* argv[])
{
    // quick sanity check - HKLM\Init will send in our order number
    if(argc == 0) return 0;

    BOOL success = FALSE;

    // wait for window manager - that should be enough for us
    #if _WIN32_WCE > 0x500
        success = (WaitForAPIReady(SH_WMGR, 5000) == WAIT_OBJECT_0);
    #else
        int i = 0;
        while((! IsAPIReady(SH_WMGR)) && (i++ < 50))
        {
             Sleep(100);
        }

        success = (i < 50);
    #endif

    if(success)
    {
        int launchCode = _ttoi(argv[1]);
        SignalStarted(launchCode);
    }
    else
    {
        RETAILMSG(TRUE, (_T("CFInitGate timed out - SH_WMGR was not ready after 5 seconds\r\n")));
    }

    return 0;
}

Wednesday, April 15, 2009 12:46:38 PM (Central Daylight Time, UTC-05:00)  #     | 
# Tuesday, April 14, 2009

If you just got the latest release of the IE8 Beta, your C++ Smart Device wizard will now fail.  When you try to create a project you'll get a few screen flashes and then an unhelpful "project creation failed" message in teh status bar of Studio.  The fix is outlined here (and worked on my XP box).

Tuesday, April 14, 2009 9:03:58 PM (Central Daylight Time, UTC-05:00)  #     | 
# Friday, March 20, 2009

OpenNETCF used to have a product that provided RAS capabilities.  Well Microsoft deprecated RAS in WindowsMobile - starting with WinMo 5.0 as near as I can figure - in favor of Connection Manager.  That depracation actually broke RAS in some scenarios.  FOr example, if you create a RAS connection and then try to use a managed TcpClient, it will try to create it's own connection through the Connection Manager instead of using the connection you created through RAS.

What this did was skyrocket our support incidents for something that we sold very, very few licenses for.  In the interest of keeping our sanity, yet allowing people using plain of Windows CE to still use RAS, we made the decision to just make it a shared source project.  It's now out on CodePlex.  If you need support for it, we still offer consulting services, but everything is there to get you going.

Friday, March 20, 2009 10:54:05 AM (Central Standard Time, UTC-06:00)  #     | 
# Tuesday, August 12, 2008
We've been getting a lot of inquiries lately about our plans for releasing the SDF built for Visual Studio 2008 and against CF 3.5, so I'll lay out our current status and short-term plan.

I realize we're a bit late in releasing a version for Studio '08.  Now you might say to yourself "how hard can it be?  Just open the solution in Studio '08, let it upgrade, recompile and release."  Sure, it could be that simple if we wer content with just tossing it out there, but we're not.  With the move to Studio '08 we decided to take advantage of some of the new tools we have.  First we migrated the entire SDF source tree from Vault to TFS.  Vault worked just fine, but we wanted to take advantage of TFS and integrate both continuous integration, automated testing and test-driven development into the product. 

That mean rearchitecting the solution and projecy layouts and then writing tests.  Lots of tests.  Of course writing tests leads to finding bugs, which then leads to fixing bugs.  We started by looking at reported bugs but also looking at some use cases and testing classes we know get the most use.  We have no delusion that we're going to have even close to full code coverage (or even 50%) by our next release, but we want to get off on the right foot and at least have some coverage for the next release.

Of course we've also added some new features like the OpenNETCF.Net.Mail namespace and all of this takes time.  As of right now we have less than 40 hours of test writing left to hit our release milestone.  Once we hit that, we then have to build the Help and installation package and release.  My hope is to have something ready in early September, but that's not a guarantee.  We know you want the release - we do - we just want to make sure it's right.

An ancillary question that also comes up is "when will we be releasing a version compiled for CF 3.5?"  As of right now we have no plans to release a CF 3.5-targeted version of the SDF.  Yes, you read that right.  We have no plan for a CF 3.5 release.  "Why is that?" you might ask, after all CF 3.5 is the latest and greatest, right?  Sure, it is, and we think that when possible you should use it.  However the SDF has historically been used by developers using older versions of the CF and is already rolled out in a *lot* of CF 2.0 projects.  If we moved to 3.5, none of those 2.0 project would be able to use the SDF without recompiling themselves.  If we moved to 3.5, then we'd also be tempted to use 3.5 features, which would then even make the source incompatible with 2.0 and a recompile wouldn't even be an option. I, for one, don't really want to leave all of those CF 2.0 developer's high and dry. 

Since CF 3.5 assemblies are unusable in CF 2.0 projects, but CF 2.0 assemblies can be used without a problem in CF 3.5 applications it makes the decision pretty simple.  If we stay with CF 2.0 as a target, then far more people can use the library.  If you absolutely must have it built targeting CF 3.5, you can always recompile the source yourself.

Tuesday, August 12, 2008 11:03:11 AM (Central Daylight Time, UTC-05:00)  #     | 
# Friday, August 01, 2008
It seems that every time I work on a project I get near the end and have to deal with actual deployment of the application and things go south.  Let's face it, Microsoft's wceload application sucks - and that's being generous. It's limited, it's got no object model, and it's behavior has changed over time without any of those changes being documented.

In a recent project I was trying to silently install an application to a directory that would change depending on the target hardware becasue different devices have their storage media named differently.  I wanted to do this without changing or having multiple CAB files, since the application was no different. Achieving this with wceload, I am convinced, is utterly impossible so I put on my reverse-engineering hat, downloaded the CAB spec (cabfmt.doc), and went to work.  Now, a few month later, and with the help of Alex Feinman, we've created a new product called the Windows CE CAB Installer SDK.  In addition to a new product, we went with a new pricing model as well.

The SDK comes with full source,  unit and integration tests designed for running under mstest, samples for generating compressed and uncompressed CAB (the SDK supports both), a template for creating custom installer DLLs and both VB and C# examples of using the SDK.

The main workhorse of the SDK is the WinCEInstallerFIle class, which looks like this:



An example of a custom installer looks like this (just to give you a flavor of how it works):

using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Text;
using OpenNETCF.Compression.CAB;
using OpenNETCF.Net.MTConnect.Components;
using OpenNETCF.Net.MTConnect.DataItems;

namespace System.Runtime.CompilerServices
{
    public class ExtensionAttribute : Attribute
    {
    }
}
namespace ONCFInstall
{
    public delegate void FileProgressHandler(int progressPercent);
    public static class Extensions
    {
        public static string Find(this List list, string findString)
        {
            foreach (string file in list)
            {
                if (string.Compare(file, findString, true) == 0)
                {
                    return file;
                }
            }
            return null;
        }
    }
    public class CustomCABInstaller : WinCEInstallerFile
    {
        private int m_fileCount = 0;
        private CommandLineArgs m_args;
        public event FileProgressHandler FileProgress;
        public CustomCABInstaller(string cabFileName, CommandLineArgs args)
            : base(cabFileName)
        {
            m_args = args;
            SkipFileNames = m_args.SkipFiles ?? new List();
            PathStringReplacements = m_args.PathStringReplacements ?? new Dictionary();
            SkipOSVersionCheck = m_args.SkipOSVersionCheck;
        }
        // List of file names to skip during installation
        public List SkipFileNames { get; set; } 
        // List of path replacement strings
        public Dictionary PathStringReplacements { get; set; } 
        // If true, the installer will not check to ensure the target meets the installer's version requirements 
        public bool SkipOSVersionCheck { get; set; }

        public override void OnInstallBegin()
        {
            m_fileCount = 0;
        }

        public override void OnTargetOSVersionCheck()
        {
            // check to see if we should skip the OS version check
            if (!SkipOSVersionCheck)
            {
                base.OnTargetOSVersionCheck();
            }
        }

        public override void OnInstallFile(ref FileInstallInfo fileInfo, out bool skipped)
        {
            // check to see if it's a name we should skip
            if (SkipFileNames.Find(fileInfo.FileName) != null)
            {
                Utility.Output(string.Format("Skipping file '{0}'", fileInfo.FileName));
                skipped = true;
                return;
            }

            // do any path replacements
            foreach (KeyValuePair val in PathStringReplacements)
            {
                fileInfo.DestinationFolder = fileInfo.DestinationFolder.Replace(val.Key, val.Value);
            }
            Utility.Output(string.Format("Installing '{0}' to '{1}'", fileInfo.FileName, fileInfo.DestinationFolder));
            base.OnInstallFile(ref fileInfo, out skipped);
            if (FileProgress != null)
            {
                FileProgress((++m_fileCount * 100) / FileCount);
            }
        }
    }
}
Friday, August 01, 2008 2:42:52 PM (Central Daylight Time, UTC-05:00)  #     | 
# Wednesday, May 28, 2008

Since the Compact Framework doesn't have support for App.Config file, we created our own implementation that follows the full framework model.  It requires that the config file be named “MyApp.exe.config” (which is how it works on the desktop) with a subset of the desktop functionality and it's worked well for some time.  Until recently that is.

Yesterday I set out to create some unit tests for some of our OpenNETCF.Rss namespace objects.  Well the FeedEngine object requires information from an app.config file on construction, so I figured it would be simple - I'd just add an app.config file to the test project and mark it as a DeploymentItem.  After a little investigation I found that the calling assembly for a device unit test is SmartDeviceTestHost.exe, which by default runs out of \Program Files\SmartDeviceTest on the target device.  That means that to use your own app config file from a unit test it would need to be named SmartDeviceTestHost.exe.config. 

Interestingly (or frustratingly, depending on when you asked me yesterday), this test host deploys *its own* version of a config file with the same name with some info on what framework it’s running against.  The test framework just heavy-handedly overwrites any existing file rather than merging its contents into the existing one, and it overwrites *after* it deploys all of the test pieces, so you can’t just merge its contents into your own app config and use it.

As a workaround I actually modified the OpenNETCF implementation for app config files.  I didn't really want to, but the only other solution I could think of was to write code that would open the MS-deployed version and do a manual merge in the unit  test code before the test is run, and that seemed like a much uglier route. The OpenNETCF Configuration implementation now looks for a file named MyApp.exe.config.unittest before looking for MyApp.exe.config and uses the "unittest"-suffixed version if it’s there.  I then modified my TestBase class (from which all of my unit tests derive) to add this:

 

 

        [TestInitialize]

        public virtual void TestInitialize()

        {

            CopyTestConfigFile();

        }

 

        private void CopyTestConfigFile()

        {

            // copy the config file to the test host folder

            string src = Path.Combine(TestContext.TestDeploymentDir, "SmartDeviceTestHost.exe.config");

            string dest = Path.Combine(TestHostFolder, "SmartDeviceTestHost.exe.config.unittest");

            if ((File.Exists(src)) && (!File.Exists(dest)))

            {

                File.Copy(src, dest);

            }

        }

 

        public string TestHostFolder

        {

            get

            {

                return  Path.GetDirectoryName(

                        Path.GetDirectoryName(

                        Path.GetDirectoryName(

                        Assembly.GetCallingAssembly().GetName().CodeBase)));

            }

        }

 

Now I simply add SmartDeviceTestHost.exe.config to the unit test project, mark it as a deployment item and voila - it works as expected.  Just how it should have yesterday morning when I set out to write a couple simple tests.

And for the record - the current "solution" for debugging device unit tests (which involves putting in a Debugger.Break() call in the unit test and then doing an "attach to process" from another instance of Studio) is an unweildy pain in the ass.  It takes no less than a minute just te get a unit test running and in a state that you can step through code.  That might not sound like a lot, but try this: put a breakpoint in your code and when the debugger hit is, wait a full minute before you step or look at the Locals window.  Now do this every time you want to debug.

 

Wednesday, May 28, 2008 11:46:42 AM (Central Daylight Time, UTC-05:00)  #     | 
# Tuesday, September 04, 2007

This morning OpenNETCF announced a new web initiative - our Community Web Site. I'll spare you explaining it in detail here, as it's on the front page of the site, but we've got articles and white papers, a public SVN server for shared-source projects and a monthly coding competition. This month we're giving away a copy of Studio 2005 professional and a Windows Mobile 5.0 device of your choice.

To come are Forums and a Wiki.

Let us know what you think.

Tuesday, September 04, 2007 9:42:06 AM (Central Daylight Time, UTC-05:00)  #     | 
# Friday, April 06, 2007

If you've done much development on non-Windows Mobile CE devices I'm sure your painfully aware of the pain in the ass process of getting Visual Studio 2005 to actually attach to the device.  Lately I've been doing nothing but non-WM development and deviced to automate and solidify the process, plus document it while I was at it.

We've got a (native) tool called CEDbgSetup that you run on your device (x86 or ARMv4I supported) and then you set up Studio once and only once, then you can debug every time using wired Ethernet, 802.11, USB RNDIS (and likely any other transport that uses TCP/IP) and without ActiveSync.

The tool supports auto-launching from \Windows\Startup or by setting up an LaunchXX entry in HKLM\Init in the device registry, or just manual click.  It should work headless too, though I've not specifically tested it.

It works with native or managed apps.

The tool, along with full source can be downloaded here (607k zip).

A white paper on how to set up Visual Studio 2005 can be viewed here (144k PDF).

Feedback is appreciated, but keep in mind that its free and completely unsupported (read: don't ask me for support).

Friday, April 06, 2007 4:49:54 PM (Central Daylight Time, UTC-05:00)  #     | 
# Thursday, December 07, 2006

I was doing a search for some info just now and came across a really well done article describing drivers in Windows CE.  Check it out.

Thursday, December 07, 2006 5:17:45 PM (Central Standard Time, UTC-06:00)  #     | 
# Wednesday, December 06, 2006

We got a request today from someone wondering if the SDF would help send a Wake-on-LAN or Magic Packet.  Well I've never had to do it before, so I looked it up on Wikipedia. The short answer is no, but that's because all of the required pieces are already there in the CF.

Here's my guess on it - keep in mind that I don't have a WOL-capable PC lying around to test this with (if you test it and can confirm if it does or does not work, by all means let me know).

UPDATE (Dec 7, 06): Alex Feinman took the time to test the original code and the broadcast didn't work.  The code has been updated with working, tested code.

/// <summary>
/// Wakes a remote PC
/// </summary>
/// <param name="targetMAC">MAC address of target. Must be 6 bytes and MUST be in network order (reversed)</param>
/// <param name="password">Optional password. Must be null or 4 or 6 bytes.</param>
public static void WOL(byte[] targetMAC, byte[] password)
{
  // target mac must be 6-bytes!
  if (targetMAC.Length != 6)
  {
    throw new ArgumentException();
  }

  // check password
  if((password != null) && 
      (password.Length != 4) && 
      (password.Length != 6))
  {
    throw new ArgumentException();
  }

  int packetLength = 6 + (20 * 6);
  if (password != null)
  {
    packetLength += password.Length;
  }

 
byte
[] magicPacket = new byte[packetLength];

  // has a 6-byte header of 0xFF
  byte[] header = new byte[] { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
  Buffer.BlockCopy(header, 0, magicPacket, 0, header.Length);

  // repeat the destination MAC 16 times

  // your MAC *is* in network (reverse) order, right??
 
int
offset = 6;
  for(int i = 0 ; i < 16 ; i++)
  {
    Buffer.BlockCopy(targetMAC, 0, magicPacket, offset, targetMAC.Length);
    offset += 6;
  }

  if (password != null)
  {
    Buffer.BlockCopy(password, 0, magicPacket, offset, password.Length);
  }

  IPEndPoint ep = new IPEndPoint(IPAddress.Broadcast, 9);
  UdpClient c = new UdpClient();
 
c.Send(magicPacket, magicPacket.Length, ep);
}

Wednesday, December 06, 2006 4:29:35 PM (Central Standard Time, UTC-06:00)  #     | 
# Thursday, June 29, 2006

Since most people like to try before they buy, we've released Evaluation Versions of our Calendar Controls.  Download the evaluation binaries and a sample project using them here.

Thursday, June 29, 2006 11:37:14 AM (Central Daylight Time, UTC-05:00)  #     | 
# Tuesday, June 27, 2006

First let me go on record as saying that I think using a 'z' to terminate words is utterly moronic, like using the number 2 instead of the word 'to'.

Anyway, on 2 my skillz....

Last week I posted a fantastic kludge for turning on the Bluetooth radio on an Axim X30.  Well, like any kludge, as soon as it shipped it broke.  Turns out the notification icon isn't always in the rightmost position - it can move.  That screwed with my intricate algorithm of moving in and up 10 pixels from the lower left corner of the screen.

So what's a developer to do?  First, let's take a quick detour into how those icons work. 

They "tray" icons are actually called Notification icons and they are displayed by calling the Shell_NotifyIcon API.  When the icon is created you provide a window handle for it to notify when it's clicked.  The icon itself doesn't have any other abilities.  This is a critical piece of info for this hack.

Since I know it's posting messages to another Window when it's clicked, I simply needed to figure out exactly what it's doing.  Time to break out Remote Spy++ in eVC (are you in the group that never really knew what the hell that tool was used for? This is a classic case).

Loaded up Spy++ and I see a Window conspicuously named "Bluetooth Console" - that's promising.  I put a watch on it and sure enough, when I tap the icon, messages get posted to that window (off is in the blue box, on in the red).  Now all I need to do is post the same messages.

So first, I need the handle for that Window.  Time for the FindWindow P/Invoke:

IntPtr btWindow = FindWindow("WCE_BTTRAY", "Bluetooth Console");

Next, replicate the messages the tap generates:


SendMessage(btWindow, WM_USER + 1, 0x1267, 0x201);
SendMessage(btWindow, WM_USER + 1, 0x1267, 0x202);
SendMessage(btWindow, WM_USER + 1, 0x1267, 0x200);

That causes the Bluetooth Console to create and show the popup menu. Now it needs a message to tell it to wait for a menu tap:

SendMessage(btWindow, WM_ENTERMENULOOP, 0x01, 0x00);

Now "generate" the tap:

SendMessage(btWindow, WM_COMMAND, BluetoothRadioState ? CMD_BT_OFF : CMD_BT_ON, 0x00);

And tell it to quit listening for menu taps:

SendMessage(btWindow, WM_EXITMENULOOP, 0x01, 0x00);

It does something else that I can't tell what the effect is, but since it's doing it, I will too:

// not sure what this does, but physically clicking does it, so replicate it here
SendMessage(btWindow, WM_USER + ((BluetoothRadioState) ? (uint)0xC00D : 0xC00C), 0x01, 0x00);

And finally get the Menu window and hide it:

IntPtr btmenu = FindWindow("MNU", "");

SendMessage(btmenu, WM_DESTROY, 0x00, 0x00);
SendMessage(btmenu, WM_CANCELMODE, 0x00, 0x00);

While it's still ugly, it's a bit cleaner than the original, and much smaller.  This is our new class in its entirety:

using System;
using Microsoft.Win32;
using System.Runtime.InteropServices;
using System.Windows.Forms;

namespace OpenNETCF.Devices
{
  public static class AximX30
  {
    public static bool BluetoothRadioState
    {
      get
      {
        RegistryKey key = Registry.LocalMachine.OpenSubKey(@"SOFTWARE\WIDCOMM\BtConfig\General");
        bool currentState = (((int)key.GetValue("StackMode")) == 1);
        key.Close();
        return currentState;
      }
      set
      {
        // see if any action is needed
        if (BluetoothRadioState == value)
        {
          return;
        }

        IntPtr btWindow = FindWindow("WCE_BTTRAY", "Bluetooth Console");

        // pop up the menu
        SendMessage(btWindow, WM_USER + 1, 0x1267, 0x201);
        SendMessage(btWindow, WM_USER + 1, 0x1267, 0x202);
        SendMessage(btWindow, WM_USER + 1, 0x1267, 0x200);

        // give it time to create the menu
        System.Threading.Thread.Sleep(100);

        // find the menu that popped up
        IntPtr btmenu = FindWindow("MNU", "");

        // start the window listening for menu messages
        SendMessage(btWindow, WM_ENTERMENULOOP, 0x01, 0x00);
        // send it the on or off message
        SendMessage(btWindow, WM_COMMAND, BluetoothRadioState ? CMD_BT_OFF : CMD_BT_ON, 0x00);
        // tell it it's done listening
        SendMessage(btWindow, WM_EXITMENULOOP, 0x01, 0x00);

        // not sure what this does, but physically clicking does it, so replicate it here
        SendMessage(btWindow, WM_USER + ((BluetoothRadioState) ? (uint)0xC00D : 0xC00C), 0x01, 0x00);

        // now hide the menu
        if (btmenu != IntPtr.Zero)
        {
          SendMessage(btmenu, WM_DESTROY, 0x00, 0x00);
          SendMessage(btmenu, WM_CANCELMODE, 0x00, 0x00);
        }

        return;
      }
    }

    [DllImport("coredll.dll")]
    private static extern IntPtr FindWindow(string lpClassName, string lpWindowName);

    [DllImport("coredll.dll")]
    private static extern int SendMessage(IntPtr hWnd, uint msg, int wParam, int lParam);

    private const uint WM_DESTROY = 0x02;
    private const uint WM_CANCELMODE = 0x1F;
    private const uint WM_USER = 0x400;
    private const uint WM_ENTERMENULOOP = 0x0211;
    private const uint WM_EXITMENULOOP = 0x0212;
    private const uint WM_COMMAND = 0x0111;

    private const int CMD_BT_OFF = 0x1001;
    private const int CMD_BT_ON = 0x1002;

  }
}

Tuesday, June 27, 2006 2:58:19 PM (Central Daylight Time, UTC-05:00)  #     | 
# Friday, June 23, 2006

I recently worked on a project that required me to connect to a printer from a Pocket PC with the Widcomm bluetooth stack on it.  Frustrating as it was, one positive thing came from it - I generated a nice start to a set of classes for using High-Point Software's BTConnect.

Of course it means that you'll need to buy BTConnect to use this library without the "evaluation mode" popup, but it abstracts the ugliness of sommand-line parameters away from the developer so you can focus on creating your app.

I've parked the library here:

www.opennetcf.org/shared

Friday, June 23, 2006 3:31:35 PM (Central Daylight Time, UTC-05:00)  #     | 
# Friday, June 02, 2006

I came across this article while doing some research.  It's well worth the read for anyone doing any kind of development.

Friday, June 02, 2006 7:54:16 PM (Central Daylight Time, UTC-05:00)  #     | 
# Wednesday, May 31, 2006

Ever want to make all CAB file installs on your device be silent?  Simply add the following registry key to your platform:

[HKEY_CLASSES_ROOT\cabfile\Shell\Open\Command]
    @="wceload.exe \"%1\" /nodelete /noaskdest /noui"

Wednesday, May 31, 2006 12:04:13 PM (Central Daylight Time, UTC-05:00)  #     | 
# Thursday, March 30, 2006
For whatever reason, Microsoft has removed the ability to sync an Access database to a Pocket PC under ActiveSync 4.0 and 4.1.  However Mike Boone seems to have found a workaround.  Here's what he posted in the newsgroups:
OK here is what I have learned so far that is necessary for Pocket
Access synchronization under Windows Mobile 5/ActiveSync 4:

The files adoce30.dll and adocedb30.dll must be on the device in the
Windows folder.  The file adosync.dll must be on the device and
registered.  Then, on the desktop, remove the following registry key:

HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows CE
Services\SpecialDefaults\PocketPC04\Services\Synchronization\Objects\~MicrosoftTable

You may have to disconnect and reconnect the device before you see the
"Pocket Access" sync enabled.  That seems to be all there is to it,
except for a percentage of users who have been reporting an "Access
Denied" error when they try the transfer of a database file.  I haven't
figured out yet why some users are getting this message, so if anyone
has any suggestions on that please let me know.
I've not tried it, but I know he's been fighting it for a couple months, so I have no doubt about it working.  Great info - hopefully me blogging it will make it a little easier to find as well.

Thursday, March 30, 2006 6:27:34 PM (Central Standard Time, UTC-06:00)  #     | 
# Thursday, February 23, 2006

If you're building a CE image and want to include CF 1.0 or CF 2.0, then it's pretty simple - just drag the component from the catalog into your workspace.  But what if you don't want to include the CF at all, but still have the plumbing there so your end-user can install the CF themselves and have it work?  One could look through the cesysgen.bat files and decipher what needs to be set or, if you're lazy like me, you could ask the CF team.

Here's the answer, courtesy of Jim Suplizio:

The appropriate support sysgen will have to be added to the image depending on what version of CF is going to be installed.

  • SYSGEN_DOTNET_SUPPORT is the CF 1.0 support sysgen.
  • SYSGEN_DOTNETV2_SUPPORT is the CF 2.0 support sysgen. SYSGEN_DOTNETV2_SUPPORT is a super-set of the CF 1.0 support.

Effectively if SYSGEN_DOTNETV2_SUPPORT is added to the image then the end user can deploy either 1.0 or 2.0 and all of the required underlying CE OS pieces will be there.

Keep in mind that required means "base functionality". CF 2.0 has optional functionality that requires other SYSGENS and they are as follows:

  • Message Queuing - SYSGEN_MSMQ
  • Soap Reliable Messaging Protocol - SYSGEN_MSMQ_SRMP
  • SQLMobile (2005) requires CoCreateGuid functionality - SYSGEN_OLE_GUIDS
  • IPv6 - SYSGEN_TCPIP6
  • IE, PIE, HTMLView (htmlview.dll) or nothing - SYSGEN_IE, SYSGEN_PIE, SYSGEN_HELP or simply nothing.
  • The following only apply to the MainstoneII, other devices will only have null driver sets:
    • D3D Mobile - BSP_D3DM_XSCALE
    • D3D Mobile - SYSGEN_D3DMXSCALE

 

Thursday, February 23, 2006 3:47:21 PM (Central Standard Time, UTC-06:00)  #     | 
# Saturday, February 18, 2006

I'm trying to debug an error in some managed code related to timezones when a P/Invoke is throwing a native access violation exception.  To make sure it's not something with the platform itself I decided to do the same in native code first to ensure that it's not some platform limitation or bug.  Surprisingly I didn't readily find any sample code for doing it, so here's my contribution to the community at large.  It uses dynamic loading (and it doesn't make sure that the function loads succeed, so you might want to add error checking if you actually intend to use this):

#include <windows.h>

typedef void    (*INITCITYDB)(void);
typedef void    (*UNINITCITYDB)(void);
typedef void    (*LOADTZDATA)(void);
typedef void    (*FREETZDATA)(void);
typedef int        (*GETNUMZONES)(void);
typedef void *    (*GETTZDATABYOFFSET)(int, int*);
typedef void *    (*GETTZDATA)(int);

struct TZData
{
    TCHAR *Name;
    TCHAR *ShortName;
    TCHAR *DSTName;
    int GMTOffset;
    int DSTOffset;
};

int _tmain(int argc, _TCHAR* argv[])
{
    TZData *pTZ = NULL;
    int index;

    // load the library
    HINSTANCE hLib = LoadLibrary(_T("CityDB.dll"));

    // load the CityDB functions
    INITCITYDB InitCityDB = (INITCITYDB)GetProcAddress(
            hLib, _T("InitCityDb"));
    UNINITCITYDB UninitCityDB = (UNINITCITYDB)GetProcAddress(
            hLib, _T("UninitCityDb"));
    LOADTZDATA ClockLoadAllTimeZoneData = (LOADTZDATA)GetProcAddress(
            hLib, _T("ClockLoadAllTimeZoneData"));
    FREETZDATA ClockFreeAllTimeZoneData = (FREETZDATA)GetProcAddress(
            hLib, _T("ClockFreeAllTimeZoneData"));
    GETNUMZONES ClockGetNumTimezones = (GETNUMZONES)GetProcAddress(
            hLib, _T("ClockGetNumTimezones"));
    GETTZDATABYOFFSET ClockGetTimeZoneDataByOffset = 
            
(GETTZDATABYOFFSET)GetProcAddress(hLib, _T("ClockGetTimeZoneDataByOffset"));
    GETTZDATA ClockGetTimeZoneData = (GETTZDATA)GetProcAddress(
            hLib, _T("ClockGetTimeZoneData"));

    // Init the library
    InitCityDB();

    // load the TZ data
    ClockLoadAllTimeZoneData();

    // find out how many zones are defined
    int zoneCount = ClockGetNumTimezones();

    // interate through them all
    for(int zone = 0 ; zone < zoneCount ; zone++)
    {
        // these are pointers to a timezone data struct
        pTZ = (TZData*)ClockGetTimeZoneDataByOffset(zone, &index);
    }

    // unload the TZ data
    ClockFreeAllTimeZoneData();

    // uninit the library
    UninitCityDB();

    return 0;
}

Saturday, February 18, 2006 12:45:07 PM (Central Standard Time, UTC-06:00)  #     | 
# Saturday, February 04, 2006

You might have noticed that SDF 2.0 no longer has serial or GPS classes.  This is intentional.  CF 2.0 now has serial classes and the Windows Mobile AKU includes GPS support.  We realize that there are some of you out there that are using GPSes on non-WM 5.0 devices and that you'd like to be able to use our stuff under Studio 2005.  For those people, we've spun the Serial and GPS classes into a stand-alone assembly: OpenNETCF.IO.Serial.  There are no plans for an installer for this assembly, and unless we get strong feedback it probably won't make it into the SDF either.

Saturday, February 04, 2006 1:41:38 PM (Central Standard Time, UTC-06:00)  #     | 
# Thursday, February 02, 2006

If you're a Windows CE device developer and you've got a device with a persistent registry, you're probably already aware that the CF Registry class doesn't help much for saving the registry, restoring branches from a file or creating volatile keys.  Once again the SDF is here to help with CreateVolatileSubkey, RestoreHiveBasedKey, RestoreRamBasedRegistry, SaveHiveBasedKey and SaveRamBasedRegistry.

One note - the doc says they're in the Registry2 class - that's already been changed to RegistryHelper.

 

Thursday, February 02, 2006 10:31:28 PM (Central Standard Time, UTC-06:00)  #     | 
# Sunday, January 29, 2006

Making apps power aware, especially through the device Power Manager works, but the code is kind of ugly and a pain to implement.  Once again SDF 2.0 simplifies things:

using System;
using System.Windows.Forms;
using OpenNETCF.WindowsCE;

namespace WindowsCETest
{
  public partial class MyPowerAwareClass
  {
    public MyPowerAwareClass()
    {
      DeviceManagement.DeviceWake +=
       new DeviceNotification(
DeviceManagement_DeviceWake);

      PowerManagement.PowerUp += new DeviceNotification(PowerManagement_PowerUp);
    }

    void PowerManagement_PowerUp()
    {
      MessageBox.Show("The Power Manager says I'm awake!");
    }

    void DeviceManagement_DeviceWake()
    {
      MessageBox.Show("Device notifications say I'm awake!");
    }
  }
}

Sunday, January 29, 2006 8:56:53 AM (Central Standard Time, UTC-06:00)  #     | 
# Saturday, January 21, 2006

We're extremely close to a beta release of SDF 2.0.  To give you a taste of what's in it, we've posted the online documentation.  Any feedback is appreciated.  Enjoy.

Saturday, January 21, 2006 10:49:17 PM (Central Standard Time, UTC-06:00)  #     | 
# Thursday, December 08, 2005

If you're seeing stange behavior in Media Player under CE 4.2, this might be of interest.

Symptom:

I have an MPEG4 QVGA file (WMV file extension) recorded with a bitrate of about 1000kbps.  When I play the video on the desktop everything is just fine.

When I play it on the device, bot the audio and video play, but the video "lags" the audio, and not by a small amount.  It's an incremental loss, so they start out fine, but over time the video get further and further behind the audio which plays at what sounds like a normal rate.

For example, when I play off of a CF card, by the time the audio is at 0:30 in, the video is only showing the frames from about 0:15.  You read that right, it's like the video is playing at about half speed.  If I play directly from RAM, the lag is about 30-40%.

Some other observations:

  • The "progress" bar on Media Player tracks with the audio, so when I play a 3:30 video, then the timer says 3:30, the audio finishes, yet the video continues to play, and from CF it will play for over another minute.  There's not enough memory on this thig for it to be buffering that entire minute of video somewhere.
  • If I pause playback at some point where the audio and video are out of sync, then restart, both continue from where they left off, still out of sync.
  • If I stop the video, drag the progress slider to some point in the middle of the video and start it, the audio and video start synchronized at that point and begin diverging immediately.
  • If I add a load to the system by holding my finger on the touchpanel and wiggling the media player window around, thereby causing lots of interrupts, the lag amount does not change at all - so it seems load on the system doesn't affect how far off it gets.
  • If I resize the window, making the video eitehr much larger (out to VGA) or much smaller than the 320x240 it was recorded at, the lag does not change.
  • The video plays fine on my WM5.0 device with a PXA270 (no graphics accelerator) off of SD, smooth video and audio.
  • The video plays ok on my Pocket PC 2003SE device from CF or SD.  The audio is smooth, but the video is a bit choppy from dropped frames.  The important thing though is that even with that, the video and audio are still in sync.  That's how I thought Media Player was supposed to work and would be the behavior I'd expect on the custom hardware.

Explanation from Microsoft

“The problem was rooted from a frame dropping algorithm developed in Windows CE media player before 5.0. We have fixed correspondent bugs in CE 5.0 regarding this issue. So, from 5.0, CE media player does not have this problem.

If the HW resource is plentiful, e.g. faster CPU and memory bus speed (270 compared to 255), there would not be any frame drop. So, there won't be any A/V sync problem, as you see on the 270 and desktop.

When you read data from a memory card (depending on how fast your card is), or display high bitrate video (e.g. 1mbps QVGA for 255), or on a slow CPU, CE Media Player on 4.2 could potentially trigger this frame dropping mode and therefore exhibit the A/V sync issue when dropping frames.

Windows CE Media Player and PocketPC Media Player use a different code base because CE Media Player needs to support a variety of HW platforms while PPC media player focuses on a single environment. This issue of A/V sync when dropping frames does not exist in the PocketPC Media Player code base.”

Thursday, December 08, 2005 5:07:21 PM (Central Standard Time, UTC-06:00)  #     | 
# Tuesday, November 29, 2005

The Crime:  My CE device runs a CF app just fine when I deploy it manually, but once I connect to it from Studio for deployment and then cycle the power, not just my app, but all CF apps no longer work.  Reflashing the image on the device repairs the sitation.  What the hell is going on?

The Evidence:
Article #1: Studio saves connection security info in the device registry
Article #2: Studio saves connection security info in RAM of the device (in the root folder)
Article #3: When a CAB file is expanded, RegFlushKey is called
Article #4: When Studio deploys the CF, it does so as a CAB
Article #5: When a device is reset all RAM is lost
Article #6: The CF requires that the info in RAM and the registry match to launch

Verdict:
When I make a connection some info is stored on the device in RAM and the registry.  When I deploy, half that is persisted.  When I reset the device or pull power the other half is lost, causing all CF apps to no longer run on the device unless I erase the persistent registry (which depending on your device may mean reflashing the whole damned thing).
 
Sentence:
Run DelCryptoKeysDevice.exe (part of Windows CE Utilities for Visual Studio .NET 2003 Add-on Pack 1.1) to erase the info from the registry.  Doing it on startup by adding it to your image and this to platform.reg means you can forget about it:
[HKEY_LOCAL_MACHINE\init]
        "Launch55"="DelCryptoKeys.exe"
        "Depend55"=hex:14,00, 1e,00

Tuesday, November 29, 2005 3:50:47 PM (Central Standard Time, UTC-06:00)  #     | 
# Tuesday, November 22, 2005

A couple new articles from OpenNETCF have finally gone public:

Device Debugging and Emulation in Visual Studio 2005 from Alex Feinman
Using Visual Studio 2005 to Design User Interfaces and Data for Device Applications from Maarten Struys

Tuesday, November 22, 2005 12:02:12 PM (Central Standard Time, UTC-06:00)  #     | 
# Monday, November 14, 2005

I just got word today from the Group Program Manager of the Compact Framework team that Compact Famework 2.0 Service Pack 1 (due out next year - dates not finalized, so I won't speculate) will have the following support for general Windows CE 4.2:

  • Runtime support only
  • Supported for all WinCE processor types (i.e., not just ARM family)

The picture for integration into Studio 2005, debugging, emulators and all of that is still fuzzy, so for now I'd plan pessimistically and assume that the two points above are all you'll get, but at least it lets you move forward.

 

Monday, November 14, 2005 4:08:19 PM (Central Standard Time, UTC-06:00)  #     | 
# Saturday, October 29, 2005

If you've not heard here are a few bits:

  1. Studio 2005 RTM is available for download for those with MSDN subscriptions.  If you've got a subscription, don't wait until the 7th, go get it now!
  2. CF 2.0 distributables are available here
  3. A Platform Builder 5.0 QFE for CF 2.0 is available here.
Saturday, October 29, 2005 9:11:41 PM (Central Daylight Time, UTC-05:00)  #     | 
# Monday, October 24, 2005

Yesterday I was working on a project using C++ for a device under Visual Studio '05 and for some reason it stopped linking with the following error:

error LNK2019: unresolved external symbol __security_check_cookie referenced in function "int __cdecl RegisterAndActivate(void)" (?RegisterAndActivate@@YAHXZ)

No idea even what the error meant, so I messed with some settings, rolled back code - all the usual things to try to find it.  Nothing.  I decided to bag it for the night - maybe fresh eyes today would help.

I loaded the project again today.  Same error.  I removed the project from the solution, created a new one, and re-added my code. Same error.  So I turned to my fellow coders to see if anyone else had seen this.

Jeff Abraham of Microsoft replied as follows:

My psychic powers tell me that you are building against PPC2003, and you aren't linking against secchk.lib. Try adding that to the linker inputs line, and seeing if that fixes the issue. I'm not sure how you would have gotten into this state without changing anything, as any project targeting PPC/SP 03 should have these libraries by default.

Sure, enough, I added secchk.lib to the Additional Dependencies line under the Project's Linker | Input section and it's now building again.  Why the error occured in the first place I'm not too concerned with - the release of Studio is only weeks away and I'll be uninstalling soon, but Googling on this error turned up nothing helpful at all.  Hopefully this blog entry will remedy that if someone else is looking.

Monday, October 24, 2005 4:14:42 PM (Central Daylight Time, UTC-05:00)  #     |