Automating Visual Studio 2010 from a console app - vb.net

I am trying to run the following code (which I got from here). The code just creates a new "Output" pane in Visual Studio and writes a few lines to it.
Public Sub WriteToMyNewPane()
Dim win As Window = _
dte.Windows.Item(EnvDTE.Constants.vsWindowKindOutput)
Dim ow As OutputWindow = win.Object
Dim owPane As OutputWindowPane
Dim cnt As Integer = ow.OutputWindowPanes.Count
owPane = ow.OutputWindowPanes.Add("My New Output Pane")
owPane.Activate()
owPane.OutputString("My text1" & vbCrLf)
owPane.OutputString("My text2" & vbCrLf)
owPane.OutputString("My text3" & vbCrLf)
End Sub
Instead of running it as a Macro, I want to run it as an independent console application that connects to a currently running instance of Visual Studio 2010. I'm having a hard time figuring out how to set the value of dte. I think I may need to call GetActiveObject, but I'm not sure how. Any pointers?

Yes, this is somewhat possible, the DTE interface supports out-of-process activation. Here's sample code that shows the approach:
Imports EnvDTE
Module Module1
Sub Main()
Dim dte As DTE = DirectCast(Interaction.CreateObject("VisualStudio.DTE.10.0"), EnvDTE.DTE)
dte.SuppressUI = False
dte.MainWindow.Visible = True
Dim win As Window = dte.Windows.Item(Constants.vsWindowKindOutput)
Dim ow As OutputWindow = DirectCast(win.Object, OutputWindow)
Dim owPane As OutputWindowPane = ow.OutputWindowPanes.Add("My New Output Pane")
owPane.Activate()
owPane.OutputString("My text1" & vbCrLf)
owPane.OutputString("My text2" & vbCrLf)
owPane.OutputString("My text3" & vbCrLf)
Console.WriteLine("Press enter to terminate visual studio")
Console.ReadLine()
End Sub
End Module
The previous to last statement shows why this isn't really practical. As soon as your program stops running, the last reference count on the coclass disappears, making Visual Studio quit.

Related

My.User.CurrentPrincipal not working in Class Library

I am trying to get the current username in a Windows environment that uses Windows Authentication. The code exists in a class library that is built and referenced within a separate Visual Studio application:
Function GetUserName() As String
If TypeOf My.User.CurrentPrincipal Is
Security.Principal.WindowsPrincipal Then
' The application is using Windows authentication.
' The name format is DOMAIN\USERNAME.
Dim parts() As String = Split(My.User.Name, "\")
Dim username As String = parts(1)
Return username
Else
' The application is using custom authentication.
Return My.User.Name
End If
End Function
I get an error when it's located in the class library. My.User.CurrentPrincipal comes back with {System.Security.Principal.GenericPrincipal} and My.User.Name is blank. When I put the exact same code into a brand new windows forms application it works - My.User.CurrentPrincipal comes back with {System.Security.Principal.WindowsPrincipal} and My.User.Name is the user's login name.
Microsoft documentation suggests that the My.User object will work in class libraries. Does anyone know why I'm getting different values when it's put into a class library and added as a .dll reference to a parent application?
The parent application is a class library that is an add-in for Microsoft PowerPoint. The code in the parent application that calls the above code (called UsageDataCollection.dll) is:
Public Class rbnOvaPowerPoint
Private DataCollector As UsageDataCollection.DataCollector
Private Sub butShare_Click(sender As Object, e As RibbonControlEventArgs) Handles butShare.Click
OtherTasks.CreateMailItem()
End Sub
End Class
And then in a separate module:
Module OtherTasks
Private DataCollector As New UsageDataCollection.DataCollector
Sub CreateMailItem()
Dim OutlookApp As Outlook._Application = CreateObject("Outlook.Application")
Dim mail As Outlook.MailItem = Nothing
Dim mailRecipients As Outlook.Recipients = Nothing
Dim mailRecipient As Outlook.Recipient = Nothing
DataCollector.UsageStatistics("CreateMailItem")
Try
mail = OutlookApp.CreateItem(Outlook.OlItemType.olMailItem)
mail.Subject = "OvaPowerPoint"
mail.Body = "Check out OvaPowerPoint, a custom-built Arup add-in for PowerPoint!" & Strings.Chr(13) & Strings.Chr(13) & "About the Add-In:" & Strings.Chr(13) & "http://wiki.oasys.intranet.arup.com/X-Wiki/index.php/OvaPowerPoint" & Strings.Chr(13) & Strings.Chr(13) & "Installation File:" & Strings.Chr(13) & "\\n-ynas12\Software\Custom%20Applications\Plug-Ins\Microsoft%20PowerPoint\OvaPowerPoint\setup.exe"
mail.Display(True)
Catch ex As Exception
System.Windows.Forms.MessageBox.Show(ex.Message,
"An exception is occured in the code of add-in.")
Finally
If Not IsNothing(mailRecipient) Then System.Runtime.InteropServices.Marshal.ReleaseComObject(mailRecipient)
If Not IsNothing(mailRecipients) Then System.Runtime.InteropServices.Marshal.ReleaseComObject(mailRecipients)
If Not IsNothing(mail) Then System.Runtime.InteropServices.Marshal.ReleaseComObject(mail)
End Try
End Sub
End Module
And the UsageStatistics subroutine in UsageDataCollection.dll looks like:
Imports System.IO
Imports System.Text
Public Class DataCollector
Public Sub UsageStatistics(myAction As String)
Dim myAssemblyName As String = System.Reflection.Assembly.GetCallingAssembly.GetName.Name
Dim myFilePath As String = "\\n-ywpress01\uploads\UsageData\" & myAssemblyName & ".csv"
Using LogFile As New StreamWriter(myFilePath, True)
LogFile.WriteLine("[" & DateTime.Now.ToUniversalTime.ToString("yyyy/MM/dd HH':'mm':'ss") & "]" & Chr(44) & GetUserName() & Chr(44) & GetUserLocation() & Chr(44) & myAction)
LogFile.Close()
End Using
End Sub
End Class
Thanks
Zak
In the MS docs, it says
For Windows applications, only projects built on the Windows Application template initialize the My.User object by default. In all other Windows project types, you must initialize the My.User object by calling the My.User.InitializeWithWindowsUser Method explicitly or by assigning a value to CurrentPrincipal.
The fix in your code is:
Function GetUserName() As String
My.User.InitializeWithWindowsUser() 'pulls the network credentials into .NET
If TypeOf My.User.CurrentPrincipal Is
Security.Principal.WindowsPrincipal Then
' The application is using Windows authentication.
' The name format is DOMAIN\USERNAME.
Dim parts() As String = Split(My.User.Name, "\")
Dim username As String = parts(1)
Return username
Else
' The application is using custom authentication.
Return My.User.Name
End If
End Function

How to use addin interface in Visual Studio 2008

Following is a code sample of Addin I copied from MSDN(http://msdn.microsoft.com/en-us/library/vstudio/envdte.addin.aspx) and did some modifications to. I create a Add-in project by VS2008 and paste the following code into it.
But it seems that it does not work properly.
1> DTE Add-in count before and after the Update does not change
2> Guid of the added addin is all zeros
3> I get error: The parameter is incorrect, at code line: DTE.Solution.AddIns.Add
Public Sub OnConnection(ByVal application As Object, ByVal connectMode As ext_ConnectMode, ByVal addInInst As Object, ByRef custom As Array) Implements IDTExtensibility2.OnConnection
_applicationObject = CType(application, DTE2)
_addInInstance = CType(addInInst, AddIn)
Me.AddInExample(_applicationObject)
End Sub
Function BrowseFile() As String
Dim OpenFileDialog1 As New OpenFileDialog
OpenFileDialog1.Filter = "*.dll file (*.dll)|*.dll|All files (*.*)|*.*"
OpenFileDialog1.FilterIndex = 1dialog
OpenFileDialog1.RestoreDirectory = True
If OpenFileDialog1.ShowDialog() = System.Windows.Forms.DialogResult.OK Then
'MsgBox(OpenFileDialog1.FileName)
Return OpenFileDialog1.FileName
End If
Return ""
End Function
Sub AddInExample(ByVal DTE As DTE2)
' For this example to work correctly, there should be an add-in
' available in the Visual Studio environment.
' Set object references.
Dim addincoll As AddIns
Dim addinobj As AddIn
' Register an add-in, check DTE Add-in count before and after the
' Update.
addincoll = DTE.AddIns
MsgBox("AddIns collection parent name: " & addincoll.Parent.Name)
MsgBox("Number of Add-ins: " & addincoll.Count)
' NOTE: Use regsvr32 for Visual C++, regasm for [Visual Basic
' and Visual C#. Also, the pathname used below is an example only.
'Shell("regasm F:\AddIns\RegExplore\Debug\regexplore.dll")
'Shell("C:\Windows\Microsoft.NET\Framework\v4.0.30319\regasm e:\AddinTest1.dll")
Shell("C:\Windows\Microsoft.NET\Framework\v4.0.30319\regasm " & BrowseFile())
addincoll.Update()
MsgBox("Number of Add-ins: " & addincoll.Count)
addinobj = addincoll.Item(1)
' Connect the add-in if it is not already connected
' and list its SatelliteDLLPath and Guid.
If addinobj.Connected = False Then
addinobj.Connected = True
End If
MsgBox("Satellite DLL Path: " & addinobj.SatelliteDllPath)
MsgBox("DLL GUID: " & addinobj.Guid)
' Activates a solution add-in so that it is available, then
'deactivates it.
MsgBox(addinobj.ProgID)
MsgBox(addinobj.Description)
MsgBox(addinobj.Name)
addinobj = DTE.Solution.AddIns.Add(addinobj.ProgID, addinobj.Description, addinobj.Name, False)
DTE.Solution.AddIns.Item(1).Remove()
End Sub
I would start at the begining if I were you: MSDN VS Addin
Doing it this way allows you to debug (step-through) your code and will give you a good start. The page you are on assumes you already know how to do this.

Convert traditional vb to vb.net 2010

Can someone help me to convert this to vb.net 2010 code. I have a window that has textbox1, i found this code bt cldnt figure ho i can write it in vb.net 2010
Imports System.Diagnostics
Module Module1
Sub Main()
Dim pc As New PerformanceCounterCategory("Network Interface")
Dim instance As String = pc.GetInstanceNames(0)
Dim bs As New PerformanceCounter("Network Interface", "Bytes Sent/sec", instance)
Dim br As New PerformanceCounter("Network Interface", "Bytes Received/sec", instance)
Console.WriteLine("Monitoring " & instance)
Do
Dim kbSent As Integer = bs.NextValue() / 1024
Dim kbReceived As Integer = br.NextValue() / 1024
Console.WriteLine(String.Format("Bytes Sent {0}k Bytes Received {1}k", kbSent, kbReceived))
Threading.Thread.Sleep(1000)
Loop
End Sub
End Module
It looks like a console app,
What you may be struggling with is how to get the data into your textbox?
Where-as in your sample it was being written to the console window.
Simply change THESE lines and you should be fine.
Console.WriteLine("Monitoring " & instance)
Change the above for:
Texbox1.text = "Monitoring " & instance & vbcrlf
Also change this line
Console.WriteLine(String.Format("Bytes Sent {0}k Bytes Received {1}k", kbSent, kbReceived))
change it to:
Textbox1.Text = Textbox1.Text & String.Format("Bytes Sent {0}k, Bytes Received {1}k", kbSent, kbReceived)

Extracting Filename and Path from a running process

I'm writing a screen capture application for a client. The capture part is fine, but he wants to get the name and path of the file that the capture is of.
Using system.diagnostics.process I am able to get the process that the capture is of, and can get the full path of the EXE, but not the file that is open.
ie. Notepad is open with 'TextFile1.txt' as its document. I can get from the process the MainWindowTitle which would be 'TextFile1.txt - Notepad' but what I need is more like 'c:\users....\TextFile1.txt'
Is there a way of getting more information from the process?
I'm sure there is a way, but I can't figure it out
Any help greatly appreciated.
You can use ManagementObjectSearcher to get the command line arguments for a process, and in this notepad example, you can parse out the file name. Here's a simple console app example that writes out the full path and file name of all open files in notepad..
Imports System
Imports System.ComponentModel
Imports System.Management
Module Module1
Sub Main()
Dim cl() As String
For Each p As Process In Process.GetProcessesByName("notepad")
Try
Using searcher As New ManagementObjectSearcher("SELECT CommandLine FROM Win32_Process WHERE ProcessId = " & p.Id)
For Each mgmtObj As ManagementObject In searcher.Get()
cl = mgmtObj.Item("CommandLine").ToString().Split("""")
Console.WriteLine(cl(cl.Length - 1))
Next
End Using
Catch ex As Win32Exception
'handle error
End Try
Next
System.Threading.Thread.Sleep(1000000)
End Sub
End Module
I had to add a reference to this specific dll:
C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\System.Managment.dll
i think it is the simplest way
For Each prog As Process In Process.GetProcesses
If prog.ProcessName = "notepad" Then
ListBox1.Items.Add(prog.ProcessName)
End If
Next
I know this post is old, but since I've searched for this two days ago, I'm sure others would be interested. My code below will get you the file paths from Notepad, Wordpad, Excel, Microsoft Word, PowerPoint, Publisher, Inkscape, and any other text or graphic editor's process, as long as the filename and extension is in the title bar of the opened window.
Instead of searching, it obtains the file's target path from Windows' hidden Recent Items directory, which logs recently opened and saved files as shortcuts. I discovered this hidden directory in Windows 7. You're gonna have to check if Windows 10 or 11 has this:
C:\Users\ "username" \AppData\Roaming\Microsoft\Windows\Recent
I slapped this code together under Framework 4, running as 64bit. The COM dlls that must be referenced in order for the code to work are Microsoft Word 14.0 Object Library, Microsoft Excel 14.0 Object Library, Microsoft PowerPoint 14.0 Object Library, and Microsoft Shell Controls And Automation.
For testing, the code below needs a textbox, a listbox, a button, and 3 labels (Label1, FilenameLabel, Filepath).
Once you have this working, after submitting a process name, you will have to click the filename item in the ListBox to start the function to retrieve it's directory path.
Option Strict On
Option Explicit On
Imports System.Runtime.InteropServices
Imports Microsoft.Office.Interop.Excel
Imports Microsoft.Office.Interop.Word
Imports Microsoft.Office.Interop.PowerPoint
Imports Shell32
Public Class Form1
'function gets names of all opened Excel workbooks, adding them to the ListBox
Public Shared Function ExcelProcess(ByVal strings As String) As String
Dim Excel As Microsoft.Office.Interop.Excel.Application = CType(Marshal.GetActiveObject("Excel.Application"), Microsoft.Office.Interop.Excel.Application)
For Each Workbook As Microsoft.Office.Interop.Excel.Workbook In Excel.Workbooks
Form1.ListBox1.Items.Add(Workbook.Name.ToString() & " - " & Form1.TextBox1.Text)
Next
Return strings
End Function
'function gets names of all opened Word documents, adding them to the ListBox
Public Shared Function WordProcess(ByVal strings As String) As String
Dim Word As Microsoft.Office.Interop.Word.Application = CType(Marshal.GetActiveObject("Word.Application"), Microsoft.Office.Interop.Word.Application)
For Each Document As Microsoft.Office.Interop.Word.Document In Word.Documents
Form1.ListBox1.Items.Add(Document.Name.ToString() & " - " & Form1.TextBox1.Text)
Next
Return strings
End Function
'function gets names of all opened PowerPoint presentations, adding them to the ListBox
Public Shared Function PowerPointProcess(ByVal strings As String) As String
Dim PowerPoint As Microsoft.Office.Interop.PowerPoint.Application = CType(Marshal.GetActiveObject("PowerPoint.Application"), Microsoft.Office.Interop.PowerPoint.Application)
For Each Presentation As Microsoft.Office.Interop.PowerPoint.Presentation In PowerPoint.Presentations
Form1.ListBox1.Items.Add(Presentation.Name.ToString() & " - " & Form1.TextBox1.Text)
Next
Return strings
End Function
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
'clears listbox to prepare for new process items
ListBox1.Items.Clear()
'gets process title from TextBox1
Dim ProcessName As String = TextBox1.Text
'prepare string's case format for
ProcessName = ProcessName.ToLower
'corrects Office process names
If ProcessName = "microsoft excel" Then
ProcessName = "excel"
Else
If ProcessName = "word" Or ProcessName = "microsoft word" Then
ProcessName = "winword"
Else
If ProcessName = "powerpoint" Or ProcessName = "microsoft powerpoint" Then
ProcessName = "powerpnt"
Else
End If
End If
End If
'get processes by name (finds only one instance of Excel or Microsoft Word)
Dim proclist() As Process = Process.GetProcessesByName(ProcessName)
'adds window titles of all processes to a ListBox
For Each prs As Process In proclist
If ProcessName = "excel" Then
'calls function to add all Excel process instances' workbook names to the ListBox
ExcelProcess(ProcessName)
Else
If ProcessName = "winword" Then
'calls function to add all Word process instances' document names to the ListBox
WordProcess(ProcessName)
Else
If ProcessName = "powerpnt" Then
'calls function to add all Word process instances' document names to the ListBox
PowerPointProcess(ProcessName)
Else
'adds all Notepad or Wordpad process instances' filenames
ListBox1.Items.Add(prs.MainWindowTitle)
End If
End If
End If
Next
End Sub
Private Sub ListBox1_MouseClick(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles ListBox1.MouseClick
Try
'add ListBox item (full window title) to string
Dim ListBoxSelection As String = String.Join(Environment.NewLine, ListBox1.SelectedItems.Cast(Of String).ToArray)
'get full process title after "-" from ListBoxSelection
Dim GetProcessTitle As String = ListBoxSelection.Split("-"c).Last()
'create string to remove from ListBoxSelection
Dim Remove As String = " - " & GetProcessTitle
'Extract filename from ListBoxSelection string, minus process full name
Dim Filename As String = ListBoxSelection.Substring(0, ListBoxSelection.Length - Remove.Length + 1)
'display filename
FilenameLabel.Text = "Filename: " & Filename
'for every file opened and saved via savefiledialogs and openfiledialogs in editing software
'Microsoft Windows always creates and modifies shortcuts of them in Recent Items directory:
'C:\Users\ "Username" \AppData\Roaming\Microsoft\Windows\Recent
'so the below function gets the target path from files's shortcuts Windows created
FilePathLabel.Text = "File Path: " & GetLnkTarget("C:\Users\" & Environment.UserName & "\AppData\Roaming\Microsoft\Windows\Recent\" & Filename & ".lnk")
Catch ex As Exception
'no file path to show if nothing was saved yet
FilePathLabel.Text = "File Path: Not saved yet."
End Try
End Sub
'gets file's shortcut's target path
Public Shared Function GetLnkTarget(ByVal lnkPath As String) As String
Dim shl = New Shell32.Shell()
lnkPath = System.IO.Path.GetFullPath(lnkPath)
Dim dir = shl.NameSpace(System.IO.Path.GetDirectoryName(lnkPath))
Dim itm = dir.Items().Item(System.IO.Path.GetFileName(lnkPath))
Dim lnk = DirectCast(itm.GetLink, Shell32.ShellLinkObject)
Return lnk.Target.Path
End Function
End Class

How do I customize the auto commenting text in Visual Studio?

When I type the trigger the auto comment feature in Visual Studio (by typing "'''" or "///"), most of the XML commenting details show up that I like. However, I typically add the history tag to the documentation so I can track and changes that are made to the method over time.
Is there any way I can customize the auto commenting feature so that it will add the history tag, and potentially some generic Name - Date - Change placeholder text?
I'd suggest using GhostDoc. It generates very smart comments using /// based on your method names and parameters. Also, it is fully customizable.
I think that you could use a tool as dgarcia said but try to chose one that makes the version control insetad, Personally I'm not a huge fan of keep the "history" or track of the project using comments in the code.
If you like that way you could create your own customized version of the snippet, this is easier if you use a tool like Snippy
Copy this file to your
My Documents\Visual Studio 2005\Code Snippets[Language]\My Code Snippets\
Just be carefull to change the file if you gonna use it in VB.NET
Hope this help
Just as followup to the comment to Olivier. Here is a copy of the macro now, look for the '' Do History section to see where I inserted code.
''// InsertDocComments goes through the current document using the VS Code Model
''// to add documentation style comments to each function.
''
Sub InsertDocComments()
Dim projectItem As ProjectItem
Dim fileCodeModel As FileCodeModel
Dim codeElement As CodeElement
Dim codeElementType As CodeType
Dim editPoint As EditPoint
Dim commentStart As String
projectItem = DTE.ActiveDocument.ProjectItem
fileCodeModel = projectItem.FileCodeModel
codeElement = fileCodeModel.CodeElements.Item(1)
''// For the sample, don't bother recursively descending all code like
''// the OutlineCode sample does. Just get a first CodeType in the
''// file.
If (TypeOf codeElement Is CodeNamespace) Then
codeElement = codeElement.members.item(1)
End If
If (TypeOf codeElement Is CodeType) Then
codeElementType = CType(codeElement, CodeType)
Else
Throw New Exception("Didn't find a type definition as first thing in file or find a namespace as the first thing with a type inside the namespace.")
End If
editPoint = codeElementType.GetStartPoint(vsCMPart.vsCMPartHeader).CreateEditPoint()
''// Make doc comment start.
commentStart = LineOrientedCommentStart()
If (commentStart.Length = 2) Then
commentStart = commentStart & commentStart.Chars(1) & " "
ElseIf (commentStart.Length = 1) Then
commentStart = commentStart & commentStart.Chars(0) & commentStart.Chars(0) & " "
End If
''// Make this atomically undo'able. Use Try...Finally to ensure Undo
''// Context is close.
Try
DTE.UndoContext.Open("Insert Doc Comments")
''// Iterate over code elements emitting doc comments for functions.
For Each codeElement In codeElementType.Members
If (codeElement.Kind = vsCMElement.vsCMElementFunction) Then
''// Get Params.
Dim parameters As CodeElements
Dim codeFunction As CodeFunction
Dim codeElement2 As CodeElement
Dim codeParameter As CodeParameter
codeFunction = codeElement
editPoint.MoveToPoint(codeFunction.GetStartPoint(vsCMPart.vsCMPartHeader))
''//editPoint.LineUp()
parameters = codeFunction.Parameters
''// Do comment.
editPoint.Insert(Microsoft.VisualBasic.Constants.vbCrLf)
editPoint.LineUp()
editPoint.Insert(Microsoft.VisualBasic.Constants.vbTab & commentStart & "<summary>")
editPoint.Insert(Microsoft.VisualBasic.Constants.vbCrLf)
editPoint.Insert(Microsoft.VisualBasic.Constants.vbTab & commentStart & "Summary of " & codeElement.Name & ".")
editPoint.Insert(Microsoft.VisualBasic.Constants.vbCrLf)
editPoint.Insert(Microsoft.VisualBasic.Constants.vbTab & commentStart & "</summary>")
editPoint.Insert(Microsoft.VisualBasic.Constants.vbCrLf)
editPoint.Insert(Microsoft.VisualBasic.Constants.vbTab & commentStart)
For Each codeElement2 In parameters
codeParameter = codeElement2
editPoint.Insert("<param name=" & codeParameter.Name & "></param>")
editPoint.Insert(Microsoft.VisualBasic.Constants.vbCrLf)
editPoint.Insert(Microsoft.VisualBasic.Constants.vbTab & commentStart)
Next ''//param
''// Do history tag.
editPoint.Insert(Microsoft.VisualBasic.Constants.vbCrLf)
editPoint.LineUp()
editPoint.Insert(Microsoft.VisualBasic.Constants.vbTab & commentStart & "<history>")
editPoint.Insert(Microsoft.VisualBasic.Constants.vbCrLf)
editPoint.Insert(Microsoft.VisualBasic.Constants.vbTab & commentStart & "Name MM/DD/YYYY [Created]")
editPoint.Insert(Microsoft.VisualBasic.Constants.vbCrLf)
editPoint.Insert(Microsoft.VisualBasic.Constants.vbTab & commentStart & "</history>")
editPoint.Insert(Microsoft.VisualBasic.Constants.vbCrLf)
editPoint.Insert(Microsoft.VisualBasic.Constants.vbTab & commentStart)
End If ''//we have a function
Next ''//code elt member
Finally
DTE.UndoContext.Close()
End Try
End Sub
For some reason, after a save, rebuild, and a restart of Visual Studio, I'm not getting the history tag. Can anybody see something here I'm missing?
vb uses a xml file to load the defults. It is VBXMLDoc.xml and it depends on what version you are running as to the location of the file.