26

Re: CMD/BAT + VBScript: два в одном

Главное — помещайте .

27 (изменено: Dragokas, 2014-02-01 23:01:01)

Re: CMD/BAT + VBScript: два в одном

Просто мысли по доработке идеи от greg zakharov-а (BAT -> JScript -> VBScript).

+ обработка ошибок
+ VBScript в исходном виде, удобном для отладки

- нет передачи аргументов
- громоздкость кода
- запуск от имени 32-разрядного сервера сценариев

@set @x=0 /*
  @echo off & set "x="
  Set "xOS=x64"& If "%PROCESSOR_ARCHITECTURE%"=="x86" If Not Defined PROCESSOR_ARCHITEW6432 Set "xOS=x32"
  if "%xOS%"=="x64" (set "engine=%windir%\syswow64\cscript.exe") else (set "engine=cscript.exe")
  "%engine%" //nologo //e:jscript "%~f0" & goto :eof

' Ваш код VBScript
Randomize
For i = 1 to 5
  n = n & vbLf & int(Rnd*50)
Next
WScript.Echo (n)
' Сгенерируем ошибку
n = 1 \ 0

*/
var ofso = new ActiveXObject("Scripting.FileSystemObject");
var oTS = ofso.OpenTextFile(WScript.ScriptFullName, 1, false);
for (i = 0; i < 5; i++) {oTS.SkipLine()}; var code = '', s = '';
do
{
  code += s + "\n";
}
while ((s = oTS.ReadLine()).slice(0,2) != '*/');

var vb  = new ActiveXObject("MSScriptControl.ScriptControl");
vb.language = "VBScript";
vb.addobject('WScript', WScript, true);
try { vb.addcode(code); } catch (e) {}
var e = vb.Error; 
if (e.Number != 0) WScript.Echo('('+(e.Line+4) + ','+e.Column + ') Error '+e.Number+': '+e.Description);

Объект "MSScriptControl.ScriptControl" можно создать только из 32-разрядного процесса.

28 (изменено: Rumata, 2014-02-02 07:00:56)

Re: CMD/BAT + VBScript: два в одном

Ага. А я-то думал, что в 64-битных системах ScriptControl уже не доступен. Надо просто использовать 32-битную версию скрипт-хоста.

На самом деле коллега greg zakharov показал в какую сторону смотреть. Если уж допиливать эту реализацию, то лучше уйти от точных значений количества строк пролога. А в случае ошибок (синтаксических или времени выполнения) точно указывать на строку в файле. Можно сделать так:


@if (true == false) @end /*
@echo off

set "SYSDIR=SysWOW64"
if "%PROCESSOR_ARCHITECTURE%" == "x86" if not defined PROCESSOR_ARCHITEW6432 set "SYSDIR=System32"

"%WINDIR%\%SYSDIR%\cscript.exe" //nologo //e:javascript "%~f0" %*

goto :EOF

*/

(function(readFile, code)
{
    var e;
    try {
        var vb = new ActiveXObject('MSScriptControl.ScriptControl');
        vb.Language = 'VBScript';
        vb.AddObject('WScript', WScript, true);
        vb.AddCode(code);
    } catch(e) {
        var file = readFile();
        var prologLen = file.slice(0, file.indexOf(code)).split('\n').length;
        var vbe = vb.Error;
        WScript.Echo(
            WScript.ScriptFullName + 
            '(' + ( prologLen + vbe.Line - 1 ) + ', ' + vbe.Column + ') ' + 
            vbe.Source + ': ' + vbe.Description);
    }
})(
function()
{
    var fso = new ActiveXObject('Scripting.FileSystemObject');
    var f = fso.OpenTextFile(WScript.ScriptFullName, 1, true);
    var file = f.ReadAll();
    f.Close();
    return file;
}, 
(function()
{
    return arguments.callee.toString().replace(/^[\s\S]+\/\*|\*\/[\s\S]+$/g, '');
/*

WScript.Echo "Hello, world!"
WScript.Quit 1000

*/
})());

Небольшое пояснение.
Основная функция исполняет vbs-код, переданный в code. В случае ошибки (синтаксической или времени выполнения) считывается весь файл с помощью readFile и вычисляется количество строк, предшествующих vbs-коду, для правильной идентификации строки, вызвавшей ошибку.

Положительных моментов два:
1. размер "пролога" не задан жестко - он вычисляется на ходу
2. для вычисления размера пролога считывается исходный файл только в случае возникновения ошибки

Другие положительные моменты:
1. vbs-код встроен таки в bat-файл
2. Допустим любой правильный vbs-код
3. код работает, понимает аргументы командной строки, читает/пишет из/в стандартные потоки и возвращает код возврата

По пункту 2 есть одно исключение. vbs-код НЕ ДОЛЖЕН содержать последовательность символов */ в любом виде (в строках или комментариях). Если требуется такая комбинация, то рекомендуется использовать следующее решение:

S = "*" & "/"
( 2 * b ) || ! ( 2 * b )

29

Re: CMD/BAT + VBScript: два в одном

Rumata пишет:

2. для вычисления размера пролога считывается исходный файл только в случае возникновения ошибки

А при возникновении ошибки исходный файл может уже не существовать или быть совсем другим (хотя, конечно, зачем в этом случае знать место ошибки).

+ Попроще
@if (true == false) @end /*
@echo off

set "SYSDIR=SysWOW64"
if "%PROCESSOR_ARCHITECTURE%" == "x86" if not defined PROCESSOR_ARCHITEW6432 set "SYSDIR=System32"

"%WINDIR%\%SYSDIR%\cscript.exe" //nologo //e:javascript "%~f0" %*

goto :EOF

*/

var prologLen = 0;
var vb = new ActiveXObject('MSScriptControl.ScriptControl');
vb.Language = 'VBScript';
vb.AddObject('WScript', WScript, true);
try {
    vb.AddCode(
(function () {
var fso = new ActiveXObject("Scripting.FileSystemObject");
var f = fso.OpenTextFile(WScript.ScriptFullName, 1, false);
do prologLen++; while (f.ReadLine() != "/* VBScript");
var code = f.ReadAll();
f.Close();
return code;
})()
    );
} catch (e) {
    var vbe = vb.Error;
    WScript.StdErr.WriteLine(
        WScript.ScriptFullName + 
        '(' + ( prologLen + vbe.Line ) + ', ' + vbe.Column + ') ' + 
        vbe.Source + ': ' + vbe.Description);
}
/* VBScript

WScript.Echo "Hello, world!"
WScript.Quit 1000

'*/

Пролог считывается построчно, vbs-код — целиком.
В памяти не остаётся переменных JScript кроме vb и prologLen, — code возаращается анонимной функцией.

30 (изменено: Rumata, 2014-02-03 11:54:23)

Re: CMD/BAT + VBScript: два в одном

Попроще варианты я тоже рассматривал - с разным расположением vbs-кода относительно js-кода. Я остановился на этом варианте именно чтобы исключить любые вспомогательные глобальные js-переменные. Хотя это проблем не вызывает - vbs не имеет к ним доступа.

В памяти не остаётся переменных JScript кроме vb и prologLen

Там есть еще одна переменная - e.

Мне кажется, идея использовать фиксированные строки-маркеры (например /* VBScript, как в Вашем случае) хорошая, но не вполне удобная.
js-функция, которая возвращает содержимое своего комментария мне видится лучше - маркеры уже заданы (js-комментарии) и автоматически обработаны самим js-интерпретатором. Мы с JSman обсуждали реализацию такой функции и ее эффективность - JS: Хранение ресурсов в файле JS. К сожалению ссылка уже не существует.

при возникновении ошибки исходный файл может уже не существовать или быть совсем другим

Мысль здравая. Для указания на источник ошибки (номер строки в исходном, неизмененном файле) необхоимо заранее считывать весь файл.

( 2 * b ) || ! ( 2 * b )

31

Re: CMD/BAT + VBScript: два в одном

Rumata пишет:

Я остановился на этом варианте именно чтобы исключить любые вспомогательные глобальные js-переменные. Хотя это проблем не вызывает - vbs не имеет к ним доступа.

Конечно, это проблем вызвать не может, поэтому не существенно. Просто ко времени исполнения vbs хотелось бы не оставлять в памяти js-переменные, которые далее не будут востребованы (глобальные или локальные — не имеет значения) или без которых можно попробовать обойтись.

32 (изменено: Rumata, 2014-04-21 14:43:01)

Re: CMD/BAT + VBScript: два в одном

Буржуи поведали шикарный код http://www.dostips.com/forum/viewtopic. … 882#p33882.


::'@echo off
::'cscript //nologo //e:vbscript "%~f0" %*
::'exit /b

WScript.Echo "Hello, world!"

Фишка:
После каждого символа апострофа стоит невидимый символ SUB (ASCII 26, 1A)

Как это работает
cmd/bat
:: начинаются обычные cmd-комментарии, внутри которых присутствует символ SUB.
SUB интерпретируется как разрыв строки, что значит, что выражение следом будет выполнено.

vbs
: - разделитель команд (x = 0 : y = 0). Не имеет значения если они написаны в начале строки.
Апостороф ' начинает vbs-комментарий. Следующий символ SUB является частью комментария и не влияет ни на что.

( 2 * b ) || ! ( 2 * b )

33 (изменено: wisgest, 2015-06-03 15:33:07)

Re: CMD/BAT + VBScript: два в одном

Rumata пишет:

После каждого символа апострофа стоит невидимый символ SUB

Можно ограничиться только одним непечатным знаком в первой строке, переписав остальные в виде

rem:& команда

(без пробелов между «rem» и «:»).

Мне, впрочем, «Option Explicit» милее полного подавления отображения команд пакетного файла, поэтому вернусь к решению http://forum.script-coding.com/viewtopi … 346#p79346:

wisgest пишет:

Option Explicit должен быть первым оператором — даже пустые операторы перед ним не допускаются, но возможны комментарии:

': 2>nul&CScript.exe /nologo /e:vbs "%~f0" %*&exit /b

— сказанное относится и к комментариям, созданным с помощью ключевого слова REM, поэтому можно обойтись без попыток обращения к несуществующему файлу/диску и подавления сообщения об ошибке:

rem:& @echo off
rem:& setlocal enableextensions disabledelayedexpansion
rem:& CScript.exe -nologo -i -t:0 -e:vbs" %~f0" %*
rem:& endlocal& exit /b

Option Explicit
Dim str
str = "Hello, world!"
WScript.Echo str

— заметим, что часть первой строки после «@» не отображается и на выход попадает только (с точностью до %PROMPT%):

C:\Documents and Settings\user\Рабочий стол>rem: &

(можно после этого «rem:» вставить какую-нибудь приличествующую случаю поучительную или пояснительную надпись, например, «VBScript in "%~nx0"»).

Ну и, конечно, не следует забывать о команде CLS. Но она поможет только при запуске из Проводника или другого файлового приказчика, а как быть с перенаправлением вывода?
Не знаю, как у вас, а у меня перенаправление вывода в загадочный для меня поток с дескриптором &3, в отличии от дескрипторов с большими значениями, приводит без дополнительных действий к выводу в окно консоли также как для &1 (stdout) и &2 (stderr).
Поэтому, в отсутствие перенаправления строка

rem:& CScript.exe -nologo -i -t:0 -e:vbs" %~f0" %*>&3

работает по прежнему, а при перенаправлении лишнее легко убрать:

vbs.bat 1>nul 3>log.txt
(vbs.bat 1>nul) 3>&1| more