开发者

Visual Studio Macros on 64 bit fail with COM error

I'm doing some javascript development and found a cool macro to region my code ("Using #region Directive With JavaScript Files in Visual Studio"). I used this on my 32 bit box, and it worked first time. (Visual Studio 2008 SP1, Win7)

For easy of reference the macro is:

Option Strict Off
Option Explicit Off

Imports System
Imports EnvDTE
Imports EnvDTE80
Imports System.Diagnostics
Imports System.Collections

Public Module JsMacros

    Sub OutlineRegions()
        Dim selection As EnvDTE.TextSelection = DTE.ActiveDocument.Selection

        Const REGION_START As String = "//#region"
        Const REGION_END As String = "//#endregion"

        DTE.ExecuteCommand("Edit.StopOutlining")

        selection.SelectAll()
        Dim text As String = selection.Text
        selection.StartOfDocument(True)

        Dim startIndex As Integer
        Dim endIndex As Integer
        Dim lastIndex As Integer = 0
        Dim startRegions As Stack = New Stack()

        Do
            startIndex = text.IndexOf(REGION_START, lastIndex)
            endIndex = text.IndexOf(REGION_END, lastIndex)

            If startIndex = -1 AndAlso endIndex = -1 Then
                Exit Do
            End If

            If startIndex <> -1 AndAlso startIndex < endIndex Then
                startRegions.Push(startIndex)
                lastIndex = startIndex + 1
            Else
                ' Outline region ...
                selection.MoveToLineAndOffset(CalcLineNumber(text, CInt(startRegions.Pop())), text.Length)
                selection.MoveToLineAndOffset(CalcLineNumber(text, endIndex) + 1, 1, True)
                selection.OutlineSection()

                lastIndex = endIndex + 1
            End If
        Loop

        selection.StartOfDocument()
    End Sub

    Private Function CalcLineNumber(ByVal text As String, ByVal index As Integer)
        Dim lineNumber As Integer = 1
        Dim i As Integer = 0

        While i < index
            If text.Chars(i) = vbCr Then
                lineNumber += 1
                i += 1
            End If

            i += 1
        End While

        Return lineNumber
    End Function

End Module

I then t开发者_StackOverflow中文版ried to use the same macro on two separate 64 bit machines (Win7 x64), identical other than the 64 bit OS version and it fails to work. Stepping through it with the Visual Studio Macros IDE, it fails the first time on the DTE.ExecuteCommand("Edit.StopOutlining") line with a COM error (Error HRESULT E_FAIL has been returned from a call to a COM component).

If I attempt to run it a second time, I can run it from the Macro Editor with no issue, but not from within Visual Studio with the macro explorer 'run macro' command.

I have reviewed the following articles without finding anything helpful:

  • Stackoverflow: Visual Studio 2008 macro only works from the Macro IDE, not the Macro Explorer
  • Recorded macro does not run; Failing on DTE.ExecuteCommand

Am I missing something dumb?


just wrap the line

DTE.ExecuteCommand("Edit.StopOutlining")

in a try catch block and squelch the exception - i had a script for doing exactly this but the one i had didnt work - after trying yours and changing the above line to

Try

  DTE.ExecuteCommand("Edit.StopOutlining")

Catch ex As Exception

 End Try

and making the method public, i then went tools, options, keyboard and assigned the keyboard combo Ctrl M, Ctrl O to the macro MyMacros.OutLineRegions and it works like a dream come true :)

Using Windows 7 64-bit, Visual Studio 2010.. YMMV


I had a similar problem and found out by looking at every commands in the _applicationObject that a command existed twice (in my case it was Debug.SaveDumpAs) One was available and not the other. "Unluckily" enough, I always retrieved the wrong one when I executed the command.

You have to retrieve the guid and the id of the command you want and of course, you want the one available. Here's an example in C#

        string guid ="";
        int ID = 0;
        string NAMEOFCOMMAND = "Edit.StopOutLining";

        try
        {
            foreach (Command command in _applicationObject.Commands)
            {                    
                if (command.Name == NAMEOFCOMMAND)
                {
                    if(command.IsAvailable)
                    {
                        guid = command.Guid;
                        ID = command.ID;
                    }
                }
            }
            //The ExecuteCommand method cannot be used to have the right guid and id. I believe though that there is a format you can use to use it anyway. In doubt: use the Raise command which is most likely the same with additional parameters which you can set to null if you don't need them
            ((DTE)_applicationObject).Commands.Raise(guid, ID, null, null);

Cheers ! :)

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜