I'm working in c# with Microsoft.Office.Interop.Excel.
I have a function used to open a workbook with excel. This workbook can be closed by user (or application). My problem is that I can't reopen this workbook.
Excel.Workbook Workbook;
private void OpenWorkbook(Excel.Application exApp)
{
// Check if a workbook has been opened
if (WorkBook != null)
{
// Create a workbook
WorkBook = exApp.Workbooks.Add();
}
else
{
// Add workbook to excel application
WorkBook = exApp.Workbooks.Add(WorkBook);
/*
=> this part doesn't work
Excel has been quit by user and I have a error : DisconnectedContext
*/
}
}
How can I reconnect or recreate my workbook ?
I think you miss the object Missing = System.Reflection.Missing.Value;.
Try it like in this example: http://pastebin.com/xqhu9eCK
Related
All,
Apologies if this is a very basic question and has been asked before, I predominately write in VBA / JAVA. However a project I am working on requires a C# script. Which carries out 3 simple steps:
Target a excel workbook which is already open. File path:
\Csdatg04\psproject\Robot\Peoplesoft To LV\Master Files - Do not use\Transactions into LV Template.xlsm
Populate cells A1,A2 & A3 with three variables already retrieved earlier in the automation.
Run a macro stored within the filepath mentioned above Macro name "ControlMacroACT"
The code I have developed is below, however in each stage identified above I am encountering errors (Probably basic errors).
Error 1: This line of code is to open a workbook I would like this to target an already active workbook.
Error 2: Worksheet not found
public void RunActualsMacro(string Filepath, string Period, String FiscalYear)
{
//~~> Define your Excel Objects
Excel.Application xlApp = new Excel.Application();
Excel.Workbook xlWorkBook;
//~~> Start Excel and open the workbook.
//Error 1
xlWorkBook = xlApp.Workbooks.Open("\\Csdatg04\\psproject\\Robot\\Peoplesoft To LV\\Master Files - Do not use\\Transactions into LV Template.xlsm");
// Populat Cells A1,A2,A3 with string variables
// Error 2 Worksheet not found
worksheet.Rows.Cells[1, 1] = Filepath;
worksheet.Rows.Cells[2, 1] = Period;
worksheet.Rows.Cells[3, 1] = FiscalYear;
//~~> Run the macro ControlMacroAct
xlApp.Run("ControlMacroACT");
//~~> Clean-up: Close the workbook
xlWorkBook.Close(false);
//~~> Quit the Excel Application
xlApp.Quit();
}
Any help would be much appreciated.
You need to use Marshal.GetActiveObject, and this code is roughly right, but cannot test right now.
public void RunActualsMacro(string Filepath, string Period, String FiscalYear)
{
//~~> Define your Excel Objects
Excel.Application xlApp = null;
Excel.Workbook xlWorkBook;
//~~> Start Excel and open the workbook.
//handle errors below
try {
xlApp = (Excel.Application) System.Runtime.InteropServices.Marshal.GetActiveObject("Excel.Application");
} catch {
//perhaps exit - or throw??
}
xlWorkBook = xlApp.Workbooks["Transactions into LV Template.xlsm"];
// Populat Cells A1,A2,A3 with string variables
Excel.Worksheet ws = xlWorkBook.Worksheets["Sheet1"] //what the tab name of sheet
ws.Cells[1, 1] = Filepath;
ws.Cells[2, 1] = Period;
ws.Cells[3, 1] = FiscalYear;
//~~> Run the macro ControlMacroAct
xlApp.Run("ControlMacroACT");
//~~> Clean-up: Close the workbook
xlWorkBook.Close(false);
//~~> Quit the Excel Application
xlApp.Quit();
}
I'm currently trying to copy a worksheet from a different workbook which i succeed by using Copy() and PasteSpecial(). However, I would like to know why the following code does not work even though many solutions online seems to use this approach.
Workbook currBook = Globals.ThisAddIn.GetActiveWorkbook();
Workbook copyBook = Globals.ThisAddIn.OpenWorkbook(Globals.ThisAddIn.Application.ActiveWorkbook.Path + #"\copyFile.xlsm", true, true);
//required worksheet
Worksheet copySheet = Globals.ThisAddIn.GetWorksheet(copyBook, "ToCopy");
copySheet.Copy(currBook.Worksheets[1]);
//close workbook
copyBook.Close();
Function used to get specific sheet:
public Excel.Worksheet GetWorksheet(Excel.Workbook book, string sheetName, bool create = false)
{
foreach (Excel.Worksheet sheet in book.Worksheets)
{
//worksheet with name found
if (sheet.Name == sheetName)
{
sheet.Activate();
return sheet;
}
}
//worksheet can't be found
if (create)
{
Excel.Worksheet sheet = book.Worksheets.Add();
sheet.Name = sheetName;
sheet.Activate();
return sheet;
}
return null;
}
There is no error from the stated code and the worksheet has been tested to exist. The program simply does not create a copy into currBook
Interestingly, I was just working on something else where this came up...
In order to specify a destination it's necessary to use Range.Copy, not Sheet.Copy:
copySheet.UsedRange.Copy(currBook.Worksheets[1].Range["A1"]);
If a destination can't be specified, then Excel puts the data in a new workbook.
Morning,
I am writing simple windows service that will take excel file from given location, generate xml file and move excel to another folder.
I am using:
Excel = Microsoft.Office.Interop.Excel
My code looks like this:
Excel.Application xlApp = null;
Excel.Workbook xlWorkBook = null;
Excel.Worksheet xlWorkSheet = null;
try
{
xlApp = new Excel.Application();
xlWorkBook = xlApp.Workbooks.Open(file);
xlWorkSheet = (Excel.Worksheet)xlWorkBook.Worksheets.get_Item("Części");
//doing something with xml and excel
xlApp.DisplayAlerts = false;
xlWorkBook.Close();
xlApp.Quit();
} catch (Exception e) {
this.writeErrorLog(e);
} finally {
// Close the Excel process
if (null != xlWorkSheet)
Marshal.ReleaseComObject(xlWorkSheet);
if (null != xlWorkBook)
Marshal.ReleaseComObject(xlWorkBook);
Marshal.ReleaseComObject(xlApp);
GC.Collect();
}
My problem is that when i run it as normal program it works fine and does everything i need. But when i create service and install it, it creates exceptions every time i upload excel file to this folder. Exception says that program could not gain access to my excel file.
System.Runtime.InteropServices.COMException
I have checked this topic but it didn't help me. Can anyone help me solve this problem?
EDIT: Btw. I am using this tutorial to create service.
EDITv2: The way i take file paths:
string sc_path = #"C:\Projekty\AAPLXML\AppFolders\upload";
string tg_path = #"C:\Projekty\AAPLXML\AppFolders\processed";
if (System.IO.Directory.Exists(sc_path) && System.IO.Directory.Exists(tg_path))
{
List<string> files = System.IO.Directory.GetFiles(sc_path).ToList();
if (files.Count == 0) return;
files.ForEach(f => new XmlGenerator(f).Start());
}
I'm using Excel = Microsoft.Office.Interop.Excel to write various data to Excel sheets.
Excel.Workbook wb = null;
Excel.Worksheet ws = null;
Excel.Application excelApp = new Excel.Application();
excelApp.Visible = true;
try {
// Create new workbook
wb = (Excel.Workbook)(excelApp.Workbooks.Add(Type.Missing));
ws = wb.ActiveSheet as Excel.Worksheet;
// write data ...
// Save & Close
excelApp.DisplayAlerts = false; // Don't show file dialog for overwrite
wb.Close(true, targetFilename, Type.Missing);
} finally {
// Close the Excel process
if (null != ws)
Marshal.ReleaseComObject(ws);
if (null != wb)
Marshal.ReleaseComObject(wb);
excelApp.Quit();
Marshal.ReleaseComObject(excelApp);
GC.Collect();
}
This code is exectued by multiple threads at a time, and it's been working almost always. Even the Excel processes disappear in task manager.
However, sometimes a System.Runtime.InteropServices.COMException is thrown at wb.Close(true, targetFilename, Type.Missing). It claims that access on the target filename was denied. Though I've been making sure that the target filenames are unique.
May the exception be due to any bad handling of Excel or maybe that I'm using threads?
Apparently, targetFilename wasn't really unique. There was one single difference in upper/lower case spelling, and it seems like two threads tried to write to the same file at once. The issue was easily solvable by using targetFilename.ToLower().
Anyway, if you discover any further potential issues, please leave a comment.
How can I open my Excel worksheet in the current open instance of Microsoft Excel? When I use my code, a new instance of Excel is opened.
private Excel.Application xlApp;
private Excel.Workbook xlWorkBook;
private Excel.Worksheet xlWorkSheet;
xlApp = new Excel.Application();
xlApp.Visible = true;
xlWorkBook = xlApp.Workbooks.Open(textBox1.Text);
xlWorkSheet = (Excel.Worksheet)xlWorkBook.ActiveSheet;
You can do something like the following to get a reference to a running Excel instance (if there is one):
public Excel.Application TryGetExistingExcelApplication()
{
try
{
object o = Marshal.GetActiveObject("Excel.Application");
return (Excel.Application)o;
}
catch (COMException)
{
// Probably there is no existing Excel instance running, return null
return null;
}
}
Once you have a reference to a running instance, you can access it's Workbooks collection.
One caveat: if you try to automate an existing Excel instance, you may get "server busy" exceptions. To avoid this, you can implement IOleMessageFilter error handlers. This article describes how to do it for automating Visual Studio; the technique is identical for automating Excel.