As I mentioned in the previous post, run-time libraries in Windows provide services for applications running in User mode. For historical reasons, this run-time layer in Windows was always known as the Win32 libraries, even when these services are requested in the 64-bit OS in 32-bit mode. A good example of a Win32 run-time service is any operation that involves opening and accessing a file somewhere in the file system (or the network, or the cloud). A more involved example is the set of Win32 services an application needs to access to play an audio file, including understanding the specific audio file compressed format, and checking authorization and security.
For Windows 8, a portion of the existing Win32 services in Windows were ported to the ARM hardware platform. The scope of the Win32 API is huge, and it was probably not feasible to convert all of it during the span of a single, time-constrained release cycle. Unfortunately, the fact that the new Windows 8 Runtime library encompasses considerably less than the full surface area of Win32 means that Windows 8 is not fully upwards compatible with previous versions of Windows. Existing Windows applications can run in the desktop mode provided in Windows 8, but that is available only for Intel-based computers not ARM tablets and phones. The number of Windows 8-specific apps that take advantage of the new UI is growing, but it is still limited, compared to tablets that run iOS or Android.
For customers using Intel-based machines, the confusion that arises from being forced to switch back and forth between the new Windows 8 Metro interface, which was designed with touch-screen based computers, tablets and phones in mind, and the legacy applications running on the desktop interface is palpable. Shortly after Christmas, I took my daughter to a local electronics store where she could pick out a new touch-based PC to use for school. (Who am I fooling? She uses her PC mainly to access Facebook and keep up with all her friends online.)
The first thing I noticed at the computer store, which featured more than 50 PCs from at least a dozen manufacturers, was the dearth of touch screen options. There weren’t very many vendors that were prepared to ship a Windows 8 machine with a touch screen in time for Christmas 2012. (In the consumer-oriented portion of the PC business, perhaps, back-to-school purchases is more important for sales than Christmas gift-giving.)
The 2nd thing I noticed was the dearth of options to purchase Windows 8 RT ARM-based tablets. Here, I think Microsoft is caught between a rock and a hard place in the realities of the PC manufacturing business. PC manufacturers like Lenovo and Toshiba have deep experience working with Intel technology in their current PC products. Switching to ARM-based processors means gaining experience with new chipsets. Graphics co-processors, NICs, hard drive interfaces, etc., on ARM-based computers all require ARM-compatible support chips that comply with the ARM architecture. These legacy PC manufacturers are naturally comfortable with the Intel-based electronics that they have used for many years and are reluctant to invest in ARM technology until they are more certain where it is going.
Meanwhile, companies like Samsung and HTC that have already made a major investment in ARM weren’t sitting around waiting for a new version of Windows from Microsoft to dive into the phone and tablet market before Apple swallowed it whole. They were putting the Android OS on ARM-based products and pushing them into the market. A manufacturer like HTC may keep one foot in the Windows camp (there is a new HTC-based Windows 8 phone), but they are continuing to deliver Android-based products on essentially the same hardware. Samsung, which is solidly number two in tablets and smartphones behind Apple, may well have decided not to dilute its Galaxy brand of Android-based tablets by introducing a Windows 8 RT variant.
But the 3rd thing I noticed was how awkward my daughter found the new Windows 8 UI. Frankly, when she encountered the new Win 8 Metro interface, she was baffled. Her initial reaction was to reject all the new PCs immediately, and, since she already has an iPad, she did not see the need for another tablet-based machine with limited capabilities. I counseled her that any new computer running the Windows 8 Metro interface without a touch screen did not make a lot of sense either, and eventually she was persuaded to go with a good-looking Acer machine. However, I can report she is much more comfortable, even happy, today with her new Win8 machine, after running it for a month or so.
You would think that among all those highly-intelligent individuals in Microsoft that were involved in planning and building Windows 8, some of them would have thought about these important concerns and done something about them. My experience with the Windows 8 planning process was that many of these concerns were known in advance, but were ignored, leaving the Windows 8 release deeply compromised. Those compromises are the subject of this series of blog postings. In this post, I intend to drill into the disconnect between the COM technology that provides the underpinning for much of the Win32 API and the .NET Framework component technology that is very popular among professional Windows developers. This disconnect is at the root of some of the compromises that the designers of Windows 8 decided to make.
Historically, the Win32 run-time libraries rely extensively on COM technology. By necessity, the new Windows Runtime is also COM-based, but most of the COM interfaces are hidden below the surface. This lends a much newer feel to new Runtime, a very welcome change that software developers will appreciate.
Borrowing an important feature of Microsoft’s proprietary .NET Framework, the new Windows Runtime libraries use metadata to describe the runtime components they contain. The metadata embedded in a Windows Runtime library – similar to full-fledged .NET assemblies – describes the classes that are defined, the interfaces that are implemented, and all the members of those classes: their methods, fields, properties, events and types. The metadata serves during runtime to provide dynamic linkage, similar to the way COM components can use the IUnknown interface. The metadata also supports the type of static, compile-time type checking that .NET Framework components rely on. (There is a more complete discussion of the metadata that is defined for .NET Framework assemblies here.)
Since metadata is available to describe the binary components in the new Windows 8 Runtime libraries, you can use tools like the Object Browser and Intellisense in Visual Studio to examine and work with them during coding and debugging. During compilation and debugging of a program that is built using a .NET language such as C#, Win 8 Runtime look and behave like .NET Framework managed code components. However, they should not be confused with managed code components – there are some very crucial differences.
One critical difference is that Windows Runtime components really are native code runtime modules that are ready to link to and run. In contrast, in .NET, modules are compiled first to a platform-independent Intermediate Language (IL) format. In a .NET assembly, the IL is run through a Just-In-Time compiler (the JIT) when it is first executed to create the executable native code dynamically on the fly. (There is also a .NET Framework utility called NGEN to generate native code from IL to build an executable that can be called directly at run-time.)
This is not the place for an extended discussion regarding the trade-offs between JIT vs. NGEN in the world of the .NET Framework. My sole intention here is to emphasize that while Windows 8 Runtime libraries appear similar to .NET components when you access them, they are directly executable and, they run native C++ code. Moreover, this was probably the correct decision architecturally: you should be able to call any layer of OS-level services directly. Moreover, OS services should begin execution immediately, without any of the delays associated with generating code at runtime.
(On the other hand, the .NET Framework approach that generates code Just-In-Time during run-time eliminates the need to build different installation packages for each platform – x86, x64, and now ARM. This remains the right choice for any Windows application that I might build, including those designed to run on top of the new Windows Runtime.)
So, because they use the same metadata, the new WinRT libraries feel a lot more like .NET Framework components during design time. And the developers of Windows 8 have also taken steps to make them behave more like Framework components during run-time, providing an inter-operability layer that projects the native types that the Windows Runtime supports into their .NET equivalents. It is no longer necessary to use PInvoke to call one of the Runtime APIs from a .NET program. But there is still a fundamental disconnect between the two objected-oriented runtimes that can easily lead to problems. Understanding how these problems can arise calls for a bit of an explanation.
In the CLR, all instances of an object are managed. This management basically entails memory management: the allocation of storage for the object is managed by the CLR. While the managed code application has a pointer to the address of that object’s storage location, the program is never permitted to access this address pointer directly. Management also means that the CLR keeps track of the object’s lifetime, and is responsible – and not the application program, directly – to clean up after the object has been discarded (or de-referenced). The CLR task that is responsible for keeping track of an object’s storage, its lifetime, and for clean-up is known as garbage collection.
Restricting a managed code application from directly accessing the memory addresses any of the objects it is manipulating has major benefits. One benefit comes from eliminating a legion of logic errors whenever address pointers are mishandled in your application. These are bugs that inevitably occur whenever address pointers get passed around. In any complex application, it is also quite easy to lose track of address pointers.
For example, you can try to enforce a coding standard where all code modules allocate working storage during entry and delete all its associated working storage at exit. Over time, even this structured code inevitably will start to spring leaks. New logic may add code paths that exit the module at earlier points. Objects allocated in the module may need to be persisted and operated on asynchronously by other modules and services. This growing code complexity is depicted in Figure 2, where a simple allocate-on-entry and delete-on-exit scheme is enforced. However, later additions to the code (indicated in blue) lead to code paths that exit the module without triggering the de-allocation on exit. Reportedly, the majority of memory leaks uncovered in native Windows code can be attributed to objects that are abandoned in this fashion.
Another common pattern illustrated in Figure 2 that leads to memory leaks is when one function allocates the object, then passes a pointer to that instance to another function which then operates on it. As the pointer is passed from function to function, it is easy to lose track of the original owner, especially once any sort of event-oriented, asynchronous processing logic is introduced.
As a computer program grows more and more complex over time, the simple, per-module bookkeeping scheme tends to break down with that growing complexity, as illustrated in Figure 2. The chain of ownership of objects across modules becomes less and less clear or can break down entirely. This never happens in .NET because the CLR tracks object ownership across the entire process. Automated memory management performed by the CLR Garbage Collector (or GC, for short) eliminates this whole class of serious bugs, namely, memory leaks, when an application allocates memory for some instance of a class and then fails to release that memory when that instance is no longer active. (To be sure, other kinds of object ownership anomalies in .NET programs can still occur that do lead to memory leaks.)
Whenever a function at one level in your program passes an address pointer to a function at another level, it is effectively a grant of access to the underlying memory structures. There is another large class of bugs that result when the called function makes a change that has an unanticipated effect back inside the original calling function. These are nasty bugs, termed side effects because they often manifest themselves in devilishly obscure ways. Side effects are the bane of any developer working in a complex, many layered application, something even the most experienced developers dread. You fix a bug in one area of the code, but the change has a ripple effect in some entirely different area of the code. This is code that is very difficult to maintain.
In fact, one of the principal rationales of the object-oriented approach to software development – no external access to a function’s internal affairs – is to eliminate, or at least reduce, the risk of side effects. With its strict approach to memory management and type safety, the .NET Framework, is actually very, very effective in reducing the impact of side effects.
Another benefit of automatic memory management – the CLR functions that allocate the memory for objects and also perform garbage collection automatically for objects that are no longer in use – is that it is not necessary to develop these memory management routines yourself. With its GC functions, the .NET run-time understands exactly what memory has been allocated for which object and which memory areas are eligible to be freed because they are no longer in use. Your application is essentially freed from this very error-prone task. And, whenever the application faces “pressure” because available memory is scarce, the GC will initiate garbage collection, releasing the memory allocated previous by discarded object instances and consolidating free space using relocation and compaction, as necessary. Furthermore, the GC is able to relocate any currently used portions of memory during a compaction because the application is restricted from accessing pointers to memory locations directly.
Last summer, MSDN Magazine published a lengthy article by Steve Tepper, a program manager in Windows, entitled “Managing Memory in Windows Store Apps” that discussed this problem in some detail. (Part 2 of the two-part article was published in November 2012.) As Tepper describes the problem, the GC has no knowledge of the lifetime of the Windows 8 Runtime resource being referenced. Meanwhile, the Windows 8 Runtime has no intrinsic knowledge of the status of the C# event handler that has a reference to one of its objects. This sort of circular reference will keep objects alive on both sides of the inter-op boundary whenever there is an active reference that crosses that boundary.
Another element of the Windows 8 Runtime that was borrowed from the proprietary .NET Framework is the use of XAML to describe the UI declaratively. XAML was originally defined and used with the Windows Presentation Foundation (WPF), an ambitious and long overdue overhaul of the legacy Windows Forms technology. XAML is the mark-up language that was used to define the graphical elements that a WPF-based application supports. XAML for WPF uses tags that look similar to html codes for defining the UI, but the tags all refer to Windows entities.
The UI for Windows 8 App store apps is based on the emerging HTML 5 standard, but instead of conventional html tags, the mark-up language is a new dialect of XAML. The decision to require using proprietary XAML with standard HTML 5 elements for the new touch screen-oriented App Store apps in Windows 8 is curious, to say the least. The HTML5 spec itself is very new and the specification itself is still fluid. (The most recent candidate specification, published in December 2012, is available here.) It was created with web-based applications in mind, the sort that are hosted inside a web browser like IE or Chrome.
Nevertheless, HTML5 may turn out to be the perfect choice for Metro-style apps, optimized for mobile computing. The new layout capabilities in HTML5, its support for high resolution graphics, and the new ability to handle audio and video content directly address a long laundry of list of concerns in the web content community. It was never designed for conventional desktop computing, but Metro-style apps aren’t either.
But then there is XAML, which is a Microsoft proprietary technology. Marrying the proprietary XAML language to HTML5 compromises Microsoft’s commitment to open standards for Windows 8 software development.
In the course of working on Windows 8, Microsoft adapted its Expression Blend graphical design tool, originally developed around WPF’s flavor of XAML, to produce the HTML5 UI that Windows Store Apps use. Blend itself is a very impressive design tool aimed at enabling collaboration among graphical designers and UI software developers. Leveraging Blend for Windows Store App development is very desirable, especially since HTML5-compliant graphical design tools are still emerging. It may not have been technically feasible to re-purpose Blend for Windows Store apps in time for Windows 8 to ship without adopting XAML. Blend now ships with Visual Studio 2012, while the rest of the Expression suite of web and graphical development tools appears dead.
The decision to use XAML also raises questions if you are an experienced developer of existing Windows desktop or phone applications and are heavily invested currently in using either WPF and/or Silverlight. The future viability of both WPF and Silverlight are seriously compromised by Windows’ adoption of HTML5 for Windows 8.
What to do now if you are a Windows software developer? Stay on Windows 7? Remain in WPF, but run only in the designated desktop application sandbox in Windows 8. Or, convert completely to HTML5 & the new Metro style UI? Or, perhaps, better start learning Objective C before your career as a software developer runs headlong into a Microsoft proprietary dead-end.