Способ обновить активный лист из активной книги Excel, используя c #? - PullRequest
4 голосов
/ 24 декабря 2009

Я хотел бы обновить значения на текущем листе в текущем документе независимо от имени файла Excel.

В vb6.0 мы могли бы сделать

Set AppExcel = GetObject(, "Excel.Application")
Set SheetExcel = AppExcel.ActiveWorkbook.ActiveSheet

Как же я пытался сделать то же самое в C #.

Есть ли способ сделать то же самое в C #.

Ответы [ 3 ]

4 голосов
/ 24 декабря 2009
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Reflection;

public class MyClass
{
    public static void Main()
    {
        object xlApp  = Marshal.GetActiveObject("Excel.Application");
        Type t = xlApp.GetType();

        t.InvokeMember("Quit", BindingFlags.InvokeMethod, null, xlApp, null);

    }
}

Я изменил код на основе приведенного примера здесь .

Сказав это, я думаю, вы могли бы написать код на vb.net (и использовать GetObject) и использовать библиотеку из c #.

OR

Вы можете сослаться на Microsoft.VisualBasic.dll.
И позвоните GetObject.

РЕДАКТИРОВАТЬ: зачем вам такая вещь? Не поможет ли создание Excel Addin?

Если вам все равно придется писать код на c #, позаботьтесь об освобождении созданных вами экземпляров COM с помощью Marshal.ReleaseComObject

EDIT2: чтобы получить ссылку на ActiveSheet, вы можете написать

object sheet = t.InvokeMember("ActiveSheet", BindingFlags.GetProperty, null, xlApp, null);

Опять же, я предлагаю вам , а не по этому маршруту.
Напишите код на VB6, чтобы делать то, что вам нужно, и вызывайте его с c # / vb.net.

4 голосов
/ 24 декабря 2009

Короче говоря, ответ, безусловно, да.

Но чтобы вы знали, ваш подход к использованию GetObject для получения существующего приложения Excel пользователя может быть подвержен ошибкам. Если запущено только одно приложение Excel, то GetObject будет работать нормально. Однако если в настоящий момент открыто несколько приложений Excel, вы не можете контролировать, какое приложение Excel возвращается из функции «GetObject» - возвращаемый экземпляр Excel может быть не тем, который вам нужен.

Возможно, вы захотите подумать о создании управляемой надстройки COM, которая запускает в самом приложении Excel и, следовательно, никогда не имеет проблем с тем, «каким» экземпляром приложения Excel он управляет. Чтобы сделать это, вы могли бы начать с просмотра статьи Как создать надстройку Office COM с помощью Visual C # .NET .

Если вам известен идентификатор процесса или дескриптор главного окна (a.k.a. "Hwnd") экземпляра приложения Excel, которым вы хотите управлять, тогда вы сможете получить доступ к этому точному экземпляру. Чтобы узнать, как это сделать, вы можете прочитать обсуждение Эндрю Уайтчепелом темы здесь . Раздел, который вас заинтересует, начинается со строки: «Чтобы заполучить объект приложения Excel, это то, что мы сделаем». Обсуждение немного сложное, но если следовать его коду к букве, оно работает точно так, как описано.

Если вы хотите продолжить работу с подходом «GetObject», то в следующем примере кода используется раннее связывание для получения активного листа запущенного в данный момент приложения Excel. Предполагается, что у вас есть оператор использования using Excel = Microsoft.Office.Interop.Excel, а также using System.Runtime.InteropServices в верхней части вашего модуля кода:

// Note:
// using System.Runtime.InteropServices;
// using Excel = Microsoft.Office.Interop.Excel;

Excel.Application excelApp = 
    Marshal.GetActiveObject("Excel.Application");

object activeSheet = excelApp.ActiveSheet;

Если бы вы использовали позднюю привязку, то это могло бы выглядеть так:

// Note:
// using System.Runtime.InteropServices;

object excelApp = 
    Marshal.GetActiveObject("Excel.Application");

object activeSheet = 
    excelApp
        .GetType()
        .InvokeMember(
            "ActiveSheet", 
            BindingFlags.GetProperty, 
            null, 
            excelApp, 
            null);

Надеюсь, это поможет ...

Последующий ответ:

Привет, даже если запущено несколько приложений Excel. Моя логика - использовать приложение, которое подсвечивается в данный момент, то есть активно в данный момент (с фокусом).

Ах, вы должны были сказать ... В вашем первоначальном вопросе говорится, что вы хотели бы продублировать поведение GetObject метода, вызванного из VB 6.0. Для этого все ответы, которые вы получили здесь, отвечают правильно.

Итак, во-первых, имейте в виду, что то, о чем вы сейчас спрашиваете, хорошо за возможностями метода GetObject VB 6.0. Для этого вам необходимо:

  1. Получить дескриптор окна активного приложения, вызвав функцию GetForegroundWindow Windows API.
  2. Выполните итерацию всех запущенных в данный момент процессов Excel с помощью Process.GetProcessesByName ("Excel") и сравните Process.MainWindowHandle для каждого запущенного процесса Excel с дескриптором окна, который вы получили ранее, используя API GetForegroundWindow . Предполагая, что у вас есть совпадение, вы подтвердили, что приложение Excel является активным в данный момент. Если совпадений не найдено, то в настоящий момент ни одно приложение Excel не имеет фокуса, и вы можете сообщить об этом пользователю.
  3. После того как вы подтвердите, что активное окно является запущенным приложением Excel, вы можете использовать дескриптор окна, полученный с помощью API GetForegroundWindow , чтобы получить объект приложения Excel, которым вы можете управлять. Чтобы сделать это, см. Статью Получение объекта приложения в надстройке Shimmed Automation от Эндрю Уайтчепела, начиная с раздела «Как получить объект приложения Excel, это то, что мы сделаем» «. Это сложная тема, но описание в статье отлично, и пример кода работает отлично. Однако в вашем случае вы захотите заменить первую строку кода int hwnd = (int)Process.GetCurrentProcess().MainWindowHandle; дескриптором окна активного окна, которое вы нашли ранее. Другими словами, что-то вроде этого: int hwnd = theHwndOfTheActiveWindowYouFoundEarlier.

Я понимаю, что это много, чтобы переварить, но если вы выполните эти шаги, он будет работать нормально. Самая сложная часть - это код Эндрю Уайтчепела, но он будет работать как есть, за исключением необходимости изменять первую строку. Удачи!

- Майк

2 голосов
/ 24 декабря 2009

Вот пример консольного приложения, которое использует Excel Automation для доступа к ActiveSheet.

using Microsoft.Office.Interop.Excel;
using System.Reflection;

namespace ExcelAutomationConsole
{
    internal class Program
    {
        private static void Main(string[] args)
        {
            _Application excelApp = null;
            try
            {
                excelApp = new Application();
                excelApp.Visible = true;

                Missing missing = Missing.Value;
                excelApp.Workbooks.Add(missing);
                // or
                //excelApp.Workbooks.Open("file.xlsx", missing, missing, missing, missing,
                //                        missing, missing, missing, missing,
                //                        missing, missing, missing, missing,
                //                        missing, missing);

                Worksheet sheet = excelApp.ActiveWorkbook.ActiveSheet as Worksheet;
                Range r = sheet.Cells[1, 1] as Range;
                r.FormulaR1C1 = "Test";
            }
            finally
            {
                excelApp.Quit();
            }
        }
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...