Создайте файл Excel в памяти и откройте его в Excel, не используя COM Interop - PullRequest
0 голосов
/ 16 апреля 2020

В настоящее время я использую COM Interop in. NET для экспорта содержимого DataTable в Excel. Это метод, которым я пользуюсь годами, но проблема в том, что COM отрывочен и генерирует случайные, прерывистые, не отслеживаемые исключения. Это не было большой проблемой, так как это всегда был код на машине, выделенной для этой цели, и исключения довольно редки, но недавно я написал интерфейс для хранилища данных, и у меня более 200 пользователей на это, и проблема выросла (как и следовало ожидать) в геометрической прогрессии.

Проблема в том, чтобы найти метод, который делает то, что делает COM, без проблем, которые идут с COM. А именно, создание файла Excel в памяти (без записи на диск), который является новой книгой, так что когда пользователь нажимает «Сохранить» в первый раз, он спрашивает, где он хочет сохранить файл и что он хочет чтобы вызвать его.

Я знаю, что могу экспортировать DataTable в файл Excel, используя Open XML: Экспортировать DataTable в Excel с Open Xml SDK в c#

И я знаю, что могу создать объект Open XML Excel в памяти без записи в файл на диске: Как создать файл Excel с помощью Open XML без создания локального файла?

Проблема заключается в последнем шаге: открытие этого файла в памяти в Excel (без использования COM)

Я бы хотел, чтобы это работало.

Теперь я предпочел бы не записывать в файл, но это не нарушает условия сделки, если нет других опций, поэтому в качестве варианта резервного копирования я также рассмотрел использование Open XML для создания шаблона Excel и открытие шаблона ( используя Process.Start).

Проблема с Этот подход заключается в том, что некоторые пользователи сообщают, что шаблоны иногда открываются как файлы xltx в режиме редактирования по умолчанию, а не открываются как новые файлы xlsx: https://answers.microsoft.com/en-us/office/forum/office_2007-customize/is-there-a-way-to-get-my-excel-template-xltx-file/ab36cd4d-f6b0-46e0-8f15-533a4acb357f?page=1

Это будет четным большая проблема, чем случайные ошибки, которые я получаю от использования COM.

Любые идеи приветствуются.

EDIT - Это ошибки COM, которые я получаю:


Невозможно создать компонент ActiveX.

Цель COM не реализует IDispatch.

Исключение из HRESULT: 0x800AC472

Ошибка при выборе метода класса Range

Операция недоступна ( Исключение из HRESULT: 0x800401E3 (MK_E_UNAVAILABLE))

Фильтр сообщений указывает, что приложение занято. (Исключение из HRESULT: 0x8001010A (RPC_E_SERVERCALL_RETRYLATER))

Ошибка удаленного вызова процедуры. (Исключение из HRESULT: 0x800706BE)

Невозможно привести объект COM типа 'System .__ ComObject' к типу интерфейса 'System.Collections.IEnumerable'. Эта операция завершилась неудачно, поскольку вызов QueryInterface в компоненте COM для интерфейса с IID '{496B0ABE-CDEE-11D3-88E8-00902754C43A}' завершился ошибкой из-за следующей ошибки: 'Запрошенный объект не существует. (Исключение из HRESULT: 0x80010114) ', а компонент COM не поддерживает вызовы IDispatch :: Invoke для DISPID_NEWENUM.

Невозможно получить свойство Add класса Workbooks

Активировать метод класса Workbook ошибка


В течение нескольких месяцев я получил 107 ошибок, но позже я получил еще больше, поскольку обновил функцию, добавив ее к любому существующему экземпляру Excel, который может уже иметь пользователь открыть вместо создания нового. Раньше, когда я всегда создавал новый экземпляр Excel каждый раз, ошибки были гораздо реже (и в основном были устранены, сделав Excel невидимым, пока я выполнял закулисную работу).

Ответы [ 2 ]

1 голос
/ 16 апреля 2020

Это предложение больше, чем ответ. Попробуйте сохранить файл во временную папку и установить для него только для чтения в файловой системе. Это заставит ваших пользователей делать SaveAs, а не Save. Затем используйте параметры командной строки Excel (очевидно, /n лучше), чтобы открыть файл XLSX, как если бы это был шаблон.

Эти параметры командной строки расположены здесь: Параметры командной строки Excel

0 голосов
/ 16 апреля 2020

Вы можете использовать следующий код в vb. net или преобразовать в c#

    Dim Parameters(1) As Object
        Dim oApp As New Excel.Application()
            oApp.UserControl = True
            With oApp
    Dim oBooks As Object = oApp.Workbooks
    Dim ci As System.Globalization.CultureInfo = New System.Globalization.CultureInfo("en-US")
                oBooks.GetType().InvokeMember("Open", Reflection.BindingFlags.InvokeMethod, Nothing, oBooks, Parameters, ci)
                System.Threading.Thread.CurrentThread.CurrentCulture = New System.Globalization.CultureInfo("en-US")
    Dim objsheet As Excel.Worksheet
                objsheet = .Worksheets(1)
    Dim range As Excel.Range = objsheet.UsedRange.Cells
    Dim countrows As Integer = objsheet.UsedRange.Rows.Count

 For rowIndex As Integer = rowstart To countrows
 Obj = range.Cells(rowIndex, "B").Value
...
  Next

releaseObject(oApp)
 releaseObject(oBooks)
 End With

Private Sub releaseObject(ByVal obj As Object)
        Try
            System.Runtime.InteropServices.Marshal.FinalReleaseComObject(obj)
            obj = Nothing
        Catch ex As Exception
            obj = Nothing
        Finally
            GC.Collect()
        End Try
    End Sub
...