Reading xlsx file int vb.net VS 2012 - vb.net

I'm trying to read/write an .xlsx file with vb.net, but I have some problems. I'm using the following code:
Imports Microsoft.Office.Interop.Excel
Imports Microsoft.Office.Interop
Public Class Form1
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Dim fileTest As String = "C:\testFile.xlsx"
Dim oExcel As Object
oExcel = CreateObject("Excel.Application")
oExcel.Workbooks.Open(fileTest)
Dim oBook As Excel.Workbook
Dim oSheet As Excel.Worksheet
oBook = oExcel.ActiveWorkbook
oSheet = oExcel.Worksheets(1)
oSheet.Range("C2").Value = "testing c2"
oExcel.DisplayAlerts = False
oBook.SaveAs(fileTest, 51)
oBook.Close()
oBook = Nothing
End Sub
End Class
What I get is this dialog:
And when I open the testFile.xlsx I get just a bunch of some awkward symbols.
What might be the issue (that I suspect) is the thing that there are two versions of Excel application on my computer: Excel 2007 and Excel 2003, in order of installation. When I go to Task Manager, Excel applicaton which is running is 2003 version (which can't handle .xlsx files).
Maybe the solution could be to force vb.net application to use 2007 version of Excel, but I don't know how to do that (if it's even possible).
Any help would be appreciated.
And I have tried number of codes found on internet for reading .xlsx files, but with no success.

you need to update your Interop dll to point to your 2007 excel assembly. Try this for reference:
https://social.msdn.microsoft.com/Forums/vstudio/en-US/87e65b6a-f211-4b4a-9d42-a264dcf2a6f4/microsoftofficeinteropexceldll?forum=csharpgeneral

Related

Share variables between excel and visual basic

I recently started programming with .NET visual basic using visual basic studio. I am also using excel VBA to make some macros. I would be very appreciative if someone could answer a question I have, apologies if the answer is obvious, I'm just getting started:
Basically, if I have set a variable in excel VBA, for example:
dim text as string
text = "hello world"
Would it be possible for me to use that variable when programming in visual basic and have it retain its value from when it was set in the excel VBA macro.
Please comment if you need clarification.
Many thanks.
SOLUTION:
Okay I managed to figure it out with the help of the solutions, the code that works in VB is as follows:
Imports Microsoft.Office.Interop.Excel
Imports Microsoft.Office.Interop
Imports Microsoft.Office.Core
Public Class Form1
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim oxl As excel.application
Dim owb As excel.workbook
Dim osheet As Excel.worksheet
Dim orng As excel.Range
Dim strtext As String
oxl = CreateObject("Excel.application")
owb = oxl.Workbooks.Open(Filename:="C:\Users\USERNAME\Documents\Variable Passing Test.xlsm")
oxl.Run("dosomethingtostrtext")
strtext = oxl.Run("getstrtext")
MsgBox(strtext)
End Sub
End Class
One way to access variables in another workbook's VBA code is to create functions that return those values to you. Then call those functions from your other app.
For example, let this be code in a module in your Excel file with the macro:
Option Explicit
Private strText As String
' Say you have a routine that manipulates strText (or not, even!)
Public Sub doSomethingToSTRTEXT()
strText = "Hello World!"
End Sub
' This is the function to call to retrieve strText
Public Function getSTRTEXT() As String
getSTRTEXT = strText
End Function
And this is code in a VBA project elsewhere (not running .Net on this machine, just microsoft office sad) where you have this:
Option Explicit
Sub Test()
' Declare
Dim WBK As Workbook
' Open the workbook in question
Set WBK = Workbooks.Open(Filename:="C:\Path\To\File\With\VBA.xls")
' This code's own variable
Dim strText As String
' Call the routine (or not) that does something to that workbook's vba's strText
Application.Run (WBK.Name & "!doSomethingToSTRTEXT")
' Now let's retrieve that value via function!
strText = Application.Run(WBK.Name & "!getSTRTEXT")
' Show it to me
MsgBox strText
End Sub
I would like to leave the conversion of the code right above ^ into VB.Net to you (or do a search here on SO for .Net code to handle Excel objects) and try it out

Code in the workbook module still runs after the file is saved as xlsx

Using a button in VB.NET form, an .xlsm file is opened and saved as .xlsx. The code in the .xlsx file (Workbook_BeforeClose event) is NOT deleted after the file is saved, therefore, when I want to close the file the code runs! After reopening the file there is no code left.
This is my VB.NET class:
Imports Excel = Microsoft.Office.Interop.Excel
Public Class Form1
Dim xlApp As Excel.Application
Dim xlWorkBook As Excel.Workbook
Dim xlWorkbooks As Excel.Workbooks
Private Sub btnSave_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnSave.Click
xlApp = New Excel.Application
xlWorkbooks = xlApp.Workbooks
xlWorkBook = xlWorkbooks.Open("C:\Temp\testTemplate.xlsm")
xlApp.DisplayAlerts = False
xlWorkBook.SaveAs(Filename:="C:\Temp\testTemp.xlsx", FileFormat:=51) '51=xlOpenXMLWorkbook
xlApp.DisplayAlerts = True
xlApp.Visible = True
'Clean Up
releaseObject(xlWorkBook)
releaseObject(xlWorkbooks)
releaseObject(xlApp)
End Sub
Private Sub releaseObject(ByVal obj As Object)
Try
System.Runtime.InteropServices.Marshal.ReleaseComObject(obj)
obj = Nothing
Catch ex As Exception
obj = Nothing
Finally
GC.Collect()
GC.WaitForPendingFinalizers()
End Try
End Sub
End Class
This is in the Excel file, workbook module:
Private Sub Workbook_BeforeClose(Cancel As Boolean)
MsgBox "event still runs"
End Sub
How to save the file properly so that NO code would remain in it?
You're right, the code isn't deleted until after it's closed. I suppose you could set some type of flag in the xlsm's BeforeClose event that checks its file type and only runs if it's xlsm. Or you could do a Worksheets.Copy instead of the SaveAs and save the resulting workbook (which won't contain the VBA) as an xlsx, but there could be reference issues to clean up. Or you could set xlApp.EnableEvents=False, close the newly saved xlsx, set it back to True and re-open the xlsx.
Here's a post I wrote on the second option: http://yoursumbuddy.com/copy-an-xlsm-xlsx/

activate a worksheet by index

I have a winform with a forward and a backwards button. What I am trying to do is to allow the user to move back and forth on the workbook by clicking on the button. I thought that the best way to achieve this is by using index. However, it is giving me fits. The IDE is telling me that I have syntax errors on lines:
(WS.Index - 1).Activate()
and
If Err.Number <> 0 Then WS(1).Activate()
Here is my entire code:
Option Explicit On
Option Strict On
'Import Libraries
Imports Microsoft.Office.Tools.Excel
Imports System.Drawing
Imports System
Imports System.IO
Imports System.Drawing.Printing
Imports System.Windows.Forms
Public Class frmNavigation
Dim WB As Excel.Workbook
Dim WS As Excel.Worksheet
Private Sub btnMoveBack_Click(sender As Object, e As EventArgs) Handles btnMoveBack.Click
'This event is triggered when the Previous Sheet button is
'clicked. The sheet moves to the previous sheet. This event
'is only run throughout the clientworksheets as the tabs and other
'standard excel navigation may be disabled.
WB = CType(Globals.ThisWorkbook.Application.ActiveWorkbook, Excel.Workbook)
WS = CType(WB.ActiveSheet, Excel.Worksheet)
WS.Application.ScreenUpdating = False
On Error Resume Next
(WS.Index - 1).Activate()
If Err.Number <> 0 Then WS(1).Activate() 'If error stay in the active sheet
WS.Application.ScreenUpdating = True
End Sub
I think it should be:
WB.WorkSheets(WS.Index -1).Activate()
Instead of just
(WS.Index -1).Activate()

Calling Sheet from a WorkBook

I'm trying to call the 5th sheet in an open workbook. When I open the workbook from the program I seem to be able to do it:
Dim CurrentRun As New Excel.Application
Dim CurrentBook As Excel.Workbook
Dim CurrentSheet As Excel.Worksheet
Private Sub GeneralButtonOpener_Click(sender As Object, e As EventArgs) Handles GeneralButtonOpener.Click
CurrentRun.Visible = True
CurrentBook = CurrentRun.Workbooks.Add(MainTemplatePath)
CurrentSheet = CurrentBook.Worksheets(4)
CurrentSheet.Activate()
End Sub
But all my attempts at calling the sheet if the file is already open have failed:
Dim CurrentRun As Microsoft.Office.Interop.Excel.Application
Dim CurrentBook As Microsoft.Office.Interop.Excel.Workbook
Dim CurrentSheet As Microsoft.Office.Interop.Excel.Worksheet
CurrentRun = System.Runtime.InteropServices.Marshal.GetActiveObject("Excel.Application")
CurrentBook = CurrentRun.Workbooks
CurrentSheet = CurrentBook.Sheets(4)
CurrentSheet.Activate()
or
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim CurrentRun As Microsoft.Office.Interop.Excel.Application
Dim CurrentBook As Excel.Workbook
Dim CurrentSheet As Excel.Worksheet
CurrentRun = System.Runtime.InteropServices.Marshal.GetActiveObject("Excel.Application")
CurrentBook = CurrentRun.ActiveWorkbook
CurrentSheet = CurrentBook.Sheets(4)
CurrentSheet.Activate()
End Sub
I've looked at several examples, but I can't figure out where I'm going wrong. Which surprises me as there seem to be a lot of questions on the subject. Ether a pointer to where this is solved/addressed or what I'm specifically doing wrong would be appreciated.
Thanks!
Much to my surprise, I found that I in fact had dozens of instances of Excel running in the background. When I am debugging, and launch the COM the first instance of Excel is started. The second is started when I open the windows form (the main part of the add-in).
What I didn't know, was that when an exception was thrown, and I stop things from within Visual Studio, only the first instance of Excel was closed. I have code that tries and clean up open applications of Excel, but of course it was not reached because an exception was thrown.
And here I had been thinking I would put Error handling a bit down the road when I had things a little more developed. Clearly I need to address some basic error handling much earlier in my build process. I'm entirely self taught, and somehow made it three years without that being an issue.
Hopefully someone else who wasn't been taught that can see this before pulling their hair out for 14 hours.
Solution
Close all other instances of Excel and the above code works. Address cleanup in error handling and earlier as addressed here: http://support.microsoft.com/kb/317109
Maybe also call the GC, though that seems controversial.
Final code:
....
Imports System.Runtime.InteropServices
....
Dim CurrentRun As New Excel.Application
Dim CurrentBook As Excel.Workbook
Dim CurrentSheet As Excel.Worksheet
....
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
On Error GoTo VortexInYourSoul
CurrentRun = System.Runtime.InteropServices.Marshal.GetActiveObject("Excel.Application")
CurrentBook = CurrentRun.Workbooks(1)
CurrentRun.Visible = True
CurrentSheet = CurrentBook.Sheets(8)
CurrentSheet.Activate()
CurrentBook.ActiveSheet.name = "LLAMA LALA LLAMALMALMAL"
....
Exit Sub
VortexInYourSoul:
CurrentSheet = Nothing
CurrentBook.Close(False)
CurrentBook = Nothing
CurrentRun.Quit()
CurrentRun = Nothing
MsgBox("Error: " & Err.Description)
End Sub

How to select a cell A3 in Excel using VB.net?

I want to select the Cell A3 using VB.net..
I tried doing this by:
sheet.Range("A3:A3").Select()
But this gives an exception = Select method of Range Class Failed !
What is the problem and how to do it ?
Please help.. I am waiting for the reply !
Assuming you meant Excel VBA try this:
sheet.Range("A3").Select
You can just specify the cell if all you want is one cell.
This program works for me in VB.NET, I agree with rajah9, check the other aspects.
Imports Excel = Microsoft.Office.Interop.Excel
Public Class Form1
Dim oExcel As Object
Dim oBook As Object
Dim oSheet As Object
Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click
oExcel = CreateObject("Excel.Application")
oBook = oExcel.Workbooks.Add()
oSheet = oBook.Worksheets(1)
oSheet.Range("A3").Select()
oExcel.ActiveCell.Value = "Put text here"
oBook.SaveAs("C:\Path\testinterop.xlsx")
oExcel.Quit()
End Sub
End Class
(based on, and drawn in part from, examples here)