I am looking to create a Visual Studio AddIn which can help me launch my own debugging process. I want to keep the original F5 based debugging intact and hence i do not want to intercept that call and need a separate AddIn.
Any suggestions
The easiest way is to capture the system events/macros using an addin. It is really easy to override what vs does in these events. All the events are automatically fired when using the standard visual studio commands such as F5. This includes all of the standard visual studio shortcut keys, menus and tool bar buttons.
Create a new vs addin project and it will automatically add the code to attach the OnBeforeCommandEvent. In vb the event handler will look like the code below.
Friend Sub OnBeforeCommandEvent(sGuid As String, ID As Integer, CustomIn As Object, CustomOut As Object, ByRef CancelDefault As Boolean)
The event passes you sGuid and ID. You can resolve these two items to a macro string name (sCommandName) as follows:-
Dim objCommand As EnvDTE.Command
Try
objCommand = _applicationObject.Commands.Item(sGuid, ID)
Catch ex As Exception
'unknown guids can be ignored
Exit Sub
End Try
If objCommand Is Nothing Then Exit Sub
Dim sCommandName As String
sCommandName = objCommand.Name
nb: The _applicationObject is passed to your code when the addin starts. A new addin project will automatically inlude the following code for the OnConnection event, the first argument is the _applicationObject shown above.
OnConnection(ByVal application As Object
Once you have the sCommandName variable it will contain the name of a Visual Studio macro such as Debug.Start.
To override the Debug.Start functions then you would add some of your own code and remember to set CancelDefault to True before you exit the handler.
When you set CancelDefault to true Visual Studio will not run the standard macro which means you can run your own debugger when F5 is pressed.
These are Visual Studio macro names that are used during the build process. You can override as many or as few as you like. I have grouped them into their related functionality but you can handle them in any combination.
Select Case sCommandName
Case "Debug.Start", _
"Debug.StartWithoutDebugging"
System.Windows.Forms.MessageBox.Show("You clicked F5, we are overriding the debug process")
CancelDefault=true
Exit Sub
Case "ClassViewContextMenus.ClassViewProject.Rebuild", _
"ClassViewContextMenus.ClassViewProject.Build", _
"Build.RebuildOnlyProject", _
"Build.RebuildSelection", _
"Build.BuildOnlyProject", _
"Build.BuildSelection"
Case "Build.RebuildSolution", _
"Build.BuildSolution"
Case "ClassViewContextMenus.ClassViewProject.Debug.Startnewinstance", _
"ClassViewContextMenus.ClassViewProject.Debug.StepIntonewinstance"
Case "Build.CleanSelection", _
"Build.CleanSolution", _
"ClassViewContextMenus.ClassViewProject.Clean"
Case "Build.SolutionConfigurations"
Related
I have VB6 code that executes various Excel macros. I set my breakpoints in VB6 and in the the Excel macro, then begin debugging in the VB6 application. When it reaches (a breakpoint) the statement to execute the macro, it skips over the command and continue traversing through my VB6 code. I was expecting it to jump to Excel and began debugging the Excel macro. Is there some configuration or trick, to debug an Excel macro that is being called from a VB6 application?
When VB6 executes the its own code, it allows the programmer using the IDE to set breakpoints and give control to user when the execution has reached those said breakpoints. However, setting breakpoints in Excel will only benefit you if you (the programmer) have executed the macro from Excel interface. Which is not the case when VB6 is in charge of firing up Excel and telling it to execute the macros within the workbook.
Here is what you can do:
migrate all of the macro code to VB6. It is fairly easy, you just need to add few words here and there like this
'In Excel macro:
Activecell.Offset(0,1).Value = "my value"
so if we want to migrate this line of macro to VB6:
'In VB6 you must declare an instance of EXCEL application:
Dim EX as Excel.Application
EX.Workbooks.Open('c:\my_excel_file.xls')
EX.Sheets(0).Activate 'Go to the first sheet
'Then you are back to business:
EX.ActiveCell.Offset(0,1).Value = "my vlaue"
'But don't forget to close and dispose of EX instance afterwards.
EX.Activeworkbook.Close 'Check save options
EX.Quit
Set EX = Nothing
After you have migrated all of the macros functionality to VB6, you can set breakpoints in VB6 and you will have all the control over the execution and will be able to debug the code as you intended to do.
Is there way to automatically maximize the output window on hitting build and then to automatically restore to previous state when the build completes?
You could create a macro that builds the solution then activates the output window. For example:
DTE.ExecuteCommand("Build.BuildSolution")
DTE.Windows.Item(Constants.vsWindowKindOutput).Activate()
You could then replace the Build button or the build keyboard shortcut to execute that macro.
I could implement a solution using a combination of macros.
Part of the solution is in this SO question:
OnBuildBegin does not fire in Visual Studio Macro until I run it from Macro Explorer
And the other part is to use 2 exported window settings and to toggle them on build events.
Something like:
Public Sub BuildEvents_OnBuildBegin() Handles BuildEvents.OnBuildBegin
DTE.ExecuteCommand("Tools.ImportandExportSettings", "-import:C:\Development\VsSettings\build_inprocess.vssettings")
End Sub
Private Sub BuildEvents_OnBuildDone(ByVal Scope As EnvDTE.vsBuildScope, ByVal Action As EnvDTE.vsBuildAction) _
Handles BuildEvents.OnBuildDone
DTE.ExecuteCommand("Tools.ImportandExportSettings", "-import:C:\Development\VsSettings\Two_Screen.vssettings")
End Sub
I have an add-in that contains a DLL and an OCX control, built in VB6. Each is separate, meaning that the add-in consists of Addin.DLL and Addin.OCX. The add-in uses a custom form, which is built off of the IPM.Appointment form in Outlook. It is deployed to the user's machine as an OFT file and is published to their Presonal Forms Library in the initial OnConnection of the add-in.
I was having issues with the form being stuck in a one off state, which required me to add code similar the following to my AppointmentItem Write and PropertyChange class:
Private Sub AppointmentItem_PropertyChange(ByVal name As String)
On Error GoTo ErrorHandler
Select Case name
Case "MessageClass"
Dim strGuid As String
' Check to see if this is one of our appointmentitems.
If IsItemUserItem(AppointmentItem_PropertyChange, strGuid) Then
' Change to our add-in message class. IPM.Appointment.XXX
AppointmentItem.MessageClass = gFormMsgClass
End If
End Select
done:
Exit Sub
ErrorHandler:
Trace "Error writing appointment item."
Resume done
End Sub
This works for most cases. However, I'm still running into instances where when I check the item during the NewInspector event if it is an Exception I cannot access UserProperties, which are used to facilitate data sharing between the DLL and OCX.
Additionally when trying to edit the form in the form designer, I cannot save the form as an OFT from Outlook 2007. I'm kind of at a loss as to what is going on with this...Any help is appreciated.
Actually it appears I have my own answer. There were some user-defined properties added to the folder that were not added to the item and they were causing the one off issues.
I have an application written in VB.Net with Visual Studio 2005. The application allows the user to create and save project files. When I distribute the application, I include some demo project files, which I install in the common application data folder.
XP - C:\Documents and Settings\All Users\Application Data
Vista & 7 - C:\Program Data
I have discovered an unexpected behavior -- if any file in the common application data folder is removed, and the application is run from the start menu, then the install procedure will start and attempt to restore the missing file(s). If the MSI file no longer exists at its original location or has been changed, then the application will fail to run. I perceive that this is a "feature", but it is one I don't want. Can anyone tell me what is going on and how I can avoid it?
Some more details:
I created the setup package by using a Visual Studio deployment
project.
This behavior will not occur if I launch the EXE directly. I
expect, therefore, that the behavior has something to do with the
start menu shortcut. I've noticed that the shortcut isn't a normal
shortcut -- it doesn't have a "Target Location".
All advice is appreciated.
-TC
I have learned that this behavior involves something called "Install-on-Demand" (aka "Self Heal"). The unusual shortcuts created by the setup package are called "Advertised Shortcuts". Now that I have a name for the problem, it is easy to find information on how to fix it. Notably:
http://msdn.microsoft.com/en-us/library/aa368297.aspx
http://groups.google.com/group/microsoft.public.dotnet.distributed_apps/browse_thread/thread/401847045f104af3
http://blog.jtbworld.com/2007/11/enable-target-and-change-icon-of.html
Those pages contain a wealth of information. For the convenience of others who may stumble upon this post, I will summarize what they say:
Advertised shortcuts are special shortcuts which do some fancy things. Most notably, they reinstall damaged application before launching their target. There is some debate over whether they are good, evil, or harmless. In my opinion, they do something most users don't expect, and that makes them evil. Therefore, I'd like to disable them for my application.
Visual Studio setup projects automatically create MSI packages which generate advertised shortcuts by default. It is easy to override that default when installing the MSI package by using DISABLEADVTSHORTCUTS=1 as a command-line argument for Setup.exe. Also, with a utility like Orca, you can manually change the default by inserting DISABLEADVTSHORTCUTS=1 as a property of the MSI. However, if you want Visual Studio to automatically create MSI packages which don't create advertised shortcuts, that is harder. I did it this way:
First, I created a VBS file using the DisableAdvt code provided by Gary Chang in one of the links above (I've repeated that code below). Just create a text file, paste in the code. and save it as DisableAdvt.vbs.
Then, create a post-build event for your setup project. The exact syntax will depend on your file locations. Because my DisableAdvt.vbs is in a "Tools" subfolder of the solution folder, my post-build event looks like this:
"$(ProjectDir)..\Tools\DisableAdvt\DisableAdvt.vbs" "$(BuiltOuputPath)"
That's all I had to do. It works like a charm.
-TC
Some notes:
In Visual Studio 2005, Build events are accessed differently for setup projects than they are for other types of projects. Click on the project name in the solution explorer, then look for PostBuildEvent in the Properties pane.
Orca is a utility that can be used to manually insert the DISABLEADVTSHORTCUTS property into the MSI file. With my approach, Orca is not necessary. However, it is useful for verifying that the build event is making the expected change.
http://www.technipages.com/download-orca-msi-editor.html
In the build event, the misspelling "BuiltOuputPath" is intentional.
Here is Gary Chang's DisableAdvt.vbs code (note that I fixed a typo on line 21 -- Very important!):
Option Explicit
Const msiOpenDatabaseModeTransact = 1
Dim argNum, argCount:argCount = Wscript.Arguments.Count
Dim openMode : openMode = msiOpenDatabaseModeTransact
' Connect to Windows installer object
On Error Resume Next
Dim installer : Set installer = Nothing
Set installer = Wscript.CreateObject("WindowsInstaller.Installer") :
CheckError
' Open database
Dim databasePath:databasePath = Wscript.Arguments(0)
Dim database : Set database = installer.OpenDatabase(databasePath, openMode) : CheckError
' Process SQL statements
Dim query, view, record, message, rowData, columnCount, delim, column
query = "INSERT INTO Property(Property, Value) VALUES ('DISABLEADVTSHORTCUTS', '1')"
Set view = database.OpenView(query) : CheckError
view.Execute : CheckError
database.Commit
If Not IsEmpty(message) Then Wscript.Echo message
Wscript.Quit 0
Sub CheckError
Dim message, errRec
If Err = 0 Then Exit Sub
message = Err.Source & " " & Hex(Err) & ": " & Err.Description
If Not installer Is Nothing Then
Set errRec = installer.LastErrorRecord
If Not errRec Is Nothing Then message = message & vbLf & errRec.FormatText
End If
Fail message
End Sub
Sub Fail(message)
Wscript.Echo message
Wscript.Quit 2
End Sub
I guess prety much everyone who does a lot of debugging have a handy macro in Visual Studio (with shortcut to it on a toolbar) which when called automatically attaches to a particular process (identified by name).
it saves a lot of time rather than clicking "Debug" -> "Attach to the process ...", but it only works if one is running a single instance of the process one wants to attach to. If theres is more than one instance of particular process in memory - the first one (with a smaller PID?) is being choose by debugger.
Does anyone have a macro which shows a dialog (if more that 1 process with a specified name running) and lets developer to select to one he/she really wants to attach to.
I guess the selection could be made based on a windwow caption text (which would be suffice in most of cases) and when the particular instance is selected macro passes the PID of the process to the Debugger object?
If someone has that macro or knows how to write it - please share.
Thanks.
You can always attach to all instances...
Here is a macro I used when debugging asp.net applications - these typically have both a UI and a Webservice and I need to attach to both.
Sub AttachToAspNET()
Try
Dim process As EnvDTE.Process
Dim listProcess As New List(Of String)
listProcess.Add("aspnet_wp.exe")
listProcess.Add("w3wp.exe")
listProcess.Add("webdev.webserver.exe")
For Each process In DTE.Debugger.LocalProcesses
For Each procname As String In listProcess
If process.Name.ToLower.IndexOf(procname) <> -1 Then
process.Attach()
End If
Next
Next
ListDebuggedProcesses()
Catch ex As System.Exception
MsgBox(ex.Message)
End Try
End Sub