Intriguing question: What standards does Authenticode use?

A colleague of mine just asked a very interesting if potentially misleading question: what standards are used/implemented by Microsoft Authenticode?

I felt pretty dumb at first, because I couldn’t even grok the question.  Authenticode implements a set of APIs, usually derived from IE and its dependencies – that’s the nearest I can think of to a reasonably relevant answer to the question.

When pressed for details, it turns out the context was a security investigation of a particular set of software being developed by a non-security group.  The security auditor was looking for answers to questions like which digital signature standards are implemented by their code, what crypto algorithms, etc, and the responses from the developers were of the form “don’t worry, we’re using crypto, it’s all well-understood”.

I’ve been in this situation many times, and I have a permanent forehead scar from the amount of time I’ve beaten my head against a wall trying to get answers to such questions out of Developers.  I have learned (the hard way) that this is a fruitless exercise – it’s like asking my mom whether her favourite game is written in managed or unmanaged code.  Either way, the only response you should expect are blank stares.  [Yes, there are a small minority of developers who actually understand what is going on deep beneath the APIs of their code, but with the growth of 3rd & 4th-generation languages, that’s a rapidly dying breed.]

Advice: Look for Code, not Standards

My advice to my colleague, which I’m sharing with you as well, is this: don’t pursue the security constructs implemented (or not) by their code.  If you don’t get an immediate answer to such questions, then switch as fast as possible to unearthing where in their code they’re “using crypto”:

  • What component/library/assembly, or which source file(s), are “doing the crypto operations”?
  • Which specific API calls/classes are they using that they believe are implementing the crypto?

With a narrowed-down list of candidate APIs, we can quickly search the SDKs & other documentation for those APIs and find out everything that’s publically known or available about that functionality.  This is a key point:

  • once the developers have implemented a piece of code that they believe meets their security requirements, often they cannot advance the discussion any further
  • once you’ve found the official documentation (and any good presentations/discussions/reverse-engineering) for that API, there’s usually no further you can take the investigation either.
  • If you’re lucky, they’re using an open-source development language and you can then inspect the source code for the language implementation itself.  However, I’ve usually found that this doesn’t give you much more information about the intended/expected behaviour of the code (though sometimes that’s the only way to supplement poorly-documented APIs), and a security evaluation at this level is more typically focused on the design than on finding implementation flaws.  [That’s the realm of such techniques as source code analysis, fuzzing & pen testing, and those aren’t usually activities that are conducted by interviewing the developers.]

Specific Case: Authenticode

Let’s take the Authenticode discussion as one example:

  • the developers are almost certainly using Win32 APIs not managed code, since managed code developers more often refer to the System.Security namespace & classes – however, ShawnFa makes it clear that Authenticode also plays in the managed code space, so watch out.
  • Authenticode is implemented by a number of cryptographic APIs in the Win32 space
  • This page leads one to think they ought to read works from such esteemed authorities as CCITT, RSA Labs and Bruce Schneier, but as with most Microsoft stuff you’re better off looking first at how Microsoft understands and have interpreted the subject.
  • My understanding of Authenticode is that it’s more or less a set of tools and common approaches for creating and validating digital signatures for a wide array of binary files
  • However, its most common (or perhaps I should say most attention-generating) usage is for digitally signing ActiveX controls, so let’s pursue that angle
  • A search of MSDN Library for “activex authenticode” leads to an array of articles (including some great historical fiction – “We are hard at work taking ActiveX to the Macintosh® and UNIX“)
  • One of the earliest (and still one of the easiest to follow) was an article written in 1996 (!) entitled “Signing and Marking ActiveX Controls“.  This article states:
    • Once you obtain the certificate, use the SIGNCODE program provided with the ActiveX software development kit (SDK) to sign your code. Note that you’ll have to re-sign code if you modify it (such as to mark it safe for initializing and scripting). Note also that signatures are only checked when the control is first installed—the signature is not checked every time Internet Explorer uses the control.
  • Another article indicates “For details on how to sign code, check the documentation on Authenticode™ in the ActiveX SDK and see Signing a CAB File.”  The latter also says to use SIGNCODE; the former wasn’t linked anywhere I looked on the related pages.

Further searches for the ActiveX SDK led to many pages that mention but do not provide a link to this mysterious SDK. [sigh…]  However, I think we can safely assume that all APIs in use are those implemented by SIGNCODE and its brethren.  [If you’re curious which ones specifically, you could use Dependency Walker (depends.exe) to make that determination.]

  • However, one of the articles I found has led me to this, which I think provides the answers we’re after: Signing and Checking Code with Authenticode
    • “The final step is to actually sign a file using the SignCode program. This program will:
      • 1. Create a Cryptographic Digest of the file.
        2. Sign the digest with your private key.
        3. Copy the X.509 certificates from the SPC into a new PKCS #7 signed-data object. The PKCS #7 object contains the serial numbers and issuers of the certificates used to create the signature, the certificates, and the signed digest information.
        4. Embed the object into the file.
        5. Optionally, it can add a time stamp to the file. A time stamp should always be added when signing a file. However, SignCode also has the ability to add a time stamp to a previously signed file subject to some restrictions (see the examples that follow the options table).”
    • –a = “The hashing algorithm to use. Must be set to either SHA1 or MD5. The default is MD5.
    • -ky = “Indicates the key specification, which must be one of three possible values:

      1. Signature, which stands for AT_SIGNATURE key specification.
      2. Exchange, which stands for AT_KEYEXCHANGE key specification.
      3. An integer, such as 3.
      See notes on key specifications below.”

    • “The ChkTrust program checks the validity of a signed file by:
      1. Extracting the PKCS #7 signed-data object.
      2. Extracting the X.509 certificates from the PKCS #7 signed-data object.
      3. Computing a new hash of the file and comparing it with the signed hash in the PKCS #7 object.

      If the hashes agree, ChkTrust then verifies that the signer’s X.509 certificate is traceable back to the root certificate and that the correct root key was used.

      If all these steps are successful, it means that the file has not been tampered with, and that the vendor who signed the file was authenticated by the root authority.”

    • “The MakeCTL utility creates a certificate trust list (CTL) and outputs the encoded CTL to a file. MakeCTL is supported in Internet Explorer 4.0 and later.

      The input to MakeCTL is an array of certificate stores. MakeCTL will build a CTL which includes the SHA1 hash of all of the certificates in the certificate stores. A certificate store can be one of the following:

      • A serialized store file
      • A PKCS #7
      • An encoded certificate file
      • A system store”

 

For those who still want more detail, I’d recommend digging into CryptoAPI and especially reviewing the FIPS submissions Microsoft has made for the Windows components that FIPS evaluated.

 

Aside: Here’s a really neat easter egg I stumbled on: the Internet Explorer Application Compatibility VPC Image.  You can download a Virtual PC image pre-installed with the stuff you need to troubleshoot compatibility issues for IE apps, add-ins etc.  Very helpful – save you a few hours of setting up a clean testing environment every time you run into a problem (or if you’re like me, it’ll save you weeks of hair pulling when trying to troubleshoot such issues when using your own over-polluted browser).

Advertisements

CacheMyWork enhancements: Managed Stack Explorer ideas

Wow, what you can learn by perusing someone else’s code…

Cool Code: Managed Stack Explorer

I stumbled across the Managed Stack Explorer app on CodePlex, and as soon as I ran it I knew that it had some killer features I wanted to implement in CacheMyWork!

  1. It’s got a two-panel layout for (a) Processes and (b) the Threads in each Process
  2. More importantly, it’s got auto-resizing of these panels when the whole app window is resized (much like I want to have a panel for Applications and another for the Documents open in each Application).  Very slick-looking.
  3. Whenever you click on a Process in the left-hand panel, it updates a lower display of detailed information about the Process (much like I’d wanted to put in tooltips in CacheMyWork, but this might be even better).
  4. It has another panel that is initially collapsed, but that can be opened/expanded by the user, and possibly by the app in response to certain events (much like I’d wanted the Documents panel to initially be hidden and/or hideable, but able to be opened by the user or in response to certain events e.g. (a) click on a Process; (b) if the Process has Documents open, automatically open the Documents panel).
  5. When a new .NET application starts, the list of Processes in this application is automatically updated!

ManagedStackExplorer

Makes me want to do it all now, but there are some questions to which I don’t know the answers right yet:

  • Is there such a thing (i.e. a native or custom Class available) to create a CheckListBox (as I have right now) that has multiple Columns?  Could the Columns be resizeable and resortable?
  • Does the auto-update of the Processes list require multi-threaded coding?

Reverse-engineering the code

It turns out that, for some unknown reason, when I download the source code and try to open the Design View on any of the WinForms classes (e.g. MainGui.cs, InfoSelect.cs), Visual Studio throws an error and won’t show me the visual design view.  That sucks, ’cause it’s a heckuva lot easier to explore the code by selecting the control(s) you’re interested in and jumping right to the relevant entry point.

Instead, I’ve spent a couple of hours poring over the MainGui.Designer.cs class, assembling a picture for myself of which components relate to which.  It was very instructive, but it felt kind of like trying to build a Lego model of a Tie Fighter in a pitch-black room:

  • I found out that the SplitContainer control class is what’s used to implement (1) and (2)
  • There are multiple SplitContainer objects in this application, nested one inside the other like those carved Russian dolls.
  • The SplitContainer object hierarchy appears to be like this (I’ve colour-coded the object names to show where they are in the UI below):
    • listsSplitData > ptSplitInfo & FixedPanel.Panel1
      • ptSplitInfo > processSplitThread & groupBox2
        • processSplitThread > processView & threadView
  • The other objects encapsulated in the SplitContainers are arranged:
    • groupBox2 > processDataLayout
      • processDataLayout > label1 – label 12
    • processView > ProcessName column, PID column
    • threadView > tid column, threadState column

This means the application’s UI is more or less constructed as follows:

ManagedStackExplorer-annotated

I think I’ve done a decent job mimic’ing the SplitContainer usage demonstrated here, so all I’d like to do at this point is figure out how to create that right-column expand/contract control.  [I’ll leave the auto-update with new Processes behaviour for later.]

After jumping back & forth through the code a few times, it appears that:

  • The control I’m after is labeled viewStackTraceToolStripMenuItem.
  • It appears be to an instance of ToolStripItem and a child of a ContextMenuStrip, and has a single Click() Event Handler.
  • That event handler calls a routine threadview_DoubleClick(), which calls ShowSelectedThreadStackTraces().
  • The former routine calls ExpandAndCollapse(), which appears to be the magic behind the whole thing.

If I were to implement this routine or similar, then all I have to figure out is how they created the “>” control that expands & collapses the FixedPanel.

Cool!

Porting Word2MediaWikiPlus to VB.NET: Part 10

Previous articles in this series: Prologue, Part 1, Part 2, Part 3, Part 4, Part 6, Part 7, Part 8, Part 9.]

CustomizationContext vs. Normal.dot

I just experienced another warning that Normal.dot was updated, and did I want to save it?  That tells me that the CustomizationContext is needed.  I’ve implemented a custom Word Template called “W2MWPPTemplate.dot” and the minimal code that I believe should cover this requirement.  [This code was copied from a previous VSTO project of mine.]

Next code library: modW2MWP_FileDialog.bas

  • Function TestIt() calls the custom function ahtCommonFileOpenSave(), and according to the code comments TestIt() is there just as an example
  • Function ahtCommonFileOpenSave() calls either aht_apiGetOpenFileName() or aht_apiGetSaveFileName(), which both appear to just be performing string functions — nothing interesting there
  • Function GetOpenFile() calls ahtCommonFileOpenSave() as well
  • The functions ahtAddFilterItem(), TrimNull() and TrimTrailingNull() are all just minor string manipulations

The most interesting thing about this file’s code is that it defines a few FileOpen filters, for Access, dBASE, Text and All (*.*).  I don’t know why this application would open or save from these specific file types, which leads me to wonder if this code is even in use.  It’s possible it was left behind from some experiments.  In any case, I’ll keep an eye out for something calling this code, but I’ll likely just use native System.IO methods once I find the caller.

Next up: frmW2MWP_Config.frm

If I remember correctly, the typical way to add a dialog box to a VSTO add-in is using a Windows Form.  I added a Windows Form to the project and named it W2MWPP UI Config.vb.  However, trying to infer what controls were on the VBA version of this form isn’t as easy as I thought it’d be from the code.  However, I’ll see what I can do.

First up I added the New() function to the form’s code-behind using the drop-downs along the top of the editing panel in VS2005.  In the New() method I’m adding functionality currently contained in UserForm_Initialize().  From what I’m seeing in this function, and what I’ve seen in the “old” documentation page, there are:

  1. a Registry setting for the Editor path/ImageExtractionPE (which appears to be unused now since the MS Photo Editor is no longer supported)
  2. a Registry setting and combo box (cboLanguage) for a Language setting (stored in a languageArr() variable)
  3. a Registry setting and textbox (txtURLTest) for the “Wiki Address Root” used for testing
  4. a Registry setting and textbox (txtURLProd) for the “Wiki Address Root” used for ‘production’
  5. a Registry setting and textbox (txtImagePath) for the filesystem folder path used to store extracted images
  6. a Registry setting and textbox (txtTabtoFileName) — though a NumericUpDown control would be better — to count the number of Tab characters needed to edit the Filename when automatically uploading image files
    • There also is a “Simulate upload” function documented here
  7. some sort of option to enable/disable “allow articles without category” is documented, but doesn’t seem to have an initialization state
  8. some sort of control to link to the Project’s online help pages

I’ll add the necessary controls to the Config form for (2) through (7).  However, since the Word2WikiPlus VBA project doesn’t support the MS Photo Editor any longer, I’ll skip (1).  As well, I’ll try using tooltips & status bar messages to provide help on what to do with each configuration control.

Porting Word2MediaWikiPlus to VB.NET: Part 9

Previous articles in this series: Prologue, Part 1, Part 2, Part 3, Part 4, Part 6, Part 7, Part 8.]

Final Feature from ThisDocument.cls: Normal.dot ?

One of the annoyances about VSTO development in Word is that Word always seems inclined to write settings into the Normal.dot file (Word’s default template).  I’ve never really looked into what these settings typically are, and I’m not sure in the case of this project either, but during the first few rounds of trying to get the CommandBar code working, I was getting asked every time whether I wanted to update the Normal.dot file (and having to create a workaround — see Part 8 for details — to avoid this).

I haven’t seen this come up in the last few days of coding, so I’m not sure if (a) I’ve gotten over whatever hurdle causes this because I’ve finally fixed a bug, or (b) I inadvertently slipped and let the Normal.dot get updated.  I’ll check it out in the near future, and I’m sure I’ll have to change something because of it, but for now it’s just not worth worrying about.

Button Click() Event

I was flipping through a copy of Visual Studio Tools for Office (by the two Eric’s — Lippert and Carter) and I happened to catch the section in Chapter 7 (Working with Word Events) entitled “Visual Studio Generation of Event Handlers”.  This little gem finally drilled home what the WithEvents keyword means: it allows me to select one of the controls for which I’ve tagged WithEvents in its declaration, then select any of the available Events, and VS2005 will automatically generate the Event Handler stub, complete with all those nasty parameter declarations that always give me heartburn.

So now I understand why I declared the ButtonControl, UploadControl and ConfigControl using WithEvents.  Now I can easily generate the Click() Event Handlers for each of these CommandBarButtons.

The more I look at them however, the less I like the names “ButtonControl” etc.  They’re not a whole lot better than “ButtonButton”, “UploadButton” and “ConfigButton” (which are obviously redundant, especially with an IDE that automatically describes each object’s type as you’re using it).  Further, they really aren’t easy to find when you’re looking for one of the buttons while you’re typing code.

Somewhere along the line I picked up an elegant convention, which is to prefix UI controls with the string “ui”, as in “uiButton”, “uiUpload”, “uiConfig”.  That way, any code you’re writing for UI controls will be easy to use Intellisense to narrow down to just those controls with the “ui” prefix.

I’m going to change “ButtonControl” to “uiConvert” as well.  I don’t know what the name “ButtonControl” was supposed to mean (other than the most generic way of addressing this first control), and it’ll be easier to remember when the Button label and the object Name are similar.

Issue: Word Macro Settings blocking the Click() event

I dropped a MessageBox.Show() call into each Event handler and Debug’d the application.  What’s odd isn’t that Word 2003 complained about Macro settings (“The macro cannot be found or has been disabled because of your Macro security settings”), but that the Configure button first displayed the MessageBox, and after I clicked OK, then it complained like the others.  There’s nothing different in the way I constructed the Event Handlers for these three buttons, and they all appear to be doing the same thing, but obviously there’s something happening differently with the uiConfig_Click() handler.

Once I set Breakpoints on all three of these handlers, I realized that only the uiConvert_Click() is actually executing the Sub, which is weird — this event handler is catching the Click event for the Configure button; the other two buttons are erroring before they even try to execute their code.

…Hmm, looks like I found the problem.  I’d originally started out with three separate blocks of near-identical code to generate the three CommandBarButtons and all their Properties.  Then, when I got the crazy idea to make my code more elegant, I collapse them into a single For Each loop.  This really made the code easier to follow, but I forgot to deal with the variable used to configure each of the buttons.

Right now, the loop performs all operations in each iteration on the variable uiConvert, which is typed a CommandBarButton.  What I actually need to do is have the For Each loop act on three separate variables (uiConvert, uiUpload and uiConfig) during its three iterations, so that the three buttons get configured properly. 

To try to fix this, I’ve tried adding a member to the Structure of type CommandBarButton that references the CommandBarButton variable for each button.  Then I use that Structure member in the For Each loop to assign all button Properties, thinking that it’d implicitly be configuring the referenced CommandBarButton variable.  Unfortunately, it doesn’t seem to quite work that way.

This code fragment should explain where I’m currently at:

    Structure CommandBarButtonSettings
        Public ButtonVariable As Office.CommandBarButton
        Public Tag As String
        Public StyleProperty As Office.MsoButtonStyle
        ...
    End Structure
        ...



Dim buttonSettings As New CommandBarButtonSettings()
        Dim buttonsList As New ArrayList()

        buttonSettings.BeginGroupProperty = True
        buttonSettings.ButtonVariable = uiConvert
        buttonSettings.StyleProperty = Office.MsoButtonStyle.msoButtonIconAndCaption
        ...

        buttonsList.Add(buttonSettings)
        For Each _buttonSettings As CommandBarButtonSettings In buttonsList

            'Create the CommandBarButton if it doesn't exist
            If W2MWPPBar.FindControl(Tag:=_buttonSettings.Tag) Is Nothing Then
(*)                buttonSettings.ButtonVariable = CType(W2MWPPBar.Controls.Add(1), Office.CommandBarButton)
            Else
                ' If it already exists, do not create the CommandBarButton but just obtain a handle to it
(*)                buttonSettings.ButtonVariable = W2MWPPBar.FindControl(Tag:=_buttonSettings.Tag)
            End If

            Try
(*)                With buttonSettings.ButtonVariable
                    .BeginGroup = _buttonSettings.BeginGroupProperty
                    .Style = _buttonSettings.StyleProperty
                    ...
                End With

                ...

            End Try

        Next

The problem is with the code marked with an (*), and I’m stumped on now to resolve this problem.

Aside: Update for VSTO SE available

If you’re using VSTO SE add-in for Visual Studio, then make sure you’ve installed the VSTO SE Update that Microsoft released a couple of months ago.  I didn’t know about this, and though it probably won’t affect my code, it’s never a bad thing to be sure.

Yes, in fact I *do* get mistaken a lot for…

Couldn’t help myself, and I was still surprised by the result:

What American accent do you have?

Your Result: North Central
 

“North Central” is what professional linguists call the Minnesota accent. If you saw “Fargo” you probably didn’t think the characters sounded very out of the ordinary. Outsiders probably mistake you for a Canadian a lot.

The Midland
 
Boston
 
The West
 
Philadelphia
 
The Inland North
 
The South
 
The Northeast
 
What American accent do you have?
Quiz Created on GoToQuiz

Porting Word2MediaWikiPlus to VB.NET: Part 8

Previous articles in this series: Prologue, Part 1, Part 2, Part 3, Part 4, Part 6, Part 7.]

Troubleshooting ThisAddIn.Startup() continued…

OK, once more and gently (as my dad always used to say): my best theory now is that my code needs to create an object that represents the W2MWPP toolbar, and create this object whether the toolbar exists or not.  Once I have that object, then I can finally get the toolbar buttons instantiated and get on with the Wiki functionality [yeah, famous last words].

I figure that the code should test whether it can find an existing instance of the toolbar.  If it can’t find it, then it should create it; if it can find it, then just assign it to a variable and we’re done.

BTW, I found a great idea in VSTO for Mere Mortals (McGrath, Stubbs): rather than continuously referring to “Word2Wiki Toolbar” as a string, I could define a CONST and then reference the CONST instead.  [This has the added advantage that I could change the string value very easily if “Word2Wiki Toolbar” was no longer suitable.]  Why didn’t I think of this myself?

Here’s the code I’ve finally come up with to instantiate the Word2Wiki toolbar:

        Try
' Create a new CommandBar instance, if it doesn't already exist
If commandBarsCollection.FindControl(Tag:=TOOLBAR_NAME) Is Nothing Then
W2MWPPBar = commandBarsCollection.Add(TOOLBAR_NAME, Microsoft.Office.Core.MsoBarPosition.msoBarTop, False, True)
Else
W2MWPPBar = Application.CommandBars(TOOLBAR_NAME)
End If

Catch ex As System.ArgumentException
MessageBox.Show(TOOLBAR_NAME + "add-in's toolbar wasn't found - you won't be able to upload to the Wiki until you restart Word and/or reinstall the Add-in." + _
vbCrLf + vbCrLf + "Error: " + ex.Message, "Add-in Error", MessageBoxButtons.OK, MessageBoxIcon.Warning)
End Try

Note: I’m not sure, but I suspect it’ll still thrown an exception on the first try.  However, it may just “take” on the second try, so that might be good enough for now.

Aside: CommandBars vs. Ribbon UI in Office 2007

While researching the CommandBar methods, I found this statement: “The use of CommandBars in some Microsoft Office applications has been superseded by the new Ribbon user interface.”  Oops, that’s right – some of this functionality may have to be re-written for Office 2007.  I’ll try to ensure the CommandBar-specific code can be decoupled from the application functionality, so we can get maximum reuse out of these efforts.

Next Issue: Word Template (changes to Normal.dot)

After instantiating the Toolbar successfully, Word 2003 at shutdown will ask me twice whether I want to save changes to Normal.dot.  The first prompt only allows you to overwrite Normal.dot or cancel out of the shutdown of Word.

If I hit Cancel, then the second time I try to shut down Word, it prompts me with:

“Changes have been made that affect the global template, normal.dot.  Do you want to save those changes?”

This time, I can say “No” to saving the changes, which leaves Normal.dot in its original form and finally lets me close Word.  The help text for this second prompt says,

“This message can appear if you made changes to items, such as macros, toolbars, or AutoText, that are stored in a global template that is attached to your document. The most commonly used global template is Normal.dot, which comes with Word.”

Next Issue: CommandBarButton creation

In the code, I’m using a well-documented sample to add the CommandBarButton to the CommandBar, and yet I’m getting the error

************** Exception Text **************
System.ArgumentException: Value does not fall within the expected range.
   at Microsoft.Office.Core.CommandBarsClass.get_Item(Object Index)
   at Word2MediaWiki__.ThisAddIn.ThisAddIn_Startup(Object sender, EventArgs e) in \Word2MediaWiki++\ThisAddIn.vb:line 50
   at Microsoft.Office.Tools.AddIn.OnStartup()
   at Word2MediaWiki__.ThisAddIn.FinishInitialization() in \Word2MediaWiki++\ThisAddIn.Designer.vb:line 65

Now that I know how to read this exception (see Part 7 for that whole twisty maze), I’ll spend a whole lot less time deciphering it.  This time it seems clear to me that it’s a problem with allocating a handle to the toolbar.  However, because I know that the toolbar is being created properly, a second glance at the offending line of code gives me the answer:

            ConvertControl = CType(Application.CommandBars("W2MWPPBar").Controls.Add(1), Office.CommandBarButton)

This one is easy: I’m mistakenly calling “W2MWPPBar” rather than “Word2Wiki Toolbar”.  Let’s fix that: highlight the string, right-click, choose Refactor (or Refactor!), and find…nothing.  D’oh — that’s right, the VB.NET refactoring tools (even the Refactor! add-on for Visual Studio) don’t have the Rename function that I’ve gotten used to in the C# world.  Guess I’m just going to have to try Edit, Find and Replace, Replace in Files instead.

With the Const now properly in place, the CommandBar and its buttons fall neatly into place.  Wasn’t that easy? 😉

Enhancement: Creating the CommandBarButton if it doesn’t exist

There’s two improvements I’ll make to the code that creates each CommandBarButton:

  1. I’ll mirror the way I construct the CommandBar – test if each CommandBar button exists, and if not, create it; if so, leave it alone.  [McGrath’s code in VSTO for Mere Mortals will Delete the existing button and then create it — I don’t know why this should be necessary, so I’ll simplify this code for now.]
  2. Replace calls to Application.CommandBars(TOOLBAR_NAME) with an object for the toolbar itself (W2MWPPBar).

Here’s the current code:

        For Each control As Microsoft.Office.Core.CommandBarControl In commandBarControlsCollection
If control.Tag = "W2MWPP Convert" Then
ConvertControl = control
buttonExists = True
Exit For
End If
Next

If buttonExists = False Then
'Create a new ControlButton
ConvertControl = CType(Application.CommandBars(TOOLBAR_NAME).Controls.Add(1), Office.CommandBarButton)
End If

And here’s my enhanced approach:

        If W2MWPPBar.FindControl(Tag:="W2MWPP Convert") Is Nothing Then
ConvertControl = CType(W2MWPPBar.Controls.Add(1), Office.CommandBarButton)
Else
ConvertControl = W2MWPPBar.FindControl(Tag:="W2MWPP Convert")
End If

Enhancement: implement For Each loop for the CommandBarButtons

This code is creating three CommandBarButtons using the same Methods and Properties, but doing it three separate times.  I know I’ve done this too, but I’d prefer to fix this.  Unfortunately, there’s one slight challenge for me: there’s too many variables to pass into a Sub, and I’m not very good with multi-dimensional arrays, so I don’t know what to do with all the variable strings that need to be fed in.

However, I recall another kind of construct somewhat like a multi-dimensional array, and a little digging on the ‘net and in my books leads to Structures.  Further, a nice little post to the MSDN Forums turns me on to another suitable idea: Arraylist.  Combine these two, and I should be able to pass in an arraylist of structures to a InstantiateButtons() method, and I’ll be able to loop through them all in one go.

The only trick is, the articles I’m finding right now don’t seem to give me useable advice for creating a structure in VB — or perhaps it’s just that Visual Studio isn’t cooperating, because if I type “Private Structure CommandBarButtonSettings” or “Private Type CommandBarButtonSettings”, Visual Studio doesn’t seem to generate the automatic “End Structure” or “End Type” statements that appear to be necessary.

The book “The Visual Basic .NET Programming Language” (Vick) showed a very simple way to write the code for a Structure, and once I tried that VS started instructing me on what I needed to add/rearrange for this to work.  One thing that hadn’t been clear is that the Structure has to appear outside of any Method, so I’ve moved it up to just after the Public Class statement.

BTW, I just stumbled across the concept of “composite formatting“, which I’m going to try to use in my MessageBox.Show() calls here.  The code sample in the MSDN Forum post mentioned above, from which I borrowed, happened to use composite formatting in their Console.Writeline() call, which tipped me off to this elegant way of generating strings with dynamic content scattered throughout.  I don’t know about you, but I’m a bit tired of all the ” + variable.ToString() + “ nonsense that I have to embed so often in my apps.

Enhancement: implement String.Empty

I’m not even sure where I read this, but it was related to some of my research into the rules that good code should follow: where an application needs to set a String variable with an empty value, we should use String.Empty instead of “”.  Thus I’m making changes such as from this:

        buttonSettings.DescriptionTextProperty = ""

to this:

        buttonSettings.DescriptionTextProperty = String.Empty

Milestone: Toolbar works!

Well I suspect you’re all just *dying* to see this app working — “wow, a toolbar with buttons that do *nothing*?  What a wonder!”  I’m going to mark the occasion on this day by creating a CodePlex project for this Add-In and uploading the current Source Code so everyone can have a laugh. 😉

Please have a look here, and leave any Comments, Issues or Suggestions that come to mind.  Any and all such assistance is appreciated.  Browse to here: http://www.codeplex.com/word2mediawikipp

Lightbulb joke for Dog Breeds

Copied from a post on Craigslist:

QUESTION: How many dogs does it take to change a light bulb?

Golden Retriever: The sun is shining, the day is young, we’ve got our whole lives ahead of us, and you’re inside worrying about a burned-out bulb?

Border Collie: Just one. And then I’ll replace any wiring that’s not up to code.

Dachshund: You know I can’t reach that ****ed stupid lamp!

Rottweiler: Make me.

Lab: Oh, me, me!!!! Pleeeeeeze let me change the light bulb! Can I? Can I? Huh? Huh? Huh? Can I?

Siberian Husky: Let the Border Collie do it. You can feed me while he’s busy.

Jack Russell Terrier: I’ll just pop it in while I’m bouncing off the walls and furniture.

Poodle: I’ll just blow in the Border Collie’s ear and he’ll do it. By the time he finishes rewiring the house, my nails will be dry.

Cocker Spaniel: Why change it? I can still pee on the carpet in the dark.

Doberman Pinscher: While it’s dark, I’m going to sleep on the couch.

Boxer: Who cares? I can still play with my squeaky toys in the dark……

Mastiff: Mastiffs are NOT afraid of the dark.

Chihuahua: Yo quiero Taco Bulb.

Irish Wolfhound: Can somebody else do it? I’ve got this hangover…..

Pointer: I see it, there it is, there it is, right there….

Greyhound: It isn’t moving. Who cares?

Australian Shepherd: First, I’ll put all the light bulbs in a little circle….

Old English Sheep Dog: Light bulb? I’m sorry, but I don’t see a light bulb?

German Shepherd: Alright, everyone stop where you are! Who busted the light? I SAID,”STOP WHERE YOU ARE!!!”

Hound Dog: ZZZZZZZZZzzzzzzzzz

Cat: Dogs do not change light bulbs. People change light bulbs. So the question is: How long will it be before I can expect light?

Porting Word2MediaWikiPlus to VB.NET: Part 7

Previous articles in this series: Prologue, Part 1, Part 2, Part 3, Part 4, [no Part 5 – apparently I lost the ability to count], Part 6.]

Troubleshooting ThisAddIn.Startup() continued…

Still struggling with getting the CommandBar and CommandBarButton instantiated in the ThisAddIn.Startup() Sub.  I’m finding that the initial exploration of the CommandBar to see if there is a pre-existing instance of the “W2MWPP Convert” button is not working.  The code starts off like this:

        Dim MyControl As Microsoft.Office.Core.CommandBarButton
        MyControl = Application.CommandBars("W2MWPPBar").FindControl(Tag:="W2MWPP Convert")

Then when I debug (F5) this addin, Word reports an unhandled exception with the error “Value does not fall within the expected range”.  I seem to recall having this same problem with my previous VSTO Word AddIn until I first had the button created — then, the next time I ran the addin, it had something to FindControl().  At present, since the button doesn’t exist, it appears that FindControl() is getting “jammed” and I’m never going to get anywhere (kind of a chicken-and-egg problem).

It will be easy to get around this problem on my computer, but I’m afraid that when I build and release this add-in for others to install, if I start the code with a FindControl() call when there’s no button to find, no one else will be able to use this addin either.

Alternative approach to creating the CommandBarButton?

I have to imagine that there’s another way to skin the cat: if we need to determine if the button exists before attempting to create it, but trying to find it by name isn’t working, then perhaps there’s some CommandBar control collection that we could iterate through, and compare the Tag value for each (if any) to find the one we want.  That should go something like this:

Dim commandBarControlsCollection As Office.CommandBarControls = W2MWPPBar.Controls
Dim buttonExists As Boolean

For Each control As Microsoft.Office.Core.CommandBarControl In commandBarControlsCollection
      If control.Tag = "W2MWPP Convert" Then
          MyControl = control
          buttonExists = True
      End If
Next

If buttonExists = False Then
      'Create a new ControlButton
      MyControl = Application.CommandBars("W2MWPPBar").Controls.Add(Type:=Microsoft.Office.Core.MsoControlType.msoControlButton)
End If
Is it a Variable Scope issue?

This still doesn’t resolve the error, so I’m continuing to search for good example code from folks who should know how to construct VSTO code.  This blog entry from the VSTO team has an interesting thing to say:

You should declare your variables for the command bar and buttons at the class level so that your buttons don’t suddenly stop working.

The referenced article (which I’ve linked from Archive.org — the Internet Wayback Machine”) says:

The solution is to always declare your toolbar/menu/form variables at the class level instead of inside the method where they’re called. This ensures that they will remain in scope as long as the application is running.

I wonder whether this advice was more relevant to document-based VSTO projects rather than the application-level add-ins that are possible today — but something tells me it can’t hurt either way, and it’s worth trying to see if it changes anything about the errors above.

Result: unfortunately, this isn’t a problem of variable scope.  In taking a closer look at the exception, here’s the first-level exception:

System.ArgumentException: Value does not fall within the expected range.
   at Microsoft.Office.Core.CommandBarsClass.get_Item(Object Index)

Am I looking at the wrong object?

What exactly is the problem?  Is this saying that get_Item() is failing to get the CommandBar, or the CommandBarButton?  I’ve assumed up to now that it’s a problem referencing the CommandBarButton, since the CommandBar is getting created in Word each time I Debug this add-in.  However, now that I’m looking at it, CommandBarsClass.get_Item() seems more likely to be acting on the CommandBar than the button (or else it’d refer to something like CommandBarButtonsClass.get_Item(), no?).

What’s odd, however, is that the VS Object Browser doesn’t even have an entry for CommandBarsClass — when I search for that term, no results come up, and when I search on “CommandBars”, the closest thing I can find is the “Class CommandBars” entry, which doesn’t have a get_Item() method.

Searching in MSDN, I found the entry for CommandBarsClass Members, which doesn’t reference the get_Item() method but does mention an Item Property.  That page says a very curious thing:

This property supports the .NET Framework infrastructure and is not intended to be used directly from your code.

I wonder what that’s all about then?  In fact, the documentation for the CommandBarsClass Class also says the same thing.  I can understand that there are some “internal functions” generated by the compiler that aren’t really meant for use in my code, but it’s really tough to debug a problem when these constructs barely get a stub page and there’s no information to explain what I should think when one of these things pops up in my day-to-day work.

I feel like I’m chasing my tail here — now I’m back on the Members page, hoping that one of the Properties or Methods that are documented will help me deduce whether this class references the CommandBar or the CommandBarButton when it calls get_Item() [and maybe even help me figure out why a just-created CommandBar object can’t be referenced in code].

The best clue I’m coming up with so far is that the page documenting the Parent Property shows that under J#, there’s what appears to be a get_Parent() method, not existing in the other languages mentioned, which leads me to believe that the get_Item() method is something generated by the compiler when it needs to get the value of the Item Property.  [At least I’m learning something for all my trouble…]

The only other tantalizing tidbit so far is that the CommandBarsClass page indicates that this class implements interfaces that all refer to CommandBar, not to any controls associated with the CommandBar: _CommandBars, CommandBars, _CommandBarsEvents_Event.  I can’t tell the difference between the first two (at least from the docs), but obviously the Event interface is its own beast.

Success: it’s the CommandBar!

I think I have confirmation, finally: the docs for _CommandBars.Item state that the Item Property “Returns a CommandBar object from the CommandBars collection.”  OK, so now I finally know: my code is barfing on trying to access the just-created CommandBar, not the CommandBarButton as I thought all along.  Whew!

Aside: Re-Using Variables

I’m not much of a code snob yet — there’s very few things I know how to do “right”.  However, I’ve found something that just doesn’t seem right in the original VBA code that I’m going to change.

The original code sets up three separate buttons in the CommandBar, and each time the code looks for the button, then creates it, then configures it, it’s using the exact same variable each time: MyControl.  I know this obviously worked (at least in the VBA code), so it’s hardly illegal, but it seems much safer to create three variables and instantiate them separately.  Maybe it’s just so that I can follow the code easier, I don’t know.  In any case, I’m having a hard time with it so I’m going to call them each something else.

However, I’m not so much of a snob that I’ll create three boolean variables to track whether I’ve found an existing instance of the button, so I’m going to re-use the buttonExists variable.

 

Keep tuning in… someday I’ll actually start getting into Wiki-related code (I swear!)