【问题标题】:Excel Interop Load Template into Existing WorkbookExcel 互操作加载模板到现有工作簿
【发布时间】:2014-12-03 19:28:38
【问题描述】:

如何将模板中的工作表加载到现有 Excel 工作簿中(如果没有现有工作簿,则先创建一个空白工作簿)。

我试过了

Excel.Application.Workbooks.Open("path");

这可行,但每次它在创建新工作簿时都会创建一个新的 Excel 会话。我无法通过 Google 找到任何关于如何将数据作为新工作表加载到现有书籍中的信息。

【问题讨论】:

  • 当您说“现有工作簿”时,您是指当前在用户计算机上打开的工作簿吗?如果是这样,您需要先获取托管它的 Excel 实例。
  • 是用户当前打开的工作簿。

标签: c# excel interop


【解决方案1】:

正如您所发现的,只需在工作簿上调用Open() 就会创建一个新的 Excel 实例,而不会连接到当前运行的实例。你需要的东西要复杂得多。下面是我用来连接到工作簿的方法,您已经知道它的名称(您也可以调整它以允许用户选择他们想要打开的工作簿):

private Excel.Workbook GetWorkbook(string workbookName)
{
    Excel.Window window = null;      // Excel window object from which application is grabbed
    Excel.Application app = null;    // Excel instance from which we get all the open workbooks
    Excel.Workbooks wbs = null;      // List of workbooks
    Excel.Workbook wb = null;        // Workbook to return
    EnumChildCallback cb;            // Callback routine for child window enumeration routine
    List<Process> procs = new List<Process>();           // List of processes

    // Get a full list of all processes that have a name of "excel"

    procs.AddRange(Process.GetProcessesByName("excel"));

    foreach (Process proc in procs)
    {
        // Make sure we have a valid handle for the window

        if ((int)proc.MainWindowHandle > 0)
        {
            // Get the handle of the child window in the current Excel process

            int childWindow = 0;
            cb = new EnumChildCallback(EnumChildProc);
            EnumChildWindows((int)proc.MainWindowHandle, cb, ref childWindow);

            // Make sure we got a valid handle

            if (childWindow > 0)
            {
                // Get the address of the child window so that we can talk to it and
                // get all the workbooks

                const uint OBJID_NATIVEOM = 0xFFFFFFF0;
                Guid IID_IDispatch =
                    new Guid("{00020400-0000-0000-C000-000000000046}");
                int res = AccessibleObjectFromWindow(childWindow, OBJID_NATIVEOM,
                    IID_IDispatch.ToByteArray(), ref window);

                if (res >= 0)
                {
                    app = window.Application;
                    wbs = app.Workbooks;

                    // Loop through all the workbooks within the current Excel window
                    // to see if any match

                    for (int i = 1; i <= wbs.Count; i++)
                    {
                        wb = wbs[i];

                        if (wb.Name == workbookName)
                        {
                            break;
                        }

                        wb = null;
                    }
                }
            }
        }

        // If we've already found our workbook then there's no point in continuing
        // through the remaining processes

        if (wb != null)
        {
            break;
        }
    }

    Release(wbs);
    Release(app);
    Release(window);

    return wb;
}

上面调用的 Release() 方法只需将引用设置为 null 并在它们上调用 Marshal.FinalReleaseComObject(),否则您最终会得到到处都是无头的 Excel 实例。

您还需要以下内容来执行一些抓取窗口的功能:

private delegate bool EnumChildCallback(int hwnd, ref int lParam);

[DllImport("User32.dll")]
private static extern bool EnumChildWindows(int hWndParent, EnumChildCallback lpEnumFunc, ref int lParam);

[DllImport("Oleacc.dll")]
private static extern int AccessibleObjectFromWindow(int hwnd, uint dwObjectID, byte[] riid, ref Excel.Window ptr);

private bool EnumChildProc(int hwndChild, ref int lParam)
{
    // Get the name of the class that owns the passed-in window handle

    StringBuilder buf = new StringBuilder(128);
    GetClassName(hwndChild, buf, 128);

    // If the class name is EXCEL7 then we've got an valid Excel window

    if (buf.ToString() == "EXCEL7")
    {
        lParam = hwndChild;
        return false;
    }

    return true;
}

[DllImport("User32.dll")]
private static extern int GetClassName(int hWnd, StringBuilder lpClassName, int nMaxCount);

【讨论】:

  • 谢谢!你应该看看 NetOffice - 他们有一个简单的方法来获取当前的 Excel 实例,除了 API 的其余部分与 MS Interop 相同:(
  • @Murtuza 我同意,NetOffice 会容易得多,不幸的是我所在的组织不喜欢第三方库。
  • @Murtuza 这回答了你的问题吗?
  • 我可能无法正常工作,但第三方库允许这样做 - 我在这里找到了答案。还是谢谢。 netoffice.codeplex.com/discussions/434906
【解决方案2】:

回答(感谢 Jon49 @NetOffice 讨论区:http://netoffice.codeplex.com/discussions/434906):

Excel.Application.Sheets.Add(Type:="TemplateWorkbookPath")

您可以从您当前的工作簿变量中执行此操作 工作:

wkb.Application.Sheets.Add(Type:="TemplateWorkbookPath")

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-10-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多