Add Datatable to Existing Excel Spreadsheet vbnet, always Corrupt - excel

UPDATED:
Appeared to be something with the SHEETID, now its finding additional worksheets when working with the USING tag instead in combo with this sheetid finder.
Dim sheetId As UInteger = 1
If (sheets.Elements(Of Sheet).Count > 0) Then
sheetId = CUInt(sheets.Elements(Of Sheet).Select(Function(s) s.SheetId.Value).Max + 1)
End If
Here is the code i used to make it work, stopped corrupting the file now:
' Given a document name, inserts a new worksheet.
Public Sub InsertWorksheet(ByVal docName As String, ByVal SQL As DataTable, ByVal sheetName As String, ByVal intSheetId As Integer)
'Dim sheetName As String
Dim fileName As String = docName
' Open an existing spreadsheet document for editing.
Dim spreadSheet As SpreadsheetDocument = SpreadsheetDocument.Open(fileName, True)
Using (spreadSheet)
' Add a blank WorksheetPart.
Dim newWorksheetPart As WorksheetPart = spreadSheet.WorkbookPart.AddNewPart(Of WorksheetPart)()
newWorksheetPart.Worksheet = New Worksheet(New SheetData())
' Create a Sheets object.
Dim sheets As Sheets = spreadSheet.WorkbookPart.Workbook.GetFirstChild(Of Sheets)()
Dim relationshipId As String = spreadSheet.WorkbookPart.GetIdOfPart(newWorksheetPart)
' Get a unique ID for the new worksheet.
Dim sheetId As UInteger = 1
If (sheets.Elements(Of Sheet).Count > 0) Then
sheetId = CUInt(sheets.Elements(Of Sheet).Select(Function(s) s.SheetId.Value).Max + 1)
End If
' Append the new worksheet and associate it with the workbook.
Dim sheet As Sheet = New Sheet
sheet.Id = relationshipId
sheet.SheetId = sheetId
sheet.Name = sheetName
sheets.Append(sheet)
'get the sheetData object so we can add the data table to it
Dim sheetData As SheetData = newWorksheetPart.Worksheet.GetFirstChild(Of SheetData)()
'add the data table
AddDataTable(SQL, sheetData)
'save the workbook
newWorksheetPart.Worksheet.Save()
' Close the document.
spreadSheet.Close()
End Using
End Sub
File is always corrupt after creating, trying to create a spreadsheet with 4 workbooks with separate data loaded via data tables. File size looks to be valid and I dont get any specific errors when creating the file. Just won't open the excel sheet after creating the file.
Existing code to call functions:
Try
CreateExcelFileFromDataTable(iExcelFileLoc & ExportFileName, iAGetTable)
Catch ex As Exception
Dim ExceptionType As Integer = Type.GetTypeCode(ex.GetType())
LogMessage(strAppName & " - Failure : " & iExcelFileLoc & ExportFileName & " Error:'" & ex.Message & "' Error Type:'" & CStr(ExceptionType) & "' Trace:" & ex.StackTrace, TraceEventType.Error)
End Try
Dim iBGetTable As DataTable = GetDataTable(SQL_SELECT_DOCUMENTS_TO_FOR_DOCS_NOT_FOUND_IN_DOCNUMS)
Dim iReportB As String = BuildReportHTML(iBGetTable)
InsertWorksheet(iExcelFileLoc & ExportFileName, iBGetTable, "Missing Scanned Documents", 2)
' ======================================================================
Both functions to create excel initially and then a function to add a new worksheet with datatable to the existing spreadsheet.
Public Sub InsertWorksheet(ByVal docName As String, ByVal SQL As DataTable, ByVal sheetName As String, ByVal intSheetId As Integer)
Dim iFinalSheetName As String = ""
Dim spreadSheet As SpreadsheetDocument = SpreadsheetDocument.Open(docName, True)
Dim newWorksheetPart As WorksheetPart = spreadSheet.WorkbookPart.AddNewPart(Of WorksheetPart)()
newWorksheetPart.Worksheet = New Worksheet(New SheetData())
' Add Sheets to the Workbook.
Dim sheets As Sheets = spreadSheet.WorkbookPart.Workbook.AppendChild(Of Sheets)(New Sheets())
Dim relationshipId As String = spreadSheet.WorkbookPart.GetIdOfPart(newWorksheetPart)
' Append a new worksheet and associate it with the workbook.
Dim sheetId As UInteger = 1
If (sheets.Elements(Of Sheet).Count > 0) Then
sheetId = CUInt(sheets.Elements(Of Sheet).Select(Function(s) s.SheetId.Value).Max + 1)
End If
iFinalSheetName = (sheetName.ToString())
' Append the new worksheet and associate it with the workbook.
Dim sheet As Sheet = New Sheet
sheet.Id = relationshipId
sheet.SheetId = CType(intSheetId, UInt32Value)
sheet.Name = iFinalSheetName
sheets.Append(sheet)
'get the sheetData object so we can add the data table to it
Dim sheetData As SheetData = newWorksheetPart.Worksheet.GetFirstChild(Of SheetData)()
'add the data table
AddDataTable(SQL, sheetData)
'save the workbook
newWorksheetPart.Worksheet.Save()
' Close the document.
spreadSheet.Close()
End Sub
Public Sub CreateExcelFileFromDataTable(ByVal FilePath As String, myDT As DataTable)
' Create a spreadsheet document by supplying the filepath.
' By default, AutoSave = true, Editable = true, and Type = xlsx.
Dim spreadsheetDocument As SpreadsheetDocument = spreadsheetDocument.Create(FilePath, SpreadsheetDocumentType.Workbook)
' Add a WorkbookPart to the document.
Dim workbookpart As WorkbookPart = spreadsheetDocument.AddWorkbookPart
workbookpart.Workbook = New Workbook
' Add a WorksheetPart to the WorkbookPart.
Dim worksheetPart As WorksheetPart = workbookpart.AddNewPart(Of WorksheetPart)()
worksheetPart.Worksheet = New Worksheet(New SheetData())
' Add Sheets to the Workbook.
Dim sheets As Sheets = spreadsheetDocument.WorkbookPart.Workbook.AppendChild(Of Sheets)(New Sheets())
' Append a new worksheet and associate it with the workbook.
Dim sheet As Sheet = New Sheet
sheet.Id = spreadsheetDocument.WorkbookPart.GetIdOfPart(worksheetPart)
sheet.SheetId = 1
sheet.Name = "Duplicate Document"
sheets.Append(sheet)
'get the sheetData object so we can add the data table to it
Dim sheetData As SheetData = worksheetPart.Worksheet.GetFirstChild(Of SheetData)()
'add the data table
'AddDataTable(myDT, sheetData)
'save the workbook
workbookpart.Workbook.Save()
' Close the document.
spreadsheetDocument.Close()
' -----------------------------------
End Sub

Here's an option for you:
Create a sample of the spreadsheet manually.
Download and Install the Open XML SDK tool
Open the spreadsheet in the tool
Once the spreadsheet is opened, there's a section where you can view .NET source code to create a sheet that looks like it.
I use the tool a lot. Working with the Office XML SDK without it can be very cumbersome.

Related

VB.NET use Microsoft OpenXML to save excel file

it's my first approach to openxml and I can't get it to work.
Hi want to create an xls file, write a value to specific cells and save it. This is the code I wrote for now, it creates the file but doesn't write any value at all. What I'm missing? Thanks
EDIT: as asked I addedd InsertCellInWorksheet function
Sub Main()
CreateSpreadsheetWorkbook("IMPOVO.XLS")
Dim spreadSheet As SpreadsheetDocument = SpreadsheetDocument.Open("IMPOVO.XLS", True)
Using (spreadSheet)
Dim worksheetPart As WorksheetPart = spreadSheet.WorkbookPart.WorksheetParts.First
Dim cell As Cell = InsertCellInWorksheet("A", 1, worksheetPart)
' Set the value of cell A1.
cell.CellValue = New CellValue("Hi World")
cell.DataType = New EnumValue(Of CellValues)(CellValues.SharedString)
' Save the new worksheet.
worksheetPart.Worksheet.Save()
End Using
End Sub
Public Sub CreateSpreadsheetWorkbook(ByVal filepath As String)
'Create a spreadsheet document by supplying the filepath.
'By default, AutoSave = true, Editable = true, and Type = xlsx.
Dim spreadsheetDocument As SpreadsheetDocument =
SpreadsheetDocument.Create(filepath, SpreadsheetDocumentType.Workbook)
'Add a WorkbookPart to the document.
Dim workbookpart As WorkbookPart = spreadsheetDocument.AddWorkbookPart
workbookpart.Workbook = New Workbook
'Add a WorksheetPart to the WorkbookPart.
Dim worksheetPart As WorksheetPart = workbookpart.AddNewPart(Of WorksheetPart)()
worksheetPart.Worksheet = New Worksheet(New SheetData())
'Add Sheets to the Workbook.
Dim sheets As Sheets = spreadsheetDocument.WorkbookPart.Workbook.AppendChild(Of Sheets)(New Sheets())
'Append a new worksheet and associate it with the workbook.
Dim sheet As Sheet = New Sheet
sheet.Id = spreadsheetDocument.WorkbookPart.GetIdOfPart(worksheetPart)
sheet.SheetId = 1
sheets.Append(sheet)
workbookpart.Workbook.Save()
'Close the document.
spreadsheetDocument.Close()
End Sub
Private Function InsertCellInWorksheet(ByVal columnName As String, ByVal rowIndex As UInteger, ByVal worksheetPart As WorksheetPart) As Cell
Dim worksheet As Worksheet = worksheetPart.Worksheet
Dim sheetData As SheetData = worksheet.GetFirstChild(Of SheetData)()
Dim cellReference As String = (columnName + rowIndex.ToString())
' If the worksheet does not contain a row with the specified row index, insert one.
Dim row As Row
If (sheetData.Elements(Of Row).Where(Function(r) r.RowIndex.Value = rowIndex).Count() <> 0) Then
row = sheetData.Elements(Of Row).Where(Function(r) r.RowIndex.Value = rowIndex).First()
Else
row = New Row()
row.RowIndex = rowIndex
sheetData.Append(row)
End If
' If there is not a cell with the specified column name, insert one.
If (row.Elements(Of Cell).Where(Function(c) c.CellReference.Value = columnName + rowIndex.ToString()).Count() > 0) Then
Return row.Elements(Of Cell).Where(Function(c) c.CellReference.Value = cellReference).First()
Else
' Cells must be in sequential order according to CellReference. Determine where to insert the new cell.
Dim refCell As Cell = Nothing
For Each cell As Cell In row.Elements(Of Cell)()
If (String.Compare(cell.CellReference.Value, cellReference, True) > 0) Then
refCell = cell
Exit For
End If
Next
Dim newCell As Cell = New Cell
newCell.CellReference = cellReference
row.InsertBefore(newCell, refCell)
worksheet.Save()
Return newCell
End If
End Function
This is just a suggestion, but try explicitly closing the document at the end of the Using block like your code does in the last instruction in the CreateSpreadsheetWorkbook() method to see if that resolved the issue. You may also need to explicitly save the spreadsheet object at the end of the Using block.

VBA - Import Macro - How do i add to the current data when importing?

I have created a macro to import data from another workbook, but i have to set which row to start. I was wondering how i would alter the code to paste the import data to the last empty row (so its adding to the table).
Currently the macro, prompts to click the file you would like to import, then imports the data from certain col from source WB to target WB. But as you can see it as been assigned the row to paste. My question is how do i get it to paste at the last empty row, so it is collecting the data rather then over writing the data.
Would i need to change the "targetSheet.Range("R2", "R4000").Value = sourceSheet.Range("Q2", "Q4000").Value"
Public Sub Extract_Excel_file()
''//--------------------------------------------
' Get customer workbook...
Dim customerBook As Workbook
Dim filter As String
Dim caption As String
Dim customerFilename As String
Dim customerWorkbook As Workbook
Dim targetWorkbook As Workbook
' make weak assumption that active workbook is the target
Set targetWorkbook = Application.ActiveWorkbook
' get the customer workbook
filter = "Text files (*.xlsx),*.xlsx"
caption = "Please Select an input file "
customerFilename = Application.GetOpenFilename(filter, , caption)
Set customerWorkbook = Application.Workbooks.Open(customerFilename)
' assume range is A1 - C10 in sheet1
' copy data from customer to target workbook
Dim targetSheet As Worksheet
Set targetSheet = ThisWorkbook.Sheets("Raw Data")
Dim sourceSheet As Worksheet
Set sourceSheet = customerWorkbook.Worksheets(1)
sourceSheet.Range("A2", "V400").NumberFormat = "#" ''//Set all cells to
text format.
' sourceSheet.Range("A2", "A4000").NumberFormat = "#" ''//Set all cells
to text format.
targetSheet.Range("B2", "B4000").Value = sourceSheet.Range("A2",
"A4000").Value
targetSheet.Range("C2", "C4000").Value = sourceSheet.Range("B2",
"B4000").Value
targetSheet.Range("D2", "D4000").Value = sourceSheet.Range("C2",
"C4000").Value
targetSheet.Range("E2", "E4000").Value = sourceSheet.Range("D2",
"D4000").Value
targetSheet.Range("F2", "F4000").Value = sourceSheet.Range("E2",
"E4000").Value
targetSheet.Range("G2", "G4000").Value = sourceSheet.Range("F2",
"F4000").Value
targetSheet.Range("H2", "H4000").Value = sourceSheet.Range("G2",
"G4000").Value
targetSheet.Range("I2", "I4000").Value = sourceSheet.Range("H2",
"H4000").Value
targetSheet.Range("J2", "J4000").Value = sourceSheet.Range("I2",
"I4000").Value
targetSheet.Range("K2", "K4000").Value = sourceSheet.Range("J2",
"J4000").Value
targetSheet.Range("L2", "L4000").Value = sourceSheet.Range("K2",
"K4000").Value
targetSheet.Range("M2", "M4000").Value = sourceSheet.Range("L2",
"L4000").Value
targetSheet.Range("N2", "N4000").Value = sourceSheet.Range("M2",
"M4000").Value
targetSheet.Range("O2", "O4000").Value = sourceSheet.Range("N2",
"N4000").Value
targetSheet.Range("P2", "P4000").Value = sourceSheet.Range("O2",
"O4000").Value
targetSheet.Range("L2", "L4000").Value = sourceSheet.Range("P2",
"P4000").Value
targetSheet.Range("Q2", "Q4000").Value = sourceSheet.Range("L2",
"L4000").Value
targetSheet.Range("R2", "R4000").Value = sourceSheet.Range("Q2",
"Q4000").Value
' Close customer workbook
Application.DisplayAlerts = False ''//Don't promt to Save
customerWorkbook.Close
Application.DisplayAlerts = True '' undo Don't promt to Save
End Sub
I just want it to collect the data rather then overriding it each month.

Get data from an Edit Text box

I want to grab data from an Edit Text box from other workbooks and insert it into a single worksheet in a different workbook.
Sub TransferCompanyNames()
for(int i = 0; i < 479; i++){
variable = Workbooks.Open Range(//Column A with index i);
//column a contains a link to the workbook C:/Users/.../Documents/file.xlsx
//grab data from Edit Text Box and insert into current sheet at column A with index i
}
End Sub
I understand that this isn't the correct syntax.
Something like this perhaps:
Sub TransferCompanyNames()
Dim i As Integer
Dim SourceBook As Workbook
Dim TargetSheet As Worksheet
Set TargetSheet = Workbooks("ChangeToYourWorkbookName").Worksheets("ChangeToYourSheetName")
For i = 1 To 480
Set SourceBook = Workbooks.Open(Range("A" & i).Value)
TargetSheet.Range("B" & i).Value = ActiveSheet.Shapes(1).TextFrame.Characters(1, _
ActiveSheet.Shapes(1).TextFrame.Characters.Count).Text
SourceBook.Close False
Next
End Sub

Excel VBA - create column names using MS Project headers

I'm in the middle of writing a script that populates an excel spreadsheet with data from an MS Project file. I would like the script to recognize the title name of the MS Project columns as I have a number of custom columns with different names (custom number fields are populated with different names)
The code below was my attempt, but i'm getting an error when it comes to writing the value of the task column title to the sheet, am I doing something wrong here?
Sub PopulateSheet()
Dim Proj As MSProject.Application
Dim NewProj As MSProject.Project
Dim t As MSProject.Task
Dim xl as workbook
Dim s as worksheet
Dim Newsheet as worksheet
Set Xl = ThisWorkbook
BookNam = Xl.Name
Set Newsheet = Xl.Worksheets.Add
'Code to find and open project files
Set Proj = New MSProject.Application
MsgBox ("Please Select MS Project File for Quality Checking")
'Select Project File
FileOpenType = Application.GetOpenFilename( _
FileFilter:="MS Project Files (*.mpp), *.mpp", _
Title:="Select MS Project file", _
MultiSelect:=False)
'Detect if File is selected, if not then stop code
If FileOpenType = False Then
MsgBox ("You Havent Selected a File")
Exit Sub
End If
'Write the FileOpenType variant to two separate strings
NewProjFilePath = Left$(FileOpenType, InStrRev(FileOpenType, "\"))
NewProjFileName = Mid$(FileOpenType, InStrRev(FileOpenType, "\") + 1)
Newsheet.Name = NewProjFileName
Set s = Newsheet
'Populate spreadsheet header row with column titles from MS Project
s.Range("A1").Value = t.Number1 ***<-- Error '91' - Object variable or With block variable not set***
End Sub
Here is generic code that loops through the fields in the active task table and prints out the field headings as displayed in the table.
Sub GetTaskTableHeaders()
Dim t As Table
Set t = ActiveProject.TaskTables(ActiveProject.CurrentTable)
Dim f As TableField
For Each f In t.TableFields
If f.Field > 0 Then
Dim header As String
Dim custom As String
custom = Application.CustomFieldGetName(f.Field)
If Len(f.Title) > 0 Then
header = f.Title
ElseIf Len(custom) > 0 Then
header = custom
Else
header = Application.FieldConstantToFieldName(f.Field)
End If
Debug.Print "Field " & f.Index, header
End If
Next f
End Sub
Note that fields can be customized at the project level to be given a different title, or they can be customized at the table level. This code looks for both customizations and if neither is found, the field name is used.
Try the code below, explanation inside the code's comments:
Option Explicit
Sub PopulateSheet()
Dim Proj As MSProject.Application
Dim NewProj As MSProject.Project
Dim PjTableField As MSProject.TableField ' New Object
Dim PjTaskTable As MSProject.Table ' New Object
Dim t As MSProject.task
Dim xl As Workbook
Dim s As Worksheet
Dim Newsheet As Worksheet
Dim BookName As String
Dim FileOpenType
Dim NewProjFilePath As String, NewProjFileName As String
Set xl = ThisWorkbook
BookName = xl.Name
Set Newsheet = xl.Worksheets.Add
'Code to find and open project files
Set Proj = New MSProject.Application
MsgBox ("Please Select MS Project File for Quality Checking")
'Select Project File
FileOpenType = Application.GetOpenFilename( _
FileFilter:="MS Project Files (*.mpp), *.mpp", _
Title:="Select MS Project file", _
MultiSelect:=False)
'Detect if File is selected, if not then stop code
If FileOpenType = False Then
MsgBox ("You Havent Selected a File")
Exit Sub
End If
'Write the FileOpenType variant to two separate strings
NewProjFilePath = Left$(FileOpenType, InStrRev(FileOpenType, "\"))
NewProjFileName = Mid$(FileOpenType, InStrRev(FileOpenType, "\") + 1)
Newsheet.Name = NewProjFileName
Set s = Newsheet
' Open MS-Project File
Proj.FileOpen NewProjFilePath & NewProjFileName
Set NewProj = Proj.ActiveProject
' ===== New code Section =====
' set the Table object
Set PjTaskTable = NewProj.TaskTables(NewProj.CurrentTable)
' loop through all tablefields in table
For Each PjTableField In PjTaskTable.TableFields
If PjTableField.Field = pjTaskNumber1 Then ' check if currect field numeric value equals the numeric value of "Number1"
'Populate spreadsheet header row with column titles from MS Project
s.Range("A1").Value = PjTableField.Title ' populate "A1" with the field's title and
End If
Next PjTableField
End Sub

VBA-Excel 2010 Macro Error "memeber or data method not found"

I know this is a super generic error but I am new to VBA / Macros and cant get past this.
I have an and excel workbook that has data I need to copy to another excel workbook.
The excel workbook that the data is copied to is on a network share and will be written to frequently.
here is my macro code:
Sub export()
Dim exportFile As String
Dim importSheet As String
Dim rowData As String
exportFile = "\\<server>\spd\_Spec_ParaData\data_import.xlsx"
importSheet = "OutPutValues"
importRange = "A2:ZZ2"
' Get the row from the workbook that we are running in
rowData = Workbooks().Worksheets(importSheet).Range(importRange)
' Not sure if this will work, or always overwrite the last row. May need to be .Row+1
newRow = Workbooks(exportFile).Worksheets(1).Cells(Rows.Count, "A").End(xlUp).Row
exportRange = "A" & (newRow + 1) & ":ZZ" & (newRow + 1)
' Assuming Workbooks() gets the current workbook.
Workbooks(exportFile).Sheets(exportSheet).Range(exportRange) = Workbooks().Sheets(importSheet).Range(importRange)
End Sub
My error is poping up on the rowData=Workbooks(exportFile).Worksheets
Can someone help me figure out what I am doing wrong?
Thank you,
Jennifer
Try your code with the following modifications, I'm just opening the workbook and referencing the worksheet (I guess the problem is that). I'm closing the workbook straight after.
Sub export()
Dim exportFile As String
Dim importSheet As String
Dim rowData As String
Dim wb As Workbook
Dim ws1 As Worksheet, ws2 As Worksheet
exportFile = "\\<server>\spd\_Spec_ParaData\data_import.xlsx"
importSheet = "OutPutValues"
importRange = "A2:ZZ2"
'Open your workbook and point to your spreadsheet
Set wb = Workbooks.Open(exportFile)
Set ws1 = wb.Sheets(importSheet)
' Get the row from the workbook that we are running in
rowData = wb.ws.Range(importRange)
' Not sure if this will work, or always overwrite the last row. May need to be .Row+1
newRow = wb.Worksheets(1).Cells(Rows.Count, "A").End(xlUp).Row
exportRange = "A" & (newRow + 1) & ":ZZ" & (newRow + 1)
'NOTE: consider definying the variable "exportSheet", I will do it just for example purpose
Dim exportSheet As String: exportSheet = "InputValues"
Set ws2 = wb.Sheets(exportSheet)
' Assuming Workbooks() gets the current workbook.
wb.ws2.Range(exportRange) = wb.ws1.Range(importRange)
wb.Close
End Sub

Resources