Access local variable from visual studio addin - vb.net

I am trying to write a visual studio addin. The following code is used to display the global variables or class names or function names of a selected text inside visual studio code window. However it do not display the variables defined inside a function. How can I modify this to display local variables?
'Call this function inside OnConnection event of the addin
Sub displayCodeElementName()
' Before running this example, open a code document from a project
' and place the insertion point inside a variable definition.
Try
' Retrieve the CodeVariable at the insertion point.
Dim sel As TextSelection = _
CType(applicationObject.ActiveDocument.Selection, TextSelection)
Dim var As CodeVariable2 = CType(sel.ActivePoint.CodeElement(vsCMElement.vsCMElementVariable), CodeVariable2)
' Display the code element name
MsgBox(var.Name & " is the name.")
Catch ex As Exception
MsgBox(ex.Message)
End Try
End sub

It appears that the underlying API is not made public by Microsoft. I did a research and nowhere I could find a way to access the code elements inside a function definition.

Related

How to get data in Access VBA from a C# method that returns an object List

I'm calling a C# WebService method called getInterventions() on a VBA Access 2003 application through a custom DLL. The signature of this method is as follows:
List<Item> getInterventions(string, string, string, string, string, string)
Item is a custom defined class.
When I try to retrieve the result of getInterventions() on VBA Access code, it pops a VBA Runtime error 242 : object required
The following is my code:
Dim WsObject As Object
Dim result As Object
Set WsObject = CreateObject("Namespace1.Path.To.Class") 'This isn't the actual DLL path as I cannot share that
'Set result = WsObject .getSingleIntervention("123, "0", "123456789", "") ' this works
Set result = WsObject .getInterventions("", "", "123456789", "", "", "") 'this doesn't work
If result Is Nothing Then
'do some stuff
Else
'do some other stuff
End If
getSingleIntervention() is a similar method which returns a single object rather than a list of objects. Returning the result of this method works without issues (see commented line). This proves that both the WS & DLL calls work. This method is defined as follows:
Item getSingleIntervention(string, string, string, string)
I have tested calling getInterventions() directly from the C# code via Visual Studio 2015 with the same parameters I'm passing in my VBA code and it worked. This proves that it's not an issue with parameters or the method content.
My conclusion:
I am guessing it's something to do with the fact that I can't simply store a C# List of objects into a VBA Object.
Any help would be appreciated, thank you.
Please, automatically add mscorlib.tlb reference, running the next code:
Sub addMscorlibRef() 'necessary to use ArrayList
'Add a reference to 'Mscorlib.dll':
'In case of error ('Programmatic access to Visual Basic Project not trusted'):
'Options->Trust Center->Trust Center Settings->Macro Settings->Developer Macro Settings->
' check "Trust access to the VBA project object model"
If dir("C:\Windows\Microsoft.NET\Framework64\v4.0.30319", vbDirectory) = "" Then _
MsgBox "You need to install ""Framework version 3.5"".": Exit Sub
On Error Resume Next
Application.VBE.ActiveVBProject.References.AddFromFile "C:\Windows\Microsoft.NET\Framework64\v4.0.30319\mscorlib.tlb"
If err.Number = 32813 Then
err.Clear: On Error GoTo 0
MsgBox "The reference already exists...": Exit Sub
Else
On Error GoTo 0
MsgBox """Mscorlib"" reference added successfully..."
End If
End Sub
Then try declaring Dim result As ArrayList.
The ArrayList is the same one that is used in C#. Then, adapt the dll to use such an object. As you deduced, no any object able to be used in VBA can receive the C# list object content.

CommandBars("Text").Controls not deleted when exiting the document - VBA word add-in

I'm trying to create a add in for MS Word with VBA.
It has a "AutoExec" procedure that creates a new item in the CommandBar("Text") collection (right click menu) and a "AutoExit" that deletes this created item.
As an example, I tried the code below that create an item "How Many Pages?", which executes a macro displaying the number of pages in the active document.
This is the AutoExec Code:
Public Sub AutoExec()
Dim objcommandbutton As CommandBarButton
Call MsgBox("AutoExec")
Set objcommandbutton = Application.CommandBars("Text").Controls.Add _
(Type:=msoControlButton, Before:=1)
objcommandbutton.Caption = "How Many Pages?"
objcommandbutton.OnAction = "HowManyPages"
End Sub
This is the AutoExit Code:
Public Sub AutoExit()
Dim objcommandbutton As CommandBarControl
Call MsgBox("AutoExit")
For Each objcommandbutton In Application.CommandBars("Text").Controls
If objcommandbutton.Caption = "How Many Pages?" Then
objcommandbutton.Delete
End If
Next objcommandbutton
End Sub
This is the Main Macro Code:
Public Sub HowManyPages()
If Documents.Count > 0 Then
Call MsgBox(ActiveDocument.BuiltInDocumentProperties("Number of Pages"))
Else
Call MsgBox("No document is currently active.")
End If
End Sub
When exiting the document, the Button previously added in CommandBars("Text") collection is not deleted. I see this when I open a new blank Word document and the button remains in the right click menu.
I know that the routine is performed correctly because there is a MsgBox instruction to verify it.
This only happen with the AutoExit subroutine of a add-in, that is, loaded as a add-in: running the code in a macro with vba module works fine.
Any help?
When working with the CommandBars object model in Word it's necessary to always specify the Application.CustomizationContext.
Word can save keyboard layouts and CommandBar customizations in various places: the Normal.dotm template, the current template or the current document. The default when you create a CommandBar addition may not be the3 same as the default when trying to delete something.
Since this is an add-in, I assume you want the change for the entire Word environment (any open document). In that case, use the context NormalTemplate. Use this before any calls to CommandBar:
Application.CustomizationContext = NormalTemplate
Note: for saving a customization in the current document: = ActiveDocument; for saving in the template attached to the current document: = ActiveDocument.AttachedTemplate.
I solved my problem with a workaround:
I was trying to "add" a template (.dotm) as a add-in (in the "Templates and Add-ins" window) to use my VBA project in a new document. That's why I was using the AutoExec() and AutoExit() procedures.
But only now I figure out that just "attaching" the .dotm template to the active document (in the same "Templates and Add-ins" window, as show in the figure below) makes the functions Private Sub Document_Open() and Private Sub Document_Close() to run normally. Which solves my problem.
Even so, I think there is a certain "issue" with the AutoExit() procedure when trying to change the CommandBars itens. But that's ok for now.
enter image description here

VB.Net Handling Multiple Forms into Panel

I have tried to find an answer to this already, but cannot find one that answers this question.
I have a Master Form which contains two panels. In the master Form I am trying to write a subroutine to handle the loading of a form into one of the panels.
One panel always contains the same form and the code which works for this is:
'Configure Toolbar Import
Dim toolbarHandler As _pnl_header = New _pnl_header()
toolbarHandler.Size = pnlHeader.Size
toolbarHandler.TopLevel = False
pnlHeader.Controls.Add(toolbarHandler)
toolbarHandler.Show()
The panel successfully shows the form _pnl_header as expected.
The second panel will change the displayed form depending on user input, so rather than having to write the above code for every eventuality i would like one Public Sub to handle them all...
I've started writing a sub along the lines of:
Public Sub LoadContentPanel(WhichForm As Form)
Try
Dim contentHandler As WhichForm = New WhichForm()
contentHandler.Size = pnlContent.Size
contentHandler.TopLevel = False
pnlContent.Controls.Add(contentHandler)
contentHandler.Show()
Catch ex As Exception
MsgBox("Unable to Handle Content Panel Change. Error: " & ex.Message, vbOKOnly + vbCritical, "Load Error")
End Try
End Sub
However this fails as 'WhichForm' is not defined - how is best to correct this? or is there a better alternative?
Thanks
Without going into what you are doing I can explain where the error comes from.
Here you declare argument variable WhichForm of type Form
Public Sub LoadContentPanel(WhichForm As Form)
. . . . .
Code is incorrect in the next declaration line. WhichForm is a variable and not a type. Hence
Dim contentHandler As WhichForm = New WhichForm()
is invalid at As WhichForm. Because after As you need a type name. If you did
Dim contentHandler As Form = New Form()
it would work.
It seems that all you need to do is remove Dim contentHandler As WhichForm... and rename argument WhichForm to contentHandler.

How to call a function in Visual Basic

Im fairly new at visual basic and im having trouble using function. ive tried many ways but failed, so ive deleted the funtion to start again. i want this function to run once someone has clicked a button, however the button is on a different form.
When button(btnAdd) is clicked on form 2 i want this to run on form one...
Using writer As System.IO.StreamWriter = New System.IO.StreamWriter(filepath", True)
Dim recipient As String = tbRecipient.Text
If (tbRecipient.Lines.Count > 1) Then
recipient = ""
For Each line As String In tbRecipient.Lines
recipient = recipient & " " & line
Next
recipient = recipient.Trim()
End If
writer.WriteLine(recipient)
End Using
Im not sure if this is the right code to achieve what i want it to do. What the code should do is when the user clicks the button add, it reads the checked options in a checklistbox and adds them to a file. that file is the outputted to a different textbox, which is on a different form. I have the funtion working correctly for the adding of the checkboxlist but need to then display it in a text box on another form. if anyone can help or point me in the right direction that would be great.
Double click on the button(btnAdd) in design window then write:
myFunction()
then in the second form code window:
public function myFunction()
'your code
end function
just call the function name where you want to execute it, or using the reserved keyword Call as Below:
First Way:
'Call by taping the function name
myFunctionName(Argumets)
Second Way:
'Use the Call Keyword:
Call myFunctionName(Argumets)

How to get all forms in a VB.net (VS08) project in an array?

Alright, so I need a method that traverses all the forms inside a VB.net project under Visual Studio 2008, and create an array of type form with references to all the forms inside it, so that the array looks like this (pseudocode)
FormsArray() = [Form1, Form2, Form3, Form4]
However, I don't have a clue as to how to begin.
You have to adjust the function to put the result of msgbox in a array
Public Sub getallforms(ByVal sender As Object)
Dim Forms As New List(Of Form)()
Dim formType As Type = Type.GetType("System.Windows.Forms.Form")
For Each t As Type In sender.GetType().Assembly.GetTypes()
If UCase(t.BaseType.ToString) = "SYSTEM.WINDOWS.FORMS.FORM" Then
MsgBox(t.Name)
End If
Next
End Sub
You must call the function from any form in the application like this (getallforms(me))
Here is how you would do this using Reflection, assuming that the class where you placed this code was in the same assembly that you wanted to iterate over. If not, then you'll need to change the Me.GetType().Assembly in the For Each loop into something else to account for loading the assembly in a different manner.
Dim Forms As New List(Of Form)()
Dim formType As Type = Type.GetType("System.Windows.Forms.Form")
For Each t As Type In Me.GetType().Assembly.GetTypes()
If t.IsSubclassOf(formType) = True Then
Forms.Add(CType(Activator.CreateInstance(t), Form))
End If
Next
Hey this is what I did to get the list of forms in my vb project, how ever this in not in code but you could write system.io code fragment to do just that.
open cmd prompt
go to project folder
run a dir /s/b *.designer.vb >> list.txt
use notepad or sublimetext and edit it to get the list ordered as you like it.
:) hope this helped!
I could not get this version to work:
Dim Forms As New List(Of Form)()
Dim formType As Type = Type.GetType("System.Windows.Forms.Form")
For Each t As Type In Me.GetType().Assembly.GetTypes()
If t.IsSubclassOf(formType) = True Then
Forms.Add(CType(Activator.CreateInstance(t), Form))
End If
Next
In VB2010 formType is always Nothing
So I dumped the formType line and simply modified your 'IF' statement to check the BaseType instead. Here is the New Version
Dim Forms As New List(Of Form)()
For Each t As Type In Me.GetType().Assembly.GetTypes()
If t.BaseType.Name = "Form" Then
Forms.Add(CType(Activator.CreateInstance(t), Form))
End If
Next
You need to either write a VS macro or an Addin.
In it, from a DTE or DTE2 instance, you can write:
Public Sub GetForms(ByVal host As DTE2)
Dim project As Project = host.ActiveDocument.ProjectItem.ContainingProject
For Each ce As CodeElement In project.CodeModel.CodeElements
If ce.Kind = vsCMElement.vsCMElementClass Then
Dim cl As CodeClass = CType(ce, CodeClass)
If cl.IsDerivedFrom("System.Windows.Forms) Then
'do something
End If
End If
Next
End Sub
2 options
I would load the actual project file into a XML reader. Then iterate all the nodes looking for all Form SubTypes and store the linked files in an array. If the name of file matches the name of the form class, you can create your FormsArray from that list. Otherwise you have to load each file and look for the public class definition of the file to get the list.
Using Reflection, examine the project using Assembly.GetTypes. Find all the System.Windows.Forms.Form Types and store them in a list. Then write out the Type.Name.