Закриття процесу подання заявок Excel у C # після доступу до даних


86

Я пишу програму на C #, яка відкриває файл шаблону Excel для операцій читання / запису. Я хочу, щоб, коли користувач закриває програму, процес програми Excel був закритий, не зберігаючи файл Excel. Перегляньте мій диспетчер завдань після декількох запусків програми.

введіть тут опис зображення

Я використовую цей код, щоб відкрити файл Excel:

public Excel.Application excelApp = new Excel.Application();
public Excel.Workbook excelBook;
excelBook = excelApp.Workbooks.Add(@"C:/pape.xltx");

а для доступу до даних я використовую цей код:

Excel.Worksheet excelSheet = (Worksheet)(excelBook.Worksheets[1]);
excelSheet.DisplayRightToLeft = true;
Range rng;
rng = excelSheet.get_Range("C2");
rng.Value2 = txtName.Text;

Я бачу подібні запитання у stackoverflow, такі як це питання та це , і тестові відповіді, але це не працює.


Excel і Word працюють дуже повільно і мають масу примх, подібних до тієї, на яку ви натрапили. Файли - це ZIP-файли, у яких є певний XML та інший вміст. Існує також Open XML SDK (або, можливо, щось новіше), яке може відкрити документи. Такий код працює без встановлення Office також локально. Подумайте про те, щоб не використовувати Excel
Стен Петров,

Відповіді:


94

Спробуйте це:

excelBook.Close(0); 
excelApp.Quit();

Закриваючи книгу, у вас є три необов’язкові параметри:

Workbook.close SaveChanges, filename, routeworkbook 

Workbook.Close(false)або якщо ви робите пізнє прив'язування, іноді простіше використовувати нуль. Workbook.Close(0) Ось як я це зробив при автоматизації закриття книг.

Також я зайшов і подивився документацію до нього і знайшов тут: Закрити книгу Excel

Дякую,


Дякую Шановний Майкл, це працює належним чином: excelBook.Close (0)
Джавад Юсефі

Привіт, хлопці, це не працює, коли ви відкриваєте файл Excel для читання. Далі наводиться код var excelApp = new Application (); var workBooks = excelApp.Workbooks.Open @ "c: \ temp \ myexcel.xlsx"); workBooks.Close (0); excelApp.Quit ();
user1131926

Я використовував applicationClass ... і використовував наведений вище код для розпорядження об’єктами, але це не працює ...
Сінгаравелан,

3
Після багатьох невдалих спроб із усіма цими відповідями я пішов із цим рішенням, щоб отримати ідентифікатор процесу, який я відкрив, і вбити його безпосередньо.
UndeadBob

@Singaravelan: Ви перевіряли відповідь Девіда Кларка?
Thế Anh Nguyễn

22
xlBook.Save();
xlBook.Close(true);
xlApp.Quit();
System.Runtime.InteropServices.Marshal.ReleaseComObject(xlApp);

спробуйте це .. це спрацювало для мене ... ви повинні звільнити цей об'єкт програми xl, щоб зупинити процес.


14

Посилання: https://stackoverflow.com/a/17367570/132599

Уникайте використання виразів із подвійною крапкою, наприклад таких:

var workbook = excel.Workbooks.Open(/*params*/)

... тому що таким чином ви створюєте об'єкти RCW не тільки для робочої книги, але і для робочих книг, і ви також повинні її звільнити (що неможливо, якщо посилання на об'єкт не підтримується).

Це вирішило проблему для мене. Ваш код стає:

public Excel.Application excelApp = new Excel.Application();
public Excel.Workbooks workbooks;
public Excel.Workbook excelBook;
workbooks = excelApp.Workbooks;
excelBook = workbooks.Add(@"C:/pape.xltx");

...

Excel.Sheets sheets = excelBook.Worksheets;
Excel.Worksheet excelSheet = (Worksheet)(sheets[1]);
excelSheet.DisplayRightToLeft = true;
Range rng;
rng = excelSheet.get_Range("C2");
rng.Value2 = txtName.Text;

А потім відпустіть усі ці об’єкти:

System.Runtime.InteropServices.Marshal.ReleaseComObject(rng);
System.Runtime.InteropServices.Marshal.ReleaseComObject(excelSheet);
System.Runtime.InteropServices.Marshal.ReleaseComObject(sheets);
excelBook .Save();
excelBook .Close(true);
System.Runtime.InteropServices.Marshal.ReleaseComObject(xlBook);
System.Runtime.InteropServices.Marshal.ReleaseComObject(workbooks);
excelApp.Quit();
System.Runtime.InteropServices.Marshal.ReleaseComObject(xlApp);

Я обертаю це в, try {} finally {}щоб переконатися, що все звільнено, навіть якщо щось піде не так (що може піти не так?), Наприклад

public Excel.Application excelApp = null;
public Excel.Workbooks workbooks = null;
...
try
{
    excelApp = new Excel.Application();
    workbooks = excelApp.Workbooks;
    ...
}
finally
{
    ...
    if (workbooks != null) System.Runtime.InteropServices.Marshal.ReleaseComObject(workbooks);
    excelApp.Quit();
    System.Runtime.InteropServices.Marshal.ReleaseComObject(xlApp);
}

2
Це спрацювало для мене, призначивши робочі книги змінній, щоб її можна було очистити. Також одне зауваження: у мене був точно такий же код для очищення програми excel у веб-програмі та консольній програмі. Код до оновлення для позбавлення від подвійних крапок працював у консольній програмі, але при запуску у веб-програмі EXCEL.EXE не очистив. Я не впевнений, чому вони поводилися по-іншому, але позбувшись посилання на подвійні крапки, це виправлено у веб-програмі.
IronHide

працює на мене. Я думаю, що, щоб звільнити об'єкт, ми повинні звільнити всі пов'язані об'єкти. У мене була така ж проблема з програмою Solidworks.
Гс.

1
Закрийте книгу, закрийте програму Excel, уникайте дзвінків із подвійними крапками та відпустіть кожен створений COM-об'єкт. Це спрацювало для мене. Відповідь на порятунок життя. Дякую.
Sinan ILYAS

13

Подумайте про це, це вбиває процес:

System.Diagnostics.Process[] process=System.Diagnostics.Process.GetProcessesByName("Excel");
foreach (System.Diagnostics.Process p in process)
{
    if (!string.IsNullOrEmpty(p.ProcessName))
    {
        try
        {
            p.Kill();
        }
        catch { }
    }
}

Крім того, ви намагалися просто закрити його нормально?

myWorkbook.SaveAs(@"C:/pape.xltx", missing, missing, missing, missing, missing, Microsoft.Office.Interop.Excel.XlSaveAsAccessMode.xlNoChange, missing, missing, missing, missing, missing);
excelBook.Close(null, null, null);                 // close your workbook
excelApp.Quit();                                   // exit excel application
excel = null;                                      // set to NULL

Дякуємо за вашу відповідь. Ваше перше рішення закриває всі відкриті файли Excel. Коли я використовую "excelBook.Close", з'являється діалогове вікно збереження Excel, і я цього не хочу :(
Джавад Юсефі

1
Я відредагував його та додав до нього рядок для збереження, як у коді, який замінить діалогове вікно кодом, сподіваюся, що це допоможе. :)
Морріс Мяо,

1
Я щойно використав це під час первинної перевірки відкритих процесів Excel і зберіг ідентифікатори у списку. Потім створив новий процес Excel, зробив редагування, яке мені довелося, і закрив будь-який процес Excel, який не містився в списку ідентифікаторів.
182764125216

Це не правильний спосіб випускати Excel з диспетчера завдань. Ви повинні звільнити всі створені об'єкти, включаючи ті, що були створені за кадром, наприклад WorkBOoks.
ehh

Таким чином, ви б вбили кожен запущений процес Excel. Проблема в тому, що одночасно можуть бути інші користувачі або програми, які використовують Excel. Просто майте на увазі, якщо ви готові це зробити.
Sinan ILYAS

5

Вбити Excel не завжди легко; див. цю статтю: 50 способів убити Excel

Ця стаття бере найкращу пораду від Microsoft ( стаття бази базових знань MS Knowlege ) про те, як змусити Excel швидко вийти, але потім також переконується в цьому, вбиваючи процес, якщо це необхідно. Мені подобається мати другий парашут.

Не забудьте закрити будь-які відкриті книги, закрити програму та звільнити об’єкт xlApp. Нарешті перевірте, чи процес ще живий, і якщо так, то вбийте його.

Ця стаття також гарантує, що ми не вбиваємо всі процеси Excel, а лише вбиваємо точний процес, який було розпочато.

Див. Також Отримати процес із ручки вікна

Ось код, який я використовую: (працює щоразу)

Sub UsingExcel()

    'declare process; will be used later to attach the Excel process
    Dim XLProc As Process

    'call the sub that will do some work with Excel
    'calling Excel in a separate routine will ensure that it is 
    'out of scope when calling GC.Collect
    'this works better especially in debug mode
    DoOfficeWork(XLProc)

    'Do garbage collection to release the COM pointers
    'http://support.microsoft.com/kb/317109
    GC.Collect()
    GC.WaitForPendingFinalizers()

    'I prefer to have two parachutes when dealing with the Excel process
    'this is the last answer if garbage collection were to fail
    If Not XLProc Is Nothing AndAlso Not XLProc.HasExited Then
        XLProc.Kill()
    End If

End Sub

'http://msdn.microsoft.com/en-us/library/ms633522%28v=vs.85%29.aspx
<System.Runtime.InteropServices.DllImport("user32.dll", SetLastError:=True)> _
    Private Shared Function GetWindowThreadProcessId(ByVal hWnd As IntPtr, _
    ByRef lpdwProcessId As Integer) As Integer
End Function

Private Sub ExcelWork(ByRef XLProc As Process)

    'start the application using late binding
    Dim xlApp As Object = CreateObject("Excel.Application")

    'or use early binding
    'Dim xlApp As Microsoft.Office.Interop.Excel

    'get the window handle
    Dim xlHWND As Integer = xlApp.hwnd

    'this will have the process ID after call to GetWindowThreadProcessId
    Dim ProcIdXL As Integer = 0

    'get the process ID
    GetWindowThreadProcessId(xlHWND, ProcIdXL)

    'get the process
    XLProc = Process.GetProcessById(ProcIdXL)


    'do some work with Excel here using xlApp

    'be sure to save and close all workbooks when done

    'release all objects used (except xlApp) using NAR(x)


    'Quit Excel 
    xlApp.quit()

    'Release
    NAR(xlApp)

End Sub

Private Sub NAR(ByVal o As Object)
    'http://support.microsoft.com/kb/317109
    Try
        While (System.Runtime.InteropServices.Marshal.ReleaseComObject(o) > 0)
        End While
    Catch
    Finally
        o = Nothing
    End Try
End Sub

Це було єдине рішення, яке працювало для мене. Дякую.
Джон

2

Я зіткнувся з тими ж проблемами і спробував багато методів, щоб вирішити їх, але не працює. Нарешті, я знайшов це по-своєму. Деякі посилання вводять тут опис посилання

Сподіваюся, мій код може допомогти комусь у майбутньому. На її вирішення я витратив більше двох днів. Нижче мій код:

//get current in useing excel
            Process[] excelProcsOld = Process.GetProcessesByName("EXCEL");
            Excel.Application myExcelApp = null;
            Excel.Workbooks excelWorkbookTemplate = null;
            Excel.Workbook excelWorkbook = null;
try{
    //DO sth using myExcelApp , excelWorkbookTemplate, excelWorkbook
}
catch (Exception ex ){
}
finally
            {
                //Compare the EXCEL ID and Kill it 
                Process[] excelProcsNew = Process.GetProcessesByName("EXCEL");
                foreach (Process procNew in excelProcsNew)
                {
                    int exist = 0;
                    foreach (Process procOld in excelProcsOld)
                    {
                        if (procNew.Id == procOld.Id)
                        {
                            exist++;
                        }
                    }
                    if (exist == 0)
                    {
                        procNew.Kill();
                    }        
                }
            }

1

excelBook.Close (); excelApp.Quit (); додайте кінець коду, цього може бути достатньо. він працює над моїм кодом


Так, але коли я ним користуюся, з’являється діалогове вікно збереження, і я не хочу, щоб воно
з’являлося

1

Ви можете вбити процес за допомогою власного COMоб'єкта excel pid

додати десь нижче dll коду імпорту

[DllImport("user32.dll", SetLastError = true)]
private static extern int GetWindowThreadProcessId(IntPtr hwnd, ref int lpdwProcessId);

і використовувати

 if (excelApp != null)
            {
                int excelProcessId = -1;
                GetWindowThreadProcessId(new IntPtr(excelApp.Hwnd), ref excelProcessId);

                Process ExcelProc = Process.GetProcessById(excelProcessId);
                if (ExcelProc != null)
                {
                    ExcelProc.Kill();
                }
            }

1

Я виявив, що важливо мати Marshal.ReleaseComObjectв межах Whileциклу І закінчити Збір сміття .

static void Main(string[] args)
{
    Excel.Application xApp = new Excel.Application();
    Excel.Workbooks xWbs = xApp.Workbooks;
    Excel.Workbook xWb = xWbs.Open("file.xlsx");

    Console.WriteLine(xWb.Sheets.Count);

    xWb.Close();
    xApp.Quit();

    while (Marshal.ReleaseComObject(xWb) != 0);
    while (Marshal.ReleaseComObject(xWbs) != 0);
    while (Marshal.ReleaseComObject(xApp) != 0);

    GC.Collect();
    GC.WaitForPendingFinalizers();
}

0
         wb.Close();
         app.Quit();

         System.Diagnostics.Process[] process = System.Diagnostics.Process.GetProcessesByName("Excel");
         foreach (System.Diagnostics.Process p in process)
         {
             if (!string.IsNullOrEmpty(p.ProcessName) && p.StartTime.AddSeconds(+10) > DateTime.Now)
             {
                 try
                 {
                     p.Kill();
                 }
                 catch { }
             }
         }

Він закриває останні 10 секунд процес з назвою "Excel"


0

Правильний спосіб закрити всі процеси Excel

var _excel = new Application();
foreach (Workbook _workbook in _excel.Workbooks) {
    _workbook.Close(0);
}

_excel.Quit();
_excel = null;
var process = System.Diagnostics.Process.GetProcessesByName("Excel");
foreach (var p in process) {
    if (!string.IsNullOrEmpty(p.ProcessName)) {
        try {
            p.Kill();
        } catch { }
    }
}

0

На основі іншого рішення. Я використовую це:

IntPtr xAsIntPtr = new IntPtr(excelObj.Application.Hwnd);
excelObj.ActiveWorkbook.Close();

System.Diagnostics.Process[] process = System.Diagnostics.Process.GetProcessesByName("Excel");
                foreach (System.Diagnostics.Process p in process)
                {
                    if (p.MainWindowHandle == xAsIntPtr)
                    {
                        try
                        {
                            p.Kill();
                        }
                        catch { }
                    }
                }

За допомогою «MainWindowHandle» ідентифікуйте процес і закрийте його.

excelObj: Це мій додаток Interop excel objecto


0

Використовуйте змінну для кожного об’єкта Excel і мусите цикл Marshal.ReleaseComObject >0. Без циклу процес Excel все ще залишається активним.

public class test{
        private dynamic ExcelObject;
        protected dynamic ExcelBook;
        protected dynamic ExcelBooks;
        protected dynamic ExcelSheet;

public void LoadExcel(string FileName)
        {
            Type t = Type.GetTypeFromProgID("Excel.Application");
            if (t == null) throw new Exception("Excel non installato");
            ExcelObject = System.Activator.CreateInstance(t);
            ExcelObject.Visible = false;
            ExcelObject.DisplayAlerts = false;
            ExcelObject.AskToUpdateLinks = false;
            ExcelBooks = ExcelObject.Workbooks;
            ExcelBook = ExcelBooks.Open(FileName,0,true);
            System.Runtime.InteropServices.Marshal.GetActiveObject("Excel.Application");
            ExcelSheet = ExcelBook.Sheets[1];
        }
 private void ReleaseObj(object obj)
        {
            try
            {
                int i = 0;
             while(   System.Runtime.InteropServices.Marshal.ReleaseComObject(obj) > 0)
                {
                    i++;
                    if (i > 1000) break;
                }
                obj = null;
            }
            catch 
            {
                obj = null;
            }
            finally
            {
                GC.Collect();
            }
        }
        public void ChiudiExcel() {
            System.Threading.Thread.CurrentThread.CurrentCulture = ci;

            ReleaseObj(ExcelSheet);
            try { ExcelBook.Close(); } catch { }
            try { ExcelBooks.Close(); } catch { }
            ReleaseObj(ExcelBooks);
            try { ExcelObject.Quit(); } catch { }
            ReleaseObj(ExcelObject);
        }
}

0

Ми можемо закрити програму Excel під час перетворення xls в xlsx, використовуючи наступний код. Коли ми виконуємо такі завдання, тоді програма Excel працює в диспетчері завдань, ми повинні закрити цей Excel, який працює у фоновому режимі. Interop - це компонент Com, для випуску компоненту com ми використовували Marshal.FinalReleaseComObject.

 private void button1_Click(object sender, EventArgs e)
    {

        Excel03to07("D:\\TestExls\\TestExcelApp.XLS");

    }
    private void Excel03to07(string fileName)
    {
        string svfileName = Path.ChangeExtension(fileName, ".xlsx");
        object oMissing = Type.Missing;
        var app = new Microsoft.Office.Interop.Excel.Application();
        var wb = app.Workbooks.Open(fileName, oMissing, oMissing,
                        oMissing, oMissing, oMissing, oMissing, oMissing, oMissing, oMissing, oMissing, oMissing, oMissing, oMissing, oMissing);
        wb.SaveAs(svfileName, XlFileFormat.xlOpenXMLWorkbook, Type.Missing, Type.Missing, Type.Missing, Type.Missing, XlSaveAsAccessMode.xlNoChange, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing);

        wb.Close(false, Type.Missing, Type.Missing);
        app.Quit();
        GC.Collect();
        Marshal.FinalReleaseComObject(wb);
        Marshal.FinalReleaseComObject(app);
   }

0

Більшість методів працює, але процес Excel завжди залишається до кінця програми.

Коли процес kill excel одного разу не може бути запущений ще раз в тому ж потоці - не знаю, чому.


-1
        GetWindowThreadProcessId((IntPtr)app.Hwnd, out iProcessId);
        wb.Close(true,Missing.Value,Missing.Value);
        app.Quit();
        System.Diagnostics.Process[] process = System.Diagnostics.Process.GetProcessesByName("Excel");
        foreach (System.Diagnostics.Process p in process)
        {
            if (p.Id == iProcessId)
            {
                try
                {
                    p.Kill();
                }
                catch { }
            }
        }
}
[DllImport("user32.dll")]

private static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId);

uint iProcessId = 0;

цей GetWindowThreadProcessId знаходить правильний ідентифікатор процесу o excell .... Після вбивства .... Насолоджуйтесь !!!


-1
private void releaseObject(object obj)
{
    try
    {
        System.Runtime.InteropServices.Marshal.ReleaseComObject(obj);
        obj = null;
    }
    catch (Exception ex)
    {
        obj = null;
        MessageBox.Show("Unable to release the Object " + ex.ToString());
    }
    finally
    {
        GC.Collect();
    }
}

Хоча цей код може вирішити питання, включаючи пояснення того, як і чому це вирішує проблему, насправді допомогло б поліпшити якість вашої публікації, і, можливо, призведе до більшої кількості голосів. Пам’ятайте, що ви відповідаєте на запитання читачам у майбутньому, а не лише тому, хто задає зараз. Будь ласка, відредагуйте свою відповідь, щоб додати пояснення, та вкажіть, які обмеження та припущення застосовуються.
Дейв
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.