My associate Brian Rasmussen released this book through Microsoft Press a few months ago:

Here's the short review I wrote on Amazon:

Performance is something that's easy to talk about but difficult to do. You could say that every app could in some way perform better, but how do you really think about where to make investments? Too often, developers take an ad hoc approach, not really clear on what they're trying to accomplish. This can waste a lot of resources in areas that won't have real impact on the customer experience. In this book Brian brings years of real-world insight to the question of finding what matters, clearly defining your performance goals, and then going through the process to measure the app's present reality, making changes, and evaluating progress. And like another reviewer has said, performance information–even just what tools are available–is scattered around, and having one place to bring it all together is super-valuable. 

At 240 pages it's a concise treatment of the subject and for the price (Amazon has it at $14.13), it only takes one or two good improvements to your app to more than pay for itself!

A partner we worked with had some troubles with a live tile image not appearing, and the process of working them out helped us understand better how to debug live tile issues.

First of all, make sure of two more global that affects tiles:

  • Live tiles don't appear in the Visual Studio simulator for Windows Store apps (though I believe they do on the phone emulator). Run locally or on a real device.
  • Make sure that live tiles for your app on the Start screen are not disabled (right-click to check).
  • Some live tiles won't look right if you've turned off system animations in PC Settings > Ease of Access > Other Options > Play Animations.

Second, the tile updater is quite sensitive to properly-formed XML. If you have any kind of glitch, the update payload will be ignored and you'll be left scratching your head. Here are some things that can trip you up:

  • The XML lacks the <?xml version="1.0" encoding="utf-8"?> header.
  • There is a space or linefeed before the <?xml> header.
  • The XML isn't properly formed (e.g. missing closing tags) or doesn't follow the Tile schema.
  • The elements you indicate for a tile template doesn't match the template itself.
  • You have a mismatch between the indicated template and the version number in the <visual> element.
  • You are using accidentally using <img> tags rather than <image> in the XML. Tile templates are not HTML: they use <image>.

If you think your XML is good but it's not working, try simplifying it to include only a single tile size payload, and try them one at a time. That can narrow down where an issue might be. Also use App Tiles and Badges sample as a reference point, specifically scenario 6 that lets you build payloads.

Next, a tile update can have proper XML but its image references might be invalid. If you're using http[s] references, double-check those links in a browser. If you're using the baseUri attribute anywhere in your XML, do that combining manually and check the URIs. Also check image references with any URI parameters that are added with the addImageQuery attributes. See "Using Local and Web Images" in Chapter 16 of my free ebook (page 897) for details.

Other allowed reference URI schemas are ms-appx:/// and ms-appdata:///local. You cannot use ms-appx-web:/// or ms-appdata:///[temp | roaming] — doing so will cause the update to be ignored.

Thirdly, remember that tile images must be 1024 pixels or less in both dimensions, and must be less than 200KB in size. This means potentially resampling an image to make it smaller, and it especially means being aware of the image format and quality as that significantly affects the size. Here's how I wrote about this issue in my book, page 899:

Sidebar: PNG vs. JPEG Image Sizes

When considering tile images for the larger 140% and 180% scales, the encoding you use for your images can make a big difference and keep them below the 200K size limit. As we saw in “Branding Your App 101” in Chapter 3, a wide tile at 180% is 558×270 pixels, a medium is 270×270 pixels, and a large is 558×558 pixels. With the wide and large tile sizes, a typical photographic PNG at this size will easily exceed 200K. I encountered this when first adding tile support to Here My Am! for this chapter, where it makes a smaller version of the current photo in the local appdata folder and uses ms-appdata:///local URIs in the tile XML payload. Originally the app was capturing PNG files that were too large, so I borrowed code from scenario 11 of the App tiles and badges sample, as we’ve been working with here, to create a smaller PNG from the img element using a temporary canvas and the blob APIs. This worked fine for a 270×270 medium tile image (a 180% scale that can be downsized), but for 558×270 and 558×558 the file was too large. So I borrowed code from scenario 3 of the Simple Imaging sample to directly transcode the StorageFile for the current image into a JPEG, where the compression is much better and we don’t need to use the canvas. For this second edition’s example I just capture JPEGs to begin with, which are already small enough, but I’ve preserved the code anyway for reference. You can find it in the transcodeImageFile function in pages/home/home.js, a routine that we’ll also rewrite in Chapter 18 using C# in a WinRT component. 

Such considerations are certainly important for services that handle the addImageQuery parameters for scale. For larger image sizes, it’s probably wise to stick with the JPEG format to avoid going over the 200K limit. 


The 200KB limit turned out to be the issue with the partner–all the images referenced in the live tile were larger than 200KB and therefore ignored. More specifically, the images were saved as PNGs, which again for photographic images produces larger file sizes than JPG. In this partner's case, even the 150×150 tile image was too large; if it had happened to be smaller, the partner would have seen it appear but not images for the other sizes, which might have revealed the problem more quickly.

What confused the process of tracking down this problem is that an invalid image will cause that particular tile update (for that size) to be ignore in toto, meaning that the text won't appear with an invalid image. This is a reasonable behavior because otherwise end users would see oddball tile updates with text but blank spots where images should be. Personally I'd love to see a debug option in the system that you could turn on so some kind of placeholder image would appear, or an error message if a tile update is invalid.

The other thing that can be confusing is that the system will always download an image from a valid URI, and then check whether it's too large to display. This makes some sense as it's difficult to know from a URI whether the image is too big or such. The system could do a round-trip to the network to check the size first and not download it, but it doesn't work that way: it will download, and then ignore the image. This means that just watching fiddler traces or such isn't deterministic in checking image validity.

If you have a service, by the way, that dynamically generates images for periodic tile updates, then it's possible to have some variance in image sizes that are being supplied in tile updates. For debugging, make sure your service is logging requests and the dimensions and file size of every image returned. Then you can see whether any images exceeded the allowable limits.

In a previous post I described how to realiably use Debug/Release build configurations in Visual Studio to selectively copy a debug or release file into your project at build time, offering a solution to JavaScript's lack of precomiler directives like #ifdef DEBUG as found in C# and C++. I wanted to expand on that post with additional options that I've seen discussed. [Thanks to Rob Paveza, Ginger Edighoffer, Howard Kapustein, Steve Bohlen, and Gearard Boland.]

In this context, people often suggest using the following structure for similar purposes:

if (Debug.debuggerEnabled) {
    // use debug settings
else {
    // use production

Although this works reasonably well, the downside is that having a debugger enabled says nothing about how the project was built. You can debug a Release build of a JavaScript app just fine, in which case debuggerEnabled will be true and you can still step through the code because JavaScript isn't compiled ahead of time. This means that stepping through the code above for a Release build will not hit the //use production block.

You can work around this, of course, by setting a breakpoint on the if statement and then setting the next statement to the //use production block. If you want to do this pervasively, then you can wrap a simple function around Debug.debuggerEnabled where you can set a single breakpoint:

function checkDebug() {
    if (Debug.debuggerEnabled) {
        return true;
    } else {
        return false;

In here I've put in two return statements so there's an obvious place to set the next statement and control the return value.

Another suggestion I've seen for this matter is to create a simple C++ WinRT component that does something like this:

namespace WrcCpp
    public ref class ModeMonitor sealed
            ModeMonitor() { };

            static property bool IsDebugMode {
                bool get() {
#ifdef _DEBUG
                    return true;
                    return false;

There's also a property in Windows.ApplicationModel.Package.current.isDevelopmentMode that you might come across but this reflects how the package was installed (that is, it was deployed from Visual Studio rather than the Store), and not how the package was built. That is, it describes the deployment mode, not the build target.

Here's another possibility: run your JavaScript code through a C++ preprocessor that can chew on the #ifdef statements to generate the JavaScript code you want to run. I imagine that this could be incorporated into a Visual Studio build process similar to my previous post. 

Along these same lines is the need to differentiate code in a universal Windows app project that's targeted specifically to Windows or Windows Phone when that code lives in the Shared folder. That is, although you can keep code for both targets separate in their own project structures, sometimes it's just easier to make a simple differentiation within some of the Shared code.

The compiled languages have the WINDOWS_APP and WINDOWS_PHONE_APP precompiler directives for this purpose, but not JavaScript. The options you have, then, are as follows [thanks to Steve Bohlen]. First is WinJS.Utilities.isPhone:

if (WinJS.Utilities.isPhone){
    // phone
    // not phone

Second is using a feature detection pattern like you do with cross-browser JavaScript:

if (PhoneAPINamespace && PhoneAPINamespace.phoneAPI) {
   //  safely call phoneAPI()

The first option is more explicit, of course, whereas the second is more resiliant to changes in the available API (a consideration with continued convergence in WinRT).


When you have a Webview hosting an iframe element, it's possible to monitor what's going on in the iframe using the MSWebViewFrame* events, which are documented with the x-ms-webview element. These are MSWebViewFrameNavigationStarting, MSWebViewFrameContentLoading, MSWebViewFrameDOMContentLoaded, and MSWebViewFrameNavigationComplete.

In the event you have multiple iframe elements in a webview, the way to distinguish between frames is with the e.uri property, where e is the event args object for the event in question. This property is presently undocumented, but should be–this comes directly from the engineers who built the webview, so we can trust that it's there!

Generally speaking, the content of a Webview is generally a black box from the host app's perspective, and for this reason you can't get into the Webview's DOM, you can't get element references (e.g. to an iframe), and so on. There'd be serious overhead to go that route.

Which brings us to the question of what happens when code within an iframe or Webview crashes. You've certainly seen some of those sites–the ones that cause the browser to pop up debugging messages about JavaScript exceptions and whatnot. Overall, crashes in a Webview or iframe should not crash the host app.

However, there is the possibility that long-running scripts within whatever web page you're hosting are taking so long that your app is considered to be unresponsive. Those are messages you've seen in the browser as well, and if the app gets blocked on the same kind of script, it's possible the Windows will take the app down. This is a known issue that might be addressed in future releases of the operating system. At present, you can consider watching the Webview/iframe NavigationStarting and setting up your own timeout so you can catch an unresponsive site before Windows takes down the app.

For some time I’ve been looking for a reliable equivalent to #ifdef DEBUG in a JavaScript app, as there are a number of needs to set up different code structures between the two build targets. This includes switching between Windows.ApplicationModel.Store.CurrentApp and CurrentAppSimulator, using test data vs. live data, using test URIs vs production URIs, using test accounts vs. live accounts, using different tokens for back end services, and so on..

I've seen some solutions that utilize t deterministic for JavaScript, but this isn't deterministic for JavaScript because you can debug a Release build just like a Debug build–all the source code is just there, so it's not like C++ where you lose your symbols. I've also seen hacky methods that check for "Debug" in the package install folder path, but that doesn't work for side-loaded apps (like you might share with testers) and maybe not for remote debugging.

It’s really best to get the target configuration straight from VS and somehow apply it to a project, and I worked out how to do it without a VS extension. See this small DebugRelease sample for a demonstration:

What I did is create two .js files in the project (debug.js and release.js in a js-buildinfo folder) that I exclude from the end package by setting their Package Action to None instead of Content. I then use in MSBuild task to selectively copy one or the other file to a common name in the package (e.g. buildinfo.js).

Here are basic file contents:


(function () {
    "use strict";

    WinJS.Namespace.define("BuildInfo", {
        isDebugBuild: true,
        isReleaseBuild: false,

        config: "Debug",
        currentApp: Windows.ApplicationModel.Store.CurrentAppSimulator

         * Include debug-only data, service URIs, access tokens, accounts, etc.



(function () {
    "use strict";

    WinJS.Namespace.define("BuildInfo", {
        isDebugBuild: false,
        isReleaseBuild: true,

        config: "Release",
        currentApp: Windows.ApplicationModel.Store.CurrentApp

         * Include release-only data, service URIs, access tokens, accounts, etc.

To do the selective copy, it’s necessary to add a BeforeBuild action in the project file. At present, VS doesn’t allow custom build configuration for JS projects through the UI, so you have to do the following:

  • Right click and Unload Project in VS.
  • Right click and Edit the project manually.
  • Make the changes below.
  • Right click and Reload Project.

Editing the .jsproj file I added the following entries under the ItemGroup with the project files:

  <BuildFlagSource Include="js-buildinfo $(Configuration).js" />
  <BuildFlagDestination Include="jsbuildinfo.js" />

And then farther down there’s a section that’s commented—you uncomment it and add the <Copy> element shown here:

<Target Name="BeforeBuild">
  <Copy SourceFiles="@(BuildFlagSource)" DestinationFiles="@(BuildFlagDestination)" OverwriteReadOnlyFiles="true" SkipUnchangedFiles="true" />
<Target Name="AfterBuild">

Ideally you’d make buildinfo.js read-only in the project to prevent editing what will be overwritten in the build.

And the you can just have this line in whatever HTML files need it (usually before other .js files that would use the BuildInfo properties):

<script src="/js/buildinfo.js"></script>

Things I like about this solution:

  • It’s extensible as you can add anything you want to the debug.js and release.js files.
  • The BuildInfo namespace can include methods to do build-specific work, which is sometimes necessary.
  • It enabled isolation of all build-specific code in these files, rather than littering it throughout the rest of the app as you would with just a simple flag. I still have a flag in here as an option, but you wouldn’t have to use that at all.
  • It works no matter how an app is deployed.
  • It’s not dependent on any compiled VS extension that you’d have to produce for x86, x64, and ARM.

A few downsides:

  • Have to hand-edit a project and do some one-time configuration like adding a buildinfo.js and making it read-only.
  • You have to make sure that the debug.js and release.js files define the same stuff.
  • It feels a bit fragile given the manual steps.

What do you think of this solution? It works well and reliably applies the chosen build target to your JS code. But are there things I've missed or things that can be improved?

With ARM devices like the Microsoft Surface and those from other OEMs, where it's not possible to run Visual Studio directly, it's good to know a few details on how to run/test apps on them.

First is remote debugging, described on It's quite easy to set this up–install the Visual Studio remote debugging tools, then select the Remote Machine option in VS on your dev machine and go from there. (Note: the link to the tools on the hh441469 page is broken as of this writing. Go to instead.) Just be sure that if you restart the ARM device, you need to restart the Remote Debugger (see the Start screen) for VS on your dev machine to pick it up on the network.

Testing on the ARM device specifically can reveal performance and responsiveness issues, as when you're doing an animation that's not running in the GPU (such one that affects CSS properties other than transform and opacity). It's also essential when you're working with sensors that aren't available on your dev box.  I also noticed with one app that running on the Surface revealed a latency issue in generating the layout, which was good to know of course!

Next, if you don't need to run the app in the debugger, and want to test as when it's directly installed, you can sideload the app. Just copy an appx package files created on your dev machine to the device, then run the PowerShell script. This does require that the ARM device has a developer license on it, which should happen when you install the remote debugging tools. (You might be prompted otherwise…I haven't tried this exact configuration so I can't say for sure.)

Next, there are occasions where you need to get a crash dump on an ARM device. You can enable generation of a local dump through some registry settings described on these two pages: and

Finally, if you ever need to obtain a screenshot (especially for filing bugs and such), you'll quickly find that Print Screen keys and other standbys just aren't on the Surface, the touch keyboard, or the on-screen keyboard. The trick for Surface, at least, is to hold down the Windows button on the front of the Surface (the one that goes to the start screen) and press and release Volume Down on the side.

Addendum (4/23/13): In working with my own Surface I found today that my developer license on the device had expired, which resulted in an error on my dev machine when trying to use remote debugging. To remedy this, open an Administrator Command Prompt, the enter powershell, then from that prompt type show-WindowsDeveloperLicenseRegistration. That shows the UI that you normally see in Visual Studio to renew the license. Once I did that, and waited about 1-2 minutes for the renewal to take effect, I was able to run the remote debugger again.

Process lifetime events, like suspend, resume, and being restarted after being terminated by the system from the suspended state, are very important to test with your app. This is because when you’re running in a debugger, these events typically don’t happen.

Fortunately, Visual Studio provides a menu at debug time to trigger these different events:

Figure 3-8 (PLM controls)

Selecting either of the first two will fire the appropriate events, allowing you to set breakpoints in your handlers to debug them.

The third command, Suspend and shutdown, simulates the case where the app is suspended (as if the user switched to another app), and then the system drops the app from memory due to the needs of other apps.

In the debugger, you’ll see your suspend events fired, then the app exits and the debugger stops. More importantly, however, is that when you start the debugger again, you’ll see the previousExecutionState flag in the activated handler set to terminated. This gives you an easy way to through the startup code path where you’ll be rehydrating the app from whatever session state you saved during suspend.

After testing in the debugger, it’s a good idea to test the app under real conditions as well. Suspend and resume are easy enough–just switch to other apps. Be sure to leave the app suspended for different lengths of time if you have any kind of timestamp checking in your resuming handler, e.g. code that determines how long it’s been since suspend so that it can refresh itself from online content, etc. If you can, try to leave the app suspended for a day or longer, even a week, to really exercise resuming.

To test terminate/restart in a real world scenario, you’ll need to basically run a bunch of other memory-hungry apps to force Windows to dump suspended apps out of memory (large games are good for this). You’ll make it easier on yourself if you have less memory in the machine to begin with; in fact, to test this condition you could shut down your machine and pull some physical memory (or use an older, less powerful machine for this purpose).

Alternately, you can use a tool that will purposely eat memory, thus triggering terminations. A good list of tools for this purpose can be found on

Working with tiles, badges, and toast notifications is a wonderful way to have your app surface information to the user when it’s not in the foreground or not running at all. Because of this, however, it can be difficult to debug updates or notifications that aren’t working. If there’s something wrong with the XML or the contents of an update, then it might not display at all, which can be difficult to figure out. So I wanted to offer a number of things you can do or check when you encounter problems.

First, consider something like the following scheduled XML payload for a toast notification:

<toast><visual><binding template=”ToastImageAndText04″>
<image id=”1″ src=”ms-appdata:///local/some_image_created_dynamically.png” />
<text id=”1″>Some text 1</text><text id=”2″>Some text 2</text><text id=”3″>Some text 3</text>

Let say you’ve called the necessary APIs to get this up, but it doesn’t appear at the appropriate time. Why? For one, consult the troubleshooting guide that’s found in the docs. But let me add to that some.

For one thing, the XML could be malformed–Windows will reject any tile, badge, or toast where the elements inside <binding> don’t match the template indicated in binding.template. To compare, run the App tiles and badges sample and go to Scenario 5. This is less of a sample and more of tool that lets you generate tile updates, where you can then see the resulting XML. It’s also worth pointing out that the XML text should always be UTF-8 encoded (contrary to the troubleshooting guide’s statement about UTF-16, which is a doc bug). I’ve also found that Windows is somewhat picky about extra line feeds at the top of the XML.

For scheduled notifications, check to make sure that you’re actually scheduling a time in the future. See the Scheduled notifications sample for reference.

Next, be sure that any image.src property is a valid URI, for one, but also make sure that the target image is 1024×1024 or smaller, and 200KB in size or smaller. Windows will not display larger images. In the example above, the overall toast will still appear, but it will have a blank image if Windows can’t find the image file or if the image is too large. In general, a blank image shows up when there is some problem loading that image.

You can also use the event log. In the event viewer, navigate to Application and Services Logs > Microsoft > Windows > Apps > Microsoft-Windows-TWinUI > Operational tile where tile activity takes place. Note that you need to click on the Details tab to see which app was involved as the General tab doesn’t show that.

Speaking of the event viewer, note also that Application and Services Logs > Microsoft > Windows > PushNotifications-Platform > Operational has additional events about push notifications.

For push notifications in particular, it’s absolutely essential that the package ID in your manifest exactly matches what you have in the Windows Store. Using the Store > Associate App with the Store command in Visual Studio will make sure of this.



WinJS.log is an interesting function. Though it's ostensibly part of the WinJS namespace, it's not actually directly implemented within WinJS itself! At the same time, it's used all over the place within the library. Take a look throughout the base.js and ui.js files of WinJS and you'll see many lines like this:

WinJS.log && WinJS.log(safeSerialize(e), "winjs", "error");

That is, WinJS checks if WinJS.log exists, and if so, outputs some log informaion for many different kinds of conditions, primarily error conditions. In other words, this logging will tell you various things that are happening inside WinJS.

To see all that output, though, you need to provide an implementation of WinJS.log yourself; that is, you need to assign some function to this particular variable. That function, as described in the documentation, should accept three parameters:

  1. The message to log
  2. A string with a tag or tags to categorize the message. WinJS always uses "winjs" and sometimes adds an additional tag like "binding" in which case the second parameter is "winjs binding"
  3. A string describing the type of the message. WinJS will use "error", "info", "warn", and "perf"

The simplest way to do this is just map WinJS.log to console.log like so:

WinJS.log = console.log.bind(console);

But this doesn't make for very nice output. For example, this call:

WinJS.log("message", "tag", "type");

Will create the output "messagetagtype" all smooshed together.

To make things a little better, WinJS itself offers a basic implementation of a logger, which is set up by calling WinJS.Utilities.startLog:


Calling this with no parameters, as shown here, sets WinJS.log to a basic function that formats the output a little more nicely using WinJS.Utilities.formatLog (which you can call directly), and outputs the result to the console. So the same test call above will then appear on the console as "type: tag: message".

If you want to filter for specific tags, which is especially useful if you're using WinJS.log in your own code and use tags to identify the module you're calling from, then you can reduce the output. The syntax is to just pass a string with tags separated by spaces. So this code:

WinJS.Utilities.startLog("tag1 tag2");
WinJS.log("message", "tag1", "type");
WinJS.log("message", "tag2", "type");
WinJS.log("message", "tag3", "type");
WinJS.log("message", "tag4", "type");

Will output two lines, "type: tag1: message" and "type: tag2: message" but ignore the other two.

You can actually do much more with that one parameter by passing an object that specified additional options, such as filtering the type and so forth. See the WinJS.Utilities.startLog documentation for details.

Note also that if you call WinJS.Utilities.startLog multiple times, it aggregates the tags you're using. This means you can call it from different modules where each module starts logging for itself.

When you're done logging, you can call WinJS.Utilities.stopLog, which just calls delete WinJS.log. This is an all-or-nothing call, though–you can't remove individual tags from the logging.

All that said, you can certainly do more interesting things with WinJS.log if you want. You could, for example, have the function call msWriteProfilerMark and use it more for perf checking than error logging (in which case you can filter on a type of "perf" or something like that).

With console.log, it's helpful to know that you can, if desired, save that output in the system Event Log, visible in Event Viewer. The steps to do that are as follows:

  1. Launch Event viewer (eventvwr.exe)
  2. Under Application And ServicesMicrosoftWindowsAppHost node, use the context menu to View->Show Analytic and Debug Logs
  3. Once the App Tracing channel shows up under the AppHost node, use the context menu to “Enable Log”
  4. Restart your app
  5. The console messages should now be in event viewer

You'll see a bunch of other events from wwahost.exe showing up here too, but you can filter on your process ID to whittle down the list. It's best to be running only your app when checking the Event Viewer!

Finally, if you use WinJS.log, you'll want to make sure it isn't being employed in release versions of your app. For this reason, when callign WinJS.log, use the same syntax as WinJS: WinJS.log && WinJS.log(…). This way you won't be spending extra cycles in your release version writing to a console that the user will never see.

Then be sure to remove the one line that assigns a function to WinJS.log (or calls WinJS.Utilities.startLog) before you build your package to upload to the Store. This is much easier than trying to scrub your app for direct console.log calls.

Thanks to Josh Williams and Andy Sterland who provided many of the details here.

As described in Chapter 16 of Programming Windows 8 Apps in HTML, CSS, and JavaScript, Visual Studio can only debug one type of code at a time. Here’s the relevant excerpt:

When you hit that [JavaScript] breakpoint, step through the code using Visual Studio’s Step Into feature (F11 or Debug > Step Into). Notice that you do not step into the C# code, an effect of the fact that Visual Studio can debug either script or managed (C#)/native (C++) code in one debugging session but unfortunately not both. Clearly, using some console output will be your friend with such a limitation.

To set the debug mode, right-click your app project in solution explorer, select Debugging on the left, and then choose a Debugger Type on the right as shown in Figure 16-3. For debugging C#, select Managed Only or Mixed (Managed and Native). Then set breakpoints in your component code and restart the app (you have to restart for this change to take effect). When you trigger calls to the component from JavaScript, you’ll hit those component breakpoints.

Fortunately, there is a way to debug both types of code at the same time using two instances of Visual Studio:

  1. Launch the app (F5) with Script Only debugging selected. This is the instance of Visual Studio in which you’ll be stepping through JavaScript.
  2. Load the project in a second instance of Visual Studio. Ignore warnings about IntelliSense files being already open, but prepare to wait a little while as VS will build a new copy of that database for this second instance.
  3. In this second instance, set the debugging mode to Native Only, Managed Only, or Mixed, depending on your needs. This is where you’ll be debugging C#/VB/C++ code, as in a WinRT component.
  4. Select the Debug -> Attach to Process… menu command. (You do this instead of running the app a second time.)
  5. Find and select the line for WWAHost.exe in the process list that has your app name in the title column.
  6. Above the list, check the Attach to value. If it says “Automatic: Script code”, press the Select… button and indicate Managed and Native instead. Close that dialog.
  7. Click the Attach button.

Then go set breakpoints in this second instance of VS where you want to step through managed/native code. While this still won’t allow you to step across the language boundaries in a single debugger, it will allow you to step through each code type in the different instances.

Thanks for Rob Paveza for this tip.