1 (изменено: lifeflame, 2020-10-31 00:50:14)

Тема: HTA & JScript: Extended Drop Target - Юникод-приемник файлов и папок

Вот мы и подошли вплотную к интерфейсной составляющей HTML приложения "Resource Extractor".

Речь пойдет о встроенной поддержке drag and drop (перетаскивания и бросания) файлов и папок в окно HTA.

Вступление. Что сейчас известно о drag and drop в HTA.

+ открыть спойлер

Стоит отметить, что в HTA с поддержкой функциональности drag and drop для файлов и папок в окно, на первый взгляд, все выглядит достаточно безнадежно - по крайней мере таких примеров мне встретить не удалось.

Уточню еще раз, что ни о каком HTML5 говорить здесь не приходится, а о сторонних ActiveX объектах Windows ничего не знает: их нужно устанавливать и регистрировать, что выходит за рамки данной темы.

Чаще всего предлагается, как после манипуляций с реестром можно добиться, чтобы HTML приложение принимало на вход файлы и папки, брошенные на его значок.
Аналогичным образом работают скрипты с хостами WScript и CScript.
Неприятности такого подхода - стороннее вмешательство, либо изменение системных настроек напрямую, отсутствие UI для данной операции, тогда как задумка HTA уходит в интерактивность посредством пользовательского интерфейса, и в довершение WScript и CScript, как мне удалось убедиться, не поддерживают пути после drag and drop на Юникоде.

Удавалось также встречать экперименты drag and drop на textarea, но там все ограничивается текстовыми файлами.

Дальше в лес - больше дров. Проблемы Web Browser, JScript и VBScript.

+ открыть спойлер

Единственный известный мне встроенный в любую версию Windows, начиная с XP (возможно и 2000), ActiveX объект с поддержкой drag and drop файлов и папок это Web Browser.

Есть у Web Browser такое интересное свойство как "RegisterAsDropTarget" - оно-то и позволяет превратить его в приемник файлов и папок.
А дальше сталкиваемся с тем, что, во-первых, Web Browser дает обратную связь с собой только через свои события, а во-вторых, обработка этих событий находится под большим вопросом.

Казалось бы, отменить событие "BeforeNavigate2" и взять с него путь брошенного на приемник файла или папки - вот и вся задача. Но не тут-то было.

VBScript умеет ловить события и отменять их для runtime-объекта, но беспомощен для объекта, представленного в виде HTML-ноды, так как не предоставляет в этом случае корректных методов для обработки событий.
JScript умеет ловить события для объекта, представленного в виде HTML-ноды, но не может отменять их в силу ограничения на передачу объектов по ссылке.

Ко всему прочему, даже поймать событие "BeforeNavigate2" в Windows XP можно только для runtime-объекта и причем на VBScript, тогда как JScript его не увидит.
Анализ приводит к описаниям схожих проблем с "BeforeNavigate2" в Windows XP от Microsoft:

h t t p://support.microsoft.com/kb/311298/EN-US/ или h t t p://c-bit.net/kb/311298/EN-US/
и
h t t p://support.microsoft.com/kb/325079/EN-US/ или h t t p://c-bit.net/kb/325079/EN-US/

В описаниях перечислены другие платформы, но и желающих отправить отчет по HTA на эту тему, как представляется, было в то время немного. Таким образом, проблема c событием "BeforeNavigate2" в Windows XP осталась и в Service Pack 3.

Стоит отметить, что событие "BeforeNavigate2" уже ловится на VBScript и JScript как для runtime-объекта, так и для объекта, представленного в виде HTML-ноды, в Windows 7 и 10, что значительно позволяет сократить код по сравнению с обходом данной проблемы.

Глубокое исследование показало, что все эти проблемы можно обойти.

Создание компонента drag and drop.

Проблемы удалось обойти за счет жесткой переинициализации Web Browser с предшествующим ей разрушением объекта.
При этом стоит отметить, что от разрушенного Web Browser, по всей видимости, остаются потоки в памяти, которые временно блокируют изменение обработанных им файлов сторонними программами до завершения скрипта.
Но это ложка дегтя в бочке меда, так как drag and drop файлов и папок в окно HTA да и еще с поддержкой путей на Юникоде оказывается возможным встроенными средствами.

Дальше мне пришлось столкнуться с анализом череды большого количества событий Web Browser, которые отличаются и количеством, и структурой, и временем появления, и порядком их возникновения на разных версиях Windows.
Тем не менее, я поставил себе цель обеспечить поддержку drag and drop файлов и папок в окно HTA для Windows XP.

Глубокое исследование позволило совместить всю эту цепь событий в единое целое.
В результате получился компонент "Extended Drop Target", поддерживающий drag and drop файлов и папок в окно HTA как для Windows XP, так и для Windows 7 и 10 (поддержка других версий ожидается, но не тестировалась).

Данная работа представляет собой расширенную, доработанную и настраиваемую под пользователя версию, представленную в виде уединенного компонента, возвращаемого функцией "createDropTarget", который можно поместить в любое место дерева DOM определенного окна с передачей на вход всех настроек в виде стилей, сообщений, функций обработки данных и ошибок.

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

Со всеми возможностями можно ознакомиться подробнее ниже.

Скриптовый пример имеет следующие специальные возможности:

+ открыть спойлер
  • не требует установки какого-либо стороннего программного обеспечения и поддерживает любую версию Windows, начиная с XP (возможно и 2000) с определенными ActiveX объектами, не запрещенными по умолчанию;

  • полностью написан на JScript в файле скриптового формата HTA и использует следующие ActiveX объекты: WScript.Shell, Scriptlet.TypeLib, WbemScripting.SWbemLocator, Shell.Application и Shell.Explorer.2, также известный как Microsoft Web Browser;

  • тестировался и адаптирован для Windows XP, Windows 7 и Windows 10;

  • не пишет каких-либо записей в реестр и не сохраняет каких-либо персональных данных на вашем жестком диске;

  • не выходит в сеть каким-либо способом;

  • поддерживает функциональность drag and drop для папок и файлов;

  • работает с именами входящих файлов на любой локали (поддержка символов Юникода в именах);

  • работает как с 32-битными, так и с 64-битными путями папок;

  • реализован как автономный компонент, который может быть вставлен в дерево DOM для определенного окна;

  • имеет множество возможностей, которые можно настроить, включая стили, принятием соответствующих входных параметров;

  • поддерживает показ дополнительного пользовательского описания продукта;

  • отправляет результаты в соответствующую функцию на входе;

  • разрешает неизвестные и пользовательские ошибки, передавая их в соответствующую функцию на входе;

  • имеет встроенную скрытую обработку ошибок в случае, если какой-либо метод устранения ошибок все еще недоступен;

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

  • поддерживает перенаправление drag and drop сообщений;

  • разделяет с основным скриптом функцию timeToHMSR для преобразования даты в представление в виде часов, минут, секунд и остатка (миллисекунд);

  • не требует какой-либо вложенной структуры для 64-битной части скрипта (новый код может быть просто добавлен в конец);

  • получает все необходимые паузы и фокусы для того, чтобы приложение оставалось поверх других окон при старте;

  • получает собственный PID, который может быть использован вновь позже;

  • не требует никаких системных путей или деклараций, которые могут отсутствовать в некоторых версиях Windows (например, "SysNative" неизвестен для Windows XP 32 bit).

Скриптовый пример демонстрирует:

  • как скрыть HTA во время его динамического создания;

  • как запустить HTA в виде 64-битного процесса без использования системных путей или деклараций;

  • как получить скрытую остановку скрипта в HTA;

  • как поддерживать функциональность drag and drop для файлов и папок в HTA;

  • как бороться с подтвержденной проблемой "BeforeNavigate2" для Web Browser в Windows XP;

  • как решить подтвержденные проблемы с немедленным вызовом <moveTo> или <resizeTo> при старте в Windows XP

  • и как передать и использовать переменные среды для процесса, созданного с помощью WMI.

Работа с исходным кодом.

  1. Для запуска скриптового примера скопируйте его исходный код и сохраните его в текстовом файле, сменив его расширение на "hta".

  2. Запуск скриптового примера осуществляется двойным нажатием, как и в случае с обычной программой.

Рекомендую использовать AkelPad для просмотра сохраненного исходного кода примера с правильными отступами.

Вы можете использовать скриптовый пример на свое усмотрение, но, пожалуйста, оставьте комментарий с прямой ссылкой на tastyscriptsforfree.wix.com/page/scripts в этом случае.

<script>
/*
Extended Drop Target v1.1.2 (h t t p s://tastyscriptsforfree.wix.com/page/scripts)
Copyright 2017-2020 Vladimir Samarets. All rights reserved.
tastyscriptsforfree@protonmail.com

Release date: October 30, 2020.


Use this script sample entirely at your own risk.
This script sample is copyrighted freeware and I am not responsible for any damage or data loss it could unintentionally cause.
You may modify it but please leave a comment with direct link to https://tastyscriptsforfree.wix.com/page/scripts in that case.


*******
The purpose of this script sample:
the script sample is intendent to maintain drag and drop functionality for files and folders in HTA with support of 64 and 32 bit folder paths and Unicode file names.

*******
The script sample has the following special features:

it requires no third party software installation and supports any Windows version since XP with certain ActiveX objects not restricted by default;
it is entirely written in JScript in HTA scripting file format and uses the following ActiveX objects: WScript.Shell, Scriptlet.TypeLib, WbemScripting.SWbemLocator, Shell.Application
    and Shell.Explorer.2 also known as Microsoft Web Browser;
it was tested and adapted for Windows XP, Windows 7 and Windows 10;
it writes no registry values and stores no personal settings on your hard disk;
it doesn't access network in any way;
it supports drag and drop functionality for files and folders;
it works for input files named in any locale (Unicode names support);
it works both for 64 and 32 bit folder paths;
it is implemented as self-contained component that could be inserted into DOM tree for certain window;
it has many features that could be customized including styles by accepting corresponding input parameters;
it supports showing an additional custom product description;
it passes its results to corresponding input function;
it resolves unknown and custom errors by passing them into corresponding input function;
it has built-in silent catching of errors if certain error resolving method is still inaccessible;
it could be easily translated to other languages by accepting input block of messages;
it supports redirecting of drag and drop messages;
it shares with the main script "timeToHMSR" function for converting date to hours, minutes, seconds and remainder (milliseconds) notation;
it requires no nested structure for 64 bit instance scripting (new code can be simply added to the end);
it obtains all necessary pauses and focuses in order for the application to stay on top of other windows during its start;
it obtains the application PID which can be reused later;
it requires no system paths or declarations which could be absent in some versions of Windows (for example, "SysNative" is unknown for Windows XP 32 bit).

*******
The script sample demonstrates:

how to hide HTA while having it dynamically created;
how to launch HTA as 64 bit without using system paths or declarations;
how to obtain hidden stop for script in HTA;
how to maintain drag and drop functionality for files and folders in HTA;
how to deal with confirmed "BeforeNavigate2" issue of Web Browser in Windows XP;
how to deal with confirmed immediate "moveTo" or "resizeTo" issues at application start in Windows XP
and how to pass and use environment variables for process created by WMI.

*******
The script sample has the following current limitations:

maximum file size for processing based on Windows 7 and Windows 10 limitations is 3.99 GB (4,293,918,718 bytes);
all successfully processed files are treated as in use under any circumstances until the script is closed;
it is possible to set some image as a background for Web Browser but it is not currently supported because it ruins Extended Drop Target functionality;
a third party error is shown in Windows 7 and Windows 10 for dropped HTML files if they have errors in their scripts with "async" property;
an excessive Web Browser error is shown in case the folder path is valid no more.

*******
Basic documentation and articles I used:

'VBScript Scripting Techniques: Environment Variables' by Rob van der Woude
    (h t t p s://w w w.robvanderwoude.com/vbstech_data_environment.php);
'Using Win32_ProcessStartup to change environment' post by Rico Rosenlund
    (h t t p s://microsoft.public.scripting.wsh.narkive.com/hW1GURnH/using-win32-processstartup-to-change-environment);

'WSH: exchanging data and objects between scripts - 2' by Xameleon (March, 2011) in Russian
    (h t t p://forum.script-coding.com/viewtopic.php?id=5573);

'VBScript Scripting Techniques: HTAs' by Rob van der Woude
    (h t t p s://w w w.robvanderwoude.com/vbstech_hta.php);

'InternetExplorer and WebBrowser objects' by Ludogovskiy Aleksander in Russian
    (h t t p s://script-coding.com/WSH/WebBrowser.html);

'Windows Script 5.6 Documentation' (script56.chm) by Microsoft Corporation
    (h t t p s://w w w.microsoft.com/en-us/download/confirmation.aspx?id=2764);
'MSDN' related documentation by Microsoft Corporation
    (h t t p s://docs.microsoft.com/en-us/);

Windows XP BeforeNavigate2 issue:
'BUG: The BeforeNavigate2 event of the WebBrowser control does not fire if hosted in a Visual Basic .NET 2002 application'
on c-bit.net and support.microsoft.com (September 14, 2005)
    (h t t p://c-bit.net/kb/311298/EN-US/, h t t p://support.microsoft.com/kb/311298/EN-US/);
'BUG: The BeforeNavigate2 Event of WebBrowser Control Does Not Fire If Hosted in a Visual C# .NET Application'
on c-bit.net and support.microsoft.com (June 25, 2004)
    (h t t p://c-bit.net/kb/325079/EN-US/, h t t p://support.microsoft.com/kb/325079/EN-US/);

Windows XP moveTo and resizeTo issues:
'"Access is denied" by executing .hta file with JScript on Windows XP x64' discussion on stackoverflow.com (January 21, 2009)
    (h t t p s://stackoverflow.com/questions/464679/access-is-denied-by-executing-hta-file-with-jscript-on-windows-xp-x64);
'Something strange with HTAs' discussion on social.technet.microsoft.com (September 19, 2011)
    (h t t p s://social.technet.microsoft.com/Forums/officeocs/en-US/92bf1e76-ebd5-4462-bd52-533e69305a5c/something-strange-with-htas?forum=ITCG).

*******
Basic software I used:

AkelPad 4.9.8 by Aleksander Shengalts and Alexey Kuznetsov (as development environment)
    (h t t p://akelpad.sourceforge.net/en/download.php);
OLE/COM Object Viewer v2.10.059 (oleview.exe) by Charlie Kindel, Michael Nelson, and Michael Antonio (for documentation purposes).
*/

offscreenBuffering = true;                                                                                       //postpone the application window appearance till its UI is ready
var O = function(o){return new ActiveXObject(o);},
WSS = O('WScript.Shell'),
env = WSS.Environment('Process'),
head = document.documentElement.firstChild,                                                      //head
PID;                                                                                                                         //PID of 64 bit HTA instance

if(!env('is64bit'))                                                                                                      //indicates whether the application is launched as 64 bit or not
{
    !function hide(e){try{moveTo(10000, 10000);}catch(e){try{hide();}catch(e){hide();}}}();                                  //hiding the application window
    head.insertBefore(document.createElement('<hta:application showInTaskBar=0>'), head.firstChild);        //hiding the application in the Taskbar

    var WMI=                                                                                                            //a small library written by me for obtaining WMI instance, its common methods and properties
    {                                                                                                                           //below is a sample of creating a process with certain window shifts and environment variables
                                                                                                                                //and obtaining its <ProcessId> by using WMI
        SWL:new ActiveXObject('WbemScripting.SWbemLocator'),
        PRMS:function(p)
        {
            var s = WMI.PS.SpawnInstance_();
            for(var i in p)
                s[i] = p[i];
            return s;
        },
        Create:function(c, s, d)
        {
            var CreateIn = WMI.CreateIn.SpawnInstance_();
            CreateIn.CommandLine = c;
            CreateIn.ProcessStartupInformation = s;
            CreateIn.CurrentDirectory = d;
            return WMI.PRC.ExecMethod_('Create', CreateIn).ProcessId;
        }
    };
    WMI.PRC = (WMI.WM = WMI.SWL.ConnectServer('.', 'root/cimv2')).Get('Win32_Process');
    WMI.PS = WMI.WM.Get('Win32_ProcessStartup');
    WMI.CreateIn = WMI.PRC.Methods_('Create').InParameters;

    var ID = O('Scriptlet.TypeLib').GUID.substr(0, 38),                                             //the unique ID obtaining
    EV = 'is64bit='+ID;                                                                                              //passing the unique ID to 64 bit HTA instance as an Environment variable
    for(var items = new Enumerator(env); !items.atEnd(); items.moveNext())
        EV += '?' + items.item();                                                                                  //obtaining all Environment variables for current process

    PID = WMI.Create                                                                                               //obtaining PID of 64 bit HTA instance
        (
            'mshta "' + decodeURIComponent(location.pathname) + '"',                     //current path
            WMI.PRMS
            (
                {
                    X:10000, Y:10000,                                                                              //hiding the application window before it is shown in order to resize it smoothly
                    EnvironmentVariables:
                        EV.split('?')                                                                                      //obtaining an array of all Environment variables by using this approach is universal for different
                                                                                                                                //versions of Windows
                        /*
                        [                                                                                                       //another way to pass certain Environment variables
                            'is64bit='+ID,                                                                              //indicates that the application is launched as 64 bit
                            'SystemRoot='+env('SystemRoot'),                                           //for start
                            'SystemDrive='+env('SystemDrive'),                                         //for hyperlinks
                            'TEMP='+env('TEMP'),                                                                //for "mailto" links
                            'CommonProgramW6432='+env('CommonProgramW6432')     //for ADODB.Stream
                        ]
                        */
                }
            )
        );

    head.firstChild.insertAdjacentHTML('afterEnd', '<object id=' + ID + ' PID=' + PID +
        ' classid=clsid:8856F961-340A-11D0-A96B-00C04FD705A2><param name=RegisterAsBrowser value=1>');      //registering current HTA window in collection of windows
    showModalDialog(0, 0, 'dialogWidth:0;unadorned:1;');                                     //stopping the script and obtaining window focus for "AppActivate"
}

var w,dt=new Date();
head.insertBefore(document.createElement('<hta:application contextMenu=no selection=no scroll=no>'), head.firstChild);      //adding custom HTA header dynamically
document.title='Extended Drop Target';
resizeTo(800, 400);
for(var ws = O('Shell.Application').Windows(), i = ws.Count; i -- > 0;)
    if((w = ws.Item(i)) && w.id == env('is64bit'))
    {
        PID = w.PID;
        w.document.Script.WSS.AppActivate(PID);                                                                                                                            //using "WScript.Shell" in focus to activate
                                                                                                                                                                                                          //the application window of 64 bit HTA instance;
                                                                                                                                                                                                          //remember that "WScript.Shell" should be
                                                                                                                                                                                                          //in focus in order "AppActivate" to work properly
        break;
    }

document.write('<body>');                                                                                      //obtaining body
if(w && w.id == env('is64bit'))
    w.document.Script.close();                                                                                 //closing previous 32 bit HTA instance while being in safe focus

document.body.appendChild(document.createTextNode('Debug screen (for test purposes only):'));
document.body.appendChild(document.createElement('br'));
document.body.appendChild(document.createElement('<textarea id=result cols=85 rows=5>'));
document.body.appendChild(document.createElement('p'));
document.body.appendChild(document.createTextNode('Extended Drop Target:'));
document.body.appendChild(document.createElement('br'));

document.body.appendChild
(
    (
        function createDropTarget(doc, filesAllowed, foldersAllowed, dTStyle, hdFont, wMColor, dMColor, pMColor, eMColor, process, resolve, msg, dBgImage, bBgImage,
            description, redirect)
        {
            var dropTarget = doc.createElement('<span style="' + dTStyle + '">'),

            ms = dropTarget.appendChild
            (
                doc.createElement('<span style="width:100%;height:100%;padding:10px;overflow:hidden;">')
            ),                                                                                                                  //message screen that hides Web Browser during dropped items processing

            WB = '<object classid=clsid:8856F961-340A-11D0-A96B-00C04FD705A2 style="width:100%;height:100%;"><param name=Location value="about:<body bgColor=' +
                dMColor + ' style=\'width:100%;height:100%;position:absolute;margin:0px;border:0px;overflow:hidden;\'>' + (description || '') + '<script>var b=document.body;' +
                'b.ondragenter=b.ondragover=b.onmouseenter=b.onmouseover=b.onmousemove=function(){clearTimeout(b);b=setTimeout(\'location.reload();\',100);}<\/script>">',
            processing = 1,                                                                                           //indicates whether a dropped item processing is started or not
            processed = 1,                                                                                            //indicates whether a dropped item is processed or not
            DBcatched = 1,                                                                                            //indicates whether DownloadBegin Web Browser event has been catched or not
            allowed,                                                                                                       //indicates whether drop target is allowed or not
            allowedText = (filesAllowed ? foldersAllowed ? msg[32] : msg[33] : foldersAllowed ? msg[34] : ''),      //"Drop a file or folder here."
            WBTReset,                                                                                                  //timeout for Web Browser reset

            startProcessing = function(p)                                                                      //processing the item path received after item drop (item path)
            {
                clearTimeout(WBTReset);
                dropTarget.children[processed = 1].removeNode();
                createDropTarget();
                setTimeout(function()
                {
                    var delay = 0;
                    if(p)                                                                                                      //the item can be accessed
                    {
                        sM(msg[38] + p + '</div>', pMColor);                                              //show "Processing"
                        var dt = new Date(),                                                                         //date before processing
                        e;                                                                                                     //error ID
                        try{e = process(p);}catch(e){e = 43;}                                               //unknown error occured
                        dt = new Date() - dt;                                                                         //date after processing
                        delay += dt>1000 ? 0 : 1000 - dt;
                        if(!e)                                                                                                 //no errors occured
                            setTimeout(function(){sM(msg[39] + createDropTarget.timeToHMSR(dt) + ' =-</div>', pMColor);}, delay);       //show "Processed in"
                        else                                                                                                 //an error occured
                        {
                            var err;
                            try{resolve(e);}catch(err){;}
                            setTimeout(function(){sM(msg[39] + createDropTarget.timeToHMSR(dt) + ' =-</div><br>' + msg[e], eMColor);}, delay);      //show "Processed in" with error
                            if(!redirect)
                                delay += 1000;
                        }
                    }
                    else                                                                                                     //the item can't be accessed
                    {
                        sM(msg[40] + msg[41] + allowedText + msg[42], eMColor);          //show "The item is not a file or folder, can't be accessed or its size is too big."
                        delay += 1000;
                    }

                    sDM(delay + 1000);
                }, 1000);
            },

            setWBTReset = function(r)                                                                          //setting a timeout for Web Browser reset (reset)
            {
                if(!processing)
                {
                    processing = 1;
                    ms.style.display = '';
                    if(r)
                        WBTReset = setTimeout(startProcessing, 1000);
                }
            },

            DB = function()                                                                                            //catching "DownloadBegin" Web Browser event
            {
                DBcatched = 1;
                setWBTReset(1);
            },

            STC = function(p)                                                                                         //catching "StatusTextChange" Web Browser event (item path)
            {
                setWBTReset(p);
                if(!processed && /file:|</.test(p))
                {
                    if(/file:/.test(p))
                        startProcessing(filesAllowed ? decodeURIComponent(p).replace(/.+:((?:\/{3})|(?=\/{2}))(.+)...$/,'$2').replace(/\//g,'\\') : 0);
                    else if(/</.test(p))
                    {
                        if(!DBcatched)                                                                                  //indicates that drop target is leaved without drop
                        {
                            clearTimeout(WBTReset);
                            sM(msg[31] + allowedText + msg[35] + '</div>', dMColor, dBgImage);      //show "Drop a file or folder here."
                            allowed = 1;
                            ms.style.display = '';
                        }
                        else                                                                                                 //shortcuts with complex structure
                            startProcessing();
                    }
                }
            },

            NC2 = function(o, p)                                                                                     //catching "NavigateComplete2" Web Browser event (Web Browser object, item path)
            {
                if(!processed)
                    startProcessing(foldersAllowed && typeof p == 'string' && p.match(/^[^:]/) ? p : 0);
            },

            NE = function()                                                                                             //catching "NavigateError" Web Browser event
            {
                if(!processed)
                    startProcessing();
            },

            sM = function(m, c, bgImage)                                                                      //show message (message, background or text color, background image)
            {
                if(dBgImage || bBgImage)
                {
                    if(bgImage)
                        ms.style.backgroundImage = 'url(' + bgImage + ')';
                    ms.style.color = c;
                }
                else
                    ms.style.backgroundColor = c;
                m = '<div style="font:' + hdFont + ';">' + m;
                if(!redirect)
                    ms.innerHTML = m;
                else
                    redirect(m);
            },

            sDM = function(delay)                                                                                 //show default message (delay)
            {
                setTimeout(function(){allowed = 1;}, delay);
                setTimeout(function(){if(allowed)sM((allowedText ? msg[31] + allowedText + msg[35] : msg[36]) + '</div>', dMColor, dBgImage);}, delay + 100);     //show "Drop a file or folder
                                                                                                                                                                                                                                                             //here." or "Drop Target is
            }                                                                                                                                                                                                                                                //disabled."

            sM(msg[30], wMColor, dBgImage);                                                             //show welcome message

            ms.ondragenter=function()
            {
                if(allowed && (filesAllowed || foldersAllowed) && !event.dataTransfer.getData('text'))      //text dropping is not allowed
                {
                    event.dataTransfer.dropEffect='move';
                    return false;
                }
            }

            ms.ondragover = function()
            {
                if(allowed && (filesAllowed || foldersAllowed) && !event.dataTransfer.getData('text'))      //text dropping is not allowed
                {
                    event.dataTransfer.dropEffect='move';
                    if(!Math.abs(event.x - this.x) && !Math.abs(event.y - this.y))              //accepting only slow mouse motion
                    {
                        this.style.display = 'none';
                        DBcatched = allowed = processing = processed = 0;
                        sM(msg[37], dMColor, bBgImage);                                                 //show "Analysing..."
                    }
                    this.x = event.x;
                    this.y = event.y;
                    return false;
                }
            }

            !(createDropTarget = function()
            {
                dropTarget.insertAdjacentHTML('beforeEnd', WB);                                 //Web Browser reset is needed because its events can't be declined further in JavaScript,
                with(dropTarget.children[1])                                                                        //BeforeNavigate2 event has also a confirmed issue and can't be catched in Windows XP
                {                                                                                                                   //by default while VBScript provides no working methods to catch them for ActiveX objects
                    RegisterAsDropTarget = Silent = Offline = 1;                                         //represented as HTML nodes
                    attachEvent('DownloadBegin', DB);
                    attachEvent('StatusTextChange', STC);
                    attachEvent('NavigateComplete2', NC2);
                    attachEvent('NavigateError', NE);
                }
            })();

            createDropTarget.timeToHMSR = function(d)                                             //convert date to hours, minutes, seconds and remainder (milliseconds) notation (date)
            {
                var r = d % 3600000,
                h = d / 3600000 ^ 0,                                                                                 //hours
                m = r / 60000 ^ 0,                                                                                     //minutes
                s = r % 60000 / 1000 ^ 0;                                                                         //seconds
                r = d % 1000;                                                                                           //remainder (milliseconds)
                return ((h ? h + 'h' : '') + (m ? (h ? ' ' : '') + m + 'm' : '') + (s ? (h || m ? ' ' : '') + s + 's' : '') + (r ? (h || m || s ? ' ' : '') + r + 'ms' : '')) || '0ms';
            },

            sDM(3000);                                                                                                  //postponing Web Browser access while it generates its events at start

            return dropTarget;
        }
        (
            //BEGIN of Extended Drop Target custom settings

            document,                                                                                                   //"document" object of certain window
            1,                                                                                                                 //indicates whether processing of files is allowed or not
            1,                                                                                                                 //indicates whether processing of folders is allowed or not
            'width:350px;height:150px;border:2px blue solid;font:bold 10pt Arial;text-align:center;cursor:default;overflow:hidden;word-break:break-all;',       //drop target style
            'bold 12pt Tahoma',                                                                                    //message header font
            'yellow',                                                                                                       //welcome message background color if background image is not set or text color otherwise
            'mediumaquamarine',                                                                                 //default message background color if background image is not set or text color otherwise
            'limegreen',                                                                                                 //processing message background color if background image is not set or text color otherwise
            'salmon',                                                                                                     //error message background color if background image is not set or text color otherwise

            function(p)                                                                                                   //data processing sample (file or folder path)
            {
                alert('Here goes data processing sample.\n\nProcessing:\n' + p);
                //throw 1;                                                                                                 //unknown error occured
                //return 1;                                                                                                //certain error 1 occured
                //return 'error 2';                                                                                     //certain error 2 occured
                return 0;                                                                                                  //no errors
            },

            function(e)                                                                                                   //error resolving sample (error ID)
            {
                switch(e)
                {
                    case 1:
                        result.value = '\nCertain error 1 is catched.';                                  //additional action sample for certain error 1
                        updateData1();                                                                                //built-in silent catching of errors if certain error resolving method is still inaccessible
                        break;
                    case 'error 2':
                        result.value = '\nCertain error 2 is catched.';                                  //additional action sample for certain error 2
                        updateData2();                                                                                //built-in silent catching of errors if certain error esolving method is still inaccessible
                        break;
                    default:
                        result.value = '\nAn unknown error is catched.';                             //additional action sample for an unknown error
                        sendEmail();                                                                                    //built-in silent catching of errors if certain error resolving method is still inaccessible
                        break;
                }
                file.Close();                                                                                              //built-in silent catching of errors if certain error resolving method is still inaccessible
            },

            {                                                                                                                   //list of all messages for Extended Drop Target
                30: 'Welcome!</div><br>Hello World!',                                                 //welcome message
                31: 'Drop a ',                                                                                           //31, 32, 33, 34, 35 - "Drop a file or folder here."
                32: 'file or folder',
                33: 'file',
                34: 'folder',
                35: ' here.',
                36: 'Drop Target is disabled.',
                37: '-= Analysing... =-</div>',
                38: '-= Processing =-</div><br><div style="text-align:left;">',
                39: '-= Processed in ',
                40: "-= Can't be processed =-</div><br>",
                41: 'The item is not a ',                                                                           //41, 32, 33, 34, 42 - "The item is not a file or folder,<br>can't be accessed or its size is too big."
                42: ",<br>can't be accessed or its size is too big.",
                43: 'An unknown error occured.',                                                            //unknown error message
                1: 'Certain error 1 occured.',                                                                   //certain error 1 message
                'error 2': 'Certain error 2 occured.'                                                         //certain error 2 message
                                                                                                                                //certain error # message
                                                                                                                                //certain error # message
                                                                                                                                //certain error # message
                                                                                                                                //...
            }

            //,'C:\\Windows\\Web\\Screen\\img103.png'                                                 //default background image or "undefined" (optional)
            //,'C:\\Windows\\Web\\Screen\\img102.jpg'                                                  //busy mode background image or "undefined" (optional)

            //,'<div style=\'font:10pt Tahoma;padding:20px;\'>List of files supported by default:<ul><li>Bitmap Files (*.bmp;*.dib)<li>JPEG (*.jpg;*.jpeg;*.jpe;*.jfif)<li>GIF(*.gif)</ul></div>'
                                                                                                                                //description length depends on the message language or its actual bytes count or "undefined" (optional)

            //,function(m){result.value = m;}                                                                  //sample for receiving messages or "undefined" (optional)

            //END of Extended Drop Target custom settings
        )
    )
);

result.value = '\nLoading time for 64 bit instance (if possible): ' + createDropTarget.timeToHMSR(new Date() - dt) + '.';
moveTo(screen.availWidth / 2 - 400, screen.availHeight / 2 - 200);

/*
    some built-in in Windows 10 background samples:
    'C:\\Windows\\Web\\Screen\\img103.png'
    'C:\\Windows\\Web\\Screen\\img102.jpg'

    some built-in in Windows 7 background samples:
    'C:\\Windows\\Web\\Wallpaper\\Nature\\img3.jpg'
    'C:\\Windows\\Web\\Wallpaper\\Landscapes\\img10.jpg'

    some built-in in Windows XP background samples:
    'C:\\WINDOWS\\Zapotec.bmp'
    'C:\\WINDOWS\\Soap Bubbles.bmp'
*/

</script>

Перевод "Extended Drop Target" на русский язык и примеры настроек.

Все настройки "Extended Drop Target" находятся в разделе между "//BEGIN of Extended Drop Target custom settings" и "//END of Extended Drop Target custom settings".

Для перевода на русский язык замените блок английских сообщений на блок русских сообщений:


        {
            30: 'Добро пожаловать!</div><br>Здравствуй, Мир!',
            31: 'Сюда принимается ',
            32: 'файл или папка',
            33: 'файл',
            34: 'папка',
            35: '.',
            36: 'Приемник элементов отключен.',
            37: '-= Анализ... =-</div>',
            38: '-= Обработка =-</div><br><div style="text-align:left;">',
            39: '-= Обработано за ',
            40: '-= Невозможно обработать =-</div><br>',
            41: 'Данный элемент это не ',
            42: ',<br>не может быть доступен<br>или его размер слишком велик.',
            43: 'Произошла неизвестная ошибка.',
            1: 'Произошла определенная ошибка 1.',
            'error 2': 'Произошла определенная ошибка 2.'
        }

Для дальнейшей обработки результатов замените функцию с комментарием "//data processing sample (file or folder path)" на свою.
Возникающие исключения в функции ловятся скрыто и автоматически.
Возвращенные функцией ID ошибок обрабатываются отдельно как пользовательские ошибки.
Пользовательские ID ошибок задаются в конце общего блока сообщений.

Для встраивания "Extended Drop Target" в другое окно передайте на вход "document" соответствующего окна.

Для включения/отключения поддержки drag and drop для файлов или папок измените соответствующий флаг (1 или true; 0, undefined или false):


            1,      //indicates whether processing of files is allowed or not
            1,      //indicates whether processing of folders is allowed or not

Для изменения размеров "Extended Drop Target", параметров границы, параметров шрифта заголовка сообщений, текста, а также выравнивания обратитесь к строкам:


            'width:350px;height:150px;border:2px blue solid;font:bold 10pt Arial;text-align:center;cursor:default;overflow:hidden;word-break:break-all;',       //drop target style
            'bold 12pt Tahoma',     //message header font

Для изменения цвета фона, на котором показывается сообщение определенной группы, или цвета текста обратитесь к строкам:


            'yellow',               //welcome message background color if background image is not set or text color otherwise
            'mediumaquamarine',     //default message background color if background image is not set or text color otherwise
            'limegreen',            //processing message background color if background image is not set or text color otherwise
            'salmon',               //error message background color if background image is not set or text color otherwise

Если в качестве фона выбрано изображение, то изменяется цвет текста.

Для обработки ошибок замените функцию с комментарием "//error resolving sample (error ID)" на свою.
Возникающие исключения в функции ловятся скрыто и автоматически.
Пользовательские ID ошибок задаются в конце общего блока сообщений.

Для показа изображений в качестве фона раскомментируйте соответствующие строки:


            ,'C:\\Windows\\Web\\Screen\\img103.png'     //default background image or "undefined" (optional)
            ,'C:\\Windows\\Web\\Screen\\img102.jpg'      //busy mode background image or "undefined" (optional)

Важно сохранять порядок следования передаваемых параметров, поэтому вместо предшествующих нераскомментированных строк в настройках всегда прописывайте:


            ,undefined

При необходимости используйте картинки для вашей версии Windows из блока ниже, либо замените раскомментированные строки на пути к своим изображениям:


/*
    some built-in in Windows 10 background samples:
    'C:\\Windows\\Web\\Screen\\img103.png'
    'C:\\Windows\\Web\\Screen\\img102.jpg'

    some built-in in Windows 7 background samples:
    'C:\\Windows\\Web\\Wallpaper\\Nature\\img3.jpg'
    'C:\\Windows\\Web\\Wallpaper\\Landscapes\\img10.jpg'

    some built-in in Windows XP background samples:
    'C:\\WINDOWS\\Zapotec.bmp'
    'C:\\WINDOWS\\Soap Bubbles.bmp'
*/

Для показа произвольного пользовательского описания продукта раскомментируйте:


            ,'<div style=\'font:10pt Tahoma;padding:20px;\'>List of files supported by default:<ul><li>Bitmap Files (*.bmp;*.dib)<li>JPEG (*.jpg;*.jpeg;*.jpe;*.jfif)<li>GIF(*.gif)</ul></div>'

Это пример дополнительной информации для пользователя, который не ограничивает текущую функциональность.

Для показа произвольного пользовательского описания продукта на русском языке замените эту запись на:


        ,'<div style=\'font:10pt Tahoma;padding:20px;\'>Список поддерживаемых файлов по умолчанию:<ul><li>Bitmap Files (*.bmp)<li>JPEG (*.jpg;*.jpeg)<li>GIF(*.gif)</ul></ul></div>'

Длина описания ограничена возможностями Web Browser.

Для перенаправления drag and drop сообщений в другую область или окно раскомментируйте:


            ,function(m){result.value = m;}     //sample for receiving messages or "undefined" (optional)

Данный пример перенаправит сообщения в textarea, расположенную выше "Extended Drop Target". При этом сообщения в "Extended Drop Target" больше показаны не будут, хотя по-прежнему может происходить смена фона как ответная реакция на происходящие события.

Если показ сообщений не нужен, но и их перенаправление не требуется, то можно поставить простую заглушку:


            ,function(m){;}     //sample for receiving messages or "undefined" (optional)

Желаю вам приятной работы с функциональностью drag and drop для файлов и папок в окне HTA.

2

Re: HTA & JScript: Extended Drop Target - Юникод-приемник файлов и папок

Дальнейшее исследование позволило устранить возможное мерцание плитки приложения на панели задач во время его запуска.
Обновленную версию скрипта вы можете найти на моем сайте.
Подробности о возникновении мерцания разобраны в теме HTA & JScript: HTA silent stop and close - тихая остановка и закрытие.

3

Re: HTA & JScript: Extended Drop Target - Юникод-приемник файлов и папок

На моем сайте доступна обновленная версия "Extended Drop Target" и новый продукт "Enhanced Drop Target".

Обновление для "Extended Drop Target" включает небольшой прирост производительности во время инициализации приемника и его покидания без бросания на него файла или папки, а также увеличение доступной длины пользовательского описания продукта.

"Enhanced Drop Target" имеет ту же функциональность, что и "Extended Drop Target", но в нем убрано ограничение на фон в виде изображения для Web Browser (истинного приемника файлов) за счет исключения пользовательского описания продукта.
Таким образом, улучшенная (enhanced) версия позволяет использовать пользовательское изображение в качестве фона истинного приемника, что обеспечивает плавный и незаметный переход на приемник при наведении.