If I have a reference to Worksheet
and I close it's parent Workbook
, the reference doesn't go away. But I can't figure out how I should check to make sure these sheets don't exist. Checking for null
doesn't work.
Example:
Workbook book = Globals.ThisAddIn.Application.ActiveWorkbook;
Worksheet sheet = (Worksheet)book.Worksheets[1]; // Get first worksheet
book.Close(); // Close the workbook
bool isNull = sheet == null; // false, worksheet is not null
string name = sheet.Name; // throws a COM Exception
This is the exception I get when I try to access the sheet:
System.Runtime.InteropServices.COMException was caught
HResult=-2147221080
Message=Exception from HRESULT: 0x800401A8
Source=MyProject
ErrorCode=-2147221080
StackTrace:
at Microsoft.Office.Interop.Excel._Worksheet.get_Name()
at MyCode.test_Click(Object sender, RibbonControlEventArgs e) in c:\MyCode.cs:line 413
InnerException:
This wouldn't even be an issue if I could check for a workbook delete event, but Excel doesn't provide one (which is really annoying).
Is there some convenient way to make sure I don't use these worksheets?
I use this method :
private void releaseObject(object obj)
{
try
{
System.Runtime.InteropServices.Marshal.ReleaseComObject(obj);
obj = null;
}
catch (Exception ex)
{
obj = null;
MessageBox.Show("Exception Occured while releasing object " + ex.ToString());
}
finally
{
GC.Collect();
}
}
or you can try something like this:
static bool IsOpened(string wbook)
{
bool isOpened = true;
Excel.Application exApp;
exApp = (Excel.Application)System.Runtime.InteropServices.Marshal.GetActiveObject("Excel.Application");
try
{
exApp.Workbooks.get_Item(wbook);
}
catch (Exception)
{
isOpened = false;
}
return isOpened;
}
If the other solutions fail, another way to handle this is to store the name of the workbook after it opens, then check to see if that name exists in the Workbooks
collection before referencing the sheet. Referencing the workbooks by name will work since you can only have uniquely named workbooks in each instance of Excel.
public void Test()
{
Workbook book = Globals.ThisAddIn.Application.ActiveWorkbook;
string wbkName = book.Name; //get and store the workbook name somewhere
Worksheet sheet = (Worksheet)book.Worksheets[1]; // Get first worksheet
book.Close(); // Close the workbook
bool isNull = sheet == null; // false, worksheet is not null
string name;
if (WorkbookExists(wbkName))
{
name = sheet.Name; // will NOT throw a COM Exception
}
}
private bool WorkbookExists(string name)
{
foreach (Microsoft.Office.Interop.Excel.Workbook wbk in Globals.ThisAddIn.Application.Workbooks)
{
if (wbk.Name == name)
{
return true;
}
}
return false;
}
Edit: for completeness, a helper extension method:
public static bool SheetExists(this Excel.Workbook wbk, string sheetName)
{
for (int i = 1; i <= wbk.Worksheets.Count; i++)
{
if (((Excel.Worksheet)wbk.Worksheets[i]).Name == sheetName)
{
return true;
}
}
return false;
}
I've not tried this, but you could check if the Workbook sheet.Parent
exists in the Application.Workbooks collection.
User contributions licensed under CC BY-SA 3.0