Veri Erişiminden Sonra Excel Uygulama İşlemini C # ile Kapatma


88

C # ile okuma / yazma işlemleri için bir Excel şablon dosyası açan bir uygulama yazıyorum. Kullanıcı uygulamayı kapattığında, excel dosyasını kaydetmeden excel başvuru işleminin kapatılmasını istiyorum. Uygulamayı birden fazla çalıştırdıktan sonra Görev Yöneticimi görün.

görüntü açıklamasını buraya girin

Excel dosyasını açmak için bu kodu kullanıyorum:

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

ve veri erişimi için bu kodu kullanıyorum:

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

Ben gibi stackoverflow benzer soruları görmek bu soruya ve bu , ve test cevapları, ama işe yarıyor etmez.


Excel ve Word çok yavaştır ve karşılaştığınız gibi bir sürü tuhaflıkla birlikte gelir. Dosyalar, içinde bazı XML ve başka içerik bulunan zip dosyalarıdır. Belgeleri açabilen Open XML SDK (veya belki daha yeni bir şey) da vardır. Bu tür kod, Office yerel olarak yüklenmeden de çalışır. Excel
Sten Petrov

Yanıtlar:


97

Bunu dene:

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

Çalışma kitabını kapatırken, üç isteğe bağlı parametreniz vardır:

Workbook.close SaveChanges, filename, routeworkbook 

Workbook.Close(false)veya geç ciltleme yapıyorsanız, bazen sıfır kullanmak daha kolaydır Workbook.Close(0) . Çalışma kitaplarının kapanmasını otomatikleştirirken bunu böyle yaptım.

Ayrıca belgelerine baktım ve burada buldum: Excel Çalışma Kitabı Kapat

Teşekkürler,


Teşekkürler Sevgili Michael, düzgün çalışıyor: excelBook.Close (0)
Javad Yousefi

Merhaba Arkadaşlar, okumak için bir excel dosyası açtığınızda bu çalışmıyor. Kod var excelApp = new Application (); var workBooks = excelApp.Workbooks.Open @ "c: \ temp \ myexcel.xlsx"); workBooks.Close (0); excelApp.Quit ();
user1131926

ApplicationClass'ı kullandım ... ve nesneleri atmak için yukarıdaki kodu kullandım ama işe
yaramayacak

3
Tüm bu cevaplarla birçok başarısız denemeden sonra, açtığım işlem kimliğini almak ve doğrudan öldürmek için bu çözüme gittim .
UndeadBob

@Singaravelan: David Clarke'ın cevabını kontrol ettiniz mi?
Anh Nguyen

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

bunu deneyin .. benim için çalıştı ... işlemi durdurmak için o xl uygulama nesnesini serbest bırakmalısınız.


14

Referans: https://stackoverflow.com/a/17367570/132599

Çift nokta çağıran ifadeler kullanmaktan kaçının, örneğin:

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

... çünkü bu şekilde yalnızca çalışma kitabı için değil, Çalışma Kitapları için de RCW nesneleri oluşturursunuz ve onu da serbest bırakmanız gerekir (bu, nesneye bir başvuru korunmazsa mümkün değildir).

Bu benim için sorunu çözdü. Kodunuz şöyle olur:

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;

Ve sonra tüm bu nesneleri serbest bırakın:

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);

Bir try {} finally {}şeyler ters gitse bile her şeyin serbest bırakılmasını sağlamak için bunu a yazıyorum (ne ters gidebilir?)

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
Bu benim için çalıştı, çalışma kitaplarını bir değişkene atayarak temizlenebilir. Ayrıca bir gözlem, Web uygulamasında ve konsol uygulamasında excel uygulamasını temizlemek için tamamen aynı koda sahiptim. Çift noktadan kurtulma güncellemesinden önceki kod, konsol uygulamasında iyi çalıştı, ancak web uygulamasında çalıştırıldığında EXCEL.EXE dosyasını temizlemedi. Neden farklı davrandıklarından emin değilim, ancak çift nokta referansından kurtulmak web uygulamasında sorunu çözdü.
IronHide

benim için çalışıyor. Bence nesneyi serbest bırakmak için, ilgili tüm nesneleri serbest bırakmalıyız. Solidworks programıyla ilgili aynı sorunu yaşadım.
Gs.

1
Çalışma kitabını kapatın, Excel uygulamasından çıkın, çift nokta aramadan kaçının ve oluşturulan her COM nesnesini serbest bırakın. Bu benim için çalıştı. Hayat kurtaran cevap. Teşekkürler.
Sinan İLYAS

13

Bunu bir düşünün, süreci öldürür:

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 { }
    }
}

Ayrıca, normal şekilde kapatmayı denediniz mi?

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

Cevabınız için teşekkürler. İlk çözümünüz Tüm açık Excel dosyalarını kapatıyor. 'ExcelBook.Close' kullandığımda, Excel kaydetme iletişim kutusu görünüyor ve istemiyorum :(
Javad Yousefi

1
Düzenledim ve koddaki saveAs'ları yapmak için bir satır ekledim, diyaloğu kodla değiştirir, umarım yardımcı olur. :)
Morris Miao

1
Bunu sadece açık Excel işlemleri için bir ilk kontrolle kullandım ve kimlikleri bir listeye kaydettim. Sonra yeni bir Excel işlemi yaptım, yapmam gereken düzenlemeyi yaptım ve ID listesinde yer almayan herhangi bir Excel işlemini kapattım.
182764125216

Excel'i görev yöneticisinden çıkarmanın doğru yolu değildir. WorkBOoks gibi sahne arkasında yaratılanlar da dahil olmak üzere oluşturulan tüm nesneleri serbest bırakmalısınız.
ehh

Bu şekilde, çalışan her Excel sürecini öldürürsünüz. Sorun şu ki, aynı anda Excel kullanan başka kullanıcılar veya uygulamalar olabilir. Bunu yapmak isteyip istemediğinizi aklınızda bulundurun.
Sinan İLYAS

6

Excel'i öldürmek her zaman kolay değildir; bu makaleye bakın: Excel'i Öldürmenin 50 Yolu

Bu makale, Microsoft'tan ( MS Bilgi Bankası Makalesi ) Excel'in nasıl güzelce çıkmasını sağlayacağına dair en iyi tavsiyeyi alır , ancak daha sonra gerekirse işlemi sonlandırarak bundan da emin olur. İkinci bir paraşüte sahip olmayı seviyorum.

Açık çalışma kitaplarını kapattığınızdan, uygulamadan çıktığınızdan ve xlApp nesnesini bıraktığınızdan emin olun. Son olarak, sürecin hala hayatta olup olmadığını kontrol edin ve öyleyse öldürün.

Bu makale ayrıca tüm Excel işlemlerini öldürmediğimizden emin olmanızı sağlar, ancak yalnızca başlatılan işlemi kesin olarak sonlandırır.

Ayrıca bkz . Pencere Tutamacından İşlem Alma

İşte kullandığım kod: (her seferinde çalışıyor)

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

Benim için işe yarayan tek çözüm buydu. Teşekkürler.
Jon

2

Aynı problemlerle karşılaştım ve çözmek için birçok yöntem denedim ama işe yaramıyor. Sonunda kendi yolumda buldum. Bazı referanslar bağlantı açıklamasını buraya girin

Umarım kodum gelecekte birine yardımcı olabilir. Çözmek için iki günden fazla zaman harcadım. Kodum aşağıdadır:

//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 (); kodun sonuna ekleyin, yeterli olabilir. kodum üzerinde çalışıyor


Evet, ancak kullandığımda kaydetme iletişim kutusu görünüyor ve görünmesini istemiyorum :(
Javad Yousefi

1

Süreci kendi COMnesne excel pid ile öldürebilirsin

dll içe aktarma kodunun altına bir yere ekle

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

ve kullan

 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.ReleaseComObjectBir Whiledöngü içinde olmanın VE Çöp Toplama ile bitirmenin önemli olduğunu buldum .

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 { }
             }
         }

Son 10 saniyelik süreci "Excel" adıyla kapatır


0

Başka çözümlere dayanarak. Bunu kullanıyorum:

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 { }
                    }
                }

İşlemi tanımlamak ve onu kapatmak için "MainWindowHandle" ı kullanma.

excelObj: Bu benim Application Interop excel nesnem


0

Her Excel nesnesi için bir değişken kullanın ve döngü olmalıdır Marshal.ReleaseComObject >0. Döngü olmadan, Excel işlemi hala etkin kalır.

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

Xls'i xlsx'e çevirirken aşağıdaki kodu kullanarak Excel uygulamasını kapatabiliriz. Bu tür bir görevi gerçekleştirdiğimizde Excel uygulaması görev yöneticisinde çalışıyor, arka planda çalışan bu excel'i kapatmalıyız. Interop, Marshal.FinalReleaseComObject kullandığımız com bileşenini serbest bırakmak için bir Com bileşenidir.

 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

Yöntemlerin çoğu işe yarıyor, ancak excel süreci her zaman uygulama kapanana kadar devam ediyor.

Excel işlemini bir kez öldürdüğünüzde, aynı iş parçacığı içinde tekrar çalıştırılamaz - nedenini bilmiyorum.


0

Tüm excel sürecini kapatmanın doğru yolu

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

_excel.Quit();
_excel = null;

İşlem örneğini kullanarak bu, tüm excel sürecini ne olursa olsun kapatabilir.

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

Bu ayrıca VS ortamının dışında açık olan tüm yasal excel örneklerini de öldürecektir. Yani, gerçek excel uygulamasında başka bir excel çalışma sayfamın açık olduğunu varsayalım, kodunuz bunu da öldürüyor.
Mark

Teşekkürler notları güncellediniz.
Md. Alim Ul Karim

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

Benim için çalıştı.


-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;

bu GetWindowThreadProcessId mükemmel bir İşlem Kimliğini bulur .... Onu öldürdükten sonra .... Keyfini çıkarın !!!


-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();
    }
}

Bu kod soruyu çözebilirken, sorunun nasıl ve neden çözüldüğüne dair bir açıklama da dahil olmak üzere , gönderinizin kalitesini artırmaya gerçekten yardımcı olur ve muhtemelen daha fazla oy almanıza neden olur. Sadece şu anda soran kişi için değil, gelecekte okuyucular için soruyu yanıtladığınızı unutmayın. Lütfen açıklama eklemek için cevabınızı düzenleyin ve hangi sınırlamaların ve varsayımların geçerli olduğuna dair bir gösterge verin.
Dave
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.