Форум программистов, компьютерный форум, киберфорум
PowerShell
Войти
Регистрация
Восстановить пароль
Карта форума Темы раздела Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.96/55: Рейтинг темы: голосов - 55, средняя оценка - 4.96
1 / 1 / 0
Регистрация: 09.07.2014
Сообщений: 67
1

Закрытие файла Excel

15.11.2018, 16:08. Показов 10943. Ответов 5
Метки нет (Все метки)

Author24 — интернет-сервис помощи студентам
Как правильно закрыть файл Excel после работы с ним?

Вот код, который как-бы закрывает книгу
PowerShell
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# Экзель-файл из которого мы берём ФИО
$File = "С:\Тест.xlsx"
 
# Открываем Экзель файл, 1 Лист
$Excel = New-Object -ComObject Excel.Application
$Excel.visible = $false
$Workbook = $Excel.workbooks.open($file)
$Worksheets = $Workbooks.worksheets
$Worksheet = $Workbook.Worksheets.Item(1)
 
 
pause
 
Write-host "Закрываем книгу..."
$WorkBook.Close()
Write-host "Ок!"
Write-host "Закрываем Экзель..."
$Excel.Quit()
[System.Runtime.Interopservices.Marshal]::ReleaseComObject($Excel)
Write-host "Ок!"
Но каждый раз после него в фоновых процессах остаётся висеть экземпляр Microsoft Excel. Как можно закрыть файл так, чтобы после закрытия не появлялись фоновые процессы?

Добавлено через 1 час 57 минут
В общем я не нашёл элегантного решения (я думал можно как-то связать запущенный файл и ID процесса, но не нашёл такого), решил задачу в лоб. Так как у меня могут быть запущены более ранние процессы Экзеля, то просто выводится список всех процессов Экзель и даётся право выбора. При выборе - выбранный процесс и все процессы Экзель запущенные после него будут закрыты.

PowerShell
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
function Excel_Killer {
 
$i=1
$script:i=1
 
# Список процессов Экзель
$process_list=Get-Process -Name Excel | sort starttime |Select-Object @{n='Index';e={($script:i++)}},name, id, starttime| ForEach-Object {
$process=""| Select-Object Index,Name, id,starttime
$process.Index=$_.Index
$process.Name=$_.Name
$process.Id=$_.id
$process.StartTime=$_.starttime
$process
 
}
 
# Выводим список на экран
$process_list | Format-Table Index,Name,Id,StartTime
 
Write-Host "Выбери процесс, сам процесс и все процессы запущенные по времени после него будут закрыты!!!" -ForegroundColor Yellow 
Write-Host
 
$nia=read-host "Выбери процесс"
 
Switch ($nia) {
 
$nia {
 
$time=$process_list | Where {$_.Index -eq $nia} |Select-Object -ExpandProperty StartTime
 
Get-Process -Name Excel | Where-Object -FilterScript {$_.name -eq 'EXCEL' -and $_.StartTime -ge $time} | Stop-Process
 
Write-Host 'Ok!'
 
Start-Sleep -Milliseconds 250
 
# Проверка, что процесс закрыт.
Get-Process -Name Excel -ErrorAction SilentlyContinue | Format-Table name, id, starttime
 
}
 
default {
cls
Write-Host 
Write-Host 'Выбирай правильно!!!' -ForegroundColor Yellow
 
Start-Sleep -Milliseconds 500
Excel_Killer
}
}
 
}
Excel_Killer
0
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
15.11.2018, 16:08
Ответы с готовыми решениями:

Переформатирование Excel файла
Есть Excel документ, порядка 50 тысяч записей со столбцами Num, Od, Zip, Control_code, Num_control,...

Корректное закрытие файла Excel
Здравствуйте, уважаемые участники! Подскажите, пожалуйста как корректно закрыть файл .xls в vba?...

Коректное закрытие Excel
Доброго времени суток, уважаемые знатоки. Возникла проблема при работе с Екселем. На форме...

Корректное закрытие Excel
Как правильно закрыть Excel приложение Пробывал ExcelApplication1->Quit();...

5
1886 / 1108 / 428
Регистрация: 22.01.2016
Сообщений: 3,050
15.11.2018, 16:19 2
Цитата Сообщение от Maret Посмотреть сообщение
Вот код, который как-бы закрывает книгу
Почему как-бы?

У меня подобный же код не оставляет excel в процессах:

PowerShell
1
2
3
4
5
6
7
8
9
10
11
12
13
$excel = New-Object -ComObject Excel.Application
$excel.Visible = $false
$excel.displayAlerts = $false
 
$file = Get-Item -Path 'C:\Temp\1.xlsx'
 
$workbook = $excel.Workbooks.Open($file.FullName)
$excel.ActiveWorkbook.RefreshAll()
$excel.ActiveWorkbook.save()
$excel.ActiveWorkbook.close()
 
$excel.Quit()
[System.Runtime.Interopservices.Marshal]::ReleaseComObject($excel)
Цитата Сообщение от Maret Посмотреть сообщение
Так как у меня могут быть запущены более ранние процессы Экзеля
Возможно в этом и причина. Включите отображение предупреждений и возможно увидите, что excel не закрывается, т.к. висит с каким-то алертом.

PowerShell
1
2
$excel.Visible = $true
$excel.displayAlerts = $true
0
1 / 1 / 0
Регистрация: 09.07.2014
Сообщений: 67
16.11.2018, 10:04  [ТС] 3
Благодарю за ответ. Я сделал как вы и предлагали, но ничего не изменилось. Никаких предупреждений не появилось, а в процесс всё равно остаётся.


Я несколько изменил подход к убитию процесса:

PowerShell
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
function Excel_Killer {
 
Get-Process -Name Excel | Where-Object -FilterScript {$_.name -eq 'EXCEL' -and $_.id -eq $result} | Stop-Process
 
}  
 
# получаем список id процессов Экзель до запуска скрипта
$original= Get-Process -Name Excel | Select-Object -ExpandProperty id
$original | Out-Null
 
 
# Экзель-файл из которого мы берём данные по зашифрованным компам
$:File = "С:\Тест.xlsx"
 
# Открываем Экзель файл, 1 Лист
$Excel = New-Object -ComObject Excel.Application
$Excel.visible = $false
$Workbook = $Excel.workbooks.open($file)
$Worksheets = $Workbooks.worksheets
$Worksheet = $Workbook.Worksheets.Item(1)
 
# получаем список id процессов Экзель, с вычетом ранее запущенных процессов. Эта перeменная потом будет использоваться в функции Excel_Killer
$result=Get-Process -Name Excel | where {$_.id -ne $original} |Select-Object -ExpandProperty id
$result | out-null
 
<#
 
# работаем с файлом
 
#>
 
 
 
Write-host "Закрываем книгу..."
$WorkBook.Close()
Write-host "Ок!"
Write-host "Закрываем Экзель..."
$Excel.Quit()
Write-host "Ок!"
Write-host "Чистим переменную..."
[System.Runtime.Interopservices.Marshal]::ReleaseComObject($Excel)
Start-Sleep -Milliseconds 250
$Excel=$null
Write-host "Ок!"
Write-host "Выходим из скрипта..."
Start-Sleep -s 1
Excel_Killer
 
# чтобы не закрывалась консоль
break Script
0
1886 / 1108 / 428
Регистрация: 22.01.2016
Сообщений: 3,050
16.11.2018, 10:56 4
Цитата Сообщение от Maret Посмотреть сообщение
Благодарю за ответ. Я сделал как вы и предлагали, но ничего не изменилось.
А вы уверенны, что остаётся именно тот excel, который был запущен этим скриптом?

Цитата Сообщение от Maret Посмотреть сообщение
Я несколько изменил подход к убитию процесса:

PowerShell
1
2
3
$original = Get-Process -Name Excel | Select-Object -ExpandProperty id
...
$result = Get-Process -Name Excel | where {$_.id -ne $original} |Select-Object -ExpandProperty id
А если в момент создания переменной $original уже будет более 1 excel процесса?
0
774 / 423 / 137
Регистрация: 03.06.2009
Сообщений: 1,223
Записей в блоге: 4
16.11.2018, 17:43 5
KDE777,

А вы уверенны, что остаётся именно тот excel, который был запущен этим скриптом?
Полагаю, что все именно так.

Вероятно, в тех случаях когда, процесс не завершается при вызове метода quit() и идет попытка вызова ReleaseComObject, то он возвращает ненулевое значение, соответственно, объект не освобождается.
По какой причине мне сложно сказать, здесь нужны углубленные знания.


У меня есть подобная проблема, я бы тоже не отказался от помощи, но товарищ Убежденный с форума ушел
Если с Excel еще можно привязаться к процессом, костыльным методом, то в моем случае этого не сделать.

Если вкратце я использую 1С-COM соединение, которое коннектится к кластеру на сервере и выполняет определенный код.
Вся проблема в том, что после выполнения кода, сеанс не снять никаким образом...
Штатного метода типа CLOSE(),QUIT(), или DISPOSE() не реализовано.
Выглядит примерно так.
PowerShell
1
2
3
4
5
6
7
8
9
10
$object=new-object -comobject V82.ComConnector
try
{
    $connection=$object.connect("Srvr=srv;Ref=ut;Usr=user;Pwd=123")
}
catch
{
    sleep -Seconds 5
    $connection=$object.connect("Srvr=srv;Ref=ut;Usr=user;Pwd=123")
}
В данном случае создается основоной COM-объект, и объект $connection, который само собой тоже является COM-объектом.
Например, сразу после его создания вызвать
PowerShell
1
[System.Runtime.Interopservices.Marshal]::ReleaseComObject($connection)
То после вызова мы получим 0 - успешное завершение метода ReleaseComObject и сеанс также удалится с кластера.
Однако мне не нужно сразу после создания коннекта сразу его завершать, а надо выполнить код.
Поэтому, далее создается еще цепочка COM-объектов
PowerShell
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
$object=new-object -comobject V82.ComConnector
try
{
    $connection=$object.connect("Srvr=srv;Ref=ut;Usr=user;Pwd=123")
}
catch
{
    sleep -Seconds 5
    $connection=$object.connect("Srvr=srv;Ref=ut;Usr=user;Pwd=123"
}
$zapros=[System.__comObject].InvokeMember("NewObject",[System.reflection.bindingFlags]::invokemethod,$null,$connection,"Запрос")                  
[system.__comObject].InvokeMember("Text",[System.reflection.bindingFlags]::setproperty,$null,$zapros,$zapros_1)
[system.__comObject].InvokeMember("УстановитьПараметр",[System.reflection.bindingFlags]::invokemethod,$null,$zapros,("Дата",$curDate))
[system.__comObject].InvokeMember("УстановитьПараметр",[System.reflection.bindingFlags]::invokemethod,$null,$zapros,("Дата2",$nextDate))
$res=[system.__comObject].invokeMember("Выполнить",[System.reflection.bindingFlags]::invokemethod,$null,$zapros,$null)
$vigruzka=[system.__comObject].invokeMember("Выгрузить",[System.reflection.bindingFlags]::invokemethod,$null,$res,$null)
В данном случае был выполнен запрос 1С и его результат сохранен в переменную $vigruzka, который тоже является COM-объектом.
Собственно, если после всего этого попытаться освободить все ком-объекты, через ReleaseComObject
PowerShell
1
2
3
4
5
6
7
[System.Runtime.Interopservices.Marshal]::ReleaseComObject($vigruzka)
[System.Runtime.Interopservices.Marshal]::ReleaseComObject($EVOTORvigruzka)
[System.Runtime.Interopservices.Marshal]::ReleaseComObject($zapros) 
[System.Runtime.Interopservices.Marshal]::ReleaseComObject($res)
[System.Runtime.Interopservices.Marshal]::ReleaseComObject($EVOTORzapros)   
[System.Runtime.Interopservices.Marshal]::ReleaseComObject($EVOTORres)              
[System.Runtime.Interopservices.Marshal]::ReleaseComObject($connection)
То все прекрасно отработает, и сеанс удалится, НО
Посколько переменная $vigruzka - хранит все табличные данные обернутые COM-объектом, то ее надо обработать.
Вот тут и начинаются сложности.
Если попытаться подсунуть ее в цикл Foreach, причем в пустой, или даже хотя бы просто вывести ее содежимое
PowerShell
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
PS C:\Users\bafomet> $vigruzka
System.__ComObject
System.__ComObject
System.__ComObject
System.__ComObject
System.__ComObject
System.__ComObject
System.__ComObject
System.__ComObject
System.__ComObject
System.__ComObject
System.__ComObject
System.__ComObject
System.__ComObject
System.__ComObject
System.__ComObject
System.__ComObject
PowerShell
1
2
3
4
foreach($element in $vigruzka)
{
 
}
То последующий вызов ReleaseComObject всегда возвращает - 1, ну и соответственно сеанс не удаляется

Почему так, я не понимаю.

Добавлено через 4 часа 21 минуту
Все, в своей проблеме я разобрался.
Все из-за кривых рук разработчиков 1С.

По поводу Excel, советую понаблюдать за возращаемым значением ReleaseComObject, если он отличен от нуля, то освобождение объекта не происходит.
Можете попробовать использовать FINALReleaseComObject
0
210 / 59 / 26
Регистрация: 16.06.2016
Сообщений: 193
16.11.2018, 20:44 6
Цитата Сообщение от v_svitere Посмотреть сообщение
По поводу Excel, советую понаблюдать за возращаемым значением ReleaseComObject, если он отличен от нуля, то освобождение объекта не происходит.
Да-да, так сегодня и делал (; Судя по форумам, это давняя проблема ?..

PowerShell
1
2
3
4
5
6
$Excel.Quit()
while( [System.Runtime.Interopservices.Marshal]::ReleaseComObject($Workbook)) {}
while( [System.Runtime.Interopservices.Marshal]::ReleaseComObject($Excel)) {}
while( [System.Runtime.Interopservices.Marshal]::ReleaseComObject($WorkSheet_p)) {}
while( [System.Runtime.Interopservices.Marshal]::ReleaseComObject($WorkSheet_u)) {}
Remove-Variable Excel -ErrorAction SilentlyContinue
0
16.11.2018, 20:44
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
16.11.2018, 20:44
Помогаю со студенческими работами здесь

Закрытие процесса Excel
Здравствуйте. Такая проблемка... У меня в работе берутся данные из файла Excel и заносятся в...

Закрытие Excel из приложения ВБ
Проблемма вот в чём: Есть файл экселя и всё я с ним отлично делаю из ВБ но после закрытия повторно...

Правильное закрытие Excel
Вот так я открываю xls файл Excel.Application app = new Excel.Application(); ...

Корректное закрытие окна Excel
Добрый день! Подскажите, пожалуйста, каким образом можно решить следующую задачу. Я...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
6
Ответ Создать тему
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2024, CyberForum.ru