Customize IntelliTrace to Collect Enums

This Guillaume Rouchon's post illustrates how to add a custom IntelliTraece event. Mine is to complement it with an enum type and updates in Visual Studio 2015 Update 2.

Let me summarize how to add a custom IntelliTrace event. The file you have to change is in a sub folder of Visual Studio installation folder, <VS installation folder>\Common7\IDE\CommonExtensions\Microsoft\IntelliTrace\14.0.0\en\collectionplan.xml. You need to have admin privilege to do that. This file only affect F5 debugging in Visual Studio. If you are using IntelliTrace standalone collector, you have to pass the collection plan file to the command line.  So you can modify default one that comes with the standalone collector or write your own one.

What you need to do to add a custom event is

  1. Add a category under TracepointProvider/Categories
  2. Add an assembly under TracepointProvider/ModuleSpecifications
  3. Add your own diagnostic event specification under TracepointProvider/DiagnosticEventSpecifications
There are two ways of querying parameter values and returned values. The first is DataQuery. It's a simple declarative way using dot notation to get values of the parameter or the field in the parameter. It only supports primitive types. The other way is ProgrammableDataQuery. You have to provide your own IProgrammableDataQuery implementation to query a complex type.
For enum, we're going to use DataQuery.
We need to specify a type in the data query for enum. Intuition tells us we can use the enum type. But that's not working. The right type should be the underlying integral type. For example, int. The value is also an integral value too.
Let me illustrate it here.
I create a sample console application
using System;
namespace ConsoleApplication1
{
    enum Color
    {
        Red,
        Green,
        Blue
    }
    class Program
    {
        static void Main(string[] args)
        {
            PrintColor(Color.Blue);
        }
        static void PrintColor(Color color)
        {
            Console.WriteLine("Color: " + color);
        }
    }
}

Let's change the collection plan.

1. Add a new category.
<Category Id="enumSample" _locID="category.enumSample">Enum Sample</Category>
2. Add a new module
<ModuleSpecification Id="sample">ConsoleApplication1.exe</ModuleSpecification>
3. Add a diagnostic event specification
We're going to query the parameter color in the method PrintColor.

<DiagnosticEventSpecification>
    <CategoryId>enumSample</CategoryId>
    <SettingsName _locID="settingsName.ConsoleApplication.PrintColor">PrintColor (Color)</SettingsName>      
    <SettingsDescription _locID="settingsDescription.ConsoleApplication.PrintColor">
       Print the color
    </SettingsDescription>
    <Bindings>
        <Binding>
            <ModuleSpecificationId>sample</ModuleSpecificationId>
            <TypeName>ConsoleApplication1.Program</TypeName>
            <MethodName>PrintColor</MethodName>
            <MethodId>ConsoleApplication1.Program.PrintColor(System.Int32):System.Void</MethodId>
            <ShortDescription _locID="shortDescription.PrintColor.Color">Print Color "{0}"</ShortDescription>
            <LongDescription _locID="longDescription.PrintColor.Color">
                Going to print the color in integral value "{0}"
            </LongDescription>
            <DataQueries>
                <DataQuery index="0" type="Int32" name="color" query=""
                    _locID="dataquery.PrintColor.Color" _locAttrData="color"></DataQuery>
            </DataQueries>
        </Binding>
    </Bindings>
</DiagnosticEventSpecification>

Save the file and restart VS. The custom event shows in Tools/Options/IntelliTrace/IntelliTrace Events

IntelliTrace Event Options screenshot

When I debug the program, the custom event appears in the Events table. Look at the description! It shows me the integral value of the enum value.VS Events tab screenshot

How simple it is to add a custom IntelliTrace event! This is helpful to diagnose a piece of code path that're prone to error in changes. When you have your own collection plan for the program, you can just debug the program and let it run, and spot the error from the Events table.

Run Windows Phone 10 Emulator on Compressed Disk

If you are like me, you may have your disk compressed and also try to do some Windows Phone development. I'm starting developing for Windows Phone 10 and have this problem:

The emulator is unable to create a differencing disk

The following screen shot explains that virtual hard disk files must be uncompressed and unencrypted and must not be sparse:

Windows Phone Emulator Error

 

Yes. I do have the whole disk compressed. So as long as I uncompressed the virtual hard disk files, I should be able to run the emulator. But unfortunately, the message box doesn't tell me what the files are and where they are.

So I searched and found a few results. Most aren't helpful. They're for emulators for Windows Phone 8 (e.g. https://msdn.microsoft.com/library/windows/apps/ff626524(v=vs.105).aspx#BKMK_uncompressed). I looked at the paths and uncompress C:\Users\username\AppData\Local\Microsoft\XDE. But I didn't  find the one for Windows Phone 10.

After a few more searching, I found the location for Windows Phone 10 VH:

C:\Program Files (x86)\Windows Kits\10\Emulation

That's it. After uncompress both directories, I could debug my app on Windows Phone 10 Emulator.

Grep in PowerShell

When I start to use PowerShell, I miss grep in bash. Luckily, PowerShell provides Get-ChildItem and  Select-String.

Some helpful parameters in Select-String are -Pattern and -Path.

Both -Pattern and -Path accept a list of string. Each item is separated by comma, for example, *.txt, *.log

-Pattern is the pattern of text you want to search

-Path is the list of files you want to search.

However, Select-String doesn't search files under a directory. You have to pass file paths to it via -Path. We can use Get-ChildItem to get a list of files, and get all files under a directory recursively by using -Recurse

The basic pattern to use both cmdlet for greping is as follow:

Get-ChildItem -Recurse -Path C:\Path\To\Folder -Include *.txt | Select-String "SearchText"

I create a script in my GitHub (https://github.com/kceiw/PowerScript/blob/master/scripts/GrepShell.ps1) so that I can reuse it.

This script is not signed though. If you want to use it, you need to change your execution policy to allow it to run. See Set-Execution.

Update Owncloud

I recently updated my Owncloud to find that I couldn't access to contacts and calendars from WebDav any more. And after tried a few things, it worked again.

At first when I tried to open the link from the browser, I got this error:

User did not have the required privileges ({DAV:}read) for path "principals/username”

I searched online and found the issue open against owncloud on GitHub. https://github.com/owncloud/core/issues/14048

The workaround mentioned in the issue was already in my Owncloud. But I still had the same issue. I couldn't go further since there's no more workaround and the issue was closed. I thought there must be some errors in upgrading Owncloud, because it's in maintenance mode for quite a long time. But anyway, I got a message about a newer version when I logged in as Admin. I decided to upgrade it manually. It wouldn't be worse.

After I'd done that, the app files_encryption for server side encryption didn't work. From the log, it's about using an undefined function. I removed it from the apps folder since I didn't really need it.

After that, when I logged in to admin, there's a message in my admin page telling me to run command "occ encryption:migrate". I did so. Surprisingly, I could sync to both contacts and calendars.

Dynamically Adding VS Menu Item

We can extend VS by using VS SDK. It provides a way to add a menu and menu items. When we do that, we may need to solvee cases where we only determine the menu items at run time. That requires us to dynamically add menu items. Luckily, there's a document and example in MSDN about how to do that (http://msdn.microsoft.com/en-us/library/bb166492.aspx). The approach seems straightforward. However, when I tried that out, I fell in a tricky trap, in my opinion. That took me a few days to figure out. So I want to write it down.

Let me summarize the approach:

1. Create a place holder menu item in the .vsct file. This menu item must have the CommandFlag DynamicVisibility. Other than that, it is similar to other menu items in the .vsct file. It is in a group and a menu, and it has its own guid and id.

2. Create a menu command class that inherits from OleMenuCommand. Override method DynamicItemMatch.
The place holder menu item is always a valid menu item. Then DynamicItemMatch is called for each consecutive id until it returns false.

3.  Add BeforeQueryStatus and other handlers for your menu items.
You can set status, text and other properties of the menu item in BeforeQueryStatus handler.

Here are my lessons.

1. The place holder menu item is always a valid .vsct menu item and shown in the menu, because it's declared in the .vsct file. DynamicItemMatch doesn't really determine it's validity. If you return false in this method, the framework just doesn't query for next id.

2. Be cautious of the id of the place holder menu item and the number of menu items you want to create. You don't want the ids of dynamically created menu items to overlap any one you use for other menu items. It can be out of control especially when you have multiple areas that you want to dynamically add menu item, and all of them are in the same menu and group.

3. DynamicItemMatch is just a way to let the framework know when to stop querying for dynamically generated menu items. You still need to set the right status and text for the generated menu item in BeforeQueryStatus handler.

4. We cannot rely on MatchedCommandId to identify a dynamically created menu item.

In the example in the MSDN document, MatchedCommandId is set to the command id if it's a match. In BeforeQueryStatus, it's used to identify a menu item and gets reset afterwards. But it's not used in the invoke handler. I didn't understand that at first. I didn't reset MatchedCommandId in BeforeQueryStatus handler, and use MatchedCommandId in the invoke handler. And when I click the first menu item, it's actually invoked on the last generated menu item. After a few debugging, I realized that all those dynamically generated menu items and the place holder menu item are actually the same instance. That means, the framework creates an instance of OleMenuCommand for the place holder menu item, and calls DynamicItemMatchBeforeQueryStatus handler and other handlers on the same instance. Once you set a property of that instance, it remains there. For example, MatchedCommandId will keep the last assigned value. Don't need to worry that dynamically generated menu items get weird text. It'll always call BeforeQueryStatus handler before setting the text or other status. Thus you always have a chance to set it to the right value for that particular menu item in the BeforeQueryStatus handler.

The approach in Visual Studio 2012 (https://msdn.microsoft.com/en-us/library/Bb166492%28v=vs.110%29.aspx) creates an instance for the place holder menu item, as well as an instance for each generated menu item. However, I believe that's not the right approach.

1. The framework still calls DynamicItemMatch of all the created instances to determine whether it should query for the next id.

2. The document of DynamicItemMatch indicates that it's used in the case where we dynamically add menu item. The approach in Visual Studio 2012 doesn't use it at all.

The above are what I learned. And since I have a data structure to represent the menu item, I don't need to use MatchedCommandId. I am not quite sure yet the usage of it. But at least, the Visual Studio 2015 approach still works and you should try to debug it if you see any problems.