automating tedious tasks in visual studio 2005 with macros and autohotkey
yes, we are still using visual studio 2005 for our development, although we hope to cut over to 2010 in the next few weeks. anyways, a customer was having problems printing reports to a particular printer, and from previous research i knew the problem was turning the "No Printer" option on in the crystal reports designer.
now we have a lot of reports, so i wanted to automate this process for all our reports. so i turned to the built-in scripting functions of visual studio, however, it turns out that you can't control dialogs through macros. so one person recommended using autohotkey, and i had a basic knowledge of that, so I would give it a try.
so i ended up using a combination of visual studio macros & autohotkey, and it works fairly well. it still errors how during processing, but i added code so it skips any projects that have already been opened or expanded in the solution explorer. here is the macro code:
Sub SetCrystalNoPrinter()
' get then instance of the solution explorer
Dim se As UIHierarchy = DTE.Windows.Item(Constants.vsext_wk_SProjectWindow).Object()
Dim bg As New System.ComponentModel.BackgroundWorker()
AddHandler bg.DoWork, AddressOf OpenReports
bg.RunWorkerAsync(se)
End Sub
Private Sub OpenReports(ByVal sender As Object, ByVal e As System.ComponentModel.DoWorkEventArgs)
Dim uih As UIHierarchy = e.Argument
Try
Dim fn As String
Dim report As String
uih.DTE.SuppressUI = True
For Each p As Project In DTE.Solution.Projects
If CheckProject("Reporting\" & p.Name, uih) Then
For Each pi As ProjectItem In p.ProjectItems
For i As Integer = 1 To pi.FileCount
fn = pi.FileNames(i)
If IO.Path.GetExtension(fn).ToLower() = ".rpt" Then
report = "Reporting" & pi.ContainingProject.Name & "\" & IO.Path.GetFileName(fn)
OpenReport(report)
SetPrinterSettings()
System.Threading.Thread.Sleep(100)
DTE.ActiveDocument.Close(vsSaveChanges.vsSaveChangesYes)
System.Threading.Thread.Sleep(200)
End If
Next
Next
End If
Next
Catch ex As Exception
System.Windows.Forms.MessageBox.Show(ex.ToString())
Finally
uih.DTE.SuppressUI = False
End Try
End Sub
Private Function CheckProject(ByVal Project As String, ByVal uih As UIHierarchy) As Boolean
DTE.Windows.Item(Constants.vsWindowKindSolutionExplorer).Activate()
DTE.ActiveWindow.Object.GetItem(Project).Select(vsUISelectionType.vsUISelectionTypeSelect)
System.Threading.Thread.Sleep(200)
For Each i As UIHierarchyItem In uih.SelectedItems
Return Not i.UIHierarchyItems.Expanded
Next
Return False
End Function
Private Sub OpenReport(ByVal Report As String)
DTE.Windows.Item(Constants.vsWindowKindSolutionExplorer).Activate()
DTE.ActiveWindow.Object.GetItem(Report).Select(vsUISelectionType.vsUISelectionTypeSelect)
System.Threading.Thread.Sleep(200)
DTE.ExecuteCommand("View.Open")
End Sub
Private Sub SetPrinterSettings()
Dim p As System.Diagnostics.Process
p = System.Diagnostics.Process.Start("pathtocrystalprintsetup.exe")
p.WaitForExit()
End Sub
yes, there is a lot going on there. i had to use a background worker because visual studio would block when waiting for the ahk application to exit.
autohotkey code:
; send key combination to get the print setup dialog open in crystal
send !rsp
WinWait, Print Setup
ControlGet chk, Checked,, No Prin&ter, Print Setup
if chk = 0
{
send t
}
send {Enter}
WinWaitClose
it's not pretty, but it (sort of) works! i will add more detailed explanations of what is going on soon.