I have a C# helper class (ExcelMacroHelper
) that assists with injecting VBA macro code into open Excel workbooks and running the resulting macros. I just realized that the following steps would break my code:
C# application injects macro code into the active workbook, which causes the ExcelMacroHelper
to mark its state as ready to run macros
The user switches to a different workbook in Excel.
The C# application attempts to run a macro. The ExcelMacroHelper
will think it is ready to run macros, but the VBA code was injected into a different workbook so the call will fail.
To fix this, I think I need some way of setting a temporary property on the Workbook
object indicating that my macro code has been injected into it, or at least a way of maintaining a list of Workbook
s that have been handled. Any ideas?
I ended up using custom document properties. Something like this:
private bool needToInjectMacroCode() {
// Get custom document property with name tagPropertyName
object properties, property, propertyValue;
properties = excel.ActiveWorkbook.GetType().InvokeMember(
"CustomDocumentProperties",
BindingFlags.Default | BindingFlags.GetProperty,
null, excel.ActiveWorkbook, null);
try {
property = properties.GetType().InvokeMember(
"Item",
BindingFlags.Default | BindingFlags.GetProperty,
null, properties, new object[] { tagPropertyName });
} catch (TargetInvocationException) {
return true;
}
propertyValue = property.GetType().InvokeMember(
"Value",
BindingFlags.Default | BindingFlags.GetProperty,
null, property, null);
return (tagString != (propertyValue as string));
}
// ...
private void setMacroCodeInjected() {
// Set custom property with name tagPropertyName to value tagString
object properties = excel.ActiveWorkbook.GetType().InvokeMember(
"CustomDocumentProperties",
BindingFlags.Default | BindingFlags.GetProperty,
null, excel.ActiveWorkbook, null);
try {
properties.GetType().InvokeMember(
"Add",
BindingFlags.Default | BindingFlags.InvokeMethod,
null, properties, new object[] {
tagPropertyName, false,
Office.MsoDocProperties.msoPropertyTypeString,
tagString
});
} catch (TargetInvocationException) {
object property = properties.GetType().InvokeMember(
"Item",
BindingFlags.Default | BindingFlags.GetProperty,
null, properties, new object[] { tagPropertyName });
property.GetType().InvokeMember(
"Value",
BindingFlags.Default | BindingFlags.SetProperty,
null, property, new object[] { tagString });
}
}