System.Runtime.InteropServices.COMException when I use Microsoft.interop.Excel.dll - c#

I use Microsoft.interop.Excel.dll to convert Excel to .pdf. The core code:
using Microsoft.Office.Interop.Excel;
using ExcelApplicationClass = Microsoft.Office.Interop.Excel.ApplicationClass;
public static bool ExcelToPdf(string sourcePath, string targetPath, out string exmsg)
{
exmsg = string.Empty;
bool result = false;
object missing = Type.Missing;
ExcelApplicationClass applicationClass = null;
Workbook workBook = null;
try
{
applicationClass = new ExcelApplicationClass();
applicationClass.Visible = false;
/* applicationClas*/
workBook = applicationClass.Workbooks.Open(sourcePath);
if (workBook != null)
{
Microsoft.Office.Interop.Excel.Worksheet worksheet = workBook.ActiveSheet as Microsoft.Office.Interop.Excel.Worksheet;
//*** if I annotation the block in this if. the code no error occured.
if (worksheet != null)
{
worksheet.PageSetup.Zoom = false;
worksheet.PageSetup.FitToPagesWide = 1;
}
workBook.ExportAsFixedFormat(XlFixedFormatType.xlTypePDF, targetPath, XlFixedFormatQuality.xlQualityMinimum, false, true);
}
result = true;
}
catch (Exception ex)
{
exmsg = ex.Message;
result = false;
}
finally
{
if (workBook != null)
{
workBook.Close(true,missing, missing);
workBook = null;
}
if (applicationClass != null)
{
applicationClass.Quit();
applicationClass = null;
}
}
return result;
}
If I don't set worksheet.PageSetup's property like zoom etc. the program runs well but if I set the property System.Runtime.InteropServices.COMException will occur nine times out of ten. Sometime there is no error.
The error info
The environment information
Microsoft Excel 2013
Windows 10
Every time it has killed the Microsoft Excel progress.

Related

Date format change in Excel using C#

I have an issue while exporting content to excel. If it's an MM/dd/yyyy date then excel is taking it as a date format. If we format into dd/MM/yyyy then it's considered to be a custom format in excel.
Below is my code:
private string GetFormattedDateforCreation(string datestring) //yyyyMMdd
{
if (string.IsNullOrEmpty(datestring))
{
return null;
}
else
{
return DateTime.ParseExact(datestring, "yyyyMMdd", CultureInfo.GetCultureInfo("fr-CA")).ToString("dd/MM/yyyy");
}
}
Excel Generate
Clipboard.Clear();
// Bulk insertion of Data into Trigger Element Excel
bool multiselect1 = dgvElement.MultiSelect;
dgvElement.MultiSelect = true;
dgvElement.SelectAll();
dgvElement.ClipboardCopyMode = DataGridViewClipboardCopyMode.EnableWithoutHeaderText;
Clipboard.SetDataObject(dgvElement.GetClipboardContent());
var resultElement = System.Convert.ToString(Clipboard.GetData(DataFormats.Text));
dgvElement.ClearSelection();
dgvElement.MultiSelect = multiselect1;
Microsoft.Office.Interop.Excel.Application XCELAPPELEMENT = null;
Microsoft.Office.Interop.Excel.Workbook XWORKBOOKELEMENT = null;
Microsoft.Office.Interop.Excel.Worksheet XSHEETELEMENT = null;
object misValueElement = System.Reflection.Missing.Value;
XCELAPPELEMENT = new Microsoft.Office.Interop.Excel.Application();
XWORKBOOKELEMENT = XCELAPPELEMENT.Workbooks.Open(ExcelFilePath);
XCELAPPELEMENT.DisplayAlerts = false;
XCELAPPELEMENT.Visible = false;
XSHEETELEMENT = XWORKBOOKELEMENT.ActiveSheet;
XSHEETELEMENT.Paste();
XWORKBOOKELEMENT.SaveAs(Path.Combine(basePath, _frmSwip.OutputExcelFilePath, "SWIP_ElementsDeclencheurs_" + DateTime.Now.ToString("dd_mm_yyy HH_ss_mm")), Microsoft.Office.Interop.Excel.XlFileFormat.xlOpenXMLWorkbook);
XWORKBOOKELEMENT.Close(true);
XCELAPPELEMENT.Quit();
try
{
System.Runtime.InteropServices.Marshal.ReleaseComObject(XSHEETELEMENT);
System.Runtime.InteropServices.Marshal.ReleaseComObject(XWORKBOOKELEMENT);
System.Runtime.InteropServices.Marshal.ReleaseComObject(XCELAPPELEMENT);
}
catch
{
return "0";
}

Display and read an Excel file into a datagridview

I have successfully displayed the data using a code I found at this particular website. The problem is, the colour, bold or italics of the font isn't carried over. I need to read the code of a specific cell and convert it into a HTML string and display it as a textbox elsewhere. So I really need to learn how to import colour, bold or italics so I can convert it too. I will be eternally grateful to any kind soul who helps me on this one. Below is my current code.
string PathConn = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" + textBox1.Text + ";Extended Properties=\"Excel 8.0;HDR=Yes;\";";
OleDbConnection conn = new OleDbConnection(PathConn);
OleDbDataAdapter myDataAdapter = new OleDbDataAdapter("Select * from [sheet1$]", conn);
DataTable dt = new DataTable();
myDataAdapter.Fill(dt);
dataGridView1.DataSource = dt;
The following opens an Excel file in the app folder, get cell value, fore color, see if bold and italic is set for range sheet1 cell H2. Please note there is a decent amount of code which is warranted so that all objects used here are released upon finishing our work.
using System;
using System.Windows.Forms;
using Excel = Microsoft.Office.Interop.Excel;
namespace WindowsFormsApplication1_CS
{
public class ExcelCode
{
public System.Drawing.Color ForeColor;
public ExcelCode() { }
public string GetCellValue(
string FileName,
string SheetName,
string CellAddress)
{
string CellValue = "";
if (System.IO.File.Exists(FileName))
{
bool Proceed = false;
Excel.Application xlApp = null;
Excel.Workbooks xlWorkBooks = null;
Excel.Workbook xlWorkBook = null;
Excel.Worksheet xlWorkSheet = null;
Excel.Sheets xlWorkSheets = null;
Excel.Range xlCells = null;
xlApp = new Excel.Application();
xlApp.DisplayAlerts = false;
xlWorkBooks = xlApp.Workbooks;
xlWorkBook = xlWorkBooks.Open(FileName);
xlApp.Visible = false;
xlWorkSheets = xlWorkBook.Sheets;
for (int x = 1; x <= xlWorkSheets.Count; x++)
{
xlWorkSheet = (Excel.Worksheet)xlWorkSheets[x];
if (xlWorkSheet.Name == SheetName)
{
Proceed = true;
break;
}
System.Runtime.InteropServices
.Marshal.FinalReleaseComObject(xlWorkSheet);
xlWorkSheet = null;
}
if (Proceed)
{
xlCells = xlWorkSheet.Range[CellAddress];
try
{
Console.WriteLine("Bold: {0}", xlCells.Font.Bold); // bool
Console.WriteLine("Italic: {0}", xlCells.Font.Italic); // bool
ForeColor = System.Drawing.ColorTranslator.FromOle((int)xlCells.Font.Color);
CellValue = Convert.ToString(xlCells.Value);
}
catch (Exception)
{
// Reduntant
CellValue = "";
}
}
else
{
MessageBox.Show(SheetName + " not found.");
}
xlWorkBook.Close();
xlApp.UserControl = true;
xlApp.Quit();
ReleaseComObject(xlCells);
ReleaseComObject(xlWorkSheets);
ReleaseComObject(xlWorkSheet);
ReleaseComObject(xlWorkBook);
ReleaseComObject(xlWorkBooks);
ReleaseComObject(xlApp);
}
else
{
MessageBox.Show("'" + FileName +
"' not located. Try one of the write examples first.");
}
return CellValue;
}
public static void ReleaseComObject(object obj)
{
try
{
if (obj != null)
{
System.Runtime.InteropServices.Marshal.ReleaseComObject(obj);
obj = null;
}
}
catch (Exception)
{
obj = null;
}
}
}
}
Form code which works from a button and has a panel
var demoExcel = new ExcelCode();
// open an Excel file in the app folder, get information from H2 in Sheet1
textBox1.Text = demoExcel
.GetCellValue(
Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Demo.xlsx"),
"Sheet1",
"H2");
// Form has a panel, set back color to Sheet1.H2 color
panel1.BackColor = demoExcel.ForeColor;
// Translate the color to HTML
var htmlColor = System.Drawing.ColorTranslator.ToHtml(demoExcel.ForeColor);
Console.WriteLine(htmlColor.ToString());

C# not creating the excel file and cannot write in different excel sheets

First of all in my code im opening an excel sheet and reading it into a list. Second of all im closing this excel sheet and creating a new excel sheet:
excel_init("C:\\Users\\oma\\Desktop\\excel2.xlsx"); // this path does NOT exist yet
Next its going to this method:
static void excel_init(String path)
{
appExcel = new Microsoft.Office.Interop.Excel.ApplicationClass();
if (System.IO.File.Exists(path))
{
// then go and load this into excel
newWorkbook_First = appExcel.Workbooks.Open(path, true, true);
objsheet = (_Worksheet)appExcel.ActiveWorkbook.ActiveSheet;
}
else
{
try
{
appExcel = new Microsoft.Office.Interop.Excel.ApplicationClass();
appExcel.Visible = true;
newWorkbook_First = appExcel.Workbooks.Add(1);
objsheet = (Microsoft.Office.Interop.Excel.Worksheet)newWorkbook_First.Sheets[1];
objsheet.Name = ("test");
var newSheet3 = (Microsoft.Office.Interop.Excel.Worksheet)appExcel.Worksheets.Add(Type.Missing, appExcel.Worksheets[appExcel.Worksheets.Count], 1, XlSheetType.xlWorksheet);
newSheet3.Name = "test2";
var newSheet2 = (Microsoft.Office.Interop.Excel.Worksheet)appExcel.Worksheets.Add(Type.Missing, appExcel.Worksheets[appExcel.Worksheets.Count], 1, XlSheetType.xlWorksheet);
newSheet2.Name = "test3";
}
catch (Exception e)
{
Console.Write("Error");
}
finally
{
}
}
}
It wont create excel2.xlsx on my desktop, why not?
Next in my main I am shouting excel_setValue this way:
excel_setValue("C", "hello", "");
This is the excel_setValue function:
static void excel_setValue(string cellname, string value, string color)
{
objsheet.get_Range(cellname).set_Value(Type.Missing, value);
if (kleur == "red")
{
objsheet.get_Range(cellname).Interior.Color = System.Drawing.ColorTranslator.ToOle(System.Drawing.Color.Red);
}
}
How do I add the sheet to this? For exmaple: excel_setValue(cellname, value, color, sheetname)
Finally I do excel_close();
the excel_close function:
static void excel_close()
{
if (appExcel != null)
{
try
{
newWorkbook_First.Close();
System.Runtime.InteropServices.Marshal.ReleaseComObject(appExcel.ActiveWorkbook.ActiveSheet);
System.Runtime.InteropServices.Marshal.ReleaseComObject(appExcel.ActiveWorkbook);
System.Runtime.InteropServices.Marshal.ReleaseComObject(appExcel);
appExcel = null;
objsheet = null;
}
catch (Exception ex)
{
appExcel = null;
Console.WriteLine("Unable to release the Object " + ex.ToString());
}
finally
{
GC.Collect();
}
}
}
It closes and ask me if I wanna save/not-save or cancel it. And it will save # documents with no errors given
I create my Excel like this worked fine for me!
You need to do the folowing in you code before the newWorkbook_First.close(); part:
newWorkbook_First.SaveAs(totalPath);
I hope this will help you solve the problems..
using Excel = Microsoft.Office.Interop.Excel;
internal static bool ExportDGV(DataGridView DGV, List<string> selectedCustomerList, string path, string fileName, string exportName, int exportType, string mailSubject)
{
string totalPath;
//Create an Excel application instance
Excel.Application excelApp = new Excel.Application();
Excel.Workbook excelWorkBook = excelApp.Application.Workbooks.Add();
Excel._Worksheet worksheet = null;
excelApp.Visible = false;
worksheet = excelWorkBook.ActiveSheet;
//set headers
for (int i = 1; i < DataGridView.Columns.Count + 1; i++)
{
worksheet.Cells[1, i] = DGV.Columns[i - 1].HeaderText;
}
createList(worksheet, DGV);
//Create excel with the choosen name
Worksheet sheet1 = excelWorkBook.Worksheets[1];
worksheet.Name = fileName;
totalPath = path + "/" + fileName + ".xlsx";
//if path exist add a number
totalPath = directoryExist(totalPath, path, fileName);
//Save exel and Quit exelApp
excelWorkBook.SaveAs(totalPath);
excelWorkBook.Close();
excelApp.Quit();
}
You can use EpPlus library for excel. It is very easy to use and well documented. You don't need to use COM classes anymore

Solve OLE DB Connection without install Data Connectivity Components

Is there a way to solve the problem of OLEDB Connection (microsoft.ace.oledb.12.0' provider is not registered on the local machine) without install Data Connectivity Components while reading an excel file .
Please Advise.
try below code
using System;
using System.IO;
using System.Reflection;
using NUnit.Framework;
using ExcelTools = Ms.Office;
using Excel = Microsoft.Office.Interop.Excel;
namespace Tests
{
[TestFixture]
public class ExcelSingle
{
[Test]
public void ProcessWorkbook()
{
string file = #"C:\Users\Chris\Desktop\TestSheet.xls";
Console.WriteLine(file);
Excel.Application excel = null;
Excel.Workbook wkb = null;
try
{
excel = new Excel.Application();
wkb = ExcelTools.OfficeUtil.OpenBook(excel, file);
Excel.Worksheet sheet = wkb.Sheets["Data"] as Excel.Worksheet;
Excel.Range range = null;
if (sheet != null)
range = sheet.get_Range("A1", Missing.Value);
string A1 = String.Empty;
if( range != null )
A1 = range.Text.ToString();
Console.WriteLine("A1 value: {0}", A1);
}
catch(Exception ex)
{
//if you need to handle stuff
Console.WriteLine(ex.Message);
}
finally
{
if (wkb != null)
ExcelTools.OfficeUtil.ReleaseRCM(wkb);
if (excel != null)
ExcelTools.OfficeUtil.ReleaseRCM(excel);
}
}
}
}

C# Excel doesn't close itself when using OleDbConnection's Open method

I am creating and releasing references to excel com interfaces to manipulate excel's worksheets.
In this situation Excel closes itself correctly.
If I use OleDbDataAdapter connection to fetch data then excel is still in the memory.
I have read almost everything on this subject.
I have created subroutines to appropriate release references.
I am using:
GC.Collect();
GC.WaitForPendingFinalizers();
What else can I do?
This seems to be obscure problem..
Here is the code:
namespace ExcelTestCode
{
class Program
{
static void Main(string[] args)
{
Application excel = null;
Workbook workbook = null;
Worksheet workSheet = null;
object oMissing = Missing.Value;
excel = new Application { Visible = false };
workbook = excel.Workbooks.Open(#"c:\temp.xls", 0, false, 5, "", "",
true, XlPlatform.xlWindows, "\t", false, false, 0, true, true, oMissing);
workSheet = (Worksheet)workbook.Sheets[1];
try
{
string strError = "";
System.Data.DataTable dtTable = null;
//If I remove the following line, everything is allright
dtTable = ImportDataTableFromExcelIMEX(#"c:\temp.xls", out strError);
}
finally
{
if (workSheet != null)
{
Marshal.ReleaseComObject(workSheet);
workSheet = null;
}
if (workbook != null)
{
workbook.Close(false, oMissing, oMissing);
Marshal.ReleaseComObject(workbook);
workbook = null;
}
if (excel != null)
{
excel.Quit();
Marshal.ReleaseComObject(excel);
excel = null;
}
GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect();
}
}
public static System.Data.DataTable ImportDataTableFromExcelIMEX(string filename, out string error)
{
string connstring = #"Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" + filename + #";Extended Properties=""Excel 8.0;HDR=Yes;IMEX=1""";
OleDbConnection upocn = new OleDbConnection(connstring);
try
{
upocn.Open();
System.Data.DataTable dt = null;
dt = upocn.GetOleDbSchemaTable(OleDbSchemaGuid.Tables, null);
using (OleDbDataAdapter upoda = new OleDbDataAdapter("select * from [" + dt.Rows[0]["TABLE_NAME"].ToString() + "]", upocn))
{
DataSet upods = new DataSet();
error = string.Empty;
upoda.Fill(upods);
if (!string.IsNullOrEmpty(error))
return null;
return upods.Tables[0];
}
}
catch (Exception ex)
{
error = ex.Message;
}
finally
{
upocn.Close();
upocn = null;
}
return null;
}
}
}
try using (OleDbConnection upocn = new OleDbConnection(connectionString)), or call upocn.Dispose()
From MSDN OleDbConnection.Dispose: Releases all resources used by the System.ComponentModel.Component.
OleDbConnection.close: Closes the connection to the data source
Updated I can produce this problem if i do connection.close like in above code, but when i call dispose it works fine, I dont see any instance of excel. Below is code that works for me. Ensure you clean running instance from task manager before you test
class Program
{
static void Main(string[] args)
{
Application excel = null;
Workbook workbook = null;
Worksheet workSheet = null;
object oMissing = Missing.Value;
excel = new Application { Visible = false };
workbook = excel.Workbooks.Open(#"c:\Book1.xls", 0, false, 5, "", "",
true, XlPlatform.xlWindows, "\t", false, false, 0, true, true, oMissing);
workSheet = (Worksheet)workbook.Sheets[1];
try
{
string strError = "";
System.Data.DataTable dtTable = null;
//If I remove the following line, everything is allright
dtTable = ImportDataTableFromExcelIMEX(#"c:\Book1.xls", out strError);
}
finally
{
if (workSheet != null)
{
Marshal.ReleaseComObject(workSheet);
workSheet = null;
}
if (workbook != null)
{
workbook.Close(false, oMissing, oMissing);
Marshal.ReleaseComObject(workbook);
workbook = null;
}
if (excel != null)
{
excel.Quit();
Marshal.ReleaseComObject(excel);
excel = null;
}
GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect();
}
}
public static System.Data.DataTable ImportDataTableFromExcelIMEX(string filename, out string error)
{
string connstring = #"Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" + filename + #";Extended Properties=""Excel 8.0;HDR=Yes;IMEX=1""";
try
{
using (OleDbConnection upocn = new OleDbConnection(connstring))
{
upocn.Open();
System.Data.DataTable dt = null;
dt = upocn.GetOleDbSchemaTable(OleDbSchemaGuid.Tables, null);
using (OleDbDataAdapter upoda = new OleDbDataAdapter("select * from [" + dt.Rows[0]["TABLE_NAME"].ToString() + "]", upocn))
{
DataSet upods = new DataSet();
error = string.Empty;
upoda.Fill(upods);
if (!string.IsNullOrEmpty(error))
return null;
return upods.Tables[0];
}
}
}
catch (Exception ex)
{
error = ex.Message;
}
return null;
}
}
I had the same problem. Basically I had to put
finally
{
if (xlCmd != null)
{
xlCmd.Dispose();
xlCmd = null;
}
}
before initializing a new OleDBCommand xlCmd and
finally
{
if (xlCon != null)
xlCon.Dispose();
}
after telling OleDBConnection xlCon to close. Make sure you also initialize your excel connection with a using block such as below:
using (OleDbConnection xlCon = new OleDbConnection("Provider = Microsoft.ACE.OLEDB.12.0; " +
"Data Source = " + xlFile + ";Mode=ReadWrite;" +
"Extended Properties='Excel 12.0;HDR=YES;'")) //Automatically creates a new excel file (Do not include IMEX=1)
{
These manual cleanups are required if you want to open your file while your application is running and you're done with your export.

Categories