2016-03-31 2 views
3

Извините за длинный заголовок.Неиспользованная функция в Excel addin вызывает сбой только при втором запуске и при запуске через VBScript

У меня есть несколько файлов .xlsm, которые содержат много кода, поэтому я переместил повторяющиеся части в файл addin .xlam. Я использую скрипт .vbs, чтобы открывать все файлы один за другим и запускать макрос в каждом.

Проблема

Проблема я столкнулся в том, что на второй запуска сценария .vbs, первенствует аварий и дает то, что кажется очень родовую ошибку, сказал here быть " Ошибка автоматизации ":

Script: C:\Users\~\Desktop\test\test.vbs 
Line: 5 
Char: 1 
Error: The server threw an exception. 
Code: 80010105 
Source: (null) 

к моему удивлению, я был в состоянии воспроизвести эту аварию даже после удаления 99% содержания моих файлов.

test.vbs:

Dim xlApp 
Dim xlBook 
Set xlApp = CreateObject("Excel.Application") 
Set xlBook = xlApp.Workbooks.Open("C:\Users\~\Desktop\test\test.xlsm") 
xlApp.Run "Auto.Run" '<~~ error on this line 
xlBook.Save 
xlBook.Close (True) 
xlApp.Quit 
Set xlBook = Nothing 
Set xlApp = Nothing 

test.xlsm:

test.xlam has a module Module1, test.xlsm has a Module Auto and a Reference to test.xlam

test.xlsm, Auto:

Sub Run() 
    MsgBox "hello" 
    Test.Load 
    MsgBox "goodbye" 
End Sub 

test.xlam, Module1

Sub Load() 
    MsgBox "Load" 
End Sub 

Function Other() 
End Function 

С прокомментированной функцией Other() код работает нормально (говоря привет, загрузка и до свидания). Он также отлично работает, если макрос запускается из excel. Только когда присутствует Other(), а Run() запускается через файл .vbs, есть ошибка (сразу после приветствия).

Обход

Если я открываю test.xlsm, сохраните его, и закройте ее снова между каждым пробеге test.vbs, нет никаких проблем. Я считаю, что это связано с добавлением, а не с электронной таблицей, потому что в моем исходном скрипте, который открыл несколько файлов excel, нужно открыть и сохранить только один файл.

Я также заметил, что файл excel немного больше в своем «проблемном» состоянии, и когда я его открываю и сохраняю, он возвращается к чуть меньшему оригинальному размеру. (EDIT: Это по крайней мере частично вызвано новыми потоками кэша __SRP_4 и __SRP_5 внутри файла vbaProject.bin, который я извлек с помощью this answer (oh и this). После того, как вручную удалил все записи SRP, я смог запустить .vbs скрипт снова без проблем, хотя так же, как открытого копи-близко стратегии, это только временно, а потом рухнет на третьем ходу, а не второй.)

Вопрос

ли Addins не подходит для общий код? Могут ли они не содержать функции? Есть ли способ обойти эту катастрофу, кроме того, что я сейчас делаю?

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

+0

Наиболее вероятно, связано [с этим] (http://stackoverflow.com/q/213375/4088852) – Comintern

ответ

1

Мне кажется, что первый экземпляр не выгружается/освобождается до вызова второго экземпляра. Возможно, используя Application.Wait Method, чтобы подождать несколько секунд, прежде чем каждый последующий прогон может помочь?

'Open file1 
'Run macro from file1 
'Close file1 
Application.Wait(Now + TimeValue("0:00:10")) 'wait 10 seconds 
'Open file1 
'Run macro from file1 
... 
... 
So on 

Чтобы установить надстройку, чтобы преуспеть с помощью VBScript вы можете использовать следующий код

'Launch Excel 
set objExcel = createobject("Excel.Application") 
strAddIn = "ESP Assistant.xlam" 
'~~> Path where the XLAM resides 
SourcePath = "Your source path\" & strAddIn 

'Add the AddIn 
On Error Resume Next 
With objExcel 
    'Add Workbook 
    .Workbooks.Add 
    'Show Excel 
    objExcel.Visible = True 
    .AddIns.Add(SourcePath, False).Installed = True 
End With 

Если это не удается, возможно, придется очистить значения реестра, а затем повторите выше сценарий

'File to use just in case Add-In installation fails 
'Refreshes Excel Registry Entries to allow for clean install of Add-In 
Dim objFSO, objShell 
Set objFSO = CreateObject("Scripting.FileSystemObject") 
Set objShell = WScript.CreateObject ("WScript.shell") 
objShell.Run "cmd /c ""C:\Program Files (x86)\Microsoft Office\Office14\excel.exe"" /unregserver && timeout /t 3 && tskill excel && ""C:\Program Files (x86)\Microsoft Office\Office14\excel.exe"" /regserver",1,True 
Set objFSO = Nothing 
Set objShell = Nothing 
x=msgbox("Excel registry refreshed." ,0, "Registry Update") 
wscript.quit 
+0

В моем примере я просто дважды нажимаю на.vbs снова после завершения. Я могу подождать минуту или около того между ними, но крушение все еще происходит во второй раз. Я также проверял, что перед тем, как щелкнуть второй раз, не запускались ни EXCEL.EXE, ни 'wscript.exe'. (Несмотря на то, что после крушения excel застрял в открытом доступе и должен быть убит) – bl184999

+0

Две вещи: 1) Я считаю, что проблема связана с надстройкой, что может означать, что Excel не распознает/не находит ее, когда она reopens (приводит к тому, что excel висит/не отвечает). Если вы используете функции надстройки и код во многих разных файлах с течением времени, я бы предложил установить надстройку для excel вместо добавления ссылки на нее из vbe (I будет обновлять мой ответ, чтобы указать, как) – CaffeinatedCoder

+0

Я изначально сохранил добавление в специальной папке excel под '% AppData%', где по умолчанию сохраняет .xlam. Я думаю, что я установил его через пользовательский интерфейс, прежде чем он появился в списке возможных ссылок по умолчанию. Ссылка в vbe, по-видимому, требуется для вызова суб; Я не мог найти другого способа сделать это, даже со странными конструкциями вроде [this] (http://stackoverflow.com/a/2814426/847423), которые включали полный путь к файлу в коде. Я решил проблему, очистив кэш vba, и я опубликую это через минуту. – bl184999

0

К сожалению, я до сих пор не знаю, почему это происходит, но я нашел автоматическое решение, с которым я буду придерживаться.

Как я уже упоминал в моем вопросе, файл test.xlsm был немного больше в своей «проблеме» состоянии, из-за, по крайней мере, частично в какой-то кэш, из которых я мог найти только одно упоминание OFFICAL here:

2.2.6 SRP Streams

Streams, которые определяют в конкретной реализации и версии в зависимости от кэша производительности. ДОЛЖЕН быть проигнорирован при чтении. НЕ ДОЛЖЕН присутствовать при записи. Имя каждого из этих потоков задается следующей грамматикой ABNF:

SRPStreamName = "__SRP_" 1*25DIGIT

Мое решение было удалить кэш, который я сделал вручную сначала с this tool. Когда, кажется, сработало, я написал программу Java, чтобы сделать это автоматически (gist here). Это клей между java.util.zip и Apache POIFS.

Я также добавил строку для вызова Java в конце сценария .vbs:

CreateObject("WScript.Shell").Run "java -jar clear-excel-cache.jar C:\Users\~\Desktop\test\test.xlsm", 1, false 

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

+0

Есть два способа избавиться от окна cmd, которое я нашел: 1) изменить 1 на 7, чтобы начать [сведено к минимуму] (https://msdn.microsoft.com/en-us/library/d5fk67ky (v = vs.84) .aspx # Anchor_2), или 2) используйте 'javaw' вместо' java' – bl184999

0

Ваша проблема может быть той же проблемой, которую я пытаюсь решить. Случайные 64-разрядные ошибки Excel 2013 VBA (ошибки VBE7.dll). Вы можете проверить журналы приложений для сбоя VBE7.dll, чтобы подтвердить это.

В моем случае различные файлы XLSM становятся прерывистыми с помощью ручного использования.

Мое исправление в качестве альтернативы вашему - это следующее VBS (что-либо, чтобы вызвать перекомпиляцию VBA).

Resave "myfile.xlsm" 

Sub Resave(filename) 
    Set objExcel = CreateObject("Excel.Application") 

    currentDirectory = left(WScript.ScriptFullName,(Len(WScript.ScriptFullName))-(len(WScript.ScriptName))) 

    objExcel.Application.AutomationSecurity = 3 ' Disable to avoid crash 
    objExcel.Application.enableevents = False 
    objExcel.Application.Workbooks.open(currentDirectory + "\" + filename) 
    objExcel.Application.Visible = True 

    objExcel.Application.DisplayAlerts = False 
    Set objSheet = objExcel.ActiveWorkbook.Sheets.Add 
    objSheet.Delete 
    objExcel.Application.DisplayAlerts = True 

    objExcel.Application.enableevents = True 
    objExcel.ActiveWorkbook.Save 
    objExcel.ActiveWorkbook.Close 

    objExcel.Application.Quit 

    Set objExcel = Nothing 
End Sub 
Смежные вопросы