The more I develop for Windows Phone 7…

… I’m not sure how to finish that sentence.

I signed up to be a Windows Phone 7 developer for free via Dreamspark, which lets you submit 5 apps for free. Considering Microsoft decided to be even greedier than Apple (which is hard to do…) and charges $100/year PLUS a $25 submission fee PER APP (including free apps), I figured this was quite a deal.

While it probably is, I’ve already run into a couple really annoying snags. The latest of which has me downright mad.

First off, I consider it a fundamental right that when you buy something, you should be able to modify it. If that something happens to be a computer, you should be able to write your own programs for it. When Microsoft first announced that Windows Phone 7 would be locked down in a manner akin to Apple… (you have to pay to put YOUR code on YOUR device) well lets just say I was disappointed. Tremendously. Nevertheless, I have been wanting to try my hand at mobile developement, and I despise Objective-C. WP7 uses .NET. I know .NET.

So after I signed up for the Dreamspark account, I learned that you cannot actually deploy an app to the phone until after your identity has been verified. If you have a Paid account, this happens as soon as you sign up. For students, it doesn’t happen until you submit your first app.

So I wrote a silly junk app and sumbitted it. (I later realized that if it passed inspection, I would have wasted one of my 5 free submissions…)
Identity verified, Phone unlocked. FINALLY, I could write my own phone apps.

So I have a couple ideas I’m banging away at – some of them are really just for my own benefit, some are headed to the marketplace.
Just today I realized that the prominent free Tip Calculator sucked, and that I could write a better one. I get it developed to the point of testing, and attempt to deploy it to the phone.
And I quote,

“Unable to install application. The maximum number of developer applications on this phone has been reached. Please uninstall a developer application and try again.”

WHAT??!!?

Why in the name of God’s green earth would they limit the number of MY OWN apps I can deploy to MY OWN phone? What possible rationale could they have?
Does this mean that I would have to buy my own app in order to use it without restriction?

Apparently if I had a paid account, I could have 10 developer apps instead of 3, but it doesn’t matter – in fact it’s even worse.

Requiring me to have a developer account to deploy my apps on my phone is stupid.
Requiring me to verify my identity to deploy my apps on my phone is stupid.
Limiting the number of my apps I can deploy on my phone is downright asinine.

Since I am having such a good time ranting, here are more greivances:

  • MVVM (Model View View-Model) Designed to create a logical separation of Design and Code. Great in theory. In practice, it makes the code much harder to read and write by a casual coder; it comes with significant overhead (most guides are recommending against using it if performance is a concern), and the name is ridiculous.
  • You have XNA or Silverlight. XNA requires redesigning the wheel if you want UI elements. Silverlight is a framework in a framework (i.e., slow)
  • Making your app resemble the functionality of the built-in apps requires reinventing the wheel. Page transitions, for example, should be built-in. Instead you have to create XAML animations to do it yourself.
    (And did I mention that the more XAML your app has, the longer it takes to load?)
  • Something as simple as the built in “I’m working” animation has a bug that causes major performance issues.
  • You cannot access the compass. Seriously? iPhones and Android phones have had compasses for how long?
  • You cannot access video from the camera. This seriously limits the usefulness of barcode scanner software…
  • You cannot do anything involving the web synchronously (inherited from silverlight). I know, I know, blocking the UI thread is a bad idea, but the sheer quantity of code required to simply pull down a web page is staggering compared to the synchronous equivalent. To do an HTTP post? Why on earth do I need a callback for a stream containing “u=jason”…

Word on the street is that Microsoft is planning to open things up a little. I really hope so. I just dusted off my Mac Mini and installed Xcode — if I’m going to have my hands tied, it might as well be on the more popular platform…

Group policy application errors

I recently encountered a server that was having problems applying group policy. I encountered the following errors:

Log: Application
Source: Group Policy Registry
Event ID: 8194
Message:The client-side extension could not remove user policy settings for 'GPONAME {n-n-n-n-n}' because it failed with error code '0x8007000d The data is invalid.' See trace file for more details.
Log: System
Source: GroupPolicy
Event ID: 1085
Message: Windows failed to apply the Group Policy Registry settings. Group Policy Registry settings might have its own log file. Please click on the "More information" link.

 

The More info link is useless -don’t waste your time. Also, it would appear there is no trace file. Searching for these errors on Google will get you suggestions about deleting GPOs on the Domain controller, but the thing is, I need this GPO.

To diagnose this issue, you will first need to enable Group Policy tracing. On the machine having the problems, open up the local group policy editor (run gpedit.msc) and browse to:

Computer Policy \ Administrative Templates \ System \ Group Policy \ Logging and tracing

This contains a list of all the Group Policy Modules / extensions. Select the one that matches the error message in the system event log. (In my case, it was Registry Policy Processing)
enable the policy, change Tracing to “On” and click Ok.

Now open an elevated (Run as Administrator) command prompt, and type gpupdate. This should get the errors to throw again, but this time it will write out a trace file.

You should be able to find that trace file in C:\ProgramData\GroupPolicy\Preference\Trace\User.log. Open it up and look for a line containing “The data is Invalid”. You should see something like the following:

GPH data file : C:\ProgramData\Microsoft\Group Policy\History\{...-...-...-...-...}\S-1-5-21-...-...-...-...\Preferences\Registry\Registry.xml
Completed parse of GPH XML. [ hr = 0x8007000d "The data is invalid." ]
Completed remove GPH. [ hr = 0x8007000d "The data is invalid." ]
Leaving ProcessGroupPolicyExRegistry() returned 0x8007000d

The filename after GPH data file is the corrupt file. Most likely is is an empty XML File. I just renamed the folder C:\ProgramData\Microsoft\Group Policy\History\{guid}\{sid} to be {sid}.bak.

(Note: you may need to change your folder options to be able to access the file)

Now run gpupdate again, and it should recreate the history file with the correct contents. Problem solved!

Finally, remember to disable the tracing.

Adding task panes in a Office Add-in when using IDTExtensibility2

If you are creating an Office Add-in using VSTO, it is easy to create task panes. But what if you do not want to involve the VSTO Runtime?

Using VSTO makes creating Add-ins very simple, but that simplicity comes at a cost. ClickOnce is a major pain to deploy to users, VSTO Add-ins have a tendency to mysteriously disable themselves, and they load slow.

I have recently switched to using the Visual Studio Add-in wizard, which created Add-ins using the IDTExtensibility2 interface. It requires you to do a bit more legwork, but the generated solution comes with a pre-configured MSI installer project, just asking to be deployed via Group Policy.

My latest project needs to prompt a user to perform an action when Word documents of a certain type are opened. Sure, I could use a pop-up form, but that is so very un-office-like. Taskpanes are a much more integrated solution, but for some reason the documentation and examples on the internet are pretty bad. And confusing. And WAY over complicated.
While working on this, I almost gave up (deleted and then started over once), but persistence and experimentation paid off – I got it to work, and it was much easier than I expected.

The following assumes you have some experience creating Add-ins using IDTExtensibility2.

Create your add-in project (be sure to change the debug properties to run your desired application – it defaults to Visual Studio) , add a reference to System.Windows.Forms, and add the following using statements:

using System.Windows.Forms;
using Microsoft.Office.Core;

First you need to create a user control for your task pane. Microsoft’s example says you have to create a Form and a user control in a separate project, well this is simply not true.

Add a user control to your project. I left the default name of “UserControl1”. Just for fun, we’ll add a button and a label to the user control as well.

Find the modifiers property on the button and change it to public.

We are doing this so we can access the button’s events from the Add-in, and because I am lazy. (The correct way would be to add a public event to your UserControl1 class, and call it from your private button1 event handler)

Next, modify your Connect class to also implement the ICustomTaskPaneConsumer interface.

    public class Connect : Object, Extensibility.IDTExtensibility2, ICustomTaskPaneConsumer
    {
    //
    //

Lets also add a couple more class variables, just to keep life simple (and prevent things from going out of scope unexpectedly)

        private object applicationObject;
        private object addInInstance;
        // New vars for Custom task pane
        private ICTPFactory myCtpFactory;
        private CustomTaskPane myPane;
        private UserControl1 myControl;

Finally, you implement the CTPFactoryAvailable method – this provides you with the ICTPFactory instance that you will use to actually create the task pane. I have also included the example code to create and display our task pane.

        public void CTPFactoryAvailable(ICTPFactory CTPFactoryInst)
        {
            // Store the CTP Factory for future use. You need this to display
            // Custom Task Panes
            myCtpFactory = CTPFactoryInst;

            // Create the task pane using UserControl1 as the contents
            // The third parameter, when supplied, is Window object.
            myPane = myCtpFactory.CreateCTP("MyAddin1.UserControl1", "My Task Pane", Type.Missing);

            //Set the dock position and show the task pane
            myPane.DockPosition = Microsoft.Office.Core.MsoCTPDockPosition.msoCTPDockPositionRight;
            myPane.Visible = true;

            // CustomTaskPane.ContentControl is a reference to the control object
            myControl = (UserControl1)myPane.ContentControl;

            // assuming UserControl1.button1 is public, add a handler to the click event.
            myControl.button1.Click += new EventHandler(button1_Click);
        }

And lastly, add an event handler for the click event

        void button1_Click(object sender, EventArgs e)
        {
            MessageBox.Show("Hello World!");
        }

Now run your project, and the task pane should be there to greet you. Clicking the button will then display the hello world messagebox.

In my project, I kept my application logic in a separate class from the Connect class. All you need is a reference to the instance of ICTPFactory supplied by CTPFactoryAvailable to create and hide task panes.

For reference, here is the entire Connect.cs file.

namespace MyAddin1
{
    using System;
    using Extensibility;
    using System.Runtime.InteropServices;
    using System.Windows.Forms;
    using Microsoft.Office.Core;
    /// <summary>
    ///   The object for implementing an Add-in.
    /// </summary>
    /// <seealso class='IDTExtensibility2' />
    [GuidAttribute("62EFAKE8-FAKE-47EF-82FC-85C5FAKE977E"), ProgId("MyAddin1.Connect")]
    public class Connect : Object, Extensibility.IDTExtensibility2, ICustomTaskPaneConsumer
    {

        public Connect()
        {
        }

        public void OnConnection(object application, Extensibility.ext_ConnectMode connectMode, object addInInst, ref System.Array custom)
        {
            applicationObject = application;
            addInInstance = addInInst;
        }

        public void OnDisconnection(Extensibility.ext_DisconnectMode disconnectMode, ref System.Array custom)
        {
        }

        public void OnAddInsUpdate(ref System.Array custom)
        {
        }

        public void OnStartupComplete(ref System.Array custom)
        {
        }

        public void OnBeginShutdown(ref System.Array custom)
        {
        }

        public void CTPFactoryAvailable(ICTPFactory CTPFactoryInst)
        {
            // Store the CTP Factory for future use. You need this to display
            // Custom Task Panes
            myCtpFactory = CTPFactoryInst;

            // Create the task pane using UserControl1 as the contents
            // The third parameter, when supplied, is Window object.
            myPane = myCtpFactory.CreateCTP("MyAddin1.UserControl1", "My Task Pane", Type.Missing);

            //Set the dock position and show the task pane
            myPane.DockPosition = Microsoft.Office.Core.MsoCTPDockPosition.msoCTPDockPositionRight;
            myPane.Visible = true;

            // CustomTaskPane.ContentControl is a reference to the control object
            myControl = (UserControl1)myPane.ContentControl;

            // assuming UserControl1.button1 is public, add a handler to the click event.
            myControl.button1.Click += new EventHandler(button1_Click);
        }

        void button1_Click(object sender, EventArgs e)
        {
            MessageBox.Show("Hello World!");
        }


        private object applicationObject;
        private object addInInstance;
        // New vars for Custom task pane
        private ICTPFactory myCtpFactory;
        private CustomTaskPane myPane;
        private UserControl1 myControl;

    }
}