gifts2017

Активизация окна стороннего приложения из 1С 8 на примере программы "АвтоДилер"

Опубликовал Николай Гусев (GusevNA) в раздел Программирование - Практика программирования

Нередко бывает необходимость открыть из 1С окно стороннего приложения, например, Word, Excel и т.д. Когда у меня появилась эта задача, в интернете было предложено много решений, однако большая часть из них оказалась неработоспособной. В этой статье предлагается решение задачи на примере внешней программы "АвтоДилер".

Функция, активизирующая окно стороннего приложения:

// ЗаголовокОкнаПриложения - текст в заголовке окна внешнего приложения
// Задержка - задержка в миллисекундах перед выполнением скрипта, строка или число
Функция АктивироватьОкноПриложения (Знач ЗаголовокОкнаПриложения = "", Знач Задержка = "1000") Экспорт
   
ВремИмяФайла = КаталогВременныхФайлов() + "~showapp.vbs";
// готовим VBS-файл
   
ТекстСкрипта = "
    |Set WshShell = CreateObject(""WScript.Shell"")
    |WScript.Sleep
    |Res = WshShell.AppActivate(""%%ЗАГОЛОВОКОКНА%%"")
    |If Not Res Then WScript.Echo ""Открыть окно не удалось""
    |"
;

    Если
ТипЗнч (Задержка) = Тип ("Число") Тогда
       
Задержка = Формат (Задержка, "ЧГ=0");
    КонецЕсли;
  
ТекстСкрипта = СтрЗаменить(ТекстСкрипта, "%%ЗАГОЛОВОКОКНА%%", ЗаголовокОкнаПриложения);
  
ТекстСкрипта = СтрЗаменить(ТекстСкрипта, "%%ЗАДЕРЖКА%%", Задержка);

  
хТекст = Новый ТекстовыйДокумент;
  
хТекст.ДобавитьСтроку(ТекстСкрипта);
  
хТекст.Записать(ВремИмяФайла, "windows-1251");

  
хШелл = Новый COMОбъект("WScript.Shell");
  
хШелл.Run ("wscript "+ВремИмяФайла, 0, Ложь);

   Возврат
0;
КонецФункции

 Функция, активизирующая окно программы "Автодилер" (версия 5.4 редакция 9):

// ИДДетали - ID детали в программе АвтоДилер
// ЗаголовокОкнаАД - текст в заголовке окна приложения АвтоДилер
// Задержка - задержка в миллисекундах перед выполнением скрипта, строка или число
Процедура ПоказатьДетальВАвтоДилереПоИД (Знач ИДДетали, Знач ЗаголовокОкнаАД = "", Знач Задержка = "1000") Экспорт
    Попытка
       
хАД = Новый COMОбъект("AutoDealer.Catalog");
    Исключение
       
Сообщить ("Не удалось получить доступ к программе 'АвтоДилер'", СтатусСообщения.ОченьВажное);
        Возврат;
    КонецПопытки;
   
хАД.GetDetailByUID (СокрЛП (ИДДетали));

    Если
ЗаголовокОкнаАД = "" Тогда
       
ЗаголовокОкнаАД = "-= Система ""АвтоДилер"" 5.4 (редакция 9) =-";
    КонецЕсли;
   
АктивироватьОкноПриложения (ЗаголовокОкнаАД, Задержка);

   Возврат;
КонецПроцедуры

Пример открытия детали в программе "АвтоДилер":

ПоказатьДетальВАвтоДилереПоИД ("386#4752164#4674", "-= Система """"АвтоДилер"""" 5.4 (редакция 9) =-");

Несколько слов о параметрах:

ЗаголовокОкнаПриложения

Для открытия окна используется функция WSH AppActiate. В документации к функции сказано, что окно ищется следующим образом: "значение параметра сравнивается по очереди с заголовками окон всех запущенных приложений. Если не найдено ни одного точного совпадения, будет производиться поиск окна, заголовок которого начинается с указанной строки. Если и в этом случае не будет найдено ни одного подходящего окна, будет производиться поиск окна, заголовок которого заканчивается на указанную строку. Если будет найдено несколько подходящих окон, произойдёт активизация одного из них (произвольно). "

Задержка

Параметр Задержка используется для того, чтобы процедура 1С отработала, открылось основное окно 1С, а затем выполнился скрипт, открывающий окно внешнего приложения. Если решение все-таки не заработает, можно поэкспериментировать с этим параметром.

Работоспособность решения:

Поскольку в данном решении использованы средства Windows, стоит сказать, что оно тестировалось на Windows 7 Home и Pro с приложения АвтоДилер, MS Office 2007 (Word, Excel).

В системах Windows часто меняется механизм активизации окна, но, поскольку используется функция механизма WSH, который тоже обновляется вместе с выходом новой версии Windows, жизнеспособность решения усиливается.

Неного дегтя:

Минусом решения, во-первых, является использование внешнего файла. Во-вторых, выполнение vbs-скриптов может быть отключено у пользователя, что потребует дополнительной настройки Windows.

Приглашаю всех, кто заинтересовался публикацией, к обсуждению и тестированию.

 


Скачать файлы

Наименование Файл Версия Размер Кол. Скачив.
Пример активизации окна стороннего приложения
.epf 7,66Kb
15.04.13
13
.epf 7,66Kb 13 Скачать

См. также

Подписаться Добавить вознаграждение

Комментарии

1. Яков Коган (Yashazz) 16.04.13 10:36
Автор знает о КомандеСистемы и о расширенных в последних релизах возможностях ЗапуститьПриложение?
2. Николай Гусев (GusevNA) 16.04.13 11:49
(1) Yashazz, если есть идеи по усовершенствованию решения, поделитесь ими, плиз.
Основным минусом я считаю использование AppActivate из WSH. За идеи, как заменить эту функцию, но так, чтобы после ее вызова управление окну 1С не передавалось, буду очень благодарен.
А что касается последних релизов - было желание сделать решение максимально универсальным. Оно работает даже на 8.2.9.х. На практике в паре организаций его даже использовали на 8.1.
3. Яков Коган (Yashazz) 16.04.13 18:33
(2) Да, ваше решение годится хоть для 7.7 и 8.0, в принципе. И это плюс. А идея, которую я мог бы предложить - это именно накрутки вокруг ЗапуститьПриложение. Хотя после ряда моих экспериментов оказалось, что эта команда умеет вышибать 1С по критикал эррору весьма неслабо.
4. Николай Гусев (GusevNA) 17.04.13 01:00
(3) Yashazz, кстати сказать, насчет ЗапуститьПриложение и КомандаСистемы. Поскольку в данном случае приложением является wscript.exe (или cscript.exe), то как я ни пытался избавиться от открытия окна с черным фоном при вызове этих функций, ничего не получилось. В итоге сделал через метод Run WSH с параметром запуска без открытия окна.
Насчет глюков ЗапуститьПриложение - абсолютно согласен. Как только начинаешь крутить - они тут как тут :-)
5. Марина Гинко (_qqq) 18.09.13 08:57
Попробовали из Розницы (1.0) открывать АвтоДилер (демо).
Пришлось провести небольшую работу над ошибками.
У автора исчезла Задержка:
ТекстСкрипта = "
|Set WshShell = CreateObject(""WScript.Shell"")
|WScript.Sleep %%ЗАДЕРЖКА%%
|Res = WshShell.AppActivate(""%%ЗАГОЛОВОКОКНА%%"")
|If Not Res Then WScript.Echo ""Открыть окно не удалось""
|";
И кавычек добавили:
хШелл.Run ("wscript """+ВремИмяФайла + """", 0, Ложь);
А то не нравились названия каталогов содержащие пробелы.

Процедуру ПоказатьДетальВАвтоДилереПоИД прикрутили к формочке (не упр.).
Окно АвтоДилера открывается, вернее начинает открываться.
Потом оно пропадает, закрыается видимо само, по какой-то причине.
И выдается сообщение "Открыть окно не удалось".
Сначала думали не хватает времени, чтобы открыться, и увеличивали Задержку.
Но это не помогло. Окно АвтоДилера закрывалось все равно, только сообщение
"Открыть окно не удалось" появлялось на некоторое время позднее.

Николай, как вы думаете в чем прична? Демоверсия АвтоДилера виновата?
Нет ли у Вас мыслей, как сделать так, чтобы у нас сработала Ваша замечательная идея?
6. Николай Гусев (GusevNA) 18.09.13 09:52
(5) _qqq,
1. При запуске функций обработки программа Автодилер должна уже быть запущена как обычное приложение (там авторизация - как авторизоваться через ActiveX - не знаю :-)).
2. Задержка исчезать не должна - проверьте в отладчике vbs-скрпит, там должно быть число строкой без пробелов.
3. Насчет кавычек - согласен, не помешают.
4. Проверьте заголовок окна приложения Автодилер - он должен точно совпадать с передаваемой строкой (а там прописана версия, которая может поменяться, сейчас уже Автодилер 6.1 вроде).
5. Если не получится, могу удаленно подключиться - посмотреть, вроде везде работало, где использовал. И в Вин7, и в ВинХР, и в Вин2к, и на ВинСерверах, версии ВинСерверов точно не помню.

7. Марина Гинко (_qqq) 18.09.13 11:04
(6) Спасибо, Николай, что ответили. Пытаемся делать, как Вы пишете:
1. Окно Автодилера открыли.
2. Извините, что не понятно написали, но %%ЗАДЕРЖКА%% пропала в статье после WScript.Sleep.
4. Заголовок проверили, он действительно другой, исправили.
5. Так было бы, конечно, Вам сподручнее, чем со слов. Но не думаю, что наши админы на это согласятся.

В результате окно Автодилера не открылось, но его кнопка на панели задач помигала.
Опять появилось сообщение, что открыть окно не удалось.

Не могли бы Вы, Николай, показать результат, что должно в Автодилере открыться.
А то тот скрин, который в заголовке публикации в увеличенном виде никак не посмотреть.
8. Николай Гусев (GusevNA) 18.09.13 11:38
(7) _qqq, В файле видео, как у меня это работает (Вин7). На картинке открывается агрегат, а активной становится деталь с указанным кодом.

Еще Вы можете мне отправить vbs-скрипт, который генерится 1С-ом. Лучше всего записанный файл, но можно и текст переменной из отладчика.

Попробуйте еще после хШелл.Run (...) поставить точку останова, на ней подождать секунд 5 и посмотреть, как поведет себя Автодилер.
Прикрепленные файлы:
autodealer_video_001.avi
9. Марина Гинко (_qqq) 18.09.13 12:24
(8) Николай, вот текст скрипта:
Set WshShell = CreateObject("WScript.Shell")
WScript.Sleep 5000
Res = WshShell.AppActivate("-= Система ""АвтоДилер"" 6.0 (редакция 2) =-")
If Not Res Then WScript.Echo "Открыть окно не удалось"

А с точкой останова еще не попробовали, работа. Будем посмотреть попозже.

За видео спасибо, будем стремиться к идеалу. У нас ВинХР.
10. Марина Гинко (_qqq) 19.09.13 11:09
(8) Николай, поставили точки останова
1. хАД.GetDetailByUID (СокрЛП (ИДДетали));
2. хШелл.Run (...)
после выполнения хАД.GetDetailByUID (СокрЛП (ИДДетали)); кнопка Автодилера на панели задач помигала.
после выполнения хШелл.Run (...) появилось сообщение "Открыть окно не удалось".
Окно Автодилера не открылось и деталь не нашлась

Пробовали еще без поиска детали (GetDetailByUID), кнопка не мигает, а остальное также.
:(
Как быть, Николай, может подскажите?
11. Николай Гусев (GusevNA) 19.09.13 11:30
(10) _qqq, Исходя из того, что у меня и на ВинХР и на Вин7 все это работает, можно предположить, что у Вас стоит какое-то программное обеспечение, которое мешает открыться окну. Подозрение, конечно, сразу падает на вирусы и антивирусы. Если у Вас есть возможность где-то попробовать на чистой ВинХР или Вин7, лучше всего это сделать, посмотреть результат и отписаться.
12. Марина Гинко (_qqq) 19.09.13 12:05
(11) Николай, если сократить заголовок окна до "-=" ;)
то окно Автодилера открывается, УРА!
Значит заголовок у нас был все-таки дефектный.

Но деталь не находится, увы.
Наверное тоже параметр не верный передается в GetDetailByUID...
13. Николай Гусев (GusevNA) 19.09.13 12:44
(12) _qqq,

Поздравляю ! Можно работать дальше.

1. Пояснение: окно открывается, потому что AppActivate получает в качестве параметра НАЧАЛО строки заголовка. Имейте ввиду, что если у другого окна заголовок будет начинаться с "-=", то может открыться оно, поэтому лучше написать строчку подлиннее, например, "-= Система".
Также советую обратить внимание на Вашу строчку скрипта:
Res = WshShell.AppActivate("-= Система ""АвтоДилер"" 6.0 (редакция 2) =-")
У Вас ""Автодилер"" - 2 кавычки, а нужно 4 - """"АвтоДилер"""", 2 для 1С и 2 для VBScript. Насчет кавычек - некоторые CMS их решут, поэтому лучше код писать не текстом, а придагать в файле - там точно все сохранится.

2. GetDetailByUID - это метод ActiveX, который устанавливает Автодилер. Его описание можно почитать в файле "Справочная система", в разделе "OLE Automation. Связь с другими программами".

3. Чтобы открылась нужная деталь, необходимо передать именно "Идентификатор детали". Обычно идентификаторы деталей загружаются в 1С специальной обработкой и выглядят примерно так "386#4752164#4674". Тогда все нормально открывается.

4. В упомянутом разделе "OLE Automation. Связь с другими программами" есть и другие методы для поиска деталей. Можно попробовать их. Там, кстати, есть пример использования ActiveX для 1С.

5. В моей обработке при открытии детали ActiveX создается каждый раз. Это не совсем правильно - у меня версия Автодилера 6.1 при такой работе начинает глючить, когда открываешь детали несколько раз. ActiveX Автодилера нужно создавать 1 раз и хранить в переменной, тогда ActiveX работает корректно. Я уже доработал свой код и чуть попозже выложу обработку.
14. Марина Гинко (_qqq) 19.09.13 13:19
Все сработало с правильным ИД детали.
Спасибо за помошь, Николай!
Нравится мне, как Вы все по пунктам расписываете :)) как Фандорин.
15. Николай Гусев (GusevNA) 19.09.13 15:08
(14) _qqq, Спасибо за комплимент :-)
Порядок в мыслях - порядок в делах :-)
16. Александр Полтава (Патриот) 08.10.14 10:44
(0) +
извиняюсь за оффтоп, но вы точно должны знать. Можно сделать так, чтобы "WScript.Shell" после отработки метода "Run" что либо возвращал в 1С? Хотя бы значение типа булево или число или строку, пофиг. Пока есть черезодносметная идея писать данные в файл, потом читать их из 1С, но хотелось бы этого избежать. Если вдобавок кинете ссыль на какие-нибудь мануалы, буду благодарен. Идея такова - выполнить некий скрипт, а потом в 1С узнать о результате выполнения. Как вы поняли, с WScript я незнаком, так что не пинайте сильно.
17. Николай Гусев (GusevNA) 08.10.14 13:28
(16) Патриот, Я часто пользуюсь докой:
http://www.script-coding.com/WSH/WshShell.html

По поводу Run там сказано:
если WaitOnReturn (второй параметр) установлен в True, метод возвращает код выхода вызванного приложения. Иначе метод всегда возвращает ноль.

У WshShell еще есть более интересный метод - Exec.

Кстати, может еще пригодиться: есть такая вещь - скриплеты, это такие скрипты на VBS, JS, которые работают как ActiveX. Соответственно, туда можно передавать и получать практически все COM-типы.
Вот по ним статья:
http://citforum.ru/internet/common/scriplet1.shtml
Для написания сообщения необходимо авторизоваться
Прикрепить файл
Дополнительные параметры ответа