How to embed an application manifest in a CodeDom generated assembly

When using CodeDom to generate executables (using CodeCompileUnit.CompileAssemblyFromDom for example), you can easily embed your custom application manifest using the CompilerParameters.CompilerOptions string, like so:

            CompilerParameters cp = new CompilerParameters();
            cp.GenerateExecutable = true;
            cp.GenerateInMemory = false;
            cp.TreatWarningsAsErrors = false;
            cp.OutputAssembly = "RandomFileName.exe";
            cp.CompilerOptions = "/optimize+ /debug- /win32manifest:RandomFileName.exe.manifest";

The relevant option being /win32manifest. Make sure you create the manifest before attempting to compile, obviously.

And use the CompileParameters in CompileAssemblyFromDom();

FYI – There are other ways to do this, but they would involve finding and running some command line utilities. This is by far the easiest, and most elegant way I could find.

Creating a Custom Tool (Single File Generator) for Visual Studio 2010

A Single File Generator or “Custom Tool” is a COM “extension” for Visual Studio that takes a project file as input, and spits out some code. (One example is the .settings files) Visual Studio automatically includes the code in your project, and updates it every time you save.

I developed a tool that reads an Office 2010 Ribbon XML file and produces an interface will all the callbacks in your file (because implementing callback signatures is a bear).

Unfortunately, Microsoft’s documentation on the subject is incomplete and obsolete. If you search the web, you will find contradictory information…
I didn’t want my assembly in the GAC, nor did want to have to register the COM object globally. I didn’t want to create a setup project, or use any fancy generated code… I just wanted it to work.

So here are some tips that should get you going.

  1. First of all, there is no need to use the Visual Studio extensibility project template for this. Just create a standard Class Library in the .NET language of your choice.
  2. Add a reference to Microsoft.VisualStudio.Shell.10.0 and Microsoft.VisualStudio.Shell.Interop to your project. (If you do not have these, you probably need to download the Visual Studio 2010 SP1 SDK)
  3. In the Project Properties, in the Application tab, click “Assembly Information…” and check the “Make Assembly COM Visible” box.
  4. Do NOT select “Register for COM interop” on the Build tab
  5. On the signing tab, check sign the assembly, and select or create a key
  6. Add the following using statements to your class file:
    using System.Runtime.InteropServices;
    using Microsoft.VisualStudio.Shell.Interop;
    using Microsoft.VisualStudio;
    
  7. Add the ComVisible attribute
  8. Add a Guid to the class (use the Tools Menu-> Create GUID and select Item 5 for c#, item 6 for vb.net, hit copy)
  9. Make your class implement the IVsSingleFileGenerator interface.
  10. It should look like this:
        [ComVisible(true)]
        [Guid("FAKEGUID-FFF6-4FF3-FFF7-FFFFRFRFRF45")]
        public class Generator : IVsSingleFileGenerator
        {
    
  11. DO NOT USE THIS GUID. YOU MUST GENERATE YOUR OWN
  12. Implement the IVsSingleFileGenerator interface’s two methods – Generate and DefaultExtension (see the documentation for more details)
  13. Build it!
  14. Now for the part where the documentation falls apart – registering and using this bad boy.

  15. The easiest way to register this is using the Visual Studio local registry at HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\VisualStudio\10.0
    Note: on 32-bit systems, this may be at HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\VisualStudio\10.0 – I am using the 64-bit
    There should be plenty of sub-keys under this key. If there are not, perhaps you need to look in a different version, or bit-ness
  16. First, you need to add the COM information like so
    Windows Registry Editor Version 5.00
    
    [HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\VisualStudio\10.0\CLSID\{FAKEGUID-FFF6-4FF3-FFF7-FFFFRFRFRF45}]
    "InprocServer32"="C:\\Windows\\SysWOW64\\mscoree.dll"
    "ThreadingModel"="Both"
    "Class"="DemoSFGen.Generator"
    "Assembly"="DemoSFGen, Version=1.0.0.0, Culture=neutral, PublicKeyToken=faketokenfffff88"
    "CodeBase"="file:///C:\\Users\\username\\Documents\\Visual Studio 2010\\Projects\\sfgen\\sfgen\\bin\\Debug\\sfgen.dll"
    

    Replace the GUID after CLSID with the GUID you generated earlier; replace the Class with your Namespace.ClassName; replace Assembly with the information from your dll (I used ILSpy – I’m sure there’s an easier way); replace CodeBase with the full path to your dll.

  17. Next, add the registry info to tell Visual Studio about the Generator:
    Windows Registry Editor Version 5.00
    
    [HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\VisualStudio\10.0\Generators\{FAE04EC1-301F-11D3-BF4B-00C04F79EFBC}\DemoSFGen]
    "CLSID"="{FAKEGUID-FFF6-4FF3-FFF7-FFFFRFRFRF45}"
    "GeneratesDesignTimeSource"=dword:00000001
    @="Nice Name For your Generator"
    

    The GUID after \Generators\ corresponds to the languages in Visual Studio. See the docs for registering single file generators for a couple (or have a look in the registry).
    The Key name under the language guid (DemoSFGen in this case) is (I believe) how you will refer to the Custom Tool
    The value of CLSID needs to match your generated GUID

  18. Run Visual Studio, open a (different) project, and select an appropriate input file (text, xml, etc) In the properties for the file, add the name of the Custom Tool (“DemoSFGen”).
  19. Right click on the file, and select “Run Custom Tool”
  20. If everything worked, you will now be able to expand the file, and see your generated source underneath it. If there was a problem, Visual Studio may or may not display an error…

I know that Custom Tools aren’t the most often created things in the world, but hopefully these steps can at least get you up and running when you do try.

Undocumented behavior of Office 2010 Word Save As dialog with Sharepoint

Here’s another Office 2010 undocumented “feature”.

First a little background regarding required fields in sharepoint:
In Office 2007, in order to attach the Sharepoint properties to a document you had to first Save it into the document library. Word would allow you to save, but the document would remain checked-out to you until you filled in the necessary required properties, and checked it in.

If you were developing a system that automated adding documents to SharePoint, you could not even present the Document Information Panel to the user until the document was already in SharePoint. If the user decided to cancel… you had hanging files.

With Office 2010, Word (and I imagine other apps) will not actually complete the Save operation to a SharePoint Document Library when there are required fields. You get a warning and the document is _not_ placed in SharePoint, but the Fields from the Document Library are attached to your Word document.

In Word, if you want to display the “Save As” dialog box pre-populated to a SharePoint library you do something like this:

dynamic dlg = Application.Dialogs[Word.WdWordDialog.wdDialogFileSaveAs];
dlg.Name = "http://sharepointserver/doclib/filename.docx";
dlg.Show();

This will act the same as the normal “Save As” dialog.

If you want to handle the save process yourself, instead of dlg.Show(), use dlg.Display. This *should* take no action regardless if the user presses Ok or Cancel. If the destination happens to be SharePoint – intsead of doing nothing like it is supposed to – Word happily retreives the Sharepoint properties and attaches them to your document.

In addition to being handy, Word will attach the document properties to Read-Only and Protected files – which is something you cannot do using CustomXMLParts.
And it’s a heck of a lot easier than trying to build and attach them yourself.

While it is undocumented (and therefore subject to change), it is kind of impossible to work around — Word WILL attach the sharepoint properties, so you might as well take advantage of it.

UPDATE 3/20/2012: Unfortunately, I have discovered that this method is unreliable. On one of our user’s machines, the Save As dialog refuses to display the sharepoint folder at all. I don’t know why, but I wouldn’t recommend relying on this.

Changing the value of an editBox office Ribbon Control at runtime

When creating VSTO Add-Ins that customize the Office Ribbon, the visual Ribbon editor makes some tasks trivial. All Ribbbon controls can be accessed by id using intellisense. The RibbonEditBox.Text field can be directly queried and modified.
Everything changes when you create the RibbonXML directly.

You cannot directly query any of the runtime values on a ribbon control. You must use the OnChange callback to get the value in the box.

        public void OnChange(Office.IRibbonControl control, string text)
        {
        }

But what if you wanted to change the value of the editBox (aka change the text)? Say perform some validation, or formatting?

I tried casting the IRibbonControl object supplied by the callback to a RibbonEditBox object… This didn’t work.
I tried casting the control object as a Dynamic and accessing the “Text” property… No dice.
I looked for some means of getting the ribbon control so I could modify the Text value – nothing.

The solution:
(Which was surprisingly difficult to find)
There are three things you will need to do:
1. Within your ribbon’s class, make sure you are saving the IRibbonUI reference provided by Ribbon_Load to a private variable. I just call it “ribbon”
2. Implement the getText callback and a private string variable to hold the internal value for the editBox
3. Implement the onChange callback to perform validation, update the private variable, and use the IRibbonUI object to invalidate the editBox control. This triggers the ribbon to call the getText callback again, effectively updating the field.

An example:
This snippet when merged into the Ribbon class, will ensure that the text entered in an edit box ends with “of doom”

First, the ribbonxml part

<?xml version="1.0" encoding="UTF-8"?>
<customUI xmlns="http://schemas.microsoft.com/office/2009/07/customui" onLoad="Ribbon_Load">
  <ribbon>
    <tabs>
      <tab id="DoomedObjects" label="DoomedObjects">
        <group id="spg" label="Stuff">
          <editBox id="txtDoomed" label="Doomed" onChange="OnChange" getText="GetText"/>
        </group>
      </tab>
    </tabs>
  </ribbon>
</customUI>

And the c# for the Ribbon class

        private string textValue;
        private Microsoft.Office.Core.IRibbonUI ribbon;


        public void Ribbon_Load(Office.IRibbonUI ribbonUI)
        {
            this.ribbon = ribbonUI;
            textValue= "";
        }

        public void OnChange(Office.IRibbonControl control, string text)
        {
            if (!text.EndsWith("of doom"))
            {
                textValue = text + " of doom";
                ribbon.InvalidateControl(control.Id);
                //Only invalidating when the value needs to change. You could invalidate after the if block as well 
            }
            else
            {
                textValue = text;
            }
        }

        public string GetText(Office.IRibbonControl control)
        {
            return textValue;
        }


Automate Word Mailmerge Preview Results

(Long story short: the property you need is ViewMailMergeFieldCodes. Set it to 0 to enable preview; -1 to disable preview)

The mail merge process in Microsoft Word is a bit of a bear to automate sometimes. I suppose I should be thankful that it can be automated at all, but there are bits of it that are very poorly documented, requring a bit of trial and error to work with. It doesn’t help that most Office interop documentation leans toward Visual Basic…

Anyway, today’s issue was attempting to programmatically Preview the results of a Mail Merge in a C# VSTO project, like the button in the ribbon:

Big surprise: Document.MailMerge doesn’t contain any properties or methods with the word “preview”

Turns out there is a property called ViewMailMergeFieldCodes that does what we need, but in reverse. Microsoft’s documentation states:

This property returns True if merge field names are displayed in a mail merge main document, and False if information from the current data record is displayed

Trouble is, the field is an int, not a bool! A little debugging to the rescue:
When this field is set to -1, Preview is disabled, and the field codes are displayed.
When set to 0, Preview is enabled, and the record data is displayed.

To switch the displayed record, change Document.MailMerge.DataSource.ActiveRecord.

Now if only there was an event that fired when the record changed…

.NET multiple dictionaries with the same keys memory usage

I need to create some objects that will allow me to access columnar data by header name. The access looks something like this:

class ParentObj {
string[] columnNames;
ChildObj[] Children;
}

class ChildObj {
Dictionary<string, string> Items;
}

All the child dictionaries will have the same set of keys, matching the column list from the parent.

Now this particular object is going to be used on computers that are resource constrained, and could contain large quantities of data. My big concern was should I actually use separate dictionaries, or should I just store the values in an array, and lookup the column number from a single dictionary.

After trying both methods with very large random data, I found the memory usage to only increase 10megs using separate Dictionaries. Certainly not worth the added complexity of managing my own Dictionary implementation.

My next question was if the CLR was wasting a bunch of memory on a bunch of duplicate keys. CLR Profiler to the rescue!

I modifed my test program to be able to either use the same keys in all child objects, or use random keys as well. After making all the strings the same size, it was clear that .NET does not keep a separate copy of each of the duplicate strings around:

Object memory when all keys are the same:

Object Memory when the keys are random:

So in conclusion, using many dictionary instances with the same set of keys does not result in a significant amount of duplicate data in memory (or memory waste).

Dynamics CRM 4.0 Optimized Web Service Generator

Microsoft Dynamics CRM 4.0 is really a beautiful thing – with a few very annoying exceptions, it is a very flexible, easy to use, easy to customize business application development platform. It includes a comprehensive Web Service that allows you to perform pretty much any UI task programmatically.

There is one problem though – the CrmService proxy class can take upwards of 7 seconds just to initialize the class. Before a singe bit is passed from client to server, you have to wait for the .NET runtime to build the ginormous XmlSerializers for the equally ginormous Web service.

Normally Sgen.exe can be used to improve the startup time of Web Services, but for some reason the CRM Service doesn’t always get along with pregenerated XmlSerializers.

The solution: remove all those unused entities! My organization’s current CRM instance has 192 entities, which translates into (at least) 1,616 separate classes in the generated proxy code.
I have built a tool that consumes a CRM 4.0 web service wsdl, and produces a nice packaged .dll (complete with embedded XmlSerializers) with practically all the unnecessary fluff removed. The produced dll fully supports Fetch and the DynamicEntity – just no static types.

On a .net IIS server, creating a new CrmService now takes 0.12 seconds – instead of 6+.

Update: Released! You can get it on Codeplex here:
http://crmservicegenerator.codeplex.com/