I'm trying to get C# to examine whatever workbook the user has selected and find any sheets which would
contain stock data. Concretely this would mean looking at a range of cells (say r<6, c<10) for "Close", "close" or
"CLOSE".
The following code shows the point at which the user has selected an .xls file.
I'm not sure how to loop through the sheets in the workbook to look for the desired text.
I'm assuming it involves creating a collection of sheets and assigning it to those in the
current workbook, but my attempts so far haven't worked.
private void button1_Click(object sender, System.EventArgs e)
{
try
{
OpenFileDialog dlg = new OpenFileDialog();
dlg.Filter = "Excel Files (*.xls)|*.XLS";
if (dlg.ShowDialog() == DialogResult.OK)
{
// MessageBox.Show(dlg.FileName, "My Application", MessageBoxButtons.OKCancel, MessageBoxIcon.Asterisk);
Excel.Application xlApp = new Excel.ApplicationClass();
xlApp.Visible = true;
Excel.Workbook xlWorkbook = xlApp.Workbooks.Open(dlg.FileName,
0, false, 5, "", "", false, Excel.XlPlatform.xlWindows, "",
true, false, 0, true, false, false);
}
}
catch (Exception theException)
{
String errorMessage;
errorMessage = "Error: ";
errorMessage = String.Concat(errorMessage, theException.Message);
errorMessage = String.Concat(errorMessage, " Line: ");
errorMessage = String.Concat(errorMessage, theException.Source);
MessageBox.Show(errorMessage, "Error");
}
}
Thanks for any ideas.
Jeff
Always take extra care to clean up when using the Interop libraries. Otherwise, you're likely to end up with a couple dozen EXCEL.EXE processes running in the background while you debug (or when a user hits an error).
private static bool IsStockDataWorkbook(string fileName)
{
Excel.Application application = null;
Excel.Workbook workbook = null;
try
{
application = new Excel.ApplicationClass();
application.Visible = true;
workbook = application.Workbooks.Open(fileName, Missing.Value, Missing.Value, Missing.Value, Missing.Value, Missing.Value, Missing.Value, Missing.Value, Missing.Value, Missing.Value, Missing.Value, Missing.Value, Missing.Value, Missing.Value, Missing.Value);
foreach (Excel.Worksheet sheet in workbook.Worksheets)
{
if (IsStockWorksheet(sheet))
{
return true;
}
}
return false;
}
finally
{
if (workbook != null)
{
workbook.Close(false, Missing.Value, Missing.Value);
}
if (application != null)
{
application.Quit();
}
}
}
private static bool IsStockWorksheet(Excel.Worksheet workSheet)
{
Excel.Range testRange = workSheet.get_Range("C10", Missing.Value);
string value = testRange.get_Value(Missing.Value).ToString();
return value.Equals("close", StringComparison.InvariantCultureIgnoreCase);
}
You'll need to assign objSheets to something, most likely:
Excel.Sheets objSheets = xlWorkbook.Sheets;
Your foreach statement should look more like this (with no prior declaration of the ws variable):
foreach(Excel.Worksheet ws in objSheets)
{
rng = ws.get_Range(ws.Cells[1,1], ws.Cells[5,9]);
}
Obviously, you'll want to do something more substantial in that loop.
This is an easy one :) use the sheets collection in the workbook object.
Workbooks workbooks = xlApp.Workbooks;
foreach(Workbook wb in workbooks)
{
Worksheets worksheets = wb.Worksheets;
foreach(Worksheet ws in worksheets)
{
Range range = ws.get_Range(ws.Cells[1,1], ws.Cells[5,9]);
Range match = range.Find("close", ws.Cells[1,1],
xlFindLookIn.xlValues, xlLookAt.xlPart,
xlSearchOrder.xlByColumns, xlSearchDirection.xlNext,
false, false, false); //that first false means ignore case
// do something with your match here
// this will only return the first match; to return all
// you'll need to run the match in a while loop
}
}
Related
I am using the below mentioned code for finding the row count of an Excel table but it seems there is something wrong since I am not getting the desired output. Please provide some solution to it.
The code is as follows:
using Excel = Microsoft.Office.Interop.Excel;
Excel.Application xlApp = null;
Excel.Workbook wb = null;
Excel.Worksheet worksheet = null;
int lastUsedRow = 0;
string srcFile = #"Path to your XLSX file";
xlApp = new Excel.ApplicationClass();
xlApp.Visible = false;
wb = xlApp.Workbooks.Open(srcFile,
0, false, 5, "", "", false, Excel.XlPlatform.xlWindows, "",
true, false, 0, true, false, false);
worksheet = (Excel.Worksheet)wb.Worksheets[1];
Excel.Range range
// Find the last real row
lastUsedRow = worksheet.Cells.Find("*",System.Reflection.Missing.Value,
System.Reflection.Missing.Value,
System.Reflection.Missing.Value,
Excel.XlSearchOrder.xlByRows,Excel.XlSearchDirection.xlPrevious,
false,System.Reflection.Missing.Value,System.Reflection.Missing.Value).Row;
xlApp.Workbooks.Close();
xlApp.Quit();
Marshal.ReleaseComObject(worksheet);
Marshal.ReleaseComObject(wb);
Marshal.ReleaseComObject(xlApp);
You can try:
wb = xlApp.Workbooks.Open(srcFile,
Missing.Value, Missing.Value, Missing.Value, Missing.Value, Missing.Value, Missing.Value, Missing.Value, Missing.Value,
Missing.Value, Missing.Value, Missing.Value, Missing.Value, Missing.Value, Missing.Value);
worksheet = (Excel.Worksheet)wb.Worksheets[1];
object[,] values = worksheet .UsedRange.Value2;
int rowCount = values.GetLength(0);
int colCount = values.GetLength(1);
I have more than 100 excel files.My job is to merge to all the excel files into one excel. I did easily by writing the C# program for merging excels. Now I need to Identify the records as per the excel file name.I mean I need to add the actual Excel file name to the new columns for all rows exists.
For Example:
I have excel Dom.xls having 2 rows in that excel.
Name SSN Address
1 0923 1 winter st
2 0924 2 winter st
Now I need the excel should create new column named"Excel File Name"
and should write the file name like beow
Name SSN Address Excel File Name
1 0923 1 winter st dom.xls
2 0924 2 winter st dom.xls
How Do I achieve this.
Either I need this requirement before merging all the excels or after merging the excels.
Below code I used to merge all excels.
class Program
{
static void Main(string[] args)
{
MergeExcel.DoMerge(new string[]
{
#"C:\Users\dom\Desktop\Reim Account\032 - dom_AMESBURY.xlsx",
#"C:\Users\dom\Desktop\Reim Account\128 - dom_BRAINTREE.xlsx",
#"C:\Users\dom\Desktop\Reim Account\960 - dom_RETIREMENT.xlsx"....etc
},
#"D:\MyExcel\dom.xlsx", "V", 2);
}
}
public class MergeExcel
{
Excel.Application app = new Microsoft.Office.Interop.Excel.ApplicationClass();
//initialize the object of saved target
Excel.Workbook bookDest = null;
Excel.Worksheet sheetDest = null;
//initialize the object of read data
Excel.Workbook bookSource = null;
Excel.Worksheet sheetSource = null;
string[] _sourceFiles = null;
string _destFile = string.Empty;
string _columnEnd = string.Empty;
int _headerRowCount = 0;
int _currentRowCount = 0;
public MergeExcel(string[] sourceFiles, string destFile, string columnEnd, int headerRowCount)
{
//Use class Missing case to indicate the missing value. e.g. when you call the method that has default parameter value
bookDest = (Excel.WorkbookClass)app.Workbooks.Add(Missing.Value);
sheetDest = bookDest.Worksheets.Add(Missing.Value, Missing.Value, Missing.Value, Missing.Value) as Excel.Worksheet;
sheetDest.Name = "Data";
_sourceFiles = sourceFiles;
_destFile = destFile;
_columnEnd = columnEnd;
_headerRowCount = headerRowCount;
}
//open worksheet
void OpenBook(string fileName)
{
bookSource = app.Workbooks._Open(fileName, Missing.Value, Missing.Value, Missing.Value, Missing.Value, Missing.Value, Missing.Value, Missing.Value, Missing.Value, Missing.Value, Missing.Value, Missing.Value, Missing.Value);
sheetSource = bookSource.Worksheets[1] as Excel.Worksheet;
}
//close worksheet
void CloseBook()
{
bookSource.Close(false, Missing.Value, Missing.Value);
}
//copy table header
void CopyHeader()
{
Excel.Range range = sheetSource.get_Range("A1", _columnEnd + _headerRowCount.ToString());
range.Copy(sheetDest.get_Range("A1", Missing.Value));
_currentRowCount += _headerRowCount;
}
//copy data
void CopyData()
{
int sheetRowCount = sheetSource.UsedRange.Rows.Count;
Excel.Range range = sheetSource.get_Range(string.Format("A{0}", _headerRowCount), _columnEnd + sheetRowCount.ToString());
range.Copy(sheetDest.get_Range(string.Format("A{0}", _currentRowCount), Missing.Value));
_currentRowCount += range.Rows.Count;
}
//save the result
void Save()
{
bookDest.Saved = true;
bookDest.SaveCopyAs(_destFile);
}
//exit the process
void Quit()
{
app.Quit();
}
void DoMerge()
{
//declare variate bool to judge if copy table header
bool b = false;
foreach (string strFile in _sourceFiles)
{
OpenBook(strFile);
if (b == false)
{
CopyHeader();
b = true;
}
CopyData();
CloseBook();
}
Save();
Quit();
}
/// merge table
/// source file
/// object file
/// the sign of the last column
/// the number of rows of table header
public static void DoMerge(string[] sourceFiles, string destFile, string columnEnd, int headerRowCount)
{
new MergeExcel(sourceFiles, destFile, columnEnd, headerRowCount).DoMerge();
}
}
You could do something like this in CopyData. Send the filename to CopyData void CopyData(string strFile). Then after range.Copy add the following lines.
Excel.Range range_name = sheetDest.get_Range(string.Format("E{0}", _currentRowCount), string.Format("E{0}", _currentRowCount + sheetRowCount));
range_name.Value = strFile;
This will add the filename to column E. Maybe some tweaking is necessary since I'm not that familiar with Excel Interop.
I'm working on c# windows application with SQL server.
I'm getting an error like the following when tried to do Save-as in excel in c#. But inside workbook.open statement and workbook.saveas am changing readonly attribute as false.I need to save the excel with the same name only.Can anybody please help me.
Cannot access readonly document filename.xlsx
private static Microsoft.Office.Interop.Excel.Workbook mWorkBook;
private static Microsoft.Office.Interop.Excel.Sheets mWorkSheets;
private static Microsoft.Office.Interop.Excel.Worksheet mWSheet1;
private static Microsoft.Office.Interop.Excel.Application oXL;
string path = #"D:\Test\test.xlsx";
oXL = new Microsoft.Office.Interop.Excel.Application();
oXL.Visible = true;
oXL.DisplayAlerts = false;
mWorkBook = oXL.Workbooks.Open(path, 0, false, 5, "", "", false, Microsoft.Office.Interop.Excel.XlPlatform.xlWindows, "", true, false, 0, true, false, false);
//Get all the sheets in the workbook
mWorkSheets = mWorkBook.Worksheets;
//Get the allready exists sheet
mWSheet1 = Microsoft.Office.Interop.Excel.Worksheet)mWorkSheets.get_Item("Sheet1");
mWSheet1.Cells[i+2, 5] = DBDaysWorked;
mWorkBook.SaveAs(path, System.Reflection.Missing.Value,
System.Reflection.Missing.Value,
System.Reflection.Missing.Value,
false,false, Microsoft.Office.Interop.Excel.XlSaveAsAccessMode.xlShared,
false,
false,
System.Reflection.Missing.Value,
System.Reflection.Missing.Value,
System.Reflection.Missing.Value);
mWorkBook.Close(Missing.Value, Missing.Value, Missing.Value);
mWSheet1 = null;
mWorkBook = null;
oXL.Quit();
GC.WaitForPendingFinalizers();
GC.Collect();
The problem is with the flag XlSaveAsAccessMode.xlShared when saving the document, it throws the error:
This workbook cannot be shared because privacy has been enabled for this workbook. To share this workbook, click the File tab, and then click Excel Options. In the Excel Options dialog box, click Trust Center, and then click the Trust Center Settings button. In the Privacy Options category, clear the check box next to the option Remove personal information from file properties on save.
Removing this option does indeed fix the error. Alternatively setting the flag to XlSaveAsAccessMode.xlNoChange works if you're not bothered about sharing the workbook.
I'm not sure if you can automate removing this property from a workbook to prevent the error.
For the record, I found this by simply wrapping your code in a try/catch and throwing an error...
Garbage Collection
Before the try block that you should have now added hint hint ;-)
Initialise everything to null so that it will be accessible in the finally block.
Microsoft.Office.Interop.Excel.Workbook mWorkBook = null;
Microsoft.Office.Interop.Excel.Sheets mWorkSheets = null;
Microsoft.Office.Interop.Excel.Worksheet mWSheet1 = null;
Microsoft.Office.Interop.Excel.Application oXL = null;
You normal code is fine and can go in the try block. Catch only errors you can handle and recover from. Then in the finally block:
if (mWorkBook != null)
{
mWorkBook.Close(Missing.Value, Missing.Value, Missing.Value);
}
if (oXL != null)
{
oXL.Quit();
if (mWSheet1 != null)
{
Marshal.FinalReleaseComObject(mWSheet1);
mWSheet1 = null;
}
if (mWorkSheets != null)
{
Marshal.FinalReleaseComObject(mWorkSheets);
mWorkSheets = null;
}
if (mWorkBook != null)
{
Marshal.FinalReleaseComObject(mWorkBook);
mWorkBook = null;
}
Marshal.FinalReleaseComObject(oXL);
oXL = null;
}
GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect();
GC.WaitForPendingFinalizers();
I'm working with Excel sheet of .xls format and writing data into it. The problem is that whenever the data doesn't start with alphabets it is prompting me different errors.
For example: When my column data started with =?us-ascii?Q?Google Keywords?= it threw me an exception:
Exception from HRESULT: 0x800A03EC
and when my data is like -------- Original Message --------Subject: the error was:
Not enough storage is available to complete this operation. (Exception from HRESULT: 0x8007000E (E_OUTOFMEMORY))
This is how I'm writing data:
foreach (AllCasesReplies infoList in allCasesReplies)
{
n = 0;
mWorkSheet.Cells[l + m, ++n] = infoList.id;
mWorkSheet.Cells[l + m, ++n] = infoList.replies;
m++;
}
This is how I clean my objects:
private static void SaveAndCollecttheGarbage(Microsoft.Office.Interop.Excel.Application excelApp, string path, Microsoft.Office.Interop.Excel.Sheets sheet)
{
excelApp.Columns.AutoFit();
mWorkBook.SaveAs(path, Microsoft.Office.Interop.Excel.XlFileFormat.xlWorkbookNormal,
Missing.Value, Missing.Value, Missing.Value, Missing.Value, Microsoft.Office.Interop.Excel.XlSaveAsAccessMode.xlExclusive,
Missing.Value, Missing.Value, Missing.Value,
Missing.Value, Missing.Value);
mWorkBook.Close(true, Missing.Value, Missing.Value);
sheet = null;
mWorkBook = null;
excelApplication.Quit();
GC.WaitForPendingFinalizers();
GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect();
}
So I have tried omitting these data and they are working great.
Are there any rules that the column has to start with specific characters and if so, what are these?
if you type "?" in excel cell that has general format, the excel automaticall interprete that as a formula. You need to change the cell format before inserting the text into the cell.
something like:
foreach (AllCasesReplies infoList in allCasesReplies)
{
n = 0;
Microsoft.Office.Interop.Excel.Range range1 = mWorkSheet.Cells[l + m, ++n] as Range;
range1.NumberFormat = "#";
range1.Value2 = infoList.id;
Microsoft.Office.Interop.Excel.Range range2 = mWorkSheet.Cells[l + m, ++n] as Range;
range2.NumberFormat = "#";
range2.Value2 = infoList.replies;
m++;
}
I write a c# program for copy sheet. I got the exception error(0x800A03EC) when I call WorkSheet.Copy method until 105 times.
This is my snippet code: using Microsoft.Office.Interop.Excel;
private void CreateSheet(string dst_fileName)
{
object cell1 = "A2";
ApplicationClass app = null;
Workbook book = null;
Worksheet sheet = null;
Worksheet sheet_to_copy = null;
int i=0;
try
{
app = new ApplicationClass();
app.Visible = false;
app.ScreenUpdating = false;
app.DisplayAlerts = false;
book = app.Workbooks.Open(dst_fileName, 0, false, 5, "", "", true,
XlPlatform.xlWindows,
"\t", false, false, 0, true, 1, 0);
// Reference to the worksheet
sheet_to_copy = (Worksheet)book.Worksheets[1];
for(;i<listViewPrg.Items.Count;i++)
{
sheet = (Worksheet)book.Worksheets[book.Worksheets.Count];
// Copy the worksheet to the end of the worksheets
sheet_to_copy.Copy(Missing.Value, sheet);
sheet.Name = "NewSheet(" + book.Worksheets.Count + ")";
}
book.SaveAs(dst_fileName, Missing.Value, Missing.Value, Missing.Value,
Missing.Value, Missing.Value, XlSaveAsAccessMode.xlNoChange, Missing.Value,
Missing.Value, Missing.Value, Missing.Value, Missing.Value);
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
}
finally
{
QuitExcel(app);
}
}
I can't found any solution about this. Could someone give me a hint to solve this problem?
Thank you so much.
Possibly you have some corrupted Excel registry entries or so?
Why don't you try to use an open source reader of excel files and do everything using them? The speed would skyrocket and i guarantee you would not get these errors!