我有一个C#帮助程序类(ExcelMacroHelper
),可以帮助将VBA宏代码注入打开的Excel工作簿并运行生成的宏。我刚刚意识到以下步骤会破坏我的代码:
C#应用程序将宏代码注入活动工作簿,这会导致ExcelMacroHelper
将其状态标记为准备运行宏
用户在Excel中切换到另一个工作簿。
C#应用程序尝试运行宏。 ExcelMacroHelper
会认为它已准备好运行宏,但是VBA代码被注入到不同的工作簿中,因此调用将失败。
要解决这个问题,我想我需要一些方法在Workbook
对象上设置一个临时属性,表明我的宏代码已经注入其中,或者至少是一种维护{{1已被处理的s。有什么想法吗?
答案 0 :(得分:1)
您可以使用名称来保存值(以及范围引用等)
在伪代码中
if not (name already exists) then
Set nm = workbook.Names.add("Injected")
nm.Value = False
nm.Visable = False
end if
if nm.value = False
//Inject Code
nm.value = true
endif
注意:测试名称是否存在的最简单方法是尝试访问它并处理错误(如果不存在)
答案 1 :(得分:0)
当您注入代码时,您可以执行以下操作:
public class ExcelMacroHelper
{
public static void Inject(Workbook workbook)
{
if ((workbook.Tag as String != "Injected"))
{
//Inject the code
workbook.Tag = "Injected";
}
}
}
答案 2 :(得分:0)
我最终使用了自定义文档属性。像这样:
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 });
}
}