pd1989 Ответов: 6

Закройте процесс Excel с помощью Interop


Всем привет,

Я запустил приложение, которое создает список Excel с помощью Interop. Проблема в том, что после сохранения списка excel у меня есть открытый процесс в Диспетчере задач. Я уже искал в Интернете решение, но не нашел решения своей проблемы, чтобы закрыть (не убить) процесс.

Вот та часть, где я пытаюсь закрыть приложение excel:
if (xlsApplication != null)
            {
                if (xlsApplication.Workbooks != null)
                {
                    if (xlsApplication.Workbooks.Count < 0)
                    {
                        xlsWorkbook.Close(true, @"C:\test.xls", null);
                        xlsApplication.Workbooks.Close();
                        xlsApplication.Quit();
                        missing = null;
                        ReleaseObjects();
                        r_Time = null;
                        r_Name = null;
                        r_ReceivedTime = null;
                        r_Received = null;
                        r_OrderedTime = null;
                        r_Ordered = null;
                        xlsRange = null;
                        xlsWorksheet = null;
                        xlsWorkbook = null;
                        xlsApplication = null;
                    }
                }
            }
            GC.Collect();
            GC.WaitForPendingFinalizers();
            GC.Collect();
            //GC.WaitForFullGCComplete();
            GC.WaitForPendingFinalizers();


Небольшое пояснение к фрагменту:
В методе " ReleaseObjects()" я освобождаю все com-объекты и диапазоны с помощью " System.Runtime.InteropServices.Маршал.Метода releasecomobject()".
Некоторые вещи в сниппете, например, чтобы установить систему.Отражение.Недостающий.Значение, отсутствующее до нуля, - это скорее акты отчаяния, чем полезный код. (Потому что я пытаюсь закрыть приложение уже с неделю! :omg: )

Во время отладки я искал открытые Com-объекты, но их там нет.
Единственное, когда я сохраняю список Excel, а затем нажимаю "закрыть", где я снова запускаю через GC - часть(в другом методе, но он делает то же самое), то приложение закроется "нормально".

Я старался автоматизировать, чтобы после каждого процесса сохранения форма закрывалась. Его функция(закрыть форму и так далее) та же, но он не закрывает приложение excel. :doh:

Похоже, что Com-объекты не освобождаются вовремя.

Есть ли у кого-нибудь опыт работы с этой проблемой.

тнх

6 Ответов

Рейтинг:
44

Jordy "Kaiwa" Ruiter

Эй там,

Это проблема, которая была у меня в течение долгого времени. Боюсь, что я не нашел решения с помощью взаимодействия. Однако я создал некоторый код, который автоматически убил этот процесс для меня. Теперь я не знаю, если это то, что вы хотите, потому что я нашел это несколько расплывчатым, но вот оно идет:

Во-первых, мы должны импортировать Dll, чтобы использовать GetWindowThreadProcessId() функция. (Не обращайте внимания на названия классов, это просто мой код).

using System.Runtime.InteropServices;

...

public partial class Quotation : Form
{
[DllImport("user32.dll", SetLastError = true)]
static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId);

...
}


Затем мы создадим переменную, которая будет хранить processId. (Я включил ваши имена переменных для этого)

uint processId = 0;

if (xlsApplication != null)
{
   if (xlsApplication.Workbooks != null)
   {
      if (xlsApplication.Workbooks.Count < 0)
      {
         GetWindowThreadProcessId(new IntPtr(xlsApplication.Hwnd), out processId);
      
      // All your actions here
      }
   }
}


И, наконец, уборка. Убийство процесса должно быть внутри попыток поймать утверждения. Это потому, что закрытие Excel, по-видимому, иногда происходит.

if (xlsApplication != null)
{
   if (xlsApplication.Workbooks != null)
   {
      if (xlsApplication.Workbooks.Count < 0)
      {
         xlsWorkbook.Close(true, @"C:\test.xls", null);
         xlsApplication.Workbooks.Close();
         xlsApplication.Quit();
         missing = null;
         ReleaseObjects();
         r_Time = null;
         r_Name = null;
         r_ReceivedTime = null;
         r_Received = null;
         r_OrderedTime = null;
         r_Ordered = null;
         xlsRange = null;
         xlsWorksheet = null;
         xlsWorkbook = null;
         xlsApplication = null;
      }
   }
}

try
{
    if (processId != 0)
    {
        Process excelProcess = Process.GetProcessById((int)processId);
        excelProcess.CloseMainWindow();
        excelProcess.Refresh();
        excelProcess.Kill();
    }
}
catch
{
    // Process was already killed
}

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


Я надеюсь, что это поможет


Dalek Dave

Хороший Ответ!

Khaled Kokah

Блестяще, GetWindowThreadProcessId сделал свое дело и закроет открытый файл excel. Мой голос-5.

Kothari Brijesh

Спасибо большое..это действительно решило мою проблему....мой голос 5 для вас.

Karthik_Mahalingam

это работает, Спасибо

Рейтинг:
2

pd1989

Привет Джорди,

Спасибо за ваш ответ.

Я уже читал об убийстве процесса, но, если я не очень ошибаюсь, если у пользователя приложения есть открытый лист excel, и вы убиваете процесс, то вы убиваете и процесс вручную открытого excel.

И это не то, что я хочу сделать.

Разве нет чистого способа закрыть excel с помощью приложения???:confused:


Рейтинг:
1

Jordy "Kaiwa" Ruiter

Нет, это другой подход. Это убивает один процесс. Как только он создает новый процесс он отслеживает идентификатор а не убивает всех Excel.exe процессы.

Я проверил это, и это действительно работает ;)


Рейтинг:
1

pd1989

Неужели?

Похоже, я искал неправильное решение!

Большое спасибо


Рейтинг:
1

mrdosu

Я только что заметил, что вы (неявно) приобретаете com-указатель на xlsApplication.Объект Workbooks никогда не вызывал ReleaseComObject на нем.
Если положить, что в переменной и выпустить его в формате Excel следует закрывать аккуратно.


Member 10881033

Это идеальная работа... Большое спасибо, дорогая! прекрасная работа... Я потратил слишком много времени на поиски решения этой проблемы

Member 11804380

хиии, как вы его закодировали, не могли бы вы поделиться со мной, я новичок в Си-Диез
Спасибо
Мохини

Рейтинг:
0

CodeMe123

Не используйте ReleaseComObject или FinalReleaseComObject, который является анти-шаблоном. В ситуациях, когда Excel собирается зависнуть, они вряд ли помогут.

Использование дескриптора окна для получения процесса, а затем использование процесса для его уничтожения-это реальный ответ на то, когда Excel зависает. И Excel иногда будет висеть - например, плохие надстройки могут привести к его зависанию.

Excel может занять некоторое время, чтобы закрыть его даже после того, как ваши экземпляры COM исчезнут. Мне нравится использовать такую петлю:

static void WaitForComCleanup()
{
    int tryCleanUp = 0;
    do
    {
        GC.WaitForFullGCComplete();
        GC.WaitForPendingFinalizers();
    }
    while (Marshal.AreComObjectsAvailableForCleanup() && tryCleanUp++ < 10);
}

Чтобы позволить CLR очистить COM-объекты. Затем подождите, пока процесс завершится в течение нескольких секунд. Если нет, то убейте его. Вот так..

if (!excelProcess.WaitForExit(5000))
{
    excelProcess.Kill();
}

Последнее замечание будет заключаться в том, что вы должны тестировать это с помощью сборки в режиме выпуска. Отладочные сборки будут держать экземпляры COM вокруг, чтобы вы могли видеть их в отладчике, а это означает, что они не убирают за собой так агрессивно, что может привести вас к мысли, что он завис.


Kats2512

Однако на 9 лет опоздал