Получение ответа от wsh-скрипта

В моем приложении HTA есть некоторые действия, которые выполняют некоторые трудоемкие задачи на сервере. Например, действие использует старый компонент ActiveX для чтения некоторых свойств файла (таких как Тема и Комментарии) файлов в определенной папке (от 0 до ~200 файлов в папке).

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

Чтобы приложение работало быстрее во время поиска файловых свойств, я передал код на аутсорсинг задания wsh. Результаты сохраняются в файле, существование которого соблюдается через интервал (5 секунд). Тем не менее, некоторые пользователи по-прежнему наблюдают заметное замедление работы приложения, даже при опросе существования файла с указанным интервалом в 5 секунд.

Теперь я хотел знать, есть ли событие или какой-то другой внутренний механизм, который я мог бы использовать, чтобы определить, когда скрипт wsh выполнил свою работу? И если возможно, то даже, возможно, есть способ отправить результаты непосредственно из задания wsh в HTA, вообще не используя промежуточный временной файл?

Вот некоторый упрощенный код для фактической задачи, выполняемой в файле wsh и приложении HTA. HTA имеет HTML5 DTD и работает в пограничном режиме с использованием IE11. ui — это служебная библиотека, мы надеемся, что упомянутые имена свойств достаточно точно описывают использование.

ВСФ:

<package>
<job id = "getFileProps">
<script language = "JScript">
    (function () {
        var topRoot = WScript.Arguments(0),                           // The starting folder <String>
            fso = WScript.CreateObject('Scripting.FileSystemObject'), // Filesystem object <ActiveXObject>
            fileProps = readProps(topRoot),                           // Fileprops, the result <Array>
            file;                                                     // The result file to read in HTA <FileObject>

        function readProps (root) {
            var fileProperties = [];
            // A bunch of code reading the fileproperties on a disk
            return fileProperties;
        }

        file = fso.openTextFile(topRoot + '\\$fileprops$.txt', 2, true);
        file.Write(fileProps.join(',');
        file.Close();
        WScript.Quit();
    )());
</script>
</job>
</package>

ЗАО «РИПТ»:

ui.winShell.Exec('WScript //Job:getFileProps ' + '"' + ui.appRoot + '"');
function fpCheck () {
        var file, fileProps;
        try {
                file = ui.fileIO.OpenTextFile('$fileprops$.txt', 1, false);
        } catch (err) {
                file && file.Close();
                setTimeout(fpCheck, 5000);
                return;
        }
        // Write the fileprops to the view
}

Если кого-то интересует средство чтения свойств файла, его имя DSOFile.OleDocumentProperties. Он происходит где-то в архивах глубокого интернета, но я не могу вспомнить, откуда я его загрузил.

Пользователи жалуются на медлительность из-за того, что файл данных находится на удаленном ресурсе? Если да, то почему бы вместо удаленного файла данных не опросить файл local, который будет изначально создан заданием WSH и удален после завершения процесса? Я уверен, что это будет довольно быстро.

Kul-Tigin 14.12.2020 18:51

@Kul-Tigin Да, файл результата сохраняется в удаленной папке, но только для части пользователей (на самом деле я не сообразил проверить, используют ли жалобщики общую копию с сервера или собственную локальную копию). Звучит разумно, чтобы создать его как локальный, я обязательно попробую. Спасибо за предложение.

Teemu 14.12.2020 18:53

Бах... Некоторые пользователи переустановили старую версию. Но все же я хотел бы знать, есть ли способ получить сообщение от wsh, когда он выполнил свою работу, или передать список свойств напрямую в HTA без использования файла.

Teemu 15.12.2020 13:39
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
2
3
253
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Будет ли ваш сценарий поддерживать использование объекта словаря или списка массивов для хранения только имени файла и последнего обновления, а также для извлечения полного набора свойств (во второй список) для новых или измененных файлов (и удалений). Думаю, зависит от того, как часто файлы приходят и уходят или обновляются. Это может быть быстрее, чем создание всего набора данных свойств файла, если большая часть деталей не меняется между опросами.

Это пользовательский файловый браузер с деревом папок и списком файлов. Список файлов показывает только имя файла и тему. Имена файлов извлекаются и отображаются быстро, но работа DSOFile.OleDocumentProperties несколько медленная, и поэтому она вызывается асинхронно после отображения имен файлов. Опрос полученного файла, по-видимому, по какой-то причине замедляет работу приложения для некоторых пользователей, возможно, у Кул-Тигина есть точка на нем (хотя я еще не проверял).

Teemu 15.12.2020 07:15
Ответ принят как подходящий

В конце концов, вам нужна межпроцессная связь.

Ни HTA, ни WSH не предлагают ничего встроенного для IPC.

Итак, я собираюсь поделиться хакерским решением, которое я редко использую.

Хитрость заключается в использовании общего объекта на двух концах, как в сценарии клиент-сервер.

Мы собираемся использовать объект Internet Explorer в качестве сервера IPC, мы будем использовать методы GetProperty и PutProperty.

Поскольку окна Internet Explorer можно перечислить с помощью метода объектов оболочки Windows(), можно получить доступ к объекту, созданному в HTA, из другого приложения.

Изучите и создайте следующие два файла, затем запустите test.hta и нажмите кнопку Start WSF.

test.hta:

<!DOCTYPE html>
<html lang = "en">
    <head>
        <meta charset = "UTF-8">
        <meta name = "viewport" content = "width=device-width, initial-scale=1.0">
        <meta http-equiv = "X-UA-Compatible" content = "IE=Edge">
        <title>IPC</title>
        <script>
            sharedObject = {
                sendData: function(data){
                    // blocking here is not a good idea 
                    // so we process the data within another callback
                    // leaving the method as soon as possible
                    var receivedData = data;
                    setTimeout(function(){alert("Data received: " + receivedData)}, 50);
                }
            };
            
            shareName = "ipcShare";
            serverId = createIPCServer(shareName);
            
            function createIPCServer(shareName){
                var ie = new ActiveXObject("InternetExplorer.Application");
                ie.PutProperty(shareName, sharedObject);
                window.onbeforeunload = function(){ ie.Quit(); };                
                return ie.HWND; // window handle
            }
            
            function starWSFJob() {
                alert("please wait about 5 seconds...");
                var wshShell = new ActiveXObject("Wscript.Shell");
                wshShell.Run('wscript.exe test.wsf //Job:TestIPC /serverId:"' + serverId + '" /shareName:"' + shareName + '"');
            }
        </script>
    </head>
    <body>
        <button onclick = "starWSFJob()">Start WSF</button>
    </body>
</html>

test.wsf:

<package>
    <job id = "TestIPC">
        <script language = "JScript">
            function getSharedObject(serverId, shareName){
                var shellApp = new ActiveXObject("Shell.Application");
                var windows = new Enumerator(shellApp.Windows());
                for (;!windows.atEnd();windows.moveNext()){
                    var window = windows.item();
                    if (window.HWND == serverId) {
                        return window.GetProperty(shareName);
                    }
                }
            }
            
            function App() {
                var serverId = Number(WScript.Arguments.Named("serverId"));
                var shareName = WScript.Arguments.Named("shareName");
                var sharedObject = getSharedObject(serverId, shareName);
                if (!sharedObject){
                    WScript.Echo("shared object not found.");
                    return 1;
                }
                
                // simulate long running job
                WScript.Sleep(5000);
                
                // send data
                sharedObject.sendData("Hello from WSF Job!");
                
                return 0;
            }

            WScript.Quit(App());
        </script>
    </job>
</package>

Ух ты! Вы действительно работали над этим. Может быть, это немного сложно, но это то, о чем я просил. Я проверю это завтра и отмечу ваш ответ, если ничего более простого не произойдет. Я использовал экземпляр IE для применения ES5 в сценарии WSH, но я никогда не думал, что его можно использовать и таким образом.

Teemu 15.12.2020 21:31

@Teemu Ничто не просто, когда дело доходит до IPC :) Но вы можете убедиться, что это одна из самых простых реализаций IPC, которые вы можете сделать в Windows. Потому что за кулисами выполняются ужасные внепроцессные операции маршалинга COM, и нам не нужно иметь дело ни с одной из них, и это благословение.

Kul-Tigin 15.12.2020 21:41

Истинный. На самом деле я не мог заставить ваш скрипт работать на меня (поскольку WScript.Sleep нельзя использовать в HTA), и я выбрал немного другой подход, чтобы ускорить чтение свойства. Но ваш фрагмент дал мне массу идей, которые я могу использовать в некоторых других задачах, большое спасибо за фрагмент.

Teemu 16.12.2020 12:31

@Teemu Мой плохой. Никогда не попадал в эту строку в своих тестах, видимо, мой компьютер был достаточно быстрым. Вызов Navigate и цикл даже не понадобились, поэтому я их удалил.

Kul-Tigin 16.12.2020 13:10

Поскольку я не мог запустить экземпляр IE (пока), как вы думаете, можно ли запустить задачу с этим экземпляром IE без WSH? Я предполагаю, что я мог бы передать даже живой объект в качестве аргументов скрипту в экземпляре IE, и скрипт решал бы некоторые задачи, используя даже прямые ссылки на объекты JS в HTA?

Teemu 16.12.2020 13:18

@ Teemu Я бы сказал да, но модели безопасности Internet Explorer похожи на минное поле, поэтому я бы точно придерживался WSH. Возможность прямой ссылки на объекты HTA также применяется в WSH в зависимости от того, какой объект вы используете совместно.

Kul-Tigin 16.12.2020 13:26

Другие вопросы по теме