1

Тема: HTA: аналог DoEvents (обновление информации из работающего скрипта)

Я в последнее время разбирался с возможностью вывода информации на форму HTA из работающего скрипта и, в итоге, обнаружил интересную особенность у метода .Run объекта 'WScript.Shell'. Когда из HTA через Run запускается с ожиданием какой-нибудь процесс, на форме HTA обновляется информация и работают (с некоторыми ограничениями) элементы управления. Соответственно, чтобы информация на форме обновлялась, нужно регулярно запускать через Run какой-нибудь процесс, который будет быстро закрываться.

Сразу приведу небольшой поясняющий пример:

<HTML> <META http-equiv="Content-Type" content="text/html; charset=windows-1251">
<META http-equiv="MSThemeCompatible" content="Yes">

<HEAD>
  <TITLE>wshSheel Run demo</TITLE>
  
  <HTA:APPLICATION      ID="oHTA"          APPLICATIONNAME="Demo" BORDER="thick"
    BORDERSTYLE="normal" CAPTION="yes"       CONTEXTMENU="no"     INNERBORDER="no"
    MAXIMIZEBUTTON="no" MINIMIZEBUTTON="yes" NAVIGABLE="no"       SCROLL="no"
    SCROLLFLAT="no"     SELECTION="yes"      SHOWINTASKBAR="yes"  SINGLEINSTANCE="no"
    SYSMENU="yes"       WINDOWSTATE="normal" VERSION="1.0" 
  >

</HEAD>

<BODY bgcolor="buttonface" onload="bodyOnLoad();">
строка1:<INPUT ID="txt1" type="text" size="30" value="str1">
&nbsp;&nbsp;
строка2:
<INPUT type="button" value="..." title="Можно выбрать каталог" onclick="chooseFolder( event );" style="font-weight: bold; ">
<INPUT ID="txt2" type="text" size="60" value="str 2">

<BR><BR>

<INPUT type="button" value="Запустить цикл" onclick="startD();">
&nbsp;
<INPUT type="button" value="Остановить цикл" onclick="stopD();">
&nbsp;
<INPUT type="button" value="Кнопка 1" onclick="but( 1 );">
&nbsp;
<INPUT type="button" value="Кнопка 2" onclick="but( 2 );">
&nbsp;
<INPUT type="button" value="Кнопка 3" onclick="but( 3 );">
<BR>
<INPUT ID="chkUnload" type="checkbox"> Не показывать запрос при закрытии
<BR>
I = <SPAN ID='spanCounter'></SPAN>
<BR>
<TEXTAREA ID="taOut" cols="100" rows="28"></TEXTAREA>

</BODY>
</HTML>

<SCRIPT language="JavaScript"><!--

function bodyOnLoad(){
  window.moveTo( 50, 50 );
  window.resizeTo( 900 , 600 );

  window.onbeforeunload = beforeUnload;

  out( 'Запуск Demo' );
  out( '' );
}

function beforeUnload(){
  if( chkUnload.checked ){
    stopD();
  }else{
    if( runFlag ){
      return 'Цикл ещё запущен. Нажмите "Отмена" и остановите выполнение цикла, иначе приложение останется в памяти.';
    }
  }
}



var runFlag;

function stopD(){
  runFlag = false;
}

function startD(){

  var wshShell = new ActiveXObject( 'WScript.Shell' );

  out( 'Цикл запущен' );
  out( '' );

  runFlag = true;
  
  for( var i = 0 ; runFlag ; ++i ){
    out( 'i = ' + i + '  строка1: ' + txt1.value + '     строка2: ' + txt2.value );
    spanCounter.innerText = i;
    wshShell.Run( 'ping 127.255.255.255 -n 1 -w 2000' , 0 , true );
  }
  out( '' );
  out( 'Цикл остановлен' );
  out( '' );
}

function but( num ){
  out( 'Нажата кнопка ' + num );
}

function out( Str ){
  taOut.value = (new Date()).toLocaleString() + ':  ' + Str + '\n' + taOut.value;
}

function chooseFolder( event ){
  var objFolder = (new ActiveXObject( 'Shell.Application' )).BrowseForFolder( 0 , 'Выберите папку' , 0x50 , 17 );
  if( objFolder !== null ){
    txt2.value = objFolder.Items().Item().Path;
  }
}

// --></SCRIPT>

В этом примере при нажатии кнопки "Запустить цикл" запустится цикл, в котором вызывается Shell.Run и обновляется информация на форме. Идея примера в том, что можно запустить цикл, понажимать на кнопки, ввести что-нибудь в текстовые поля и посмотреть на то, как это отразится на форме.

Я попробовал несколько разных вариантов вызова метода Run, и проверил несколько ОС -Win Xp, Server 2003, Win 7, Server 2008 R2.

На текущий момент выяснил следующее:
1. Регулярный вызов .Run( ‘ping /?’ , 0 , true ) обновляет форму на всех 4 ОС, которые я проверял.
2. При таком варианте обновления формы не работает переход между элементами управления по TAB, хотя информация в текстовые поля вводится и нажатия на кнопки мышью отслеживаются.
3. Когда скрипт запущен нажатием на кнопку – повторное нажатие на эту-же кнопку не срабатывает.
4. Если закрыть приложение не завершив цикл с doEvents, процесс mshta.exe останется в памяти, даже если повесить свой обработчик на onbeforeunload и останавливать цикл из обработчика. В этом случае вызовы Shell.Run прекращаются, но mshta всё равно остаётся в памяти.
5. В Win7 и Server 2008 R2 форма так-же обновляется при выполнении следующей команды: try{ wshShell.Run( '/' , 0 , false ) }catch( e ){}; . При использовании этого варианта, если закрыть приложение с запущенным скриптом и из обработчика onbeforeunload установится флаг прекращения работы – скрипт останавливается и процесс mshta.exe выгружается из памяти.

Пока, как результат этих опытов, я написал вариант объекта для обновления формы (приведён ниже). Объект создаётся конструктором DoEventsFunc, конструктор возвращает объект-функцию, которую нужно вызывать, когда необходимо обновление формы и реакция на элементы управления. Конструктору может быть передано 2 параметра - минимальный промежуток между вызовами wshShell.Run и режим работы – быстрый ( с wshShell.Run( '/' , … ) ) или обычный. Если режим работы не указан – он выбирается исходя из версии ОС.
Так же у объекта есть два метода - .set( aDelay)  - изменяет промежуток между вызовами Run во время работы и .isFast() - позволяет узнать режим работы (быстрый / обычный).

/*
   DoEventsFunc - объект для обновления информации в окне приложения.

   Исходно в HTA информация на странице не обновляется, пока не закончится 
   выполнение работающего кода. Данный объект позволяет из работающего скрипта
   обновить информацию на странице и произвести реакцию на возможные события
   (нажатие кнопок, перемещение окна). Работа объекта основана на том, что
   при запуске из HTA приложений через метод Run объекта 'WScript.Shell'
   обновляется информация на форме HTA и запускается цикл обработки событий.

   бработать за счёт того, что вся страница перерисовывается в случае, если,
   даже программно, скролится какой-либо элемент. 
   Для работы объекта на странице должен быть размещён DIV, HTML код которого
   приведён в комметарии внутри тела объекта, а ссылка на этот DIV должна быть 
   передана либо при создании объекта, либо позже, вызовом функции Set
   пример:   RefreshForm.Set( document.getElementById( 'pRefresh') );

   Конструктору DoEventsFunc может быть передано 2 параметра:

   aDelay - минимальный промежуток между вызовами wshShell.Run(), чтобы
            вызовы не происходили слишком часто. По умолчанию - 100 мс.

   fastRun - выбор режима работы.
   fastRun = false - обычный режим, более медленный и с особенностями, которые 
                     могут привести к тому, что процесс mshta.exe останется в 
                     память, но работающий на всех опробованных ОС.
   fastRun = true - быстрый режим, меньше грузит систему, mshta.exe в памяти 
                    не остаётся, но пока работает только на Win7 и Server 2008 R2.
   Если fastRun не указан или undefined - режим выбирается исходя из версии ОС

   У объекта есть кроме непосредственного вызова есть два метода:
   .set(aDelay)  - устанавливает задержку.
   .isFast() - позволяет узнать режим работы.

//*/

function DoEventsFunc( aDelay , fastRun ){

  var wshShell = new ActiveXObject( 'WScript.Shell' );
  var delay = 100 , lastDate = 0 ;// задержка по умолчанию, мс.

  var runStr , runWait , fastMode; // Параметры вызова wshShell.Run.
  var fastOS = false;

  try{ //определяем версию ОС.
    if( new Enumerator( 
              GetObject( 'winmgmts:')
                .ExecQuery( 'Select * from Win32_OperatingSystem' ) 
        
        ).item().Version.match( /^6\.1/ )
      ){
      fastOS = true;
    }
  }catch( e ){
  }

  // Выбираем режим работы.
  if( ( typeof fastRun === 'undefined' && fastOS ) || fastRun ){
    runStr = '/'; // настройки быстрого режима.
    runWait = false;
    fastMode = true;
  }else{
    runStr = 'ping.exe /?'; // настройки для обычного режима.
    runWait = true;
    fastMode = false;
  }

// RetFunc - функция, которая вернётся как результат вызова функции, создающей
// объект и которая будет вызывать обновление формы.
  var retFunc = function(){ 
    var t = new Date();
    if( t - lastDate > delay ){
      lastDate = t;
      try{ wshShell.Run( runStr , 0 , runWait ) }catch( e ){};
    }
  }; 

// функция Set - изменение задержки между вызовами.
  retFunc.set = function( aDelay ){ delay = parseInt( aDelay , 10 ); };
// функция isFast - получение режима работы.
  retFunc.isFast = function(){ return fastMode; };

  if( typeof aDelay !== 'undefined' ) retFunc.set( aDelay );

  return retFunc;
};

Пример использования объекта – приложение для поиск файлов, заданных маской - регулярным выражением по дереву каталогов. В этом примере объект doEvents создаётся в функции-обработчике события onload – bodyOnLoad, вызывается в функции outStatus(). Также нужно посмотреть функцию – обработчик события onbeforeunload - beforeUnloadFunc().

<!--
    Поиск файлов в дереве каталогов с использованием регулярного выражения.

    Пример использования эмулятора DoEvents.
    

    Copyright (C) 2013 Valery Chernysh (spy00000@gmail.com)

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
-->

<HTML> <META http-equiv="Content-Type" content="text/html; charset=windows-1251">
<META http-equiv="MSThemeCompatible" content="Yes">

<HEAD>
  <TITLE>DoEvents Example</TITLE>
  
  <HTA:APPLICATION      ID="oHTA"          APPLICATIONNAME="Exam" BORDER="thick"
    BORDERSTYLE="normal" CAPTION="yes"       CONTEXTMENU="no"     INNERBORDER="no"
    MAXIMIZEBUTTON="no" MINIMIZEBUTTON="yes" NAVIGABLE="no"       SCROLL="no"
    SCROLLFLAT="no"     SELECTION="yes"      SHOWINTASKBAR="yes"  SINGLEINSTANCE="no"
    SYSMENU="yes"       WINDOWSTATE="normal" VERSION="1.0" 
  >

  <STYLE type="text/css">
    .Tab  {height:100%; width:100%; background-color: #000000; font-family: Courier New; border:1px solid black;}
    .Tab2 {height:100%; width:100%; background-color: buttonface;}
    TD    {background-color: buttonface; color: buttontext; font-weight: bold; }
    INPUT {font-weight: bold; }

    .Status {background-color: #C0C0FF;  font-weight: bold; }

    .logSpan {width:100%; font-family: Courier New;} 
    .logOk   {background-color: #C0FFC0;} 
    .logErr  {background-color: #FFC0C0;} 
    .logWarn {background-color: #FFFFC0;}  
    .logLog  {background-color: #C0C0FF;}

  </STYLE>

</HEAD>

<BODY bgcolor="buttonface" onload="bodyOnLoad()">
<TABLE class="Tab">
  <TR>
    <TD>Шаблон:<INPUT ID="txtRE" type="text" size="20" value=".*\.txt$" title="шаблон для поиска"></TD>
    <TD style="width:100%;">
    <TABLE class="Tab2">
      <TR>
        <TD style="width:10px;">Каталог:</TD>
        <TD style="width:10px;">
          <INPUT type="button" value="..." title="Выбрать каталог" onclick="chooseFolder( event )">
        </TD>
        <TD style="width:100%;">
          <INPUT ID="txtFolder" type="text" style="width:100%">
        </TD>
      </TR>
    </TABLE>
  </TD></TR>
  <TR>
    <TD style="padding: 5px;">
      <INPUT type="button" value="    Начать поиск    " onclick="startSearch()">
      <BR>
      <INPUT type="button" value="Прекратить поиск" onclick="stopSearch()">
    </TD>
    <TD style="height:10px; width:100%;"  class="Status">
      <DIV ID="divStatus" class="Status" style="width:100%;">Выберите каталог</DIV>
    </TD>
  </TR>
  <TR><TD style="height:100%; width:100%;" colspan="2">
    <DIV ID='divLog' style="overflow:auto; width: 100%; height: 100%;"></DIV>
  </TD></TR>
</TABLE>
</BODY>
</HTML>

<SCRIPT language="JavaScript"><!--

// Функция представлющая данные об ошибке в виде строки
Error.prototype.toStr = function( delim ){
  return 'N='+this.number.toString(16)+'('+(this.number & 0xFFFF)+')'
             +((typeof(delim)==='undefined')?' ':delim)+'D='+this.description;
}


// Глобальные переменные 
// FSO , sysShell - стандартные объекты для работы
// log - объект для вывода информации на экран.
// doEvents - объект для демонстрации работы котрого и написан этот пример.
// stopSearchFlag - флаг, показывающий, что поиск нужно прекратить.
var FSO , sysShell , log , doEvents , stopSearchFlag = true;

function bodyOnLoad(){

  try{

    //Стандартные объекты для работы скрипта
    FSO = new ActiveXObject( 'Scripting.FileSystemObject' );
    sysShell = new ActiveXObject( 'Shell.Application' );

//  Создаём объект для вывода информации на экран и передаём ссылку на DIV который 
//    будет отображать информацию.
    log = LogFunc( divLog );

//  Объект для обновления информации из работающего скрипта.
    doEvents = DoEventsFunc();
//    doEvents = DoEventsFunc( 100 , true );

//  устанавливаем обработчик проверки закрытия приложения при работающем поиске.
    window.onbeforeunload = beforeUnloadFunc;

  }catch( e ){ 
  // В случае ошибки выводим информацию об ошибке на экран в виде простого сообщения
  // в дальнейшем информацию об ошибке можно будет выводить в файл и в список
    alert( 'Ошибка при инициализации программы.\n\n' + e.toStr('\n') );
    window.close();
    return;
  }

  log( '' );
  log( '-----------------------' );
  log( 'Запуск' );
}

// Функция, для реакции на закрытие приложения при работающем поиске. 
// В быстром режиме поиск просто останавливается, в обычном режиме - 
// HTA передаётся строка которая будет показана пользователю.
function beforeUnloadFunc(){
  if( ! stopSearchFlag ){
    if( doEvents.isFast() ){
      stopSearch();
    }else{
      return '!!! Поиск файлов не остановлен !!!\nПожалуйста нажмите кнопку "Отмена" и потом нажмите "Прекратить поиск", иначе приложение останется в памяти.';
    }
  }
  return;
}

// функция остановки поиска - устанавливается флаг, что поиск нужно прекратить.
function stopSearch(){
  stopSearchFlag = true;
}

// startSearch - основная функция поиска.
// проверяем началый каталог и шаблон, затем запускаем рекурсивный поиск.
function startSearch(){

  if( txtFolder.value == '' ){
    alert( outStatus( 'Не выбран каталог' ) );
    return;
  }

  try{
    var folder = FSO.GetFolder( txtFolder.value );
  }catch( e ){
    log( 2 , 'Ошибка при доступе к каталогу "' + txtFolder.value + '".\n' + e.toStr('\n') );
    return;
  }

  try{
    var RE = (new RegExp()).compile( txtRE.value , 'i' );
  }catch( e ){
    log( 2 , 'Шаблон поиска составлен неверно.\n' + e.toStr('\n') );
    return;
  }

  log( 0 , '' );
  log( 0
     , 'Поиск по шаблону "' + txtRE.value 
       + '" начиная с каталога "' + txtFolder.value + '"' 
     );
  log( 0 , '' );

  stopSearchFlag = false;
  if( req( folder ) ){
    log( 1 , '' );
    log( 1 , outStatus( 'Поиск прекращён' ) );
  }else{
    log( 0 , '' );
    log( 0 , outStatus( 'Поиск закончен' ) );
  }

  
  function req( folder ){ // рекурсивная функция поиска файлов по маске

    if( stopSearchFlag ){ // если нужно прекращать поиск - сразу выходим
      return true;
    }

    outStatus( folder.Path );

    var fc , i = 1;
    for( fc = new Enumerator( folder.Files ) ; ! fc.atEnd() ; fc.moveNext() , ++i ){
      if( fc.item().Name.match( RE ) ){
        log( fc.item().Path );
      }
      if( i % 100 === 0 ){
        if( stopSearchFlag ){ 
          return true;
        }
        outStatus( folder.Path + ' - ' + i + ' файлов');
      }
    }

    for( fc = new Enumerator( folder.SubFolders ) ; ! fc.atEnd() ; fc.moveNext() ){
      if( fc.item().Name.match( RE ) ){
        log( fc.item().Path );
      }

      try{
        if( req( fc.item() ) )
          return true;
      }catch( e ){
        log( 1 
           , 'Ошибка при доступе к каталогу "' + fc.item().Path + '".\n' 
             + e.toStr('\n') 
           );
      }
    }
    return false;
//*/
  }
}


// chooseFolder( event ) - показ диалога выбора каталога
function chooseFolder( event ){
  var objFolder = sysShell.BrowseForFolder( 0 
                                          , 'Выберите папку для поиска файлов' 
                                          , 0x50 
                                          , 17 
                                          );
  if( objFolder != null ){
    txtFolder.value = objFolder.Items().Item().Path;
  }
}



// outStatus( Str ) - вывод информации в строку статуса и обновление формы
function outStatus( Str ){
  divStatus.innerText = Str;
  doEvents();
  return Str;
}
//  outStatus( log( 'Синхронизация начата') );



/*
   DoEventsFunc - объект для обновления информации в окне приложения.

   Исходно в HTA информация на странице не обновляется, пока не закончится 
   выполнение работающего кода. Данный объект позволяет из работающего скрипта
   обновить информацию на странице и произвести реакцию на возможные события
   (нажатие кнопок, перемещение окна). Работа объекта основана на том, что
   при запуске из HTA приложений через метод Run объекта 'WScript.Shell'
   обновляется информация на форме HTA и запускается цикл обработки событий.

   бработать за счёт того, что вся страница перерисовывается в случае, если,
   даже программно, скролится какой-либо элемент. 
   Для работы объекта на странице должен быть размещён DIV, HTML код которого
   приведён в комметарии внутри тела объекта, а ссылка на этот DIV должна быть 
   передана либо при создании объекта, либо позже, вызовом функции Set
   пример:   RefreshForm.Set( document.getElementById( 'pRefresh') );

   Конструктору DoEventsFunc может быть передано 2 параметра:

   aDelay - минимальный промежуток между вызовами wshShell.Run(), чтобы
            вызовы не происходили слишком часто. По умолчанию - 100 мс.

   fastRun - выбор режима работы.
   fastRun = false - обычный режим, более медленный и с особенностями, которые 
                     могут привести к тому, что процесс mshta.exe останется в 
                     память, но работающий на всех опробованных ОС.
   fastRun = true - быстрый режим, меньше грузит систему, mshta.exe в памяти 
                    не остаётся, но пока работает только на Win7 и Server 2008 R2.
   Если fastRun не указан или undefined - режим выбирается исходя из версии ОС

   У объекта есть кроме непосредственного вызова есть два метода:
   .set(aDelay)  - устанавливает задержку.
   .isFast() - позволяет узнать режим работы.

//*/

function DoEventsFunc( aDelay , fastRun ){

  var wshShell = new ActiveXObject( 'WScript.Shell' );
  var delay = 100 , lastDate = 0 ;// задержка по умолчанию, мс.

  var runStr , runWait , fastMode; // Параметры вызова wshShell.Run.
  var fastOS = false;

  try{ //определяем версию ОС.
    if( new Enumerator( 
              GetObject( 'winmgmts:')
                .ExecQuery( 'Select * from Win32_OperatingSystem' ) 
        
        ).item().Version.match( /^6\.1/ )
      ){
      fastOS = true;
    }
  }catch( e ){
  }

  // Выбираем режим работы.
  if( ( typeof fastRun === 'undefined' && fastOS ) || fastRun ){
    runStr = '/'; // настройки быстрого режима.
    runWait = false;
    fastMode = true;
  }else{
    runStr = 'ping.exe /?'; // настройки для обычного режима.
    runWait = true;
    fastMode = false;
  }

// RetFunc - функция, которая вернётся как результат вызова функции, создающей
// объект и которая будет вызывать обновление формы.
  var retFunc = function(){ 
    var t = new Date();
    if( t - lastDate > delay ){
      lastDate = t;
      try{ wshShell.Run( runStr , 0 , runWait ) }catch( e ){};
    }
  }; 

// функция Set - изменение задержки между вызовами.
  retFunc.set = function( aDelay ){ delay = parseInt( aDelay , 10 ); };
// функция isFast - получение режима работы.
  retFunc.isFast = function(){ return fastMode; };

  if( typeof aDelay !== 'undefined' ) retFunc.set( aDelay );

  return retFunc;
};


//
// Объект Log - вывод логов.
//
function LogFunc( aDivLog ){ 

// divLog - ссылка на DIV для вывода информации на экран;
  var divLog;
  
// RetFunc - функция, которая вернётся как результат вызова функции, создающей
// объект и которая будет "логгировать" информацию.
  var retFunc = function ( type, str ){

    var curDate , span // переменные для временного хранения информации
// если второй параметр не передан, то первый параметр - информация для вывода в лог
    if( typeof str === 'undefined' ){ 
      str = type;
      type = 0;
    }

    if( type != 3 ){
      curDate = (new Date()).toLocaleString() + ': ';
    }else{
      curDate = '';
    }

    if( divLog ){
// выводим информацию на экран в DIV.
      try{
        span = document.createElement( 'SPAN' );
        span.className = 'logSpan ';

        switch( type ){
          case  1: span.className += 'logWarn'; break;
          case  2: span.className += 'logErr';  break;
          case  3: span.className += 'logLog';  break;
          default: span.className += 'logOk'
        }

        var needScroll = divLog.scrollTop + divLog.clientHeight >= divLog.scrollHeight - 30;

        span.innerText = curDate + str;
        divLog.appendChild( span );
        divLog.appendChild( document.createElement( 'BR' ) );

        if( needScroll )
          span.scrollIntoView( false );

      }catch( e ){
        alert( 'Ошибка при добавлении информации в Лог.\n\n' + e.toStr( '\n' ) );
      }
    }

    return str;
  };

// функция Set - запоминание ссылки на DIV.
  retFunc.set = function ( aDivLog ){ 
    divLog = aDivLog;
  };

  if( typeof aDivLog !== 'undefined' ) retFunc.set( aDivLog );

  return retFunc;
};


// --></SCRIPT>

Если есть какие-то замечания или идеи – пишите. Особенно интересуют идеи – как сделать, чтобы на XP/2003 mshta.exe выгружалось из памяти, при закрытии приложения с работающим скриптом.

И ещё просьба – если есть возможность проверить работу обновления формы на Vista , Win 8 , Server 2008 , Server 2012, попробуйте запустить последний скрипт на этих ОС с обновлением в быстром режиме. Чтобы сделать это, надо в функции bodyOnLoad раскомментировать  строку
//    doEvents = DoEventsFunc( 100 , true );
и запустить HTA.

2 (изменено: Rom5, 2013-10-07 17:46:23)

Re: HTA: аналог DoEvents (обновление информации из работающего скрипта)

Spy00000 пишет:

[...]
И ещё просьба – если есть возможность проверить работу обновления формы на Vista , Win 8 , Server 2008 , Server 2012, попробуйте запустить последний скрипт на этих ОС с обновлением в быстром режиме. Чтобы сделать это, надо в функции bodyOnLoad раскомментировать  строку
//    doEvents = DoEventsFunc( 100 , true );
и запустить HTA.

На системе Server 2008 R2 Satndart проверка обновления формы Вашего скрипта - успешна.



Идея старта команды типа

shell.run('ping /?',0,true)

для "форсирования" прорисовки окна hta при работе длинной процедуры мне очень пригодилась - не надо разрывать работу на части через вызов settimeout().

Идея, IMHO, достойна коллекции.

WBR. Roman

3

Re: HTA: аналог DoEvents (обновление информации из работающего скрипта)

Доброго времени суток господа. Позволю себе вмешаться и добавить свои "5 копеек". Тоже сталкивался с подобной задачей, но решил её для себя иначе. Возможно и Вам подойдёт такой вариант.

Создал класс модуль clsTimeout с методом Wait и Clear.
Весь принцип строится на методе WaitForResponse  объекта Msxml2.ServerXMLHTTP
Метод Wait() Позволяет передать управление внешнему коду на выполнение необходимых задач. Имеет входной параметр seconds - На сколько секунд передать управление внешнему коду. Добавил его, чтобы в некоторых случаях не загружать процессор на 100% при работе (Обычный DoEvents к сожалению грузит проц полностью, ну ли то ядро на котором процесс крутится). Так что это некий аналог Sleep-а.

На случай обычной эмуляции DoEvents можно задать Timeout.Wait(0)

Метод Clear добавил на случай ожидания событий. К примеру длительного запроса. На этот случай поступаю так:


'Ждать 10 секунд
Timeout.Wait 10

Sub SomeObject_Event()
    Timeout.Clear()
End Sub

Таким образом дождавшись события можно дальше продолжить выполнять код.

Ниже пример с класс модулем.


<html>
    <head>
    <style>
    *{font-family:Tahoma;}
    </style>
    </head>
    <body>
        <script language="vbscript">
        
        Dim Timeout
        Set Timeout = New clsTimeout
        
        Sub window_onload()
            For i=1 to 10000
                Timeout.Wait(0)
                document.body.innerText = i
            Next
        End Sub
        
        Class clsTimeout
            Private ServerXMLHTTP
            
            Private Sub Class_Initialize()
                Set ServerXMLHTTP = CreateObject("Msxml2.ServerXMLHTTP")
            End Sub
            
            Sub Wait(seconds)
                With ServerXMLHTTP
                    .Abort
                    .Open "HEAD", "http://1.0.0.1", True
                    .Send
                    .WaitForResponse seconds
                End With
            End Sub
            
            Sub Clear()
                ServerXMLHTTP.Abort
            End Sub
        End Class
        </script>
    </body>
</html>

Либо в самом грубом и некрасивом исполнении, на мой взгляд, можно сделать так


Sub DoEvents()
    With CreateObject("Msxml2.ServerXMLHTTP")
        .Abort
        .Open "HEAD", "http://1.0.0.1", True
        .Send
        .WaitForResponse 0
    End With
End Sub
Передумал переделывать мир. Пашет и так, ну и ладно. Сделаю лучше свой !

4

Re: HTA: аналог DoEvents (обновление информации из работающего скрипта)

Хоть тема и старая, но добавлю свой метод, "тупой до нелепости":

function UpdateElement(elem)
{
    // style.left > 0
    elem.focus()
    window.scrollTo(1, 0);
    window.scrollTo(0, 0);
}

Скроллы для маленьких элементов выполняются очень быстро (на относительно быстрой машине) поэтому моргание почти незаметно. Можно попробовать скроллить div, но вроде этот метод не вызывал прорисовку, уже не помню... Вроде для данного случая elem.style.left должен был быть больше нуля, - тоже уже не помню...