I want to generate a SQL Script from an Excel Sheet and therefore i need to know the types from all cells.
Therefore i tried to get the type from the cells in the following code with the results afterward in a textbox
C# code:
using System;
using System.IO;
using System.Collections.Generic;
using System.Linq;
using Excel = Microsoft.Office.Interop.Excel;
using System.Windows.Forms;
namespace Export
{
internal class ExcelWorker
{
Excel.Application _xlApp = new Excel.Application();
Excel.Workbook _xlWorkBook;
Excel.Range _range;
object misValue = System.Reflection.Missing.Value;
private void Show(string value) => MessageBox.Show(value);
internal void ReadExcelFile(string path, string cell)
{
try
{
_xlWorkBook = OpenBook(_xlApp, path, false, true, false);
Excel.Worksheet sheet = _xlWorkBook.Sheets["Sheet1"] as Excel.Worksheet;
Show(string.Format("Cell {0} \n\n Cell Number Format {1}", cell, sheet.get_Range(cell).NumberFormat));
}
catch (Exception ex)
{
throw new Exception(ex.Message);
}
}
private static Excel.Workbook OpenBook(Excel.Application excelInstance, string fileName, bool readOnly, bool editable,
bool updateLinks)
{
Excel.Workbook book = excelInstance.Workbooks.Open(
fileName, updateLinks, readOnly,
Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing,
Type.Missing, editable, Type.Missing, Type.Missing, Type.Missing,
Type.Missing, Type.Missing);
return book;
}
}
}
excel sheet:
results for each cell:
Now i'm not sure if that's the only to get the "correct" type to cast the excel cell values to the exact sql type or if there's a better solution i don't know.
Is there a better way to get the type for each cell or should I create a enum or something like this and map each possible cell format ?
You won´t be able to get the type of a cell. If you want to enter data from an excel sheet into a db, try casting to the needed SQL-type and fromat. Especially for datetime this is mandatory as the datetime format depends on you db settings.
Be carefull with empty cells. You have to check them before casting. In Office 2010 and 2013 empty cells are NULL. You need to check this before using ToString() or something like this, because this would throw an exceeption. Also be cautious with double, e.g. using "," or "." this depends on you settings in Ecxel.
Related
Point of problem:
1. I have a list of objects and i need to export them in excel file. Each Object must be on one separate sheet and sheet is made of template.
My algorithm:
1. Created excel template file in project
2. For each object of list, copy template sheet in excel file and fill content.
For this purpose, i created ExcelWorker worker class and pass list of object to AutomateExcelImpl method. The problem is that app. throws. an exception on
oXL.Workbooks[1].Worksheets.Copy(sheet);
I googled it but almost broke my head digging this issue.
Please, help.
using JiraExample.Entities.Projects;
using Microsoft.Office.Interop.Excel;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
namespace JiraExample.Helpers
{
class ExcelWorker
{
public static void AutomateExcel()
{
//AutomateExcelImpl();
// Clean up the unmanaged Excel COM resources by forcing a garbage
// collection as soon as the calling function is off the stack (at
// which point these objects are no longer rooted).
GC.Collect();
GC.WaitForPendingFinalizers();
// GC needs to be called twice in order to get the Finalizers called
// - the first time in, it simply makes a list of what is to be
// finalized, the second time in, it actually is finalizing. Only
// then will the object do its automatic ReleaseComObject.
GC.Collect();
GC.WaitForPendingFinalizers();
}
public static void AutomateExcelImpl(List<ProjectDescription> projects)
{
object missing = Type.Missing;
try
{
// Create an instance of Microsoft Excel and make it invisible.
Microsoft.Office.Interop.Excel.Application oXL = new Microsoft.Office.Interop.Excel.Application();
oXL.Visible = false;
// Create a new Workbook.
Microsoft.Office.Interop.Excel.Workbook oWB = oXL.Workbooks.Add(1);
foreach (ProjectDescription project in projects)
{
createContent(project, oXL);
}
// Save the workbook as a xlsx file and close it.
Console.WriteLine("Save and close the workbook");
string fileName = Path.GetDirectoryName(
Assembly.GetExecutingAssembly().Location) + "\\Sample2.xlsx";
oWB.SaveAs(fileName, Microsoft.Office.Interop.Excel.XlFileFormat.xlOpenXMLWorkbook,
missing, missing, missing, missing,
Microsoft.Office.Interop.Excel.XlSaveAsAccessMode.xlNoChange,
missing, missing, missing, missing, missing);
oWB.Close(missing, missing, missing);
// Quit the Excel application.
Console.WriteLine("Quit the Excel application");
// Excel will stick around after Quit if it is not under user
// control and there are outstanding references. When Excel is
// started or attached programmatically and
// Application.Visible = false, Application.UserControl is false.
// The UserControl property can be explicitly set to True which
// should force the application to terminate when Quit is called,
// regardless of outstanding references.
oXL.UserControl = true;
oXL.Quit();
AutomateExcel();
}
catch (Exception ex)
{
Console.WriteLine("Solution2.AutomateExcel throws the error: {0}",
ex.Message);
}
}
private static void createSheet(Microsoft.Office.Interop.Excel.Application oXL, ProjectDescription project)
{
Worksheet sheet = getTemplate();
oXL.Workbooks[1].Worksheets.Copy(sheet);
}
private static Worksheet getTemplate()
{
Microsoft.Office.Interop.Excel.Application excelApp = new Microsoft.Office.Interop.Excel.Application();
excelApp.Visible = false;
string path = (Path.GetDirectoryName(
Assembly.GetExecutingAssembly().Location) + "\\Template.xlsx");
Microsoft.Office.Interop.Excel.Workbook workbook = excelApp.Workbooks.Open(path,
Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing,
Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing,
Type.Missing, Type.Missing, Type.Missing, Type.Missing);
// The key line:
Microsoft.Office.Interop.Excel.Worksheet worksheet = (Microsoft.Office.Interop.Excel.Worksheet)workbook.Worksheets[1];
return worksheet;
}
private static void createContent(ProjectDescription project,Microsoft.Office.Interop.Excel.Application oXL)
{
createSheet(oXL, project);
}
}
}
How can I preserve a worksheet's formatting when using Microsoft.Office.Interop.Excel.Workbook.SaveAs(...)?
For example, I open a previously created workbook with Excel 2010 and I see that it looks beautiful: bold fonts in column headers, nice grid lines, good highlight colors showing input cells, etc.
The I switch to VS2012 and using the ExcelAppManager I wrote below I start by opening the workbook that has the beautiful formatting. I then use the Interop library to write new cell values, programmatically, to one of the worksheets. I then save the worksheet using SaveAs(), as shown below in the ExcelAppManager. I then open the worksheet using Microsoft Excel 2010: I can see the values I wrote in the respective cells - which is great, it worked - but the entire workbook no longer has formatting. It's plain vanilla formatting and all the beautiful format is gone.
I define formatting as anything that format painter would operate on: bold, font, alignment, grid lines, indents, widths and heights, etc.
Sample code:
using System;
using System.Reflection;
using System.Runtime.InteropServices;
using Microsoft.Office.Interop.Excel;
namespace ExcelStuff
{
public class ExcelAppManager
{
private Application _excelApp;
private bool _isDefaultWorksheets = true;
private Workbook _workBook;
private Workbooks _workBooks;
private Sheets _workSheets;
public ExcelAppManager(string pathToExistingWorksheet)
{
_excelApp = new Application {DisplayAlerts = false};
_workBooks = _excelApp.Workbooks;
_workBook = _workBooks.Open(pathToExistingWorksheet, Type.Missing, false, Type.Missing, Type.Missing,
Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing,
Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing);
_workSheets = _workBook.Worksheets;
// NOTE: following lines are nice for debug of existing worksheets (to find the worksheets names)
//Get the reference of second worksheet
// var worksheet = (Microsoft.Office.Interop.Excel.ExcelWorksheet) _workSheets.Item[1];
// string strWorksheetName = worksheet.Name; //Get the name of worksheet.
_isDefaultWorksheets = true;
}
public ExcelAppManager()
{
}
public void Initialize()
{
_excelApp = new Application {DisplayAlerts = false};
_workBooks = _excelApp.Workbooks;
_workBook = _workBooks.Add(Missing.Value);
_workSheets = _workBook.Worksheets;
_isDefaultWorksheets = true;
}
public void KillProcess()
{
_workBook.Close();
_workBooks.Close();
_excelApp.Quit();
GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect();
GC.WaitForPendingFinalizers();
Marshal.FinalReleaseComObject(_workSheets);
Marshal.FinalReleaseComObject(_workBook);
Marshal.FinalReleaseComObject(_workBooks);
Marshal.FinalReleaseComObject(_excelApp);
}
public void SaveAs(string filepath, string fileExtensionOfExcelFile)
{
_excelApp.DisplayAlerts = false;
if (fileExtensionOfExcelFile == "xlsm")
{
_workBook.SaveAs(filepath, XlFileFormat.xlOpenXMLWorkbookMacroEnabled,
Type.Missing, Type.Missing, true, false, XlSaveAsAccessMode.xlNoChange,
XlSaveConflictResolution.xlLocalSessionChanges, Type.Missing, Type.Missing);
}
else
{
_workBook.SaveAs(filepath, Type.Missing,
Type.Missing, Type.Missing, true, false, XlSaveAsAccessMode.xlNoChange,
XlSaveConflictResolution.xlLocalSessionChanges, Type.Missing, Type.Missing);
}
}
internal Sheets GetSheets()
{
return _workSheets;
}
}
And in my client code, I use the ExcelAppManager like this:
var _manager = new ExcelAppManager(_excelFilepath);
When you use Interop library in VS2012 it use Office 2013 by default and your saving the workbook in that format. And later you are opening it up with Office 2010. This may be the reason for the Original format loss. Try to save the excel workbook in 2010 format this might resolve the issue.
I am trying to figure out the best way to interact with an OLE Server using C# .NET
i have found some code that enables interaction with COM+ that appears to work for the OLE server but I wonder if there is a more elegant or simpler way?
I require that it be late bound.
Code (as pilfered from elsewhere on the net)
// Code start
Type excel;
object[] parameter = new object[1];
object excelObject;
try
{
//Get the excel object
excel = Type.GetTypeFromProgID("Excel.Application");
//Create instance of excel
excelObject = Activator.CreateInstance(excel);
//Set the parameter whic u want to set
parameter[0] = true;
//Set the Visible property
excel.InvokeMember("Visible", BindingFlags.SetProperty, null, excelObject, parameter);
Obviously in my case I am putting the name of my ole server in where Excel.Application is, but I have seen cases in EARLY binding where you can call the function directly off the object without having to go via 'InvokeMember'
Is this possible? Can I use Type to cast as object as my type?
Thanks.
If you are using .NET 4.0 you can use dynamic instead of object and invoke the members as if they were there. This will then be checked at runtime, and if the name is correct, execute it.
//Get the excel object
var excel = Type.GetTypeFromProgID("Excel.Application");
//Create instance of excel
dynamic excelObject = Activator.CreateInstance(excel);
excelObject.Visible = true;
Try having a look at this from the add references. It gives you useful access to Excel.
Microsoft.Office.Core
Microsoft.Office.Interop.Excel
using Excel = Microsoft.Office.Interop.Excel;
...
if (openFileDialog.ShowDialog() == DialogResult.OK)
{
Excel.Application app;
Excel.Workbook workbook;
app = new Excel.ApplicationClass();
app.AutomationSecurity = Microsoft.Office.Core.MsoAutomationSecurity.msoAutomationSecurityForceDisable;
workbook = app.Workbooks.Open( openFileDialog.FileName,
0,
Type.Missing,
Type.Missing,
Type.Missing,
Type.Missing,
Type.Missing,
Type.Missing,
Type.Missing,
Type.Missing,
Type.Missing,
Type.Missing,
Type.Missing,
Type.Missing,
Type.Missing);
return workbook;
}
Cells and worksheets etc can be accessed like this:
Excel.Worksheet worksheet = (Excel.Worksheet)workbook.Worksheets.Item[1];
worksheet.Cells.Item[6, 1]).Value;
I have set my connection string as follows:-
"Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" + saveFilenameAndLocation + ";Extended Properties='Excel 12.0 xml; HDR=Yes' "
I have specified that the first row is a header and my excel spreadsheet is created with the header row, followed by all the data rows. However, I want to make my header row bold, how do i do this? Any help appreciated.
You need to use Office Interop; it can't be done with ADO.
Add a reference to your project to Microsoft.Office.Interop.Excel by right-clicking References in the Solution Explorer, and clicking 'Add Reference'. Then choose "Microsoft.Office.Interop.Excel".
Here is a very simple example that opens up an Excel document and makes the first row bold when you click a button on the user form.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using Microsoft.Office.Interop.Excel;
namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
String filename = "C:\\Path\\To\\Excel\\File\\file.xls";
Microsoft.Office.Interop.Excel.Application xlApp = new Microsoft.Office.Interop.Excel.Application();
xlApp.Visible = true;
Workbook xlWkb = xlApp.Workbooks.Open(filename, Type.Missing, Type.Missing, Type.Missing, Type.Missing,
Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing);
Worksheet xlSh = xlWkb.Sheets[1] as Worksheet;
Range xlRng = xlSh.UsedRange.get_Range("A1", Type.Missing).EntireRow;
xlRng.Font.Bold = true;
xlWkb.Save();
xlApp.Quit();
xlRng = null;
xlSh = null;
xlWkb = null;
xlApp = null;
}
}
}
OLEDB provides access to the data only, not the formatting.
To access cell attributes and so on, you need to either use Interop (http://msdn.microsoft.com/en-us/library/ms173186%28v=vs.80%29.aspx) or a thrid party component like Spire.xls (http://www.e-iceblue.com/Introduce/excel-for-net-introduce.html, commercial) or one of the other similar options (check Import and Export Excel - What is the best library?).
I have a C# application where I am creating numerous Excel Files from Data in a Database. This part is working fine. However, my user asked if the sheet tab could be modified to reflect a field from the database. This sounds simple, however, when I try to reset the name, it tells me that it is read only and cannot be set. I have tried the following and it has not worked:
xlApp.Sheets[0].Range["A1"].Value = "NewTabName";
ALSO TRIED:
xlApp.Name = "NewTabName";
I did a google search and saw some other approaches which did not work for me as well. And a few responses indicated that it is readonly and could not be done.
This seems like something that should be simple. How can I do it.
You need to get access to the actual worksheet. Try something like:
Microsoft.Office.Interop.Excel.Worksheet worksheet = (Worksheet)xlApp.Worksheets["Sheet1"];
worksheet.Name = “NewTabName”;
Here is a fairly complete example I am copying in from existing code.
Works perfectly on Windows 10 with Excel from Office 365
Ensure you add a reference to -
Microsoft.Office.Interop.Excel
My path for this DLL (may differ depending on office version) -
C:\WINDOWS\assembly\GAC_MSIL\Microsoft.Office.Interop.Excel\15.0.0.0__71e9bce111e9429c\Microsoft.Office.Interop.Excel.dll
// Add this at top of C# file -
using Excel = Microsoft.Office.Interop.Excel;
// In your class or function -
private static Excel.Application XlApp = null;
private static Excel.Workbook XlWorkbook = null;
// In your function -
XlApp = new Excel.ApplicationClass();
// Load workbook
XlWorkbook = XlApp.Workbooks.Open(#"Filename.xls",
0, false, Type.Missing, "", "", true, Excel.XlPlatform.xlWindows,
Type.Missing, Type.Missing, Type.Missing,
Type.Missing, true, Type.Missing,
Type.Missing);
// Get reference to sheet
XlWorksheet = (Excel.Worksheet)XlWorkbook.Worksheets["Sheet1"];
int numsheets = XlWorkbook.Sheets.Count;
// iterates through all sheets (1-n inclusive, not zero based)
for(int i=1;i<=numsheets;i++)
{
Excel.Worksheet sht = (Excel.Worksheet)XlWorkbook.Worksheets[i];
// Show sheet name
Console.WriteLine(i+" "+sht.Name);
}
// To save with a same or different filename
XlWorkbook.SaveAs(#"Filename.xls",
Excel.XlFileFormat.xlWorkbookNormal, "",
"", false, false,
Excel.XlSaveAsAccessMode.xlNoChange, Type.Missing,
true, Type.Missing, Type.Missing, Type.Missing);
// Close Excel
XlWorkbook.Close(true, Type.Missing, Type.Missing);
XlApp.Quit();
// Ensure you release resources
releaseObject(XlApp);
releaseObject(XlWorkbook);
releaseObject(XlWorksheet);
Separate function called from above
private static void releaseObject(object obj)
{
// try .. catch
System.Runtime.InteropServices.Marshal.ReleaseComObject(obj);
}