使用来自 c# 应用程序的插件启动 excel 应用程序
starting excel application with addins from c# application
我有一个 C# 应用程序,它需要创建一个 excel 应用程序,然后打开一个工作簿。问题是我需要在 excel 打开时加载 Bloomberg addinn。我找到的唯一方法是在这个 post working example 中。
这确实启动了 excel 并且能够使用 Bloomberg 功能。但是我想知道是否有办法将 myXl 转换为 xlApp,其中 xlApp 的类型为 Microsoft.Office.Interop.Excel.Application?
var myXl = Process.Start("excel.exe");
原因是我有一个库,它有一些我想使用的有用功能,但它需要一个 Microsoft.Office.Interop.Excel.Application 类型的参数。我该怎么做?
添加对 Excel 库的引用,您可以实例化工作簿对象而不是 var myXL
Excel.Application myXl = New Excel.Application();
那么您只需手动加载加载项即可。
foreach (Excel.AddIn item in myXl.AddIns)
{
if (item.Name.Equals("BLOOMBERG ADDIN NAME"))
{
item.Installed = true;
}
}
您可以从外部应用程序自动化 Excel。有关详细信息,请参阅 How to automate Microsoft Excel from Microsoft Visual C#.NET and C# app automates Excel (CSAutomateExcel)。
Application
class 提供以下用于访问加载项的属性:
- AddIns - returns 一个
AddIns
集合,代表“加载项”对话框(“开发人员”选项卡上的“加载项”命令)中列出的所有加载项; XLL 加载项。
- COMAddIns - returns Microsoft Excel 的
COMAddIns
集合,代表当前安装的 COM 加载项。
因此,如果您需要确保启用了 COM 加载项,则需要使用应用程序 class.
的 ComAddins
属性
您可以使用以下代码:
这将启动 Excel,然后遍历 运行 对象 Table 中注册的所有工作簿,以找到在刚刚启动的进程中运行的工作簿。为此,它获取工作簿 window 句柄的进程 ID,并将其与刚刚启动的进程的 ID 进行比较。
在 运行 对象 Table 中查找会重复多次,中间有等待期,因为 Excel 在 ROT 启动后可能需要一些时间来注册。在较慢的计算机上,您可能需要增加 maxAttempts
和 waitTimeMS
。
如果找到正确的工作簿,则将其返回。在示例中,我将 "hello world" 写入 Excel 应用程序实例的第一个单元格。
private void button1_Click(object sender, EventArgs e)
{
Microsoft.Office.Interop.Excel.Application excelApplication = StartExcel();
if (excelApplication != null)
{
excelApplication.ActiveCell.Value = "Hello World";
}
}
[DllImport("user32.dll", SetLastError = true)]
static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint processId);
[DllImport("ole32.dll")]
private static extern int GetRunningObjectTable(int reserved, out IRunningObjectTable prot);
private Microsoft.Office.Interop.Excel.Application StartExcel()
{
// Maximum number of attempts to look for started Excel Application
const int maxAttempts = 3;
// Number of milliseconds to wait between attempts to look for started Excel Application
const int waitTimeMS = 200;
Microsoft.Office.Interop.Excel.Application result = null;
// Start Excel
var process = Process.Start("Excel.exe");
process.WaitForInputIdle();
// Try to find started Excel Application
int currentAttempt = 1;
while ((result == null) && (currentAttempt <= maxAttempts))
{
// Wait between attempts
if(currentAttempt != 1)
{
Thread.Sleep(waitTimeMS);
}
// List all running Excel automation objects and find the one with the same process id
IRunningObjectTable lRunningObjectTable = null;
IEnumMoniker lMonikerList = null;
try
{
// Query Running Object Table
if (GetRunningObjectTable(0, out lRunningObjectTable) == 0 && lRunningObjectTable != null)
{
// List Monikers
lRunningObjectTable.EnumRunning(out lMonikerList);
// Start Enumeration
lMonikerList.Reset();
// Array used for enumerating Monikers
IMoniker[] lMonikerContainer = new IMoniker[1];
IntPtr lPointerFetchedMonikers = IntPtr.Zero;
// foreach Moniker
while (lMonikerList.Next(1, lMonikerContainer, lPointerFetchedMonikers) == 0)
{
object lComObject;
lRunningObjectTable.GetObject(lMonikerContainer[0], out lComObject);
// Check the object is an Excel workbook
if (lComObject is Microsoft.Office.Interop.Excel.Workbook)
{
Microsoft.Office.Interop.Excel.Workbook lExcelWorkbook = (Microsoft.Office.Interop.Excel.Workbook)lComObject;
// Get the Process ID for the Window Handle
uint processId;
GetWindowThreadProcessId(new IntPtr(lExcelWorkbook.Application.Hwnd), out processId);
if (processId == process.Id)
{
// Correct automation object found, return Application
result = lExcelWorkbook.Application;
break;
}
}
}
}
}
finally
{
// Release ressources
if (lRunningObjectTable != null) Marshal.ReleaseComObject(lRunningObjectTable);
if (lMonikerList != null) Marshal.ReleaseComObject(lMonikerList);
}
currentAttempt++;
}
return result;
}
我有一个 C# 应用程序,它需要创建一个 excel 应用程序,然后打开一个工作簿。问题是我需要在 excel 打开时加载 Bloomberg addinn。我找到的唯一方法是在这个 post working example 中。
这确实启动了 excel 并且能够使用 Bloomberg 功能。但是我想知道是否有办法将 myXl 转换为 xlApp,其中 xlApp 的类型为 Microsoft.Office.Interop.Excel.Application?
var myXl = Process.Start("excel.exe");
原因是我有一个库,它有一些我想使用的有用功能,但它需要一个 Microsoft.Office.Interop.Excel.Application 类型的参数。我该怎么做?
添加对 Excel 库的引用,您可以实例化工作簿对象而不是 var myXL
Excel.Application myXl = New Excel.Application();
那么您只需手动加载加载项即可。
foreach (Excel.AddIn item in myXl.AddIns)
{
if (item.Name.Equals("BLOOMBERG ADDIN NAME"))
{
item.Installed = true;
}
}
您可以从外部应用程序自动化 Excel。有关详细信息,请参阅 How to automate Microsoft Excel from Microsoft Visual C#.NET and C# app automates Excel (CSAutomateExcel)。
Application
class 提供以下用于访问加载项的属性:
- AddIns - returns 一个
AddIns
集合,代表“加载项”对话框(“开发人员”选项卡上的“加载项”命令)中列出的所有加载项; XLL 加载项。 - COMAddIns - returns Microsoft Excel 的
COMAddIns
集合,代表当前安装的 COM 加载项。
因此,如果您需要确保启用了 COM 加载项,则需要使用应用程序 class.
的ComAddins
属性
您可以使用以下代码:
这将启动 Excel,然后遍历 运行 对象 Table 中注册的所有工作簿,以找到在刚刚启动的进程中运行的工作簿。为此,它获取工作簿 window 句柄的进程 ID,并将其与刚刚启动的进程的 ID 进行比较。
在 运行 对象 Table 中查找会重复多次,中间有等待期,因为 Excel 在 ROT 启动后可能需要一些时间来注册。在较慢的计算机上,您可能需要增加 maxAttempts
和 waitTimeMS
。
如果找到正确的工作簿,则将其返回。在示例中,我将 "hello world" 写入 Excel 应用程序实例的第一个单元格。
private void button1_Click(object sender, EventArgs e)
{
Microsoft.Office.Interop.Excel.Application excelApplication = StartExcel();
if (excelApplication != null)
{
excelApplication.ActiveCell.Value = "Hello World";
}
}
[DllImport("user32.dll", SetLastError = true)]
static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint processId);
[DllImport("ole32.dll")]
private static extern int GetRunningObjectTable(int reserved, out IRunningObjectTable prot);
private Microsoft.Office.Interop.Excel.Application StartExcel()
{
// Maximum number of attempts to look for started Excel Application
const int maxAttempts = 3;
// Number of milliseconds to wait between attempts to look for started Excel Application
const int waitTimeMS = 200;
Microsoft.Office.Interop.Excel.Application result = null;
// Start Excel
var process = Process.Start("Excel.exe");
process.WaitForInputIdle();
// Try to find started Excel Application
int currentAttempt = 1;
while ((result == null) && (currentAttempt <= maxAttempts))
{
// Wait between attempts
if(currentAttempt != 1)
{
Thread.Sleep(waitTimeMS);
}
// List all running Excel automation objects and find the one with the same process id
IRunningObjectTable lRunningObjectTable = null;
IEnumMoniker lMonikerList = null;
try
{
// Query Running Object Table
if (GetRunningObjectTable(0, out lRunningObjectTable) == 0 && lRunningObjectTable != null)
{
// List Monikers
lRunningObjectTable.EnumRunning(out lMonikerList);
// Start Enumeration
lMonikerList.Reset();
// Array used for enumerating Monikers
IMoniker[] lMonikerContainer = new IMoniker[1];
IntPtr lPointerFetchedMonikers = IntPtr.Zero;
// foreach Moniker
while (lMonikerList.Next(1, lMonikerContainer, lPointerFetchedMonikers) == 0)
{
object lComObject;
lRunningObjectTable.GetObject(lMonikerContainer[0], out lComObject);
// Check the object is an Excel workbook
if (lComObject is Microsoft.Office.Interop.Excel.Workbook)
{
Microsoft.Office.Interop.Excel.Workbook lExcelWorkbook = (Microsoft.Office.Interop.Excel.Workbook)lComObject;
// Get the Process ID for the Window Handle
uint processId;
GetWindowThreadProcessId(new IntPtr(lExcelWorkbook.Application.Hwnd), out processId);
if (processId == process.Id)
{
// Correct automation object found, return Application
result = lExcelWorkbook.Application;
break;
}
}
}
}
}
finally
{
// Release ressources
if (lRunningObjectTable != null) Marshal.ReleaseComObject(lRunningObjectTable);
if (lMonikerList != null) Marshal.ReleaseComObject(lMonikerList);
}
currentAttempt++;
}
return result;
}