How To Develop My Own Excel Add-in in VB.Net - vb.net

I am trying to create an Excel Add-in using Vb.Net. I've started an Excel 2007 Add-in Project in VS2010. Sadly, I am not good with vb.net; I am more a VB6 developer in this regard, and my ThisAddin.vb code is:
Public Class ThisAddin
Private Sub ThisAddIn_Startup() Handles Me.Startup
End Sub
Private Sub ThisAddIn_Shutdown() Handles Me.Shutdown
End Sub
' test function; simple
Public Function getRowCount() As Long
Dim thisWB As Workbook = Me.Application.ThisWorkbook
Dim activWS As Worksheet
activWS = thisWB.ActiveSheet
Return activWS.UsedRange.Rows.Count
End Function
End Class
I've also added a Ribbon item (via Add New Item... menu option) in designer mode (not xml) - and then add a button. Then I go to code and try to call the function and I get this error when using:
MsgBox(Globals.ThisAddIn.getRowCount())
Which I got from this link: Calling a procedure within another class
To be honest, I've been trying a myriad things and I've been getting so many errors. I've been looking online as well for a tutorial on creating my own Excel Addin from scratch with no real luck. I would like not to use Add-In-Express since that's a third party app and I have to create an Excel add-in for my company from scratch.
Does anyone have an idea on how I can create a vb.net coded Excel Addin (2007) that I can use as a template or guide? I've tried several and many rely on Add-In-express and I really cannot go that way. I have a lot of VBA code (natural VBA so it's in a module in an my excel files' VBA/Developer section) and I think I can translate those from VBA/VB6 to VB.Net format so that's not my concern. It is really about getting to code my own Excel Addin in VB.Net. Any help would really be great. Thank you.
*note: I would also like not to have to ask coworkers (or do myself) to just add to the quick access toolbar the functions and subs I've created since that's really not a solution, considering that those buttons will be there when they create or open another workbook. Essentially, I've got to create my own excel addin in vb.net. Thank you once again.

The issue has to do with the definitions in Microsoft.Office.Tools.Excel and Microsoft.Office.Interop.Excel. To code an "Interop" version you could use this:
Public Function getRowCount() As Long
Dim thisWB As Excel.Workbook = Application.ActiveWorkbook
Dim activWS As Excel.Worksheet = CType(thisWB.ActiveSheet, Excel.Worksheet)
Return activWS.UsedRange.Rows.Count
End Function
To extend the functionality of the Native objects and use VSTO, you could do it like this:
Public Function getRowCount() As Long
Dim NativeWorkbook As Excel.Workbook = Application.ActiveWorkbook
Dim NativeWorksheet As Excel.Worksheet = CType(NativeWorkbook.ActiveSheet, Excel.Worksheet)
Dim thisWB As Workbook = Nothing
Dim activWS As Worksheet = Nothing
If NativeWorkbook IsNot Nothing Then
thisWB = Globals.Factory.GetVstoObject(NativeWorkbook)
End If
If NativeWorksheet IsNot Nothing Then
activWS = Globals.Factory.GetVstoObject(NativeWorksheet)
End If
Return activWS.UsedRange.Rows.Count
End Function
This is a function you can put in ThisAddin.vb that will create a new Worksheet. Note that this function names the Worksheet and adds it to the end.
Public Function AddWorkSheet(sheetName As String) As Worksheet
Dim wk = Application.ActiveWorkbook
Dim ws As Worksheet = Nothing
Try
ws = CType(wk.Sheets.Add(, wk.Sheets(wk.Sheets.Count)), Worksheet)
ws.Name = sheetName
Catch ex As Exception
Throw
Finally
AddWorkSheet = ws
End Try
End Function
To use this outside of ThisAddin.vb you could do something like this:
Dim ws As Excel.Worksheet
Dim newSheetName As String
.
'
ws = Globals.ThisAddIn.AddWorkSheet(newSheetName)

Related

Get Excel Object when Option Strict On

I have got following codes from this microsoft page.
https://msdn.microsoft.com/en-us/library/e9waz863(v=vs.90).aspx
' Add Option Strict Off to the top of your program.
Option Strict Off
.
Private Sub getExcel()
Dim fileName As String = "c:\vb\test.xls"
If Not My.Computer.FileSystem.FileExists(fileName) Then
MsgBox(fileName & " does not exist")
Exit Sub
End If
' Set the object variable to refer to the file you want to use.
Dim excelObj As Object = GetObject(fileName)
' Show Excel through its Application property.
excelObj.Application.Visible = True
' Show the window containing the file.
Dim winCount As Integer = excelObj.Parent.Windows.Count()
excelObj.Parent.Windows(winCount).Visible = True
' Insert additional code to manipulate the test.xls file here.
' ...
excelObj = Nothing
End Sub
Everything is okey when Option Strict Off
Everything is not okey when Option Strict On
So, how to solve that errors when Option Strict On?
Be careful! I want to get specific excel file from the same excel instance.
+1 for striving to use Option Strict On. :)
However, the code is using what is known as Late Binding and that requires you have Option Strict Off. You can however, minimize the scope of Option Strict Off by creating a new code file and using a Partial Class definition to contain the code that needs Late Binding.
You might be able to get by using the VB CallByName function with Option Strict On, but that would get ugly real quick and probably be very slow.
There also is an advanced technique using native API's that is called COM reflection that should work with Option Strict On. This technique is described in the article: [Basic Instincts - Inspecting COM Objects with Reflection].(https://msdn.microsoft.com/en-us/magazine/dd347981.aspx).
The typical method for early binding (Option Strict On) is to add a reference to the Excel primary interop assembly. This technique has some detractors as well, but is by far the easiest method.
Edit: The following demonstrates how to use the Excel PIA's and early binding to open a workbook directly similar to the OP's original code.
Dim wbPath As String = "*** replace with path to your workbook ***"
Dim wb As Excel.Workbook = CType(GetObject(wbPath), Excel.Workbook)
'or
'Dim wb As Excel.Workbook = CType(Marshal.BindToMoniker(wbPath), Excel.Workbook)
Dim app As Excel.Application = wb.Application
app.Visible = True
wb.Windows(1).Visible = True
As a side note, there is no need to depend on the Interop.Excel early binding, if you know that it works. You can change the Error Notifications to Warning and still compile and run.
' Imports Microsoft.Office.Interop.Excel
Dim fileName = "c:\vb\test.xls"
If Not IO.File.Exists(fileName) Then MsgBox(fileName & " does not exist") : Exit Sub
Dim obj = GetObject(fileName, "Excel.Application")
Dim wb = TryCast(obj, Workbook)
wb.Application.Visible = True
wb.Windows(1).Visible = True

Range.Formula error with user defined functions

Hello guy I have a user defined function inside VBA
Function clean(word As String, ParamArray characters() As Variant) As String
For i = 0 To UBound(characters)
word = Replace(word, characters(i), "")
Next i
clean = word
End Function
whenever I try to use it in another subroutine like that
Sub prova()
Dim wb As Workbook
Dim wsB As Worksheet
Set wb = ThisWorkbook
Set wsB = wb.Sheets("Bond Holdings")
wsB.Range("R3").Formula = "=clean(""dfsduuu"",""u"")"
End Sub
I get runtime error 1004. Could you guys help me figure out why? this is driving me crazy.
Thank you
Excel has a built-in function called CLEAN. You have a name-clash. If you call your function e.g. cleaner, it will work as expected.

Adding reference to VBA

I am trying to automatically add a reference while running a sub.
But I get "User defined-type not defined" for project As VBAProject
What's wrong?
Sub tester()
Dim SolverPath As String
SolverPath = Application.LibraryPath & "\SOLVER\SOLVER.XLA"
Dim wb As Workbook
Set wb = ThisWorkbook
Dim project As VBAProject
project = wb.VBProject
wb.project.References.AddFromFile SolverPath
End Sub
VBAProject is actually a special type of library, not a variable type. If you hit F2 to bring up the Object Browser, you can select it from the library dropdown. So you can't create variables of type VBAProject. However, it's not necessary to, nor for ThisWorkbook, unless you just want a shorter alias. Just use the workbook's VBProject property to gain access to the current project instance and add/remove components. Your code could be simplified to:
Sub tester()
Dim SolverPath As String
SolverPath = Application.LibraryPath & "\SOLVER\SOLVER.XLA"
ThisWorkbook.VBProject.References.AddFromFile SolverPath
End Sub

Late bound resolution using COM objet for Excel

The following is inside an SSIS script task using VB.net
I have read a bit into this error, and it seems that something is wrong with this line:
worksheet = CType(workbook.Sheets(4), Excel.Worksheet)
My code is below. I think it will be simple for the more experienced folks here.
text:
Public Sub Main()
Dim excel As New Excel.Application
Dim filename As String = "S:\UK\Clients\Direct\xxxxxxx.xls"
excel.Visible = True
excel.DisplayAlerts = False
Dim workbook As Excel.Workbook
workbook = excel.Workbooks.Open(filename, , False) 'True = ReadOnly
Dim worksheet As Excel.Worksheet
worksheet = CType(workbook.Sheets(4), Excel.Worksheet)
worksheet.Rows(1).delete()
Dts.TaskResult = ScriptResults.Success
End Sub
add Option Strict Off at the top of your code, This will allow late binding.
To know Early vs. Late Binding , refer here
you can replace this statement
worksheet.Rows(1).delete()
with
Dim rw As Excel.Range
rw = CType(worksheet.Rows(1), Excel.Range)
rw.Delete()
And set Option Strict On at the top
All your code will be early bound. Hope this helps

Loop through excel workbooks in vb.net

I am working with a folder of xls files that are all in identical format (automatically generated by entering numbers into a pricing app). I need to pull the data that is in cell D54 on the worksheet of the same name in every file. Can't seem to get anything to work to make it loop.
Any ideas how this can be done?
If you can have the files generated in XLSX format then this is what I would do.
http://epplus.codeplex.com/
This is an amazing component library for dealing with Excel XLSX sheets.
Example...
Sub temp()
Dim out As New List(Of String)
Using pac As New ExcelPackage(New IO.FileInfo("c:\temp.xlsx"))
For Each wb As ExcelWorksheet In pac.Workbook.Worksheets
out.Add(wb.Cells("D54").Value.ToString)
Next
End Using
End Sub
Otherwise the option is to reference the Excel Com+ Library from office to open an XLS sheet with what should be similar code as below.
Sub temp2()
Dim out As New List(Of String)
Dim app As New Microsoft.Office.Interop.Excel.Application
app.DisplayAlerts = False
Dim wb As Microsoft.Office.Interop.Excel.Workbook = app.Workbooks.Open("c:\temp.xls")
For Each ws As Microsoft.Office.Interop.Excel.Worksheet In wb.Worksheets
Dim r As Microsoft.Office.Interop.Excel.Range = ws.Cells(54, 4)
out.Add(r.Value.ToString)
Next
app.close()
End Sub