可变数量的参数 C# Interop
Variable number of Parameters C# Interop
有一个 dtsx 包,运行s SSRS 使用配置 table 报告,然后在生成的 .xls(它是 2008 R2 服务器)文件上需要时执行宏.
配置的每一行 table 包含要 运行 的报告的详细信息、宏的详细信息以及要传递给宏的参数和值的 xml 列表;包中有一个 foreach 循环,运行s 报告,向输出文件添加一个宏,运行s 宏并继续。
看起来好像是为了尽可能通用化而设计的,所以任何报告和任何宏都可以在配置中输入table。
这工作正常,但尽管它看起来很灵活,但加载的脚本代码中的实际 C# 和 运行s 宏具有非常严格的结构,这意味着只有宏具有4 个参数可以是 运行 - 我想让它更灵活,但我正在努力研究如何根据节点的数量为 ExcelObject.Run()
命令提供正确(可变)的参数数量配置 xml.
我在使用 C# 方面不是很有经验,但从阅读 this Microsoft and this Whosebug 文章看来,我可以制作一个参数数组并传递它...我只是不知道如何做。这是现有的脚本:
using System;
using System.IO;
using System.Xml;
using System.Collections;
using System.Collections.Generic;
using System.Data;
using System.Diagnostics;
using System.Text;
using Excel = Microsoft.Office.Interop.Excel;
using Microsoft.SqlServer.Dts.Runtime;
using System.Reflection;
using VBIDE = Microsoft.Vbe.Interop;
namespace ST_b2148758d9a44ee4bc0d01a2d900ce9d.csproj
{
[System.AddIn.AddIn("ScriptMain", Version = "1.0", Publisher = "", Description = "")]
public partial class ScriptMain : Microsoft.SqlServer.Dts.Tasks.ScriptTask.VSTARTScriptObjectModelBase
{
enum ScriptResults
{
Success = Microsoft.SqlServer.Dts.Runtime.DTSExecResult.Success,
Failure = Microsoft.SqlServer.Dts.Runtime.DTSExecResult.Failure
};
public void Main()
{
Variables UserVariables = null;
Dts.VariableDispenser.LockForRead("User::SaveLoc_Root");
Dts.VariableDispenser.LockForRead("User::SaveLoc_SubFolder");
Dts.VariableDispenser.LockForRead("User::SaveLoc_FileName");
Dts.VariableDispenser.LockForRead("User::SaveLoc_FileExtension");
Dts.VariableDispenser.LockForRead("User::VBA_Macro_Name");
Dts.VariableDispenser.LockForRead("User::VBA_Parameters");
Dts.VariableDispenser.LockForRead("User::VBA_Script");
Dts.VariableDispenser.GetVariables(ref UserVariables);
string SaveToLocation = null, ConstantName = null, DateFormat = null , SheetNameInCell = null;
//build the filename of the report we just made.
//@"C:\Temp\Repart.xls";
string Report_File_name = UserVariables["User::SaveLoc_Root"].Value.ToString()
+ UserVariables["User::SaveLoc_SubFolder"].Value.ToString()
+ UserVariables["User::SaveLoc_FileName"].Value.ToString()
+ UserVariables["User::SaveLoc_FileExtension"].Value.ToString();
//The macro and the macro name were stored in the original data set, so we can get those from local variables.
string Macro = UserVariables["User::VBA_Script"].Value.ToString();
string Macro_name = UserVariables["User::VBA_Macro_Name"].Value.ToString();
XmlDocument doc = new XmlDocument();
doc.LoadXml(UserVariables["User::VBA_Parameters"].Value.ToString());
XmlNodeList Parameters = doc.GetElementsByTagName("Parameter");
//skip through all the parameters we might have - if more are added, this will need to be changed.
for (int i = 0; i < Parameters.Count; i++)
{
string ParamName = Parameters[i].Attributes["Name"].Value.ToString();
if (ParamName == "SaveToLocation")
{
SaveToLocation = Parameters[i].Attributes["Value"].Value.ToString();
}
else if (ParamName == "ConstantName")
{
ConstantName = Parameters[i].Attributes["Value"].Value.ToString();
}
else if (ParamName == "DateFormat")
{
DateFormat = Parameters[i].Attributes["Value"].Value.ToString();
}
else if (ParamName == "SheetNameInCell")
{
SheetNameInCell = Parameters[i].Attributes["Value"].Value.ToString();
}
}
//Get Excel ready to be opened
Excel.Application ExcelObject = default(Excel.Application);
Excel.WorkbookClass oBook = default(Excel.WorkbookClass);
Excel.Workbooks oBooks = default(Excel.Workbooks);
//get the vba module ready
VBIDE.VBComponent module = null;
//open excel in the background
ExcelObject = new Excel.Application();
ExcelObject.Visible = false;
//Open our report
oBooks = ExcelObject.Workbooks;
oBook = (Excel.WorkbookClass)oBooks.Open
(Report_File_name
,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);
//Add a module to our report and populate it with our vba macro
module = oBook.VBProject.VBComponents.Add(VBIDE.vbext_ComponentType.vbext_ct_StdModule);
module.CodeModule.AddFromString(Macro);
//run the macro
ExcelObject.Run
( Macro_name,SaveToLocation,ConstantName,DateFormat,SheetNameInCell, 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, Missing.Value,Missing.Value, Missing.Value, Missing.Value, Missing.Value,Missing.Value
,Missing.Value, Missing.Value, Missing.Value,Missing.Value, Missing.Value, Missing.Value);
ExcelObject.Visible = false;
ExcelObject.UserControl =false;
//oBook.Save();
ExcelObject.DisplayAlerts =false;
ExcelObject.Application.Quit();
ExcelObject =null;
}
}
}
xml 看起来像这样(我希望能够添加更多或更少的参数,而不会失败 - 也就是说,我不介意参数的最大数量):
<VBAParameters>
<Notes>The source spreadsheet is produced by the SSIS package "Reports.dtsx" which runs on SQL7. The settings here will be used to split that workbook into several files.
*SaveToLocation is where the script will save the each departments report (each sheet from the source workbook)
*ConstantName is the text that will appear in all files, along with the date and the department name
*DateFormat is the format of the date that will appear in the filename
*SheetNameInCell gives the address of the cell that in each sheet of the source spreadsheet contains the department name.
</Notes>
<Parameters>
<Parameter Name="SaveToLocation" Value="C:\Temp" />
<Parameter Name="ConstantName" Value="Post Summary" />
<Parameter Name="DateFormat" Value="yyyyMM" />
<Parameter Name="SheetNameInCell" Value="A5" />
</Parameters>
</VBAParameters>
任何关于我如何能够将必要数量的非 missing.value
参数传递给宏的指导都将非常感激。因此,我的努力是徒劳的。幸运的是 xml reader 按谓词 table 顺序执行 return 参数,因此不需要名称。
关于你的问题
it seems from reading this Microsoft and this Whosebug article that I can make an array of parameters and pass this...
不,您不能通过 Excel 宏调用来实现。根据MS Doc on Run method,您必须指定全部30 个参数。这是在您的代码示例中完成的。
您可以修改代码以生成动态数量的参数。在这种情况下,我会创建变量 MacroParam1
、MacroParam2
等到 MacroParam30
,初始值为 Missing.Value
。
在您的代码中,您必须根据某些逻辑设置这些参数。换句话说,对元数据进行编码并将其提取到脚本中。
其实施示例如下。您可以扩展 XML 文件以支持特定的宏,在以下示例中 - ABC
<VBAParameters>
<Macro Name="ABC" ParamNum="5">
<Parameters>
<Parameter Name="SaveToLocation" Value="C:\Temp" />
<Parameter Name="ConstantName" Value="Post Summary" />
<Parameter Name="DateFormat" Value="yyyyMM" />
<Parameter Name="SheetNameInCell" Value="A5" />
<Parameter Name="AnotherParam" Value="123" />
</Parameters>
</Macro>
<Macro Name="ABC2" ParamNum="4">
<Parameters>
<Parameter Name="SaveToLocation" Value="C:\Temp" />
<Parameter Name="ConstantName" Value="Post Summary" />
<Parameter Name="DateFormat" Value="yyyyMM" />
<Parameter Name="SheetNameInCell" Value="A5" />
</Parameters>
</Macro>
</VBAParameters>
然后,在您的主代码中,通过将对 doc.GetElementsByTagName("Parameter")
的调用替换为
来获取 XML 元素
XmlNodeList Parameters = doc.XmlNodeList("//Macro[@Name='"
+ Macro_name + "'/Parameters/Parameter");
此 Xpath 仅选择名称属性等于 Macro_name
变量的 <Macro>
节点,并获取其参数。然后,您可以按照与原始代码类似的方式处理参数。
按照@Ferdipux 的指示,我已经解决了这个问题,方法是制作一个长度正确的变量数组,默认值为 Missing.value
,然后将实际参数插入到开头此数组以提供所需数量的值:
using System;
using System.IO;
using System.Xml;
using System.Collections;
using System.Collections.Generic;
using System.Data;
using System.Diagnostics;
using System.Text;
using Excel = Microsoft.Office.Interop.Excel;
using Microsoft.SqlServer.Dts.Runtime;
using System.Reflection;
using VBIDE = Microsoft.Vbe.Interop;
namespace ST_b2148758d9a44ee4bc0d01a2d900ce9d.csproj
{
[System.AddIn.AddIn("ScriptMain", Version = "1.0", Publisher = "", Description = "")]
public partial class ScriptMain : Microsoft.SqlServer.Dts.Tasks.ScriptTask.VSTARTScriptObjectModelBase
{
enum ScriptResults
{
Success = Microsoft.SqlServer.Dts.Runtime.DTSExecResult.Success,
Failure = Microsoft.SqlServer.Dts.Runtime.DTSExecResult.Failure
};
public void Main()
{
Variables UserVariables = null;
Dts.VariableDispenser.LockForRead("User::VBA_MacroName");
Dts.VariableDispenser.LockForRead("User::VBA_Script");
Dts.VariableDispenser.LockForRead("User::VBA_Parameters");
Dts.VariableDispenser.GetVariables(ref UserVariables);
//The macro and the macro name were stored in the original data set, so we can get those from local variables.
string Macro = UserVariables["User::VBA_Script"].Value.ToString();
string Macro_name = UserVariables["User::VBA_MacroName"].Value.ToString();
XmlDocument doc = new XmlDocument();
doc.LoadXml(UserVariables["User::VBA_Parameters"].Value.ToString());
XmlNodeList Parameters = doc.GetElementsByTagName (@"Parameter");
object[] AllParamArray = new object[31];
object[] MyParamArray = new object[Parameters.Count];
//Fill the array with as many missing values as there are parameters in the Run macro command
for (int i = 0; i < AllParamArray.Length; i++)
{
AllParamArray[i] = Missing.Value;
}
//get the parameters that we are actually going to use.
for (int i = 0; i < Parameters.Count; i++)
{
MyParamArray[i] = Parameters[i].Attributes["Value"].Value.ToString();
}
//the first parameter is always the macro name
AllParamArray[0] = Macro_name;
//after that, we can insert our list of all the parameters we need into the list of all the parameters Excel needs
MyParamArray.CopyTo(AllParamArray, 1);
//Get Excel ready to be opened
Excel.Application ExcelObject = default(Excel.Application);
Excel.WorkbookClass oBook = default(Excel.WorkbookClass);
Excel.Workbooks oBooks = default(Excel.Workbooks);
//get the vba module ready
VBIDE.VBComponent module = null;
//open excel in the background
ExcelObject = new Excel.Application();
ExcelObject.Visible = false;
ExcelObject.DisplayAlerts = false;
//Open our report
oBooks = ExcelObject.Workbooks;
oBook = (Excel.WorkbookClass)oBooks.Add(Missing.Value);
//Add a module to our report and populate it with our vba macro
module = oBook.VBProject.VBComponents.Add(VBIDE.vbext_ComponentType.vbext_ct_StdModule);
module.CodeModule.AddFromString(Macro);
ExcelObject.Run
(AllParamArray[0], AllParamArray[1], AllParamArray[2], AllParamArray[3], AllParamArray[4], AllParamArray[5], AllParamArray[6], AllParamArray[7], AllParamArray[8],
AllParamArray[9], AllParamArray[10], AllParamArray[11], AllParamArray[12], AllParamArray[13], AllParamArray[14], AllParamArray[15], AllParamArray[16], AllParamArray[17],
AllParamArray[18], AllParamArray[19], AllParamArray[20], AllParamArray[21], AllParamArray[22], AllParamArray[23], AllParamArray[24], AllParamArray[25], AllParamArray[26],
AllParamArray[27], AllParamArray[28], AllParamArray[29], AllParamArray[30]);
oBook.Close(false,Missing.Value,Missing.Value);
ExcelObject.Application.Quit();
ExcelObject =null;
}
}
}
这不完全是上一个答案中建议的解决方案,而是基于那里提出的建议以及缺失值不是可选的这一事实。
有一个 dtsx 包,运行s SSRS 使用配置 table 报告,然后在生成的 .xls(它是 2008 R2 服务器)文件上需要时执行宏.
配置的每一行 table 包含要 运行 的报告的详细信息、宏的详细信息以及要传递给宏的参数和值的 xml 列表;包中有一个 foreach 循环,运行s 报告,向输出文件添加一个宏,运行s 宏并继续。
看起来好像是为了尽可能通用化而设计的,所以任何报告和任何宏都可以在配置中输入table。
这工作正常,但尽管它看起来很灵活,但加载的脚本代码中的实际 C# 和 运行s 宏具有非常严格的结构,这意味着只有宏具有4 个参数可以是 运行 - 我想让它更灵活,但我正在努力研究如何根据节点的数量为 ExcelObject.Run()
命令提供正确(可变)的参数数量配置 xml.
我在使用 C# 方面不是很有经验,但从阅读 this Microsoft and this Whosebug 文章看来,我可以制作一个参数数组并传递它...我只是不知道如何做。这是现有的脚本:
using System;
using System.IO;
using System.Xml;
using System.Collections;
using System.Collections.Generic;
using System.Data;
using System.Diagnostics;
using System.Text;
using Excel = Microsoft.Office.Interop.Excel;
using Microsoft.SqlServer.Dts.Runtime;
using System.Reflection;
using VBIDE = Microsoft.Vbe.Interop;
namespace ST_b2148758d9a44ee4bc0d01a2d900ce9d.csproj
{
[System.AddIn.AddIn("ScriptMain", Version = "1.0", Publisher = "", Description = "")]
public partial class ScriptMain : Microsoft.SqlServer.Dts.Tasks.ScriptTask.VSTARTScriptObjectModelBase
{
enum ScriptResults
{
Success = Microsoft.SqlServer.Dts.Runtime.DTSExecResult.Success,
Failure = Microsoft.SqlServer.Dts.Runtime.DTSExecResult.Failure
};
public void Main()
{
Variables UserVariables = null;
Dts.VariableDispenser.LockForRead("User::SaveLoc_Root");
Dts.VariableDispenser.LockForRead("User::SaveLoc_SubFolder");
Dts.VariableDispenser.LockForRead("User::SaveLoc_FileName");
Dts.VariableDispenser.LockForRead("User::SaveLoc_FileExtension");
Dts.VariableDispenser.LockForRead("User::VBA_Macro_Name");
Dts.VariableDispenser.LockForRead("User::VBA_Parameters");
Dts.VariableDispenser.LockForRead("User::VBA_Script");
Dts.VariableDispenser.GetVariables(ref UserVariables);
string SaveToLocation = null, ConstantName = null, DateFormat = null , SheetNameInCell = null;
//build the filename of the report we just made.
//@"C:\Temp\Repart.xls";
string Report_File_name = UserVariables["User::SaveLoc_Root"].Value.ToString()
+ UserVariables["User::SaveLoc_SubFolder"].Value.ToString()
+ UserVariables["User::SaveLoc_FileName"].Value.ToString()
+ UserVariables["User::SaveLoc_FileExtension"].Value.ToString();
//The macro and the macro name were stored in the original data set, so we can get those from local variables.
string Macro = UserVariables["User::VBA_Script"].Value.ToString();
string Macro_name = UserVariables["User::VBA_Macro_Name"].Value.ToString();
XmlDocument doc = new XmlDocument();
doc.LoadXml(UserVariables["User::VBA_Parameters"].Value.ToString());
XmlNodeList Parameters = doc.GetElementsByTagName("Parameter");
//skip through all the parameters we might have - if more are added, this will need to be changed.
for (int i = 0; i < Parameters.Count; i++)
{
string ParamName = Parameters[i].Attributes["Name"].Value.ToString();
if (ParamName == "SaveToLocation")
{
SaveToLocation = Parameters[i].Attributes["Value"].Value.ToString();
}
else if (ParamName == "ConstantName")
{
ConstantName = Parameters[i].Attributes["Value"].Value.ToString();
}
else if (ParamName == "DateFormat")
{
DateFormat = Parameters[i].Attributes["Value"].Value.ToString();
}
else if (ParamName == "SheetNameInCell")
{
SheetNameInCell = Parameters[i].Attributes["Value"].Value.ToString();
}
}
//Get Excel ready to be opened
Excel.Application ExcelObject = default(Excel.Application);
Excel.WorkbookClass oBook = default(Excel.WorkbookClass);
Excel.Workbooks oBooks = default(Excel.Workbooks);
//get the vba module ready
VBIDE.VBComponent module = null;
//open excel in the background
ExcelObject = new Excel.Application();
ExcelObject.Visible = false;
//Open our report
oBooks = ExcelObject.Workbooks;
oBook = (Excel.WorkbookClass)oBooks.Open
(Report_File_name
,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);
//Add a module to our report and populate it with our vba macro
module = oBook.VBProject.VBComponents.Add(VBIDE.vbext_ComponentType.vbext_ct_StdModule);
module.CodeModule.AddFromString(Macro);
//run the macro
ExcelObject.Run
( Macro_name,SaveToLocation,ConstantName,DateFormat,SheetNameInCell, 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, Missing.Value,Missing.Value, Missing.Value, Missing.Value, Missing.Value,Missing.Value
,Missing.Value, Missing.Value, Missing.Value,Missing.Value, Missing.Value, Missing.Value);
ExcelObject.Visible = false;
ExcelObject.UserControl =false;
//oBook.Save();
ExcelObject.DisplayAlerts =false;
ExcelObject.Application.Quit();
ExcelObject =null;
}
}
}
xml 看起来像这样(我希望能够添加更多或更少的参数,而不会失败 - 也就是说,我不介意参数的最大数量):
<VBAParameters>
<Notes>The source spreadsheet is produced by the SSIS package "Reports.dtsx" which runs on SQL7. The settings here will be used to split that workbook into several files.
*SaveToLocation is where the script will save the each departments report (each sheet from the source workbook)
*ConstantName is the text that will appear in all files, along with the date and the department name
*DateFormat is the format of the date that will appear in the filename
*SheetNameInCell gives the address of the cell that in each sheet of the source spreadsheet contains the department name.
</Notes>
<Parameters>
<Parameter Name="SaveToLocation" Value="C:\Temp" />
<Parameter Name="ConstantName" Value="Post Summary" />
<Parameter Name="DateFormat" Value="yyyyMM" />
<Parameter Name="SheetNameInCell" Value="A5" />
</Parameters>
</VBAParameters>
任何关于我如何能够将必要数量的非 missing.value
参数传递给宏的指导都将非常感激。因此,我的努力是徒劳的。幸运的是 xml reader 按谓词 table 顺序执行 return 参数,因此不需要名称。
关于你的问题
it seems from reading this Microsoft and this Whosebug article that I can make an array of parameters and pass this...
不,您不能通过 Excel 宏调用来实现。根据MS Doc on Run method,您必须指定全部30 个参数。这是在您的代码示例中完成的。
您可以修改代码以生成动态数量的参数。在这种情况下,我会创建变量 MacroParam1
、MacroParam2
等到 MacroParam30
,初始值为 Missing.Value
。
在您的代码中,您必须根据某些逻辑设置这些参数。换句话说,对元数据进行编码并将其提取到脚本中。
其实施示例如下。您可以扩展 XML 文件以支持特定的宏,在以下示例中 - ABC
<VBAParameters>
<Macro Name="ABC" ParamNum="5">
<Parameters>
<Parameter Name="SaveToLocation" Value="C:\Temp" />
<Parameter Name="ConstantName" Value="Post Summary" />
<Parameter Name="DateFormat" Value="yyyyMM" />
<Parameter Name="SheetNameInCell" Value="A5" />
<Parameter Name="AnotherParam" Value="123" />
</Parameters>
</Macro>
<Macro Name="ABC2" ParamNum="4">
<Parameters>
<Parameter Name="SaveToLocation" Value="C:\Temp" />
<Parameter Name="ConstantName" Value="Post Summary" />
<Parameter Name="DateFormat" Value="yyyyMM" />
<Parameter Name="SheetNameInCell" Value="A5" />
</Parameters>
</Macro>
</VBAParameters>
然后,在您的主代码中,通过将对 doc.GetElementsByTagName("Parameter")
的调用替换为
XmlNodeList Parameters = doc.XmlNodeList("//Macro[@Name='"
+ Macro_name + "'/Parameters/Parameter");
此 Xpath 仅选择名称属性等于 Macro_name
变量的 <Macro>
节点,并获取其参数。然后,您可以按照与原始代码类似的方式处理参数。
按照@Ferdipux 的指示,我已经解决了这个问题,方法是制作一个长度正确的变量数组,默认值为 Missing.value
,然后将实际参数插入到开头此数组以提供所需数量的值:
using System;
using System.IO;
using System.Xml;
using System.Collections;
using System.Collections.Generic;
using System.Data;
using System.Diagnostics;
using System.Text;
using Excel = Microsoft.Office.Interop.Excel;
using Microsoft.SqlServer.Dts.Runtime;
using System.Reflection;
using VBIDE = Microsoft.Vbe.Interop;
namespace ST_b2148758d9a44ee4bc0d01a2d900ce9d.csproj
{
[System.AddIn.AddIn("ScriptMain", Version = "1.0", Publisher = "", Description = "")]
public partial class ScriptMain : Microsoft.SqlServer.Dts.Tasks.ScriptTask.VSTARTScriptObjectModelBase
{
enum ScriptResults
{
Success = Microsoft.SqlServer.Dts.Runtime.DTSExecResult.Success,
Failure = Microsoft.SqlServer.Dts.Runtime.DTSExecResult.Failure
};
public void Main()
{
Variables UserVariables = null;
Dts.VariableDispenser.LockForRead("User::VBA_MacroName");
Dts.VariableDispenser.LockForRead("User::VBA_Script");
Dts.VariableDispenser.LockForRead("User::VBA_Parameters");
Dts.VariableDispenser.GetVariables(ref UserVariables);
//The macro and the macro name were stored in the original data set, so we can get those from local variables.
string Macro = UserVariables["User::VBA_Script"].Value.ToString();
string Macro_name = UserVariables["User::VBA_MacroName"].Value.ToString();
XmlDocument doc = new XmlDocument();
doc.LoadXml(UserVariables["User::VBA_Parameters"].Value.ToString());
XmlNodeList Parameters = doc.GetElementsByTagName (@"Parameter");
object[] AllParamArray = new object[31];
object[] MyParamArray = new object[Parameters.Count];
//Fill the array with as many missing values as there are parameters in the Run macro command
for (int i = 0; i < AllParamArray.Length; i++)
{
AllParamArray[i] = Missing.Value;
}
//get the parameters that we are actually going to use.
for (int i = 0; i < Parameters.Count; i++)
{
MyParamArray[i] = Parameters[i].Attributes["Value"].Value.ToString();
}
//the first parameter is always the macro name
AllParamArray[0] = Macro_name;
//after that, we can insert our list of all the parameters we need into the list of all the parameters Excel needs
MyParamArray.CopyTo(AllParamArray, 1);
//Get Excel ready to be opened
Excel.Application ExcelObject = default(Excel.Application);
Excel.WorkbookClass oBook = default(Excel.WorkbookClass);
Excel.Workbooks oBooks = default(Excel.Workbooks);
//get the vba module ready
VBIDE.VBComponent module = null;
//open excel in the background
ExcelObject = new Excel.Application();
ExcelObject.Visible = false;
ExcelObject.DisplayAlerts = false;
//Open our report
oBooks = ExcelObject.Workbooks;
oBook = (Excel.WorkbookClass)oBooks.Add(Missing.Value);
//Add a module to our report and populate it with our vba macro
module = oBook.VBProject.VBComponents.Add(VBIDE.vbext_ComponentType.vbext_ct_StdModule);
module.CodeModule.AddFromString(Macro);
ExcelObject.Run
(AllParamArray[0], AllParamArray[1], AllParamArray[2], AllParamArray[3], AllParamArray[4], AllParamArray[5], AllParamArray[6], AllParamArray[7], AllParamArray[8],
AllParamArray[9], AllParamArray[10], AllParamArray[11], AllParamArray[12], AllParamArray[13], AllParamArray[14], AllParamArray[15], AllParamArray[16], AllParamArray[17],
AllParamArray[18], AllParamArray[19], AllParamArray[20], AllParamArray[21], AllParamArray[22], AllParamArray[23], AllParamArray[24], AllParamArray[25], AllParamArray[26],
AllParamArray[27], AllParamArray[28], AllParamArray[29], AllParamArray[30]);
oBook.Close(false,Missing.Value,Missing.Value);
ExcelObject.Application.Quit();
ExcelObject =null;
}
}
}
这不完全是上一个答案中建议的解决方案,而是基于那里提出的建议以及缺失值不是可选的这一事实。