1

Тема: WSH: обсуждаем DynamicWrapperX от YMP - 2

Продолжение темы: WSH: обсуждаем DynamicWrapperX от YMP.

2

Re: WSH: обсуждаем DynamicWrapperX от YMP - 2

Комрады, я продолжаю успешно использовать эту замечательную компоненту.
Вопрос у меня вот какой, будет ли кому интересен опыт допиливания ее,  с возможность обработки SEH/VEH исключений.

Дело в том, что я активно занимаюсь перехватом различных функций внутри 1С-ки (версий 7.7 и 8.2) для расширения возможностей движков.  Все нормально работает, пока в 1С не возникает нештатная ситуация. В обычном режиме (без перехвата), 1С-ка ругается на что-то, допустим на отсутствие какого-нить свойства объекта, выбрасывает предупреждение и далее продолжает нормально работать. Если вдруг это происходит в перехваченной функции, то 1С-ка после этого вылетает в космос.
Я давно хотел обернуть , IDispatch::Invoke в "транзакционные" скобки типа catch-try, даже проводил какие-то исследования в этом направлении, но вопрос мне казался через чур сложным, так что я бросал это занятие и обходил проблему какими-то другими способами. Но, в этот раз, все таки решил дожать ситуацию и вроде как это не очень и сложно оказалось.

Жду отклика.

3

Re: WSH: обсуждаем DynamicWrapperX от YMP - 2

Вы пишите, а мы почитаем. :-)

4

Re: WSH: обсуждаем DynamicWrapperX от YMP - 2

Для демонстрации ситуации, которая может привести к краху программы,  предлагаю рассмотреть следующий пример.
Попробуем выполнить с помощью DWX следующий код:

XOR EAX,EAX
MOV EAX,DWORD PTR DS:[EAX]

Вот скрипт, который выполнит данный код, после нажатия на кнопку "Test":

<html>
    <head>
        <script language="vbscript">
            Public Const HEAP_ZERO_MEMORY         = &h8
            Public Const PAGE_EXECUTE_READWRITE    = &h40
            
            Public Wrap
            Public oServ
                 
            Class Service
                Private hHeap
                Private Ref
                Private buf
            
                Private Sub Class_Initialize
                    Set Wrap = CreateObject("DynamicWrapperX")
                    Wrap.Register "kernel32", "HeapAlloc",    "i=lll",    "r=l"
                    Wrap.Register "Kernel32", "HeapFree", "i=lll","r=l"
                    Wrap.Register "kernel32", "GetProcessHeap", "r=l"
                    Wrap.Register "kernel32", "VirtualProtect" , "i=lllp", "r=l"
            
                    hHeap         = Wrap.GetProcessHeap()
                    buf            = Wrap.HeapAlloc(hHeap, HEAP_ZERO_MEMORY, 4)
                    res            = Wrap.HeapAlloc(hHeap, HEAP_ZERO_MEMORY, 4)
                    Wrap.VirtualProtect buf, 4, PAGE_EXECUTE_READWRITE, res
            
                    Wrap.NumPut &hC033,     buf, 0, "n"                'XOR EAX,EAX
                    Wrap.NumPut &h008B,     buf, 2, "n"                'MOV EAX,DWORD PTR DS:[EAX]
            
                    Wrap.RegisterAddr buf, "Test", "r=l"
                End Sub
                
                Private Sub Class_Terminate
                    Wrap.HeapFree hHeap, 0, buf
                    Wrap.HeapFree hHeap, 0, res
                End Sub
            End Class
            
            Set oServ = New Service
                
            
            Sub btnTest_onclick()
                MsgBox "Test"
                On Error Resume Next
                Test = Wrap.Test()
                MsgBox "Код ошибки: " & Hex(Err.Number)
            End Sub
         </script>
    </head>
    
    <body>
        <button id=btnTest>Test</button>    
    </body>
</html>

5

Re: WSH: обсуждаем DynamicWrapperX от YMP - 2

Если этот скрипт выполнить в режиме "hta", по программа закроется, как выполнившая недопустимую операцию.
Под IE ситуация лучше - тут видимо код оборачивается в SEH по умолчанию.

Моя цель была такая - поправить DWX так, чтобы он обернул код

Test = Wrap.Test()

в SEH и по крайней мере не приводил к краху программы.

6 (изменено: chessman, 2013-04-01 14:21:37)

Re: WSH: обсуждаем DynamicWrapperX от YMP - 2

Ниже привожу код, который на лету поправляет DWX, оборачивая вызовы IDispatch::Invoke в SEH.
Код несколько длинный, но зато удобный для внесения правок, поскольку идет с комментариями.

<html>
    <head>
        <script language="vbscript">
        
            Public Const HEAP_ZERO_MEMORY         = &h8
            Public Const PAGE_EXECUTE_READWRITE    = &h40
            
            Public Wrap
            Public oServ
                 
            Class Service
                Private hHeap
                Private buf
                Private buf1
            
                Private Sub Class_Initialize
                    Set Wrap = CreateObject("DynamicWrapperX")
                    Wrap.Register "kernel32", "HeapAlloc",    "i=lll",    "r=l"
                    Wrap.Register "Kernel32", "HeapFree", "i=lll","r=l"
                    Wrap.Register "kernel32", "GetProcessHeap", "r=l"
                    Wrap.Register "kernel32", "VirtualProtect" , "i=lllp", "r=l"
            
                    hHeap                 = Wrap.GetProcessHeap()
                    res                    = Wrap.HeapAlloc(hHeap, HEAP_ZERO_MEMORY, 4)
                    
                    pObj                 = Wrap.GetIDispatch(Wrap)
                    num                    = Wrap.NumGet(pObj, 4) 'Увеличим на счетчик ссылок, чтоб никогда не выгружался
                    Wrap.NumPut    num + 1, pObj, 4         
                    vt                     = Wrap.NumGet(pObj)
                    IDispatch_Invoke     = Wrap.NumGet(vt, 6 * 4)
            
                    If Wrap.NumGet(IDispatch_Invoke, 0, "b") = &h68 Then
                        Exit Sub
                    End If
            
                    sz_buf        = 140
                    buf            = Wrap.HeapAlloc(hHeap, HEAP_ZERO_MEMORY, sz_buf)
                    Wrap.VirtualProtect buf, sz_buf, PAGE_EXECUTE_READWRITE, res
            
                    'Оборачиваем в SEH
                    SEH IDispatch_Invoke, 9, buf
            
                    Wrap.VirtualProtect vt, 4, PAGE_EXECUTE_READWRITE, res
                    Wrap.NumPut buf, vt, 6 * 4
                    Wrap.VirtualProtect vt, 4, Wrap.Numget(res), res
                    
                    
                    buf1    = Wrap.HeapAlloc(hHeap, HEAP_ZERO_MEMORY, 4)
                    Wrap.VirtualProtect buf, 4, PAGE_EXECUTE_READWRITE, res
                        
                    Wrap.NumPut &hC033,     buf1, 0, "n"                'XOR EAX,EAX
                    Wrap.NumPut &h008B,     buf1, 2, "n"                'MOV EAX,DWORD PTR DS:[EAX]
                        
                    Wrap.RegisterAddr buf1, "Test", "r=l"
                End Sub
                
                Private Sub Class_Terminate
                    Wrap.HeapFree hHeap, 0, res
                    Wrap.HeapFree hHeap, 0, buf1
                End Sub
                
                Private Function SEH(callAddr, numParams, buf)
                    szParams = numParams * 4
            
                    Wrap.NumPut &h68,             buf, 0, "b"                    'PUSH SEH-обработчик
                    Wrap.NumPut buf + 52 + szParams,    buf, 1                '
                    Wrap.NumPut &h64,             buf, 5, "b"                    'PUSH DWORD PTR FS:[0]
                    Wrap.NumPut &h35FF,         buf, 6, "n"                    '
                    Wrap.NumPut 0,                buf, 8                        '    
                    Wrap.NumPut &h64,             buf, 12, "b"                'MOV DWORD PTR FS:[0],ESP
                    Wrap.NumPut &h2589,         buf, 13, "n"                '
                    Wrap.NumPut 0,                buf, 15                        '
                    Wrap.NumPut &h60,             buf, 19, "b"                'PUSHAD    Сохраняем регисты
                    
                    For j = 0 To numParams - 1
                        Wrap.NumPut &hFF,             buf, 20 + j * 4, "b"    'PUSH DWORD PTR SS:[ESP+(10 + numParams) * 4]
                        Wrap.NumPut &h74,             buf, 21 + j * 4, "b"
                        Wrap.NumPut &h24,             buf, 22 + j * 4, "b"
                        Wrap.NumPut 40 + szParams,     buf, 23 + j * 4, "b"
                    Next
            
                    Wrap.NumPut    &hE8,                                     buf, 20 + szParams, "b"        'CALL ....callAddr
                    Wrap.NumPut    callAddr - (buf +21 + szParams + 4),    buf, 21    + szParams            '
            
                    'Сохраняем значение ф-и в стек
                    Wrap.NumPut &hC483,        buf, 25 + szParams, "n"            'ADD ESP,20
                    Wrap.NumPut &h20,         buf, 27 + szParams, "b"            '
                    Wrap.NumPut &h09EB,        buf, 28 + szParams, "n"            'JMP SHORT  ------------------------------------+
                    Wrap.NumPut &h1C2444C7,    buf, 30 + szParams                'MOV DWORD PTR SS:[ESP+1C], DISP_E_EXCEPTION    |    
                    Wrap.NumPut &h80020009, buf, 34 + szParams                '                                                |
                    Wrap.NumPut &h61,         buf, 38 + szParams, "b"            'POPAD                                            |
                    Wrap.NumPut &h64,         buf, 39 + szParams, "b"            'POP DWORD PTR FS:[0]        <-------------------+
                    Wrap.NumPut &h058F,     buf, 40 + szParams, "n"            '
                    Wrap.NumPut 0,            buf, 42 + szParams                    '
                    Wrap.NumPut &hC483,     buf, 46 + szParams, "n"            'ADD ESP,4
                    Wrap.NumPut &h4,         buf, 48 + szParams, "b"            '
                    Wrap.NumPut &hC2,         buf, 49 + szParams, "b"            'RETN 24
                    Wrap.NumPut szParams,    buf, 50 + szParams, "n"            '
            
                    '___SEH    
                    '__cdecl _except_handler(
                    '        struct _EXCEPTION_RECORD     *ExceptionRecord,
                     '        void                         *EstablisherFrame,
                     '        struct _CONTEXT             *ContextRecord,
                     '        void                         *DispatcherContext
                     '        )
                    Wrap.NumPut &h0C24448B,    buf, 52 + szParams                'MOV EAX,DWORD PTR SS:[ESP+C]        pFrame                
                    Wrap.NumPut &h08244C8B,    buf, 56 + szParams                'MOV ECX,DWORD PTR SS:[ESP+8]        pContext
                    Wrap.NumPut &hE983,     buf, 60 + szParams, "n"            'SUB ECX,20                            вычисляем правильную позицию стека
                    Wrap.NumPut &h20,         buf, 62 + szParams, "b"            '
                    '======Восстанавливаем ESP======
                    Wrap.NumPut &h8889,     buf, 63 + szParams, "n"            'MOV DWORD PTR DS:[EAX+C4], ECX        mov (CONTEXT ptr [eax]).regEsp, 
                    Wrap.NumPut &hC4,        buf, 65 + szParams                '                        
                    '======Восстанавливаем EIP======
                    Wrap.NumPut &h80C7,     buf, 69 + szParams, "n"            'MOV DWORD PTR DS:[EAX+B8], addr    mov (CONTEXT ptr [eax]).regEip, offset ....
                    Wrap.NumPut &hB8,        buf, 71 + szParams                '
                    Wrap.NumPut buf + 30 + szParams,    buf, 75 + szParams    '
                    '======Сбрасываем бит у ExceptionFlags======
                    Wrap.NumPut &h04244C8B,    buf, 79 + szParams                'MOV ECX,DWORD PTR SS:[ESP+4]        ExceptionRecord    
                    Wrap.NumPut &hFE046180,    buf, 83 + szParams                'AND BYTE PTR DS:[ECX+4],FE           очищаем флаг EXCEPTION_NONCONTINUABLE у ExceptionFlags
                    '======Выходим из обработки исключения======
                    Wrap.NumPut &hB8,         buf, 87 + szParams, "b"            'MOV EAX,ExceptionContinueExecution
                    Wrap.NumPut 0,            buf, 88 + szParams                '
                    Wrap.NumPut &hC3,         buf, 92 + szParams, "b"            'RETN
                End Function
            End Class
            
            Set oServ = New Service

            Sub btnTest_onclick()
                MsgBox "Test"
                'On Error Resume Next
                Test = Wrap.Test()
                MsgBox "Error code: " & Hex(Err.Number)
            End Sub
         </script>
    </head>
    
    <body>
        <button id=btnTest>Test</button>    
    </body>
</html>

7

Re: WSH: обсуждаем DynamicWrapperX от YMP - 2

Код вроде бы нормально отрабатывает. Идея правильная, конечно, исключения надо обрабатывать. Я как-то уже делал это на ассемблере, но подробности подзабылись. Особо сложного чего-то действительно нет. К сожалению, на x64 технология изменилась и, как я понял, сложнее будет реализовать.

8 (изменено: chessman, 2013-04-01 19:10:18)

Re: WSH: обсуждаем DynamicWrapperX от YMP - 2

Честно говоря не знаю, что именно изменилось для x64, но у меня еще есть вариант с оберткой в VEH. В принципе тоже самое, только мне показалось менее удобно. Может этого будет достаточно для x64.

9

Re: WSH: обсуждаем DynamicWrapperX от YMP - 2

Отличная утилита. Я написал hta-скрипты "пианино" с использование midi библиотеки. А также находил окно VirtualDub, брал команды списка меню окна и управлял им. Всё работает.
Тем более, я написал шаблон, облегчающий подключение всех функций.
Однако вчера споткнулся и не знаю, почему CreateFile даёт ошибку. Мне нужно открыть мэппинг файла и на лету его читать-изменять оперативно. Одна моя утилита рабоотает в фоне и использует 4кб файл как псевдо-интерфейс (управляю параметрами изменением этого файла в Hiew). Hiew-дамп использовать несколько неудобно, решил в hta прямо dhtml путями менять параметры.
Вот скрипт.

Что я делаю не так?

Спасибо!

Post's attachments

dump.hta 5.74 kb, 10 downloads since 2013-04-03 

You don't have the permssions to download the attachments of this post.

10

Re: WSH: обсуждаем DynamicWrapperX от YMP - 2

Вероятно, проблема в том, что результат операции GENERIC_READ | GENERIC_WRITE сохраняется JScript'ом в виде знакового целого числа (тип VT_I4), а учитывая, что в GENERIC_READ в старшем бите стоит 1, число получается отрицательное. А тип параметра у вас задан как uint.

Можно изменить тип параметра на int, но тогда может возникнуть та же ошибка при передаче GENERIC_READ самого по себе, т.к. он имеет тип VT_R8 (дробное число двойной точности), является положительным и выходит за пределы положительных значений int (максимум там 0x7FFFFFFF).

Можно заменить "GENERIC_READ | GENERIC_WRITE" на "GENERIC_READ + GENERIC_WRITE" — здесь результатом будет положительное число типа VT_R8. Либо изобрести собственный флаг GENERIC_READ_WRITE со значением 0xC0000000.

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

11 (изменено: Dragokas, 2014-02-01 20:50:05)

Re: WSH: обсуждаем DynamicWrapperX от YMP - 2

Приветствую!
YMP, спасибо за огромнейшую работу !!!

Подскажите, а как вызвать функцию из 32-битной бибилиотеки в 64-битной ОС ?
Если запускать cscript file.vbs из 32-битной cmd.exe, то все нормально отрабатывает.

Post's attachments

GoogleTranslateAPI by raxp - call to vbs.zip 536.99 kb, 13 downloads since 2014-02-01 

You don't have the permssions to download the attachments of this post.

12

Re: WSH: обсуждаем DynamicWrapperX от YMP - 2

Значение имеет битность процесса, а не ОС. Т.е. если скрипт выполнять 32-битным интерпретатором — тем, который в папке SysWOW64 — то будут использоваться 32-битные DLL.

13

Re: WSH: обсуждаем DynamicWrapperX от YMP - 2

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

14 (изменено: maksim32, 2014-02-28 23:23:44)

Re: WSH: обсуждаем DynamicWrapperX от YMP - 2

YMP, огромное спасибо за вашу разработку!!!
Подскажите, как с помощью DynamicWrapperX воспользоваться Direct3D в JScript?

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

В C++ пишут так:


LPDIRECT3D9 pDirect3D=NULL;
bool InitDirectX(void)
{
    if((pDirect3D=Direct3DCreate9(D3D_SDK_VERSION)) == NULL) return(false);
    D3DDISPLAYMODE stDisplay;
    if(FAILED(pDirect3D->GetAdapterDisplayMode(D3DADAPTER_DEFAULT, &stDisplay)))
        return(false);
    <...>
}

На Fasm:


d3d9  MACRO  func, this, arglist :VARARG
 mov   eax , [this]
 mov   eax , [eax]
 IFB <arglist>
      INVOKE [IDirect3D9Vtbl. func][eax], this
 ELSE
      INVOKE [IDirect3D9Vtbl. func][eax], this, arglist
 ENDIF
ENDM

IDirect3D9Vtbl    STRUC
 <...>
 STDMETHOD    GetAdapterDisplayMode, :PTR IDirect3D9, :UINT, :PTR D3DDISPLAYMODE,
 <...>
IDirect3D9Vtbl    ENDS

 <...>
.COD
 invoke    Direct3DCreate9, D3D_SDK_VERSION
 mov    pd3d, eax
 d3d9    GetAdapterDisplayMode, pd3d, D3DADAPTER_DEFAULT, ADDR d3ddm
 <...>

А на JScript никак не получается:


var DWX=new ActiveXObject("DynamicWrapperX");
function InitDirect3D(){
 DWX.Register("d3d9.dll","Direct3DCreate9","i=u","r=p");
 var D3D_SDK_VERSION=32;
 var pDirect3D=DWX.Direct3DCreate9(D3D_SDK_VERSION);
 if(pDirect3D==0){WScript.Echo("Интерфейс Direct3D недоступен!");return 1}
 var D3DADAPTER_DEFAULT=0;
 var pDisplay=DWX.StrPtr(DWX.Space(16,""));
 var Direct3D=DWX.ObjGet(pDirect3D); // получаем интерфейс IUnknown Direct3D
 Direct3D.GetAdapterDisplayMode(D3DADAPTER_DEFAULT,pDisplay); // не работает ни один метод ((
 return 0;
}

Так тем более не работает:


var DX=new ActiveXObject("DynamicWrapperX");
function InitDirect3D(){
 DX.Register("d3d9.dll","Direct3DCreate9","i=u","r=p");
 var D3D_SDK_VERSION=32;
 var pDirect3D=DX.Direct3DCreate9(D3D_SDK_VERSION);
 var D3DADAPTER_DEFAULT=0;
 var IDirect3D9=new Object();
 DX.NumPut(pDirect3D,IDirect3D9); // здесь пишет ошибку...
 IDirect3D9.GetAdapterDisplayMode(D3DADAPTER_DEFAULT);
 return 0;
}

15

Re: WSH: обсуждаем DynamicWrapperX от YMP - 2


Direct3D.GetAdapterDisplayMode(D3DADAPTER_DEFAULT,pDisplay);

Проблема в том, что в скриптах так можно вызывать только методы объектов, поддерживающих интерфейс IDispatch. С IUnknown так работать не получится. Нужно получать адрес соответствующего метода, регистрировать его в DWX через RegisterAddr и потом уже вызывать как метод DWX. Т.е. работать с методами как с функциями.

Указатель на интерфейс, возвращаемый Direct3DCreate9, указывает на другой указатель, который уже указывает на список указателей (адресов) методов (т.е. фактически на адрес метода QueryInterface). Методы IDirect3D9 должны идти после методов IUnknown.


pIUnknown -> pVTable -> pQueryInterface
                        pAddRef
                        pRelease
                        pCheckDepthStencilMatch
                        ...
                        pGetAdapterDisplayMode
                        ...

Если вас такой геморрой не пугает, могу попробовать написать пример вызова метода.

16

Re: WSH: обсуждаем DynamicWrapperX от YMP - 2

Был бы очень рад примеру! Адрес метода не знаю как из COM-интерфейса получить. Спасибо!

17

Re: WSH: обсуждаем DynamicWrapperX от YMP - 2

Вот так у меня работает. При регистрации и вызове методов нужно учитывать, что все они имеют первым параметром указатель на интерфейс (хотя в описании об этом не говорится). Порядок методов в VTable нужно смотреть не в описании интерфейса (там методы по алфавиту), а в header-файле.


DWX = new ActiveXObject("DynamicWrapperX");
PtrSize = DWX.Bitness() / 8;

DWX.Register("d3d9.dll","Direct3DCreate9","i=u","r=p");
D3D_SDK_VERSION = 32;
pDirect3D = DWX.Direct3DCreate9(D3D_SDK_VERSION);
if(pDirect3D == 0){WScript.Echo("Интерфейс Direct3D недоступен!");}
pVTable = DWX.NumGet(pDirect3D, 0, "p")
pGetAdapterDisplayMode = DWX.NumGet(pVTable, 8 * PtrSize, "p");
DWX.RegisterAddr(pGetAdapterDisplayMode, "GetAdapterDisplayMode", "i=pup", "r=l");

D3DADAPTER_DEFAULT = 0, D3D_OK = 0;
pDisplay = DWX.MemAlloc(32, 1);
ret = DWX.GetAdapterDisplayMode(pDirect3D, D3DADAPTER_DEFAULT, pDisplay);
if (ret == D3D_OK) {
    Width = DWX.NumGet(pDisplay, 0, "u");
    Height = DWX.NumGet(pDisplay, 4, "u");
    RefreshRate = DWX.NumGet(pDisplay, 8, "u");
    WSH.echo(Width, Height, RefreshRate);
}
else {
    WSH.echo("Ошибка при вызове GetAdapterDisplayMode: " + ret);
}

DWX.MemFree(pDisplay);

Методы в VTable (файл d3d9.h):


DECLARE_INTERFACE_(IDirect3D9, IUnknown)
{
    /*** IUnknown methods ***/
    STDMETHOD(QueryInterface)(THIS_ REFIID riid, void** ppvObj) PURE;
    STDMETHOD_(ULONG,AddRef)(THIS) PURE;
    STDMETHOD_(ULONG,Release)(THIS) PURE;

    /*** IDirect3D9 methods ***/
    STDMETHOD(RegisterSoftwareDevice)(THIS_ void* pInitializeFunction) PURE;
    STDMETHOD_(UINT, GetAdapterCount)(THIS) PURE;
    STDMETHOD(GetAdapterIdentifier)(THIS_ UINT Adapter,DWORD Flags,D3DADAPTER_IDENTIFIER9* pIdentifier) PURE;
    STDMETHOD_(UINT, GetAdapterModeCount)(THIS_ UINT Adapter,D3DFORMAT Format) PURE;
    STDMETHOD(EnumAdapterModes)(THIS_ UINT Adapter,D3DFORMAT Format,UINT Mode,D3DDISPLAYMODE* pMode) PURE;
    STDMETHOD(GetAdapterDisplayMode)(THIS_ UINT Adapter,D3DDISPLAYMODE* pMode) PURE;
    STDMETHOD(CheckDeviceType)(THIS_ UINT Adapter,D3DDEVTYPE DevType,D3DFORMAT AdapterFormat,D3DFORMAT BackBufferFormat,BOOL bWindowed) PURE;
    STDMETHOD(CheckDeviceFormat)(THIS_ UINT Adapter,D3DDEVTYPE DeviceType,D3DFORMAT AdapterFormat,DWORD Usage,D3DRESOURCETYPE RType,D3DFORMAT CheckFormat) PURE;
    STDMETHOD(CheckDeviceMultiSampleType)(THIS_ UINT Adapter,D3DDEVTYPE DeviceType,D3DFORMAT SurfaceFormat,BOOL Windowed,D3DMULTISAMPLE_TYPE MultiSampleType,DWORD* pQualityLevels) PURE;
    STDMETHOD(CheckDepthStencilMatch)(THIS_ UINT Adapter,D3DDEVTYPE DeviceType,D3DFORMAT AdapterFormat,D3DFORMAT RenderTargetFormat,D3DFORMAT DepthStencilFormat) PURE;
    STDMETHOD(CheckDeviceFormatConversion)(THIS_ UINT Adapter,D3DDEVTYPE DeviceType,D3DFORMAT SourceFormat,D3DFORMAT TargetFormat) PURE;
    STDMETHOD(GetDeviceCaps)(THIS_ UINT Adapter,D3DDEVTYPE DeviceType,D3DCAPS9* pCaps) PURE;
    STDMETHOD_(HMONITOR, GetAdapterMonitor)(THIS_ UINT Adapter) PURE;
    STDMETHOD(CreateDevice)(THIS_ UINT Adapter,D3DDEVTYPE DeviceType,HWND hFocusWindow,DWORD BehaviorFlags,D3DPRESENT_PARAMETERS* pPresentationParameters,IDirect3DDevice9** ppReturnedDeviceInterface) PURE;
    
    #ifdef D3D_DEBUG_INFO
    LPCWSTR Version;
    #endif
};

18 (изменено: maksim32, 2014-03-01 16:04:42)

Re: WSH: обсуждаем DynamicWrapperX от YMP - 2

Спасибо!! Всё отлично работает! Вы мне о-очень помогли!
А какая разница между параметрами "p" и "v"? Зачем нужен "v"? Изменяется ли размер в зависимости от разрядности хоста?

19

Re: WSH: обсуждаем DynamicWrapperX от YMP - 2

p — это указатель. Для чисел влияет только на размер (4 или 8 байт в зависимости от битности процесса). В случае строки функции передастся указатель на неё, в случае объекта — указатель на объект. v — указатель на структуру VARIANT. В таких структурах передаются методам их аргументы в скриптовых языках. Если тип указан как "v", то значение из такой структуры не извлекается, как обычно, а функции передаётся указатель на саму структуру. Предполагается, что функция знает, что с ней делать.

По коду выше есть одно соображение: указатель pDirect3D в конце работы с интерфейсом, как я понял, положено освобождать. Т.е. нужно зарегистрировать метод Release


pRelease = DWX.NumGet(pVTable, 2 * PtrSize, "p");
DWX.RegisterAddr(pRelease, "Release", "i=p");

а где-то в конце вызвать


DWX.Release(pDirect3D);

20 (изменено: maksim32, 2014-03-01 22:58:23)

Re: WSH: обсуждаем DynamicWrapperX от YMP - 2

Спасибо за важное замечание. Я заметил, что не только "h", "p" меняют область значений в зависимости от битности процесса, но и "f". В документации об этом нет информации.

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

Вот, если нужно, код:

var DWX=new ActiveXObject("DynamicWrapperX");
var DWXTypes=["l","u","m","q","h","p","n","t","c","b","f","d"];//,"w","s","z","v"];
var str="x"+DWX.Bitness()+"\n";
var t0;
var t1="яяяяяяяяяяяяяяяяяяяяяяяяяяяяяяяя"; // 1111 1111
var t2="UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU"; // 0101 0101
var ptr1=DWX.StrPtr(t1,"cp1251");
var ptr2=DWX.StrPtr(t2,"cp1251");

for(var i=0;i<DWXTypes.length;i++){
 str+=DWXTypes[i]+"\t"+DWX.NumGet(ptr1,0,DWXTypes[i])+" \t\t "+DWX.NumGet(ptr2,0,DWXTypes[i])+"\n";
}
WSH.Echo(str);

21

Re: WSH: обсуждаем DynamicWrapperX от YMP - 2

Нет, там ошибка была в коде DWX. Спасибо за репорт! Попробуйте версию 2.0.0.1, сейчас должно быть одинаково.

Кстати, текст диалоговых окон можно копировать по Ctrl-C.

22

Re: WSH: обсуждаем DynamicWrapperX от YMP - 2

YMP пишет:

Нет, там ошибка была в коде DWX. Спасибо за репорт! Попробуйте версию 2.0.0.1, сейчас должно быть одинаково.

Кстати, текст диалоговых окон можно копировать по Ctrl-C.

Привет, Юрий!
Это официальная версия?

Я так понимаю, что ошибка была не критичная?

23

Re: WSH: обсуждаем DynamicWrapperX от YMP - 2

Да, можно сказать, официальная. Ошибка связана с сохранением в переменную дробного числа типа Float из регистра. Т.е., например, если функция возвращает такое значение или NumGet читает его из памяти. Я дробные сохраняю в переменные как Double, и вот забыл в 64-битной версии прописать преобразование.

Кроме того ещё ObjGet вызывал исключение, если его вызвать без сохранения результата в переменную (смысла нет так вызывать, но всё-таки). Это тоже исправлено.

24

Re: WSH: обсуждаем DynamicWrapperX от YMP - 2

Спасибо.

25 (изменено: maksim32, 2014-03-04 02:34:41)

Re: WSH: обсуждаем DynamicWrapperX от YMP - 2

YMP пишет:

Нет, там ошибка была в коде DWX. Спасибо за репорт! Попробуйте версию 2.0.0.1, сейчас должно быть одинаково.

Кстати, текст диалоговых окон можно копировать по Ctrl-C.

Вам огромное спасибо за предоставленные возможности и оперативную техподдержку!
Библиотека работает отлично).

26 (изменено: leshenkosa, 2014-03-21 17:19:34)

Re: WSH: обсуждаем DynamicWrapperX от YMP - 2

Помогите, пожалуйста с передачей строк в DWX.
Пробую подключить длл написанную на delphi 7.
Описание ф-ции


function fWriteDoc(Idtypedoc:Integer; Idsenddoc:integer; IDWAY:Integer;
             BlockInfo: PChar; SenderKODOTD:Integer; SenderKODUS:Integer; Note: PChar;
             Datedoc:TDateTime; SendNote:PChar; ParentIDDOC:Integer):Integer;
             stdcall;  external Name;

Как правильно описать входные параметры? Как правильно передавать строку PChar?

Я пробовал объявить так:
Set Wrap = CreateObject("DynamicWrapperX")

Wrap.Register "ElDocDll.dll", "fWriteDoc", "i=lllsllsdsl", "f=s", "r=l"

При вызове фц-ции пишет что не верно заданы параметры
Вот тут вызов ф-ции:


IdTypeDoc = 83
IdSendDoc = id
IDWay = 0
BlockInfo = "" 
'      pBlockInfo = Wrap.StrPtr(BlockInfo, "s")
'      MsgBox pBlockInfo
SenderKODOTD = 268
SenderKODUS = 0
Note = Zakaz & " " & DOsn & Spec
'      pNote = Wrap.StrPtr(note, "s")
'      MsgBox Note
Datedoc = now
SendNote = ""
'      pSendNote = Wrap.StrPtr(SendNote, "s")
ParentIDDOC = 0 
res = Wrap.fWriteDoc(IdTypeDoc, IdSendDoc, IDWay, BlockInfo, SenderKODOTD, SenderKODUS, Note, Datedoc, SendNote, ParentIDDOC)

27

Re: WSH: обсуждаем DynamicWrapperX от YMP - 2

Что-то не пойму. Описание вы приводите для fSendDoc, а регистрируете fWriteDoc.

28

Re: WSH: обсуждаем DynamicWrapperX от YMP - 2

Ошибся ф-цией, сейчас поправлю

29 (изменено: leshenkosa, 2014-03-21 17:32:39)

Re: WSH: обсуждаем DynamicWrapperX от YMP - 2

После того как загрузил новую версию отсюда yuripopov.ucoz.net/load/0-0-0-8-20 и скопировал в system32 вообще стал ругаться на строку

Set Wrap = CreateObject("DynamicWrapperX")

С этим разобрался так

Set Wrap = CreateObject("DynamicWrapperX.2")

30

Re: WSH: обсуждаем DynamicWrapperX от YMP - 2

Вам надо старую версию разрегистрировать, а новую зарегистрировать. У неё CLSID другой.

31 (изменено: leshenkosa, 2014-03-21 17:49:36)

Re: WSH: обсуждаем DynamicWrapperX от YMP - 2

Что делать со строками в ф-циях? Integer в делфи это параметр "l" правильно? Дата и время это по-моему 8-байтное с плавающей точкой, передается параметром "d".
Не пойму никак с PChar что делать, перепробовал много всего ошибки лезут.
При чем если передавать в функцию не переменной, а статической строкой "Test1", то все работает отлично.
Какая-то особенность Vbscript в работе со строками, не пойму какая.

32

Re: WSH: обсуждаем DynamicWrapperX от YMP - 2

Что за ошибки и от кого сообщение о них приходит?

33

Re: WSH: обсуждаем DynamicWrapperX от YMP - 2

Простите за беспокойство, но после обновления DWX до 2 версии все заработало. Строки передаются корректно, информация в базу пишется. Спасибо за помощь.

34 (изменено: maksim32, 2014-03-21 18:51:59)

Re: WSH: обсуждаем DynamicWrapperX от YMP - 2

Здравствуйте, Юрий. Я обычно работаю за Windows XP, но сегодня я запускал программу на восьмёрочке. На Windows XP x32/x64, Windows 7 x32/x64 работает, а на Windows 8 x64 - нет. Ничего не пишет даже, доходя до строчки создания окна. Типы пробовал менять, но не помогло. Вот та неработающая часть программы:

+ открыть спойлер
var IDI_APPLICATION=0x7F00, IDC_ARROW=0x7F00, CS_VREDRAW=0x1, CS_HREDRAW=0x2,
 CS_DBLCLKS=0x8, CS_OWNDC=0x20, WS_OVERLAPPEDWINDOW=0xCF0000,
 WS_VISIBLE=0x10000000, WS_EX_TOPMOST=8, WS_POPUP=0x80000000, WM_DESTROY=0x2,
 WM_ACTIVATE=0x6, WM_CHAR=0x102, WM_SETCURSOR=0x20, WM_QUIT=0x12;

function WNDCLASSEX(){
 // UINT, UINT, WNDPROC, int, int, HINSTANCE, HICON, HCURSOR, HBRUSH, LPCTSTR, LPCTSTR, HICON
 var a=["cbSize","style","lpfnWndProc","cbClsExtra","cbWndExtra","hInstance",
  "hIcon","hCursor","hbrBackground","lpszMenuName","lpszClassName","hIconSm"];
 for(var i in a)this[a[i]]=arguments[i];
 this._const="uupllhhhhpph";
}
function getStructWin(struct){
 var types=struct._const, // строка типов в стандарте DynamicWrapperX
  size=0, // размер структуры (вначале исходной, потом возвращаемой)
  data; // информация для внесения в стуктуру
 for(var i=0;i<types.length;i++)size+=DWXTypes[types.charAt(i).toLowerCase()]; // Вычисляем размер структуры /*на строку память не выделится!!*/
 var ns=DWX.MemAlloc(size,1); // MemFree() // выделение памяти в БАЙТАХ // создание структуры (new struct)
 size=0;i=0;
 for(var p in struct){ // заполняем структуру
  if(p=="_const")continue; // исключаем из структуры МОЮ строку типов
  data=struct[p];
  if(data==null)data=0;
  DWX.NumPut(data,ns,size,types.charAt(i)); // заносим данные data в стуктуру ns со смещением size
  size+=DWXTypes[types.charAt(i++).toLowerCase()];
 }
 return ns; // возвращаем преобразованную структуру
}
function WndProc(hWnd,uMsg,wParam,lParam){ // Callback function
 switch(uMsg){
  case WM_DESTROY:
   Close=1;
   break;
 }
 return DWX.DefWindowProcW(hWnd,uMsg,wParam,lParam);
}

function InitWindow(){
 DWX.Register("user32","LoadIconW","i=hp","r=h");
 DWX.Register("user32","LoadCursorW","i=hp","r=h")
 DWX.Register("user32","RegisterClassExW","i=p","r=t"); // ATOM
 var pWndProc=DWX.RegisterCallback(WndProc,"i=huul","r=l");
 var szClass="Class_name";
 var myWClass=new WNDCLASSEX((bit==32)?48:80, CS_VREDRAW|CS_HREDRAW|CS_DBLCLKS|CS_OWNDC,
  pWndProc, 0, 0, hModule, DWX.LoadIconW(0,IDI_APPLICATION),
  DWX.LoadCursorW(0,IDC_ARROW), 0, 0, szClass, 0);
 var wc=getStructWin(myWClass);
 if(DWX.RegisterClassExW(wc)==0){WSH.Echo("Ошибка при регистрации класса.");return false}
 DWX.Register("user32.dll","CreateWindowExA","i=ussullllhhhl","r=h"); // i=DWORD,LPCTSTR,LPCTSTR,DWORD,int,int,int,int,HWND,HMENU,HINSTANCE,LPVOID r=HWND
 var szTitle="My window";
 hWnd=DWX.CreateWindowExA(0,szClass,szTitle,WS_OVERLAPPEDWINDOW|WS_VISIBLE,
  20,20,500,400,0,0,hModule,0);
 //  hWnd=DWX.CreateWindowExA(WS_EX_TOPMOST,szClass,szTitle,WS_POPUP, 0,0,800,600,0,0,hModule,0);
 if(hWnd==0){WSH.Echo("Ошибка при создании окна.");return false}
 return true;
}

var DWX=new ActiveXObject("DynamicWrapperX");
var bit=DWX.Bitness(); // разрядность процесса
// типы по стандарту DynamicWrapperX в БАЙТАХ (строковые - 0)
var DWXTypes={"l":4,"u":4,"m":8,"q":8,"h":bit/8,"p":bit/8,"n":2,"t":2,"c":1,"b":1,"f":4,"d":8,"w":0,"s":0,"z":0,"v":0};
DWX.Register("kernel32","GetModuleHandleW","i=p","r=h"); // i=(LPCTSTR); r=HMODULE
DWX.Register("user32","DefWindowProcW","i=hupp","r=l"); // i=(HWND, UINT, WPARAM, LPARAM); r=LRESULT
DWX.Register("user32","ShowWindow","i=hl","r=l"); // i=(HWND, int); r=BOOL
DWX.Register("user32","UpdateWindow","i=h","r=l"); // i=(HWND); r=BOOL
var hModule=DWX.GetModuleHandleW(0);
var hWnd=0;
var Close=0;
if(!InitWindow())WSH.Quit(); // hWnd
DWX.ShowWindow(hWnd,1);
DWX.UpdateWindow(hWnd);
do{WSH.Sleep(200);}while(Close==0);

35

Re: WSH: обсуждаем DynamicWrapperX от YMP - 2

Да, я с этим тоже сталкивался. В регистрации WndProc нужно задать wParam и lParam типом "h" или "p", т.е. меняющим размер в соответствии с битностью.

36 (изменено: maksim32, 2014-03-21 20:13:29)

Re: WSH: обсуждаем DynamicWrapperX от YMP - 2

Точно, спасибо! Странно, что в остальных 64-битных версиях винды работало.
Похожая проблема с IDirect3DDevice9::CreateVertexBuffer (типы uuuuph). Тоже только в WinNT6.2x64 не работает.
Ещё, волнует вопрос: обязательно ли освобождать память (DWX.MemFree), ведь по завершению процесса память сама, по-идее, высвобождается? Что особенного происходит после выполнения DWX.MemAlloc? Чем он лучше DWX.Space, память после использования которого не требуется очищать?

37 (изменено: YMP, 2014-03-21 20:23:10)

Re: WSH: обсуждаем DynamicWrapperX от YMP - 2

Могу только предположить, что там обнулённая память выделяется, а в восьмёрке нет. Поэтому в верхней части wParam и lParam оказывается мусор, если писать их как 32-битные в 64-битном процессе.

Да, по завершении процесса память освобождается, поэтому, если разово выделяются небольшие объёмы, то можно и не освобождать. Space возвращает строковую переменную, и тут проблема в том, что скриптовый движок может памятью строки манипулировать по своему усмотрению. Он-то думает, что это строка, а у вас там что угодно может храниться. Могут быть проблемы из-за этого.

38

Re: WSH: обсуждаем DynamicWrapperX от YMP - 2

YMP пишет:

Значение имеет битность процесса, а не ОС. Т.е. если скрипт выполнять 32-битным интерпретатором — тем, который в папке SysWOW64 — то будут использоваться 32-битные DLL.

Спасибо, YMP.
Сделал примерно так: Батник для регистрации DynamicWrapperX 2.0 (x32, x64) и вызова функций из 32/64-битных библиотек.

Может, кому окажется полезным.

39

Re: WSH: обсуждаем DynamicWrapperX от YMP - 2

Dragokas
Возвращаемое значение FindWindow и первый параметр ShowWindow — хэндл, поэтому лучше для них задать тип "h". Возможно, значения оконных хэндлов и не выходят на данный момент за пределы 32 бит, но за будущее ручаться мы ведь не можем. Что там придёт в голову разработчикам Windows.

40

Re: WSH: обсуждаем DynamicWrapperX от YMP - 2

Подскажите, как в буфер (MemAlloc) вставить строку (или скопировать другой буфер) со смещением, если StrPut (как и StrGet) не работают со смещением, как, например, NumPut?

41

Re: WSH: обсуждаем DynamicWrapperX от YMP - 2

Вот так, например:


DWX.StrPut("Hello", pBuf + Offset, "s")

42 (изменено: maksim32, 2014-06-19 15:49:54)

Re: WSH: обсуждаем DynamicWrapperX от YMP - 2

Но ведь в x64 системах указатели типа VT_UI8, а движком JScript не поддерживаются (с ними нельзя выполнять арифметические операции). Или в данном случае от этого не зависит?
А если буферы копировать (часть одного буфера заменить другим), то это побайтово в цикле тогда делать?

43

Re: WSH: обсуждаем DynamicWrapperX от YMP - 2

Ну, MemAlloc такой тип вернёт только, если тип VT_R8 окажется недостаточен. А это 53 бита, т.е. до числа 0x1FFFFFFFFFFFFF включительно будет VT_R8. Думаете, система может выдать память с более высоких адресов? Хм... Поручиться я тут не могу, конечно.

Можно, в принципе, добавить параметр смещения в строковые функции. Что касается копирования участков памяти, то я думал, не сделать ли метод MemCopy. Раз он реально нужен, то тоже можно добавить. Хотя можно и RtlMoveMemory зарегистрировать и использовать.


DWX.Register("kernel32.dll", "RtlMoveMemory", "i=pph");
DWX.RtlMoveMemory(Dest, Source, Size);

44 (изменено: maksim32, 2014-06-19 17:02:54)

Re: WSH: обсуждаем DynamicWrapperX от YMP - 2

Но RtlMoveMemory замещает опять же без смещения. И смещение тоже придётся делать с помощью сложения, которое не всегда допустимо (имею ввиду те, высокие, адреса).
Может добавить MemCopy со смещением, тогда и строки можно будет копировать, не боясь указателей типа VT_UI8? Хотя можно расширить функционал с помощью RegisterCode, но я в asm не силён.

45

Re: WSH: обсуждаем DynamicWrapperX от YMP - 2

maksim32 пишет:

Может добавить MemCopy со смещением, тогда и строки можно будет копировать, не боясь указателей типа VT_UI8?

Тогда нужно будет два смещения — к исходному и целевому адресу. Как-то громоздко получается. Либо сделать их необязательными и определять по алгоритму: если указаны 3 параметра, то это 2 адреса и размер; 5 параметров = адреса со смещениями и размер. Надо подумать. Или, может, сделать метод для операций с такими типами.

А всё потому, что в МС поленились добавить два типа в 64-битные движки. Неужели так трудно было?

46

Re: WSH: обсуждаем DynamicWrapperX от YMP - 2

MemCopy(Address, Source, Length [,Offset1] [,Offset2]));
Address - базовый адрес; Source - адрес замещаемого блока памяти; Length - количество байт на замену; Offset1 - смещение к исходному, Offset2 - к целевому. Хотя... можно и одним смещением обойтись, вызвав её 2 раза.
Метод для операций — сложение (+отрицательные чисела), которое нужно будет только для x64. Не знаю что лучше.

В функции RegisterCode преобразуется hex-строка (по-идее же). Можно было бы вынести это как отдельную функцию. Чтобы избежать костылей типа таких:

function hex2mem(str){var l=str.length-str.length%2, ptr=DWX.MemAlloc(l/2+1,1);
 for(var i=0,q=0;i<l;i+=2,q++)DWX.NumPut("0x"+str.substr(i,2)-0,ptr,q,"b");
 return ptr;
}

47

Re: WSH: обсуждаем DynamicWrapperX от YMP - 2

Да, в принципе, можно бы и в конце их указывать. Но есть одно "но" — хотелось бы избежать разнобоя с NumGet/NumPut. По моему опыту такие вещи обычно раздражают, когда в одной функции так, а в другой этак. Думаю, ничего страшного даже если они обязательными бы были — два нуля поставить недолго.


DWX.MemCopy(SrcAddr, 0, DestAddr, 0, BytesToCopy);

Про hex2mem (и наоборот) тоже были мысли. Иногда удобная вещь. Например, глянуть, что находится где-то в памяти.


DWX.MemRead(SrcAddr, Offset, BytesToRead [, BytesPerGroup] [, GroupsPerLine]);
DWX.MemWrite(HexStr, DestAddr, Offset [, BytesToWrite]) 

Последние два параметра в MemRead — число байт в группе и групп на строке, для удобства обзора. Хотя отформатировать и средствами скрипта не проблема, конечно, так что, может, это и лишнее.

48

Re: WSH: обсуждаем DynamicWrapperX от YMP - 2

YMP пишет:

А всё потому, что в МС поленились добавить два типа в 64-битные движки. Неужели так трудно было?

Это да. Они много чего поленились сделать. Указатели в тип Real теперь переводи

Согласен, два нуля - недолго. MemRead/MemWrite, я лично, считаю полезным. На этапе debug'а скорость выполнения не так важна, как в готовом алгоритме. А побайтово составлять буфер, используя substr и сложение строк для поллучения  - неоптимально.

49

Re: WSH: обсуждаем DynamicWrapperX от YMP - 2

YMP пишет:

Ну, MemAlloc такой тип вернёт только, если тип VT_R8 окажется недостаточен. А это 53 бита, т.е. до числа 0x1FFFFFFFFFFFFF включительно будет VT_R8. Думаете, система может выдать память с более высоких адресов? Хм... Поручиться я тут не могу, конечно.

Почитал немного про память в х64. На данный момент для адресов используются 48 нижних бит (да и то только с Windows 8.1), причём это ограничение на уровне процессора. Так что VT_R8 хватит с запасом. Есть, правда, ещё память ядра, у которой верхние биты заполняются единицами, так что числа формально получаются больше. Но в эту память у приложений допуска нет.

Т.е. есть две зоны: 0 - 00007FFF'FFFFFFFF и FFFF8000'00000000 - FFFFFFFF'FFFFFFFF. В сумме это 256 терабайт, так что смысла расширять адрес дальше нет.

http://en.wikipedia.org/wiki/X86-64_vir … RESS-SPACE

50

Re: WSH: обсуждаем DynamicWrapperX от YMP - 2

Большое спасибо за полезное разъяснение.
Я пытаюсь реализовать буферизированный вывод элементов структур. Чтобы скопировать информацию из структуры в буфер хотел воспользоваться RtlCopyMemory, но при её регистрации происходит ошибка: функция не найдена в библиотеке. Ни в ntdll, ни в kernel32. А RtlMoveMemory находит. Не пойму в чём дело. Или вообще нужно как-то по-другому составлять буфер?
Вот пример:

+ открыть спойлер
var DWX=WScript.CreateObject("DynamicWrapperX");
var bit=DWX.Bitness(); // разрядность процесса
var dwxsize={l:4,u:4,m:8,q:8,h:bit/8,p:bit/8,n:2,t:2,c:1,b:1,f:4,d:8}; // размеры типов

function ld0n(val,n){val+="";while(val.length<n)val="0"+val;return val}
function cnv_num(val,f,t){return parseInt(val,f).toString(t).toUpperCase()} // Lower
function gethex(addr,size){
 for(var i=0,str="";i<size;i++)str+=ld0n(cnv_num(DWX.NumGet(addr,i,"b"),10,16),2);
 return str;
}

DWX.Register("advapi32.dll","GetTokenInformation","i=hupup","r=l"); // HANDLE,enum,LPVOID,DWORD,PDWORD; BOOL
DWX.Register("kernel32.dll","GetCurrentProcess","r=h"); // void; HANDLE
DWX.Register("advapi32.dll","OpenProcessToken","i=hup","r=l"); // HANDLE,DWORD,PHANDLE; BOOL
DWX.Register("kernel32.dll","LocalFree","i=h","r=h");
DWX.Register("kernel32.dll","CloseHandle","i=h","r=l");
DWX.Register("ntdll.dll","RtlMoveMemory","i=ppu"); // VOID UNALIGNED,const VOID UNALIGNED,SIZE_T; VOID

// буфер для последующего вывода
var BUFFER=DWX.MemAlloc(256,1),nBUFFER=0;

// добавляем в буфер какую-нибудь информацию
var test_str="Another info\0";
DWX.RtlMoveMemory(BUFFER+nBUFFER,test_str,test_str.length*2);
nBUFFER+=test_str.length*2;

var TOKEN_QUERY=0x0008;
var phToken=DWX.MemAlloc(dwxsize.h,1);
var hProcess=DWX.GetCurrentProcess();
DWX.OpenProcessToken(hProcess,TOKEN_QUERY,phToken);
var hToken=DWX.NumGet(phToken,0,"h");
var uSizeToken=dwxsize.p*2+28;
var ptiUser=DWX.MemAlloc(uSizeToken);
DWX.GetTokenInformation(hToken,1,ptiUser,uSizeToken,0);

// ещё добавляем информацию (User SID)
DWX.RtlMoveMemory(BUFFER+nBUFFER,DWX.NumGet(ptiUser,0,"p"),28);
nBUFFER+=28;

DWX.MemFree(ptiUser);
DWX.CloseHandle(hToken);
DWX.MemFree(phToken);
DWX.CloseHandle(hProcess);

// выводим буфер
WScript.Echo(gethex(BUFFER,nBUFFER));

51

Re: WSH: обсуждаем DynamicWrapperX от YMP - 2

Судя по всему, это инлайновая функция. Т.е. она ниоткуда не экспортируется, а просто в то место, где она вызывается, компилятор вставляет её код.

В последней версии DWX есть метод MemCopy. Проще всего его использовать. А для чтения памяти в хекс-строку есть метод MemRead.

52

Re: WSH: обсуждаем DynamicWrapperX от YMP - 2

YMP, прошу прощение за неграмотность, но у меня не получилось реализовать нормальный рабочий манифест под вторую версию. Смысл в использовании Вашей библиотеки без ее регистрации в реестре. Буду признателен за помощь.
Также хотел уточнить будут ли отличатся манифесты на 86 и 64-битных версиях ОС?

53

Re: WSH: обсуждаем DynamicWrapperX от YMP - 2

JSman
Возможно, CLSID не поправили? Сейчас потестил, у меня для обеих битностей работают такие манифесты.

wscript.exe.manifest


<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">

<assemblyIdentity
  type="win32"
  name="wscript.exe"
  version="1.0.0.0" /> 

  <dependency>
          <dependentAssembly>
              <assemblyIdentity
                  type="win32"
                  name="dynwrapx.sxs"
                  version="2.1.0.0" />
          </dependentAssembly>
  </dependency>

</assembly>

dynwrapx.sxs.manifest


<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">

<assemblyIdentity
    type="win32"
    name="dynwrapx.sxs"
    version="2.1.0.0" />

<file name="dynwrapx.dll">
     <comClass
        clsid="{89565276-A714-4a43-912E-978B935EDCCC}"
        threadingModel="Both"
        progid="DynamicWrapperX" />
</file>

</assembly>

54

Re: WSH: обсуждаем DynamicWrapperX от YMP - 2

Да... Это я не смотрел за обновлениями. Огромное спасибо за MemCopy и MemRead/MemWrite!!
Вопрос как скрипту запросить права администратора? Запускаю скрипт обычным wscript.exe, в скрипт же не вставишь manifest.

55

Re: WSH: обсуждаем DynamicWrapperX от YMP - 2

Не знаю, не озадачивался таким вопросом. Наверно, как-то можно запросить повышение прав через API.

56

Re: WSH: обсуждаем DynamicWrapperX от YMP - 2

YMP пишет:

JSman
Возможно, CLSID не поправили? Сейчас потестил, у меня для обеих битностей работают такие манифесты.

Так и получилось. Причем на 64-битной ОС отлично работает 32-битная сборка. Получился универсальный вариант. Большое спасибо!

57 (изменено: maksim32, 2014-10-19 20:01:07)

Re: WSH: обсуждаем DynamicWrapperX от YMP - 2

На разных архитектурах размер типа LRESULT изменяется (4/8). В справке к DynamicWrapperX он относится к знаковым целым 32-битным (l). По-идее UINT_PTR=WPARAM=LPARAM=LRESULT=LONG_PTR="p".

typedef LONG_PTR LRESULT;
+ YMP

58

Re: WSH: обсуждаем DynamicWrapperX от YMP - 2

Повысить права скрипту можно только его перезапуском от другого пользователя или так:
http://msdn.microsoft.com/en-us/library … s.85).aspx

59

Re: WSH: обсуждаем DynamicWrapperX от YMP - 2

maksim32 пишет:

На разных архитектурах размер типа LRESULT изменяется (4/8). В справке к DynamicWrapperX он относится к знаковым целым 32-битным (l).

typedef LONG_PTR LRESULT;

Да, действительно, надо будет исправить. Спасибо!

60 (изменено: maksim32, 2014-10-19 20:34:57)

Re: WSH: обсуждаем DynamicWrapperX от YMP - 2

Кстати, вопрос, почему для указателей мы используем беззнаковый тип ("p"), ведь эти типы все знаковые?:
WNDPROC, LPCTSTR, LPCWSTR, UINT_PTR, WPARAM, LPARAM, LONG_PTR, LRESULT, LPVOID, LPMSG, PDWORD, PHANDLE, PSID, ULONG_PTR, PULONG_PTR...
В тоже время для дескрипторов используем знаковый ("h") (как оно и есть). Или вообще без разницы знаковые они или нет?

61

Re: WSH: обсуждаем DynamicWrapperX от YMP - 2

Ну, указатель — это адрес. Может ли адрес быть отрицательным?

Вообще-то сейчас я убрал проверку на знаковость для входных параметров. В 1-й версии нельзя было для параметра с типом "p" или "u" подать отрицательное число. Но проблема в том, что в скриптовых языках у нас нет полного контроля за типами, да и сам набор типов не полон. Так что в некоторых случаях такая строгая проверка вызывала неудобства.

Поэтому на данный момент разница между "p" и "h", "u" и "l", и т.д. — чисто мнемоническая. Просто чтобы видно было, знаковый или беззнаковый параметр в определении функции. Указатель или хэндл. По факту в обоих случаях передаётся тот же набор битов, а как его интерпретировать, функция знает сама.

Но для возвращаемых значений разница остаётся. Поскольку здесь уже сам DWX должен откуда-то знать, как ему интерпретировать, например, 32-битное число 0xFFFFFFFF: если как "l", тогда это -1 и её можно поместить в тип VT_I4; если как "u", тогда число положительно и выходит за диапазон VT_I4, нужно использовать тип VT_R8. Тогда и отображаться это число будет корректно, если вы захотите посмотреть, что вернула функция, и арифметические операции с ним будут правильны.

62 (изменено: maksim32, 2014-11-03 19:40:59)

Re: WSH: обсуждаем DynamicWrapperX от YMP - 2

А как работать с типом long double? И можно ли ограничить (расширить) диапазон чтения строки StrGet (типа Bytes — размер в байтах)? Например,

var DWX=WScript.CreateObject("DynamicWrapperX.2");
var MyStruct=DWX.MemAlloc(14+2*4,0);
DWX.MemWrite("48656C6C6F2C20667269656E6473",MyStruct,14); // Hello, friends
DWX.NumPut(0x6C65645F,MyStruct,14,"u");
DWX.NumPut(0x00657465,MyStruct,18,"u");
var str=DWX.StrGet(MyStruct,0,"s");
DWX.MemFree(MyStruct);
WScript.Echo(str); // хочу получить "Hello, friends"

В данном случае можно обойтись строчкой

str=str.substr(0,14);

Второй случай, с необходимостью расширения строки:

var str1="Hello,\0World"; str1+=" my friend!"; // длина строки 23
WScript.Echo(DWX.MemRead(DWX.StrPtr(str1),str1.length*2,2,0));
// length=23; echo = 4800 6500 6C00 6C00 6F00 2C00 0000 5700 6F00 7200 6C00 6400 2000 6D00 7900 2000 6600 7200 6900 6500 6E00 6400 2100
// в JScript поддерживается работа со строками, содержащими терминальный 0
var MyStruct=DWX.MemAlloc(23*2+4,0);
DWX.StrPut(str1,MyStruct,0,"w");
DWX.NumPut(0x6C65645F,MyStruct,46,"u");
WScript.Echo(DWX.MemRead(MyStruct,23*2+4,2,0));
// echo = 4800 6500 6C00 6C00 6F00 2C00 0000 0100 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 FFFF 5F64 656C
// NumPut записала строку до нуля (не всю)
DWX.MemCopy(DWX.StrPtr(str1),MyStruct,23*2); // теперь запишем всю строку
var str2=DWX.StrGet(MyStruct,0,"w"); // и получим её
WScript.Echo(str2.length); // её длина стала 6
DWX.MemFree(MyStruct);

В этом случае уже нужно пользоваться MemCopy.
Получается лучше сразу использовать MemCopy для чтения и записи строки; для чтения:

var str2=DWX.Space(23,"");
DWX.MemCopy(MyStruct,DWX.StrPtr(str2),23*2);

Полный код:

+ открыть спойлер
var DWX=WScript.CreateObject("DynamicWrapperX.2");
var MyStruct=DWX.MemAlloc(14+2*4,0);
DWX.MemWrite("48656C6C6F2C20667269656E6473",MyStruct,14); // Hello, friends
DWX.NumPut(0x6C65645F,MyStruct,14,"u");
DWX.NumPut(0x00657465,MyStruct,18,"u");
var str0=DWX.StrGet(MyStruct,0,"s");
DWX.MemFree(MyStruct);
WScript.Echo(str0); // хочу получить "Hello, friends"
// str0=str0.substr(0,14);
var str1="Hello,\0World"; str1+=" my friend!"; // длина строки 23
WScript.Echo(DWX.MemRead(DWX.StrPtr(str1),str1.length*2,2,0));
// length=23; echo = 4800 6500 6C00 6C00 6F00 2C00 0000 5700 6F00 7200 6C00 6400 2000 6D00 7900 2000 6600 7200 6900 6500 6E00 6400 2100
// в JScript поддерживается работа со строками, содержащими терминальный 0
var MyStruct=DWX.MemAlloc(23*2+4,0);
DWX.StrPut(str1,MyStruct,0,"w");
DWX.NumPut(0x6C65645F,MyStruct,46,"u");
WScript.Echo(DWX.MemRead(MyStruct,23*2+4,2,0));
// echo = 4800 6500 6C00 6C00 6F00 2C00 0000 0100 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 FFFF 5F64 656C
// NumPut записала строку до нуля (не всю)
DWX.MemCopy(DWX.StrPtr(str1),MyStruct,23*2); // теперь запишем всю строку
var str2=DWX.StrGet(MyStruct,0,"w"); // и получим её
WScript.Echo(str2.length); // её длина стала 6
str2=DWX.Space(23,"");
DWX.MemCopy(MyStruct,DWX.StrPtr(str2),23*2);
WScript.Echo(DWX.MemRead(DWX.StrPtr(str2)-4,23*2+4,2,0));
// 2E00 0000 4800 6500 6C00 6C00 6F00 2C00 0000 5700 6F00 7200 6C00 6400 2000 6D00 7900 2000 6600 7200 6900 6500 6E00 6400 2100
// Всё в порядке
DWX.MemFree(MyStruct);

63

Re: WSH: обсуждаем DynamicWrapperX от YMP - 2

Параметр для длины строки сделать можно, конечно. Хотя логичнее задавать его в символах, а не байтах. Но тут не всё так просто в многобайтных кодировках вроде UTF-8 или каких-нибудь восточно-азиатских.

А как работать с типом long double?

А где он реально нужен? Возвращать его в скрипт не в чем. Для 64-битного целого типы хотя и не используются в JScript, но существуют, а тут типа вообще нет. По логике он бы должен называться VT_R10. Если возвращать в VT_R8, будет обрезаться по точности. Да и по величине может не влезть.

Передача его в функцию и возврат из неё нигде не оговорены, по кр. мере я не нашёл. Видимо, передаётся и возвращается по указателю. А в Visual Studio он вообще не отличается от double: Type long double.

64 (изменено: maksim32, 2014-11-04 20:09:57)

Re: WSH: обсуждаем DynamicWrapperX от YMP - 2

Да, стандартных функций, передающих long double, я не встречал. Но в структуре встретиться может. В принципе, можно было бы использовать 10-символьную строку (10-байтовый участок памяти). А если вычисления производить, тогда преобразовать в double.
Я делаю объект struct, чтобы легче было работать с winapi (но скорость теряется). В него и хотел добавить поддержку long doube.
Пример использования "структуры" (поиск всех dll в папке windows):

+ открыть спойлер
var DWX=WScript.CreateObject("DynamicWrapperX");
var bit=DWX.Bitness(); // разрядность процесса
var dwxsize={l:4,u:4,m:8,q:8,h:bit/8,p:bit/8,n:2,t:2,c:1,b:1,f:4,d:8}; // размеры типов

var defWINAPI={
 /*  4 */ LONG:"l", INT:"l", BOOL:"l", HRESULT:"l", NTSTATUS:"l", "int":"l",
 /* u4 */ ULONG:"u", UINT:"u", DWORD:"u", PUINT:"u", LPUINT:"u", ULONG32:"u", "enum":"u",
 /*  8 */ INT64:"m", LONGLONG:"m",
 /* u8 */ UINT64:"q", ULONGLONG:"q", DWORDLONG:"q", ULONG64:"q",
 /*  $ */ HANDLE:"h", HWND:"h", HMODULE:"h", HLOCAL:"h", HINSTANCE:"h", HICON:"h", HCURSOR:"h", HBRUSH:"h", HDROP:"h", PVOID:"h", INT_PTR:"h", LONG_PTR:"h", /*?*/ 
 /* u$ */ WNDPROC:"p", LPCTSTR:"p", LPCWSTR:"p", UINT_PTR:"p", WPARAM:"p", LPARAM:"p", LPVOID:"p", ULONG_PTR:"p", PULONG_PTR:"p", LRESULT:"p", SIZE_T:"p" /*unsigned*/, LPMSG:"p", PDWORD:"p", PHANDLE:"p", PSID:"p",
 /*  2 */ SHORT:"n",
 /* u2 */ USHORT:"t", WORD:"t", PWORD:"t", LPWORD:"t", WCHAR:"t", OLECHAR:"t", wchar_t:"t",
 /*  1 */ CHAR:"c", CCHAR:"c",
 /* u1 */ UCHAR:"b", BYTE:"b", PBYTE:"b", BOOLEAN:"b",
 /*  4 */ FLOAT:"f",
 /*  8 */ DOUBLE:"d",
 BSTR:"w", LPWSTR:"w", LPOLESTR:"w",
 LPSTR:"s", LPCSTRL:"s"
};
var struct={ // добавить описание обязательно к этому объекту
 use: [], // для очистки
 create: function(name,crtaddr){ // если crtaddr задан числом, отличным от 0, то память на структуру выделяться не будет
  if(typeof(struct[name])=="undefined"){WScript.Echo("Error, struct "+name+" is undefined!");WScript.Quit();return false} // исключение
  var obj={
   addr: crtaddr?crtaddr:DWX.MemAlloc(struct[name].$_size,1), // при crtaddr не выделяем память
   type: name,
   put: function(aStr,data){struct.put(this,aStr,data)},
   get: function(aStr){return struct.get(this,aStr)},
   size: struct[name].$_size,
   _nid: crtaddr?-1:struct.use.length // номер структуры, для destroy
  };
  if(!crtaddr)struct.use.push(obj);
  return obj
 },
 put: function(obj,aStr,data){
  var tp=struct[obj.type],sz=0; aStr=aStr.split(".");
  for(var i=0;i<aStr.length-1;i++){sz+=tp[aStr[i]].offset;tp=tp[aStr[i]].obj;}
  tp=tp[aStr.pop()];
  DWX.NumPut(data,obj.addr,(sz+tp.offset),tp.type);
 },
 get: function(obj,aStr){ // use: 'var SysTimeInfo=struct.create("SYSTEM_TIME_OF_DAY_INFORMATION"); SysTimeInfo.get("CurrentTime.LowPart");' - вернёт значение поля, а 'SysTimeInfo.get("CurrentTime");' вернёт указатель на поле
  var tp=struct[obj.type],sz=0,tmp; aStr=aStr.split(".");
  var charonly=false;
  for(var i=0;i<aStr.length;i++){
   tmp=aStr[i].split(/(\[)|(\])/g); // разделяем каждый элемент строки адреса по []
   tp=tp[tmp[0]]; sz+=tp.offset;
   if(tmp[1]){tmp=tmp[1]-0;charonly=true;if(tp.obj)sz+=tp.obj.$_size*tmp; else sz+=dwxsize[tp.type]*tmp;} // tmp=eval(tmp[1])-0; (убрал eval)
    else{charonly=false;}
   if(tp.obj)tp=tp.obj; else break;
  }
  if(tp.$_size)return obj.addr+sz; // если это не "лист" дерева структуры, то просто возвращаем указатель на память
  // DebugStr+=typeof(tmp)+": "+tmp+"\n";
  if((!tp.count)||charonly/*(tmp>=0) - bad*/)return DWX.NumGet(obj.addr,sz,tp.type); // (tmp>=0), где tmp=[srt,n] - чтобы при запросе str[n] не выводилась оставшаяся часть строки - bag solution (tp.count - количество элементов массива)
  // else: tmp=[str] => массив (пока обработчики только строки)
   if(tp.elemtype=="WCHAR")return DWX.StrGet(obj.addr+sz,"w"); // если это строка
   if(tp.elemtype=="UCHAR")return DWX.StrGet(obj.addr+sz,"s"); // если это строка
    WScript.Echo("TODO: добавить обработчик для типа: "+tp.elemtype); // debug
   return obj.addr+sz;
 },
 define: function(name,str,pack){ // pack - выравнивание для структуры (default(0): по максимальному члену)
  var obj={},sz=0,arg,tp;
  var align=1,tost; // new vars (renamed)
  if(!pack)pack=8; // размеры всех типов не превышают 8
  str=str.split(";");
  for(var i=0;i<str.length;i++){
   arg=str[i].split(/\s/gm);
   if(arg.length<2)continue;
   tp=defWINAPI[arg[0]];
   if(typeof(tp)=="undefined"){WScript.Echo("Error, type "+arg[0]+" is undefined!");WScript.Quit();return false} // исключение
   /* // без выравнивания:
   if(typeof(tp)=="string"){obj[arg[1]]={type:tp,offset:sz};sz+=dwxsize[tp];}
    else{obj[arg[1]]={obj:tp,offset:sz};sz+=tp.$_size}
   
   // с выравниванием:
   if(typeof(tp)=="string"){ // если тип является простым
    align=Math.max(align,dwxsize[tp]); // высчитываем общее выравнивание структуры
    tost=Math.min(pack,dwxsize[tp]); // выравнивание текущего члена (исключительно при изменении выравнивания pack)
    sz=Math.ceil(sz/tost)*tost; // отступ по выравниванию
    
    obj[arg[1]]={type:tp,offset:sz}; // создание члена в структуре
    sz+=dwxsize[tp];
   } else { // иначе (составным)
    align=Math.max(align,tp.$_align);
    tost=Math.min(pack,tp.$_align);
    sz=Math.ceil(sz/tost)*tost;
    
    obj[arg[1]]={obj:tp,offset:sz};
    sz+=tp.$_size;
   }
   */
   // с множественным обозначением (массивами)   
   var data,kdata;
   tost=arg[1].split(/(\[)|(\])/g); // temp var
   if(tost.length==1){data=arg[1];kdata=1;}else{data=tost[0];kdata=tost[1]-0;} // kdata=eval(tost[1])-0; (убрал eval)
   
   if(typeof(tp)=="string"){ // простой тип
    align=Math.max(align,dwxsize[tp]); // общее выравнивание структуры
    tost=Math.min(pack,dwxsize[tp]);
    sz=Math.ceil(sz/tost)*tost;
    
    obj[data]={type:tp,offset:sz};
    if(kdata>1){obj[data].count=kdata;obj[data].elemtype=arg[0];} // если массив (кол-во членов больше 1)
    sz+=dwxsize[tp]*kdata;
   } else { // составной тип
    align=Math.max(align,tp.$_align);
    tost=Math.min(pack,tp.$_align);
    sz=Math.ceil(sz/tost)*tost;
    
    obj[data]={obj:tp,offset:sz};
    if(kdata>1){obj[data].count=kdata;obj[data].elemtype=arg[0];}
    sz+=tp.$_size*kdata;
   }
  }
  tost=Math.min(pack,align);
  sz=Math.ceil(sz/tost)*tost; // выравниваем последний элемент структуры, оставляя после ного пустоту (правило выравнивание последнего поля)
  obj.$_size=sz;
  obj.$_align=Math.min(align,pack); // для маленьких структур
  defWINAPI[name]=obj;
  struct[name]=obj;
 },
 destroy: function(obj){DWX.MemFree(obj.addr);obj.addr=0;struct.use[obj._nid]=null;},
 destroyAll: function(){
  var t; while(struct.use.length){t=struct.use.pop();if(t!=null)struct.destroy(t);}
 }
/* Пример структуры - результат struct.define("WIN32_FIND_DATAW","DWORD dwFileAttributes; FILETIME ftCreationTime; FILETIME ftLastAccessTime; FILETIME ftLastWriteTime; DWORD nFileSizeHigh; DWORD nFileSizeLow; DWORD dwReserved0; DWORD dwReserved1; WCHAR cFileName[260]; WCHAR cAlternateFileName[14]"):
struct.WIN32_FIND_DATAW = defWINAPI.WIN32_FIND_DATAW = {
 "dwFileAttributes": {type: "u", offset: 0},
 "ftCreationTime": {
  obj: {
   "dwLowDateTime": {type: "u", offset: 0},
   "dwHighDateTime": {type: "u", offset: 4},
   $_size: 8,
   $_align: 4
  },
  offset: 4
 },
 "ftLastAccessTime": {
  obj: {
   "dwLowDateTime": {type: "u", offset: 0},
   "dwHighDateTime": {type: "u", offset: 4},
   $_size: 8,
   $_align: 4
  },
  offset: 12
 },
 "ftLastWriteTime": {
  obj: {
   "dwLowDateTime": {type: "u", offset: 0},
   "dwHighDateTime": {type: "u", offset: 4},
   $_size: 8,
   $_align: 4
  },
  offset: 20
 },
 "nFileSizeHigh": {type: "u", offset: 28},
 "nFileSizeLow": {type: "u", offset: 32},
 "dwReserved0": {type: "u", offset: 36},
 "dwReserved1": {type: "u", offset: 40},
 "cFileName": {type: "t", offset: 44, count: 260, elemtype: "WCHAR"},
 "cAlternateFileName": {type: "t", offset: 564, count: 14, elemtype: "WCHAR"},
 $_size: 592,
 $_align: 4
}
*/
}

// include
DWX.Register("kernel32.dll","FindFirstFileW","i=pp","r=h"); // LPCTSTR,LPWIN32_FIND_DATAW; HANDLE
DWX.Register("kernel32.dll","FindNextFileW","i=hp","r=l"); // HANDLE,LPWIN32_FIND_DATAW; BOOL
DWX.Register("kernel32.dll","FindClose","i=h","r=l"); // HANDLE; BOOL

// typedef
struct.define("FILETIME","DWORD dwLowDateTime; DWORD dwHighDateTime");
struct.define("WIN32_FIND_DATAW","DWORD dwFileAttributes; FILETIME ftCreationTime; FILETIME ftLastAccessTime; FILETIME ftLastWriteTime; DWORD nFileSizeHigh; DWORD nFileSizeLow; DWORD dwReserved0; DWORD dwReserved1; WCHAR cFileName[260]; WCHAR cAlternateFileName[14]"); // MAX_PATH=260

// define
var INVALID_HANDLE_VALUE=-1;

function FindFiles(path){
 var Files=[];
 var FindFileData=struct.create("WIN32_FIND_DATAW");
 var hFind=DWX.FindFirstFileW(path,FindFileData.addr);
 if(hFind!=INVALID_HANDLE_VALUE){
  while(1){
   if((FindFileData.get("dwFileAttributes")&0x10)==0) // FILE_ATTRIBUTE_DIRECTORY=0x00000010
    Files.push(FindFileData.get("cFileName")); // если не дирректория
   if(DWX.FindNextFileW(hFind,FindFileData.addr)==0)break;
  }
  DWX.FindClose(hFind);
 }
 struct.destroy(FindFileData);
 return Files;
}

// main
var DllFiles=FindFiles("C:\\Windows\\*.dll");
WScript.Echo(DllFiles.join("\n"));

65

Re: WSH: обсуждаем DynamicWrapperX от YMP - 2

Т.е. вам реально попадались такие структуры или это чисто теоретически? Я думаю, этот тип используется внутри функций, чтобы в промежуточных вычислениях уменьшить потери в точности. А результат всё равно будет возвращён как double.

Да, про объект Struct я тоже думал и даже начал реализовывать некоторое время назад, как дочерний объект DWX. Синтаксис создания структуры, например, такой:


struct = DWX.Struct( "uwd", 1000, "Hello, world!", 33.44 );

Т.е. сначала список типов членов, потом их значения. И впоследствии доступ к членам по их порядковым номерам. Можно, наверно, и вариант с именованными членами сделать.


struct = DWX.Struct( "size:u name:w value:d", 1000, "Hello", 44.55 );

66 (изменено: maksim32, 2014-11-05 00:58:12)

Re: WSH: обсуждаем DynamicWrapperX от YMP - 2

Нет, чисто теоретически. Допустим мы сохраняем 3D-модель, представленную в виде структуры (работать со структурированными файлами проще).

Я первоначально структуры делал, используя конструкторы (этот код я уже присылал, когда у меня проблема с IDirect3DDevice9 была на Windows8 x64 (и осталась)):

+ открыть спойлер
var DWX=new ActiveXObject("DynamicWrapperX");
var bit=DWX.Bitness(); // разрядность процесса
// типы по стандарту DynamicWrapperX в БАЙТАХ (строковые - 0)
var DWXTypes={"l":4,"u":4,"m":8,"q":8,"h":bit/8,"p":bit/8,"n":2,"t":2,"c":1,"b":1,"f":4,"d":8,"w":0,"s":0,"z":0,"v":0};

 // функция преобразования (создания) структуры из объекта JScript (без строк)
function getStructWin(struct){
 var types=struct._const, // строка типов в стандарте DynamicWrapperX
  size=0, // размер структуры (вначале исходной, потом возвращаемой)
  data; // информация для внесения в структуру
 for(var i=0;i<types.length;i++)size+=DWXTypes[types.charAt(i).toLowerCase()]; // Вычисляем размер структуры /*на строку память не выделится!!*/
 var ns=DWX.MemAlloc(size,1); // MemFree() // выделение памяти в БАЙТАХ // создание структуры (new struct)
 size=0;i=0;
 for(var p in struct){ // заполняем структуру
  if(p=="_const")continue; // исключаем из структуры МОЮ строку типов
  data=struct[p];
  if(data==null)data=0;
  DWX.NumPut(data,ns,size,types.charAt(i)); // заносим данные data в структуру ns со смещением size
  size+=DWXTypes[types.charAt(i++).toLowerCase()];
 }
 return ns; // возвращаем преобразованную структуру
}

function getStructJS(ns,struct){ /*строки!!*/
 var types=struct._const, size=0;
 for(var i in struct){
  struct[i]=DWX.NumGet(ns,size,types.charAt(i))
  size+=DWXTypes[types.charAt(i).toLowerCase()]; // получая размер параметра
 }
 return struct; // возвращаем преобразованную структуру
}

// typedef struct
function WNDCLASSEX(){
 // UINT, UINT, WNDPROC, int, int, HINSTANCE, HICON, HCURSOR, HBRUSH, LPCTSTR, LPCTSTR, HICON
 var a=["cbSize","style","lpfnWndProc","cbClsExtra","cbWndExtra","hInstance",
  "hIcon","hCursor","hbrBackground","lpszMenuName","lpszClassName","hIconSm"];
 for(var i in a)this[a[i]]=arguments[i];
 this._const="uupllhhhhpph";
}

var IDI_APPLICATION=0x7F00, IDC_ARROW=0x7F00, CS_VREDRAW=0x1, CS_HREDRAW=0x2,
 CS_DBLCLKS=0x8, CS_OWNDC=0x20;

// использование:
DWX.Register("user32","LoadIconW","i=hp","r=h");
DWX.Register("user32","LoadCursorW","i=hp","r=h")
DWX.Register("user32","RegisterClassExW","i=p","r=t");
DWX.Register("user32","DefWindowProcW","i=hupp","r=l"); // HWND,UINT,WPARAM,LPARAM; LRESULT
DWX.Register("kernel32","GetModuleHandleW","i=p","r=h"); // i=(LPCTSTR); r=HMODULE

function WndProc(hWnd,uMsg,wParam,lParam){return DWX.DefWindowProcW(hWnd,uMsg,wParam,lParam);}
var hModule=DWX.GetModuleHandleW(0);
var pWndProc=DWX.RegisterCallback(WndProc,"i=hupp","r=l");
var szClass="DirectX9"; // То самое имя класса, которое мы будем регистрировать
// заполняем структуру и получаем её в нужном нам формате
var myWClass=new WNDCLASSEX((bit==32)?48:80, CS_VREDRAW|CS_HREDRAW|CS_DBLCLKS|CS_OWNDC,
 pWndProc, 0, 0, hModule, DWX.LoadIconW(0,IDI_APPLICATION),
 DWX.LoadCursorW(0,IDC_ARROW), 0/*цвет фона*/, 0, szClass, 0);
var wc=getStructWin(myWClass);
// регистрация класса
if(DWX.RegisterClassExW(wc)==0){WSH.Echo("Ошибка при регистрации класса.");/*return false*/}
// ... и т.д.

Но я столкнулся с некоторыми проблемами: это не удобно и громоздко; у структур есть выравнивание, которое не всегда одинаковое; в структуре может быть массив (строка); не слишком просто вручную переводить типы в формат DWX, к тому же бывали случаи, когда приходилось всем одинаковым типам (например, LRESULT) сменить их "значение" DWX, к тому же наличие типов в стиле winapi (хотя бы в комментариях) облегчает написание программы (в документациях они же используются). И к тому же мало возможностей. Вот и получился тот вариант struct. Хотел, кстати, ещё копирование структур/части структур сделать и ограничить вывод строк, но пока это "горло не резало" (об этом я уже здесь спрашивал).

Ещё думаю как сделать структуру с динамическим размером (но как выделить дополнительную память в уже имеющуюся структуру (и изменить смещения и т.п.) я не придумал), типа:

typedef struct {
  ...
  LONG nSize; // размер следующего поля
  WCHAR cText[nSize]; // массив длины не определённой изначально
  ...
} MYTMPSTRUCT;

67

Re: WSH: обсуждаем DynamicWrapperX от YMP - 2

Интересно, сколько их вообще, этих производных типов. Теоретически можно было бы их свести в какую-то таблицу и использовать в обозначениях типов параметров и т.п., но впечатление такое, что их куева туча и всё равно какие-то останутся не охваченными. Может быть, держать их в текстовом файле, который можно было бы постепенно пополнять по мере надобности.

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

68 (изменено: maksim32, 2014-11-05 11:35:18)

Re: WSH: обсуждаем DynamicWrapperX от YMP - 2

Типов таких очень много. В зависимости от используемых технологий. Я их по мере необходимости в тот список добавлял. В моём случае их можно добавлять непосредственно, можно написать defWINAPI["HMENU"]=defWINAPI["HANDLE"] или сделать функцию. Мне кажется что носить с собой текстовый файл будет неудобно, лучше, наверное, непосредственно в код вставлять.

Вот пример из структур сохранения игры (SAS.bt):

...
// Block 2: Players & Objects
struct tBlock02_Players_n_Objects
{
    tblockHeader header;
    int         nPlayers;
    tPlayer     players[nPlayers];
    int         nObjects;
    tObject     objects[nObjects];
} block2;

// Block 3: Garages
struct tBlock03_Garages
{
    tblockHeader header;
    int                 nGarages;
    byte                boolFreeBombs, boolFreeResprays;
    byte                boolRespraysDisabled;
    DWORD               unknown[8];
    tGarageVehiclesTown GarageVehicles[4];
    tGarage             Garages[nGarages];
} block3;
...

Как тогда происходит чтение/запись таких "полуструктурированных" файлов? Может она вначале в кучу всё считывает, а потом, считав и узнав размер, уже размечает память? Хотел сделать поддержку таких структур тоже.

69

Re: WSH: обсуждаем DynamicWrapperX от YMP - 2

Т.е. такие структуры хранятся в файле? Тогда значения nPlayers и т.п. там тоже есть и несложно вычислить размер массивов, а значит и структуры в целом.

70 (изменено: maksim32, 2014-11-06 20:02:15)

Re: WSH: обсуждаем DynamicWrapperX от YMP - 2

Отбой, не бывает таких структур. Этот файл со структурой интерпретируется не как сишная структура, всё считывается отдельно написанным кодом.

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

Да, можно, но заранее (перед прочтением поля структуры, содержащего размер) размера мы не знаем. И в ходе выполнения программы это количество и размер структуры соответственно может измениться. Я подумал, что можно допустим массив players в структуре представить указателем на связный список nPlayers элементов, а работать как с обычной структурой ("struct" это должен будет обеспечивать) в том числе и чтение/запись её. К тому же, создавая пустую такую структуру, предполагается, что nPlayers=0.

71 (изменено: maksim32, 2014-11-30 22:43:52)

Re: WSH: обсуждаем DynamicWrapperX от YMP - 2

Глобальные хуки устанавливаются только с использованием DLL.
http://www.prog.org.ru/index.php?topic= … #msg157278
Может добавить возможность устанавливать хуки для скриптов? Поставить хук на всё, а скрипту передавать только то, что требуется.

72

Re: WSH: обсуждаем DynamicWrapperX от YMP - 2

Для мыши и клавиатуры DLL не обязательна, если использовать WH_MOUSE_LL и WH_KEYBOARD_LL.

Ставить хук на всё, по-моему, незачем. От DLL требуется только callback-функция, причём для всех хуков она одинакова по набору параметров и возвращаемому значению. По идее функция может просто передавать свои параметры скрипту, а их обработка будет уже там, в зависимости от того, какой это хук. Вопрос в том, как осуществить эту передачу.

73

Re: WSH: обсуждаем DynamicWrapperX от YMP - 2

Здравствуйте, YMP! Спасибо, с низкоуровневыми хуками действительно работает.

Пытался получить имя файла с сервера и заметил падение хоста при использовании возвращаемого значения функции DWX.LastError(1).

+ открыть спойлер
function ld0n(val,n){val+=""; while(val.length<n)val="0"+val; return val;}
function alert(val){WScript.Echo(val);}

var DWX;
try{DWX=new ActiveXObject("DynamicWrapperX.2");}
catch(e){WScript.Echo("Ошибка. Не установлен компонент DynamicWrapperX 2.");WScript.Quit();}

// include <wininet.h>
DWX.Register("wininet.dll","InternetOpenW","i=puppu","r=h"); // LPCTSTR,DWORD,LPCTSTR,LPCTSTR,DWORD; HINTERNET
DWX.Register("wininet.dll","InternetConnectW","i=hpuppuup","r=h"); // HINTERNET,LPCTSTR,INTERNET_PORT,LPCTSTR,LPCTSTR,DWORD,DWORD,DWORD_PTR; HINTERNET
DWX.Register("wininet.dll","InternetCloseHandle","i=h","r=l"); // HINTERNET; BOOL
DWX.Register("wininet.dll","HttpOpenRequestW","i=hpppppup","r=h"); // HINTERNET,LPCTSTR,LPCTSTR,LPCTSTR,LPCTSTR,LPCTSTR,DWORD,DWORD_PTR; HINTERNET
DWX.Register("wininet.dll","HttpQueryInfoW","i=huppp","f=l","r=l"); // HINTERNET,DWORD,LPVOID,LPDWORD,LPDWORD; BOOL

// defile
var NULL = 0;
var HTTP_QUERY_CONTENT_DISPOSITION = 47;
var INTERNET_OPEN_TYPE_PRECONFIG = 0;
var INTERNET_FLAG_RELOAD = 0x80000000;
var INTERNET_SERVICE_HTTP = 3;
var INTERNET_DEFAULT_HTTP_PORT = 80;
var INTERNET_FLAG_PRAGMA_NOCACHE = 0x00000100;

function GetUrlInfo(dwInfoLevel, FileURL){
 var result = "<Error>";
 var servname = FileURL.substr(0, FileURL.indexOf("/"));
 var objname = FileURL.substr(FileURL.indexOf("/")+1);
 var hInternet = DWX.InternetOpenW(NULL, INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0); 
 if(hInternet){
  var hConnect = DWX.InternetConnectW(hInternet, servname, INTERNET_DEFAULT_HTTP_PORT, NULL, NULL, INTERNET_SERVICE_HTTP, 0, NULL/*""*/);
  if(hConnect){
   var hRequest = DWX.HttpOpenRequestW(hConnect, "GET", objname, NULL, NULL, NULL, INTERNET_FLAG_RELOAD || INTERNET_FLAG_PRAGMA_NOCACHE, NULL);
   if(hRequest){

    var size = 2048;
    var pBuffer = DWX.MemAlloc(size, 0);
    var pSizeBuffer = DWX.MemAlloc(4, 0); // DWORD
    DWX.NumPut(size, pSizeBuffer, 0, "u");
    if(DWX.HttpQueryInfoW(hRequest, dwInfoLevel, pBuffer, pSizeBuffer, NULL)) result = DWX.StrGet(pBuffer);
    else{
     // 12150: ERROR_HTTP_HEADER_NOT_FOUND (Не удалось найти запрошенный заголовок.)
     alert("Error: "+DWX.LastError(0)+"");
     alert(DWX.LastError(1)); // На этой строчке происходит crash
    }
    alert("Test alert"); // соответственно, не сработает
    DWX.MemFree(pBuffer);
    DWX.MemFree(pSizeBuffer);

    DWX.InternetCloseHandle(hRequest);
   }
   DWX.InternetCloseHandle(hConnect);
  }
  DWX.InternetCloseHandle(hInternet);
 }
 return result;
}

GetUrlInfo(HTTP_QUERY_CONTENT_DISPOSITION, "www.yandex.ru/images/today");
+ YMP

74

Re: WSH: обсуждаем DynamicWrapperX от YMP - 2

Спасибо за сообщение, ошибку исправил. Использовалось возвращаемое значение LoadString вместо указателя на переданный ей буфер.

75

Re: WSH: обсуждаем DynamicWrapperX от YMP - 2

Что делает недокументированная функция UseLastError?

76

Re: WSH: обсуждаем DynamicWrapperX от YMP - 2

Ничего, это артефакт, оставшийся от процесса брожения идей по поводу того, как реализовать использование API GetLastError. Видимо, была идея включать и выключать её использование для данного экземпляра объекта. Т.е. сразу для всех зарегистрированных им функций.

77

Re: WSH: обсуждаем DynamicWrapperX от YMP - 2

Прошу помощи в освоении DynamicWrapperX.

Интересует пример активации установленной на ПК программы с параметрами.
Конкретней: запуск Adobe Reader, с открытием конкретного файла и посылке в Adobe Reader
комбинации клавиш CTRL+L.

Если сообщение не в тему - прошу извинить.

78

Re: WSH: обсуждаем DynamicWrapperX от YMP - 2

Для таких вещей гораздо удобнее использовать AutoHotkey. Тут на форуме есть раздел про него. А так же описание возможностей: http://www.script-coding.com/AutoHotkeyTranslation.html. Если нет желания или возможности устанавливать AutoHotkey на целевой машине, можно будет скрипт скомпилировать в EXE.

79

Re: WSH: обсуждаем DynamicWrapperX от YMP - 2

По некоторым причинам не могу использовать AutoHotkey.
Нужен vbscript.
Запуск на ПК Adobe Reader в скрипте реализована, но не могу послать именно ему комбинацию клавиш. Думал может с помощью DynamicWrapperX получиться.

80

Re: WSH: обсуждаем DynamicWrapperX от YMP - 2

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

81 (изменено: Flasher, 2015-08-12 13:39:44)

Re: WSH: обсуждаем DynamicWrapperX от YMP - 2

vzaitsev
Я подобные вещи обычно делаю стандартными средствами:

With CreateObject("WScript.Shell")
  Set Exec = .Exec("C:\Path to Program.exe ""C:\Path to my file.ext""")
  PID = Exec.ProcessID : Do : A = .AppActivate(PID) : Loop Until A
  Wscript.Sleep 50 : .SendKeys "^l"
End With

А если прямо таки необходимо работать с классами/хэндлами окон, то лучше посмотреть в сторону AutiItX3.

82 (изменено: YMP, 2015-08-12 10:12:32)

Re: WSH: обсуждаем DynamicWrapperX от YMP - 2

Flasher
Работает. Только лучше маленькую букву посылать, иначе результат не тот. Не полноэкранный режим, а просто максимальное растягивание окна.

83

Re: WSH: обсуждаем DynamicWrapperX от YMP - 2

Через API у меня работает так. При условии, что программа уже запущена с открытым документом.


Set DWX = CreateObject("DynamicWrapperX")
DWX.Register "user32", "FindWindowW", "i=ww", "r=h"
DWX.Register "user32", "SetForegroundWindow", "i=h", "r=l"
DWX.Register "user32", "SendInput", "i=upl", "r=u"

window_class = "AcrobatSDIWindow"

hwnd = DWX.FindWindowW( window_class, 0 )

If hwnd = 0 Then
    MsgBox "Окно не найдено."
    WScript.Quit
End If

If DWX.Bitness = 32 Then
    input_size = 28
    input_data = "01000000 A200 0000 00000000 00000000 00000000 00000000 00000000" &_
                 "01000000 4C00 0000 00000000 00000000 00000000 00000000 00000000" &_
                 "01000000 4C00 0000 02000000 00000000 00000000 00000000 00000000" &_
                 "01000000 A200 0000 02000000 00000000 00000000 00000000 00000000"
Else
    input_size = 40
    input_data = "01000000 00000000 A200 0000 00000000 00000000 00000000 0000000000000000" &_
                 "0000000000000000" &_
                 "01000000 00000000 4C00 0000 00000000 00000000 00000000 0000000000000000" &_
                 "0000000000000000" &_
                 "01000000 00000000 4C00 0000 02000000 00000000 00000000 0000000000000000" &_
                 "0000000000000000" &_
                 "01000000 00000000 A200 0000 02000000 00000000 00000000 0000000000000000" &_
                 "0000000000000000"
End If

INPUTS = DWX.MemAlloc( input_size * 4 )
DWX.MemWrite input_data, INPUTS

ret = DWX.SetForegroundWindow( hwnd )

If ret = 0 Then
    MsgBox "Ошибка активации окна."
    DWX.MemFree INPUTS
    WScript.Quit
End If

ret = DWX.SendInput( 4, INPUTS, input_size )

If ret = 0 Then
    MsgBox "Ошибка посылки клавиш."
End If

DWX.MemFree INPUTS

84 (изменено: Flasher, 2015-08-12 13:40:26)

Re: WSH: обсуждаем DynamicWrapperX от YMP - 2

YMP пишет:

Не полноэкранный режим, а просто максимальное растягивание окна.

В XP быть не должно, это в последующих версиях добавка шифта появилась при задействовании верхнего регистра. Исправил.

85

Re: WSH: обсуждаем DynamicWrapperX от YMP - 2

YMP пишет:

Через API у меня работает так. При условии, что программа уже запущена с открытым документом.

Классссс! Работает. Проверил на XP (x32). Большое Спасибо!
Если можно в код вставить комментарии, т.к. мне не все понятны команды.
Через API я еще не работал.
Я так понимаю, что данный код будет работать на х32 и х64, при условии регистрации в системе библиотеки dynwrapx.dll (http://www.script-coding.com/dynwrapx.html).

86

Re: WSH: обсуждаем DynamicWrapperX от YMP - 2

При условии, что в системе обе версии зарегистрированы (32 и 64 бита). Какая из них будет использоваться, зависит от того, каким интерпретатором будет выполняться скрипт. В 64-битных Windows есть как 64-, так и 32-битный интерпретатор.

Чтобы понять, как работает код, почитайте описание функции SendInput. Ей передаётся массив из 4-х структур INPUT (они тоже описаны на MSDN). input_size — это размер такой структуры, разный для 32 и 64 бит. В первой прописано нажатие Ctrl, во второй нажатие L, потом отпускания этих клавиш. Клавиши обозначены соответствующими кодами виртуальных клавиш: Ctrl — A2, L — 4C. Список этих кодов можно найти в Интернете. Единица в начале означает, что передаётся событие клавиатуры, а двойка в двух последних структурах означает отпускание.

87

Re: WSH: обсуждаем DynamicWrapperX от YMP - 2

vzaitsev пишет:

Классссс! Работает. Проверил на XP (x32). Большое Спасибо!

К сожалению рано радовался.
Скрипт работает нормально если его запустить на ПК нажав на нем Ентер.
Если запускать скрипт при старте ОС, то может не сработать. Фокус на окне Adobe Reader не устанавливается, если загружаются еще программы.
Т.е. скрипт с подключением библиотеки dynwrapx.dll аналогичен следующему без библиотеки:
WshShell.AppActivate ("Adobe Reader")
WScript.Sleep 1000
WshShell.SendKeys "^l"

Вопрос: можно-ли послать комбинацию клавиш именно окну (приложению)?

88

Re: WSH: обсуждаем DynamicWrapperX от YMP - 2

vzaitsev
Так а мой скрипт чем не устроил?

89

Re: WSH: обсуждаем DynamicWrapperX от YMP - 2

Flasher пишет:

vzaitsev
Так а мой скрипт чем не устроил?

Код клавиш посылается на клавиатуру, а не приложению.
Если окно не в фокусе, оно не получит эту комбинацию.

90

Re: WSH: обсуждаем DynamicWrapperX от YMP - 2

vzaitsev
Комбинация клавиш посылается после активации окна приложения вообще-то. Сперва стоило попробовать, не так ли?

91

Re: WSH: обсуждаем DynamicWrapperX от YMP - 2

Flasher пишет:

vzaitsev
Комбинация клавиш посылается после активации окна приложения вообще-то. Сперва стоило попробовать, не так ли?

Да именно так, после активации окна. Но если в промежутке активации окна и посылки комбинации клавиш, запустится или активируется еще программа (например:какой то месенжер, фар, тотал ком.), то комбинация клавиш пойдет уже другой программе.

92 (изменено: Flasher, 2015-08-14 13:14:11)

Re: WSH: обсуждаем DynamicWrapperX от YMP - 2

vzaitsev
Этот промежуток составляет 50 мс, половину доли секунды. Какова вероятность, что какое-то ещё окно в этом промежутке появится? Не говоря о том, что этот промежуток условный, т.е. его можно изменить под себя.

P.S.: В цитировании предыдущего поста нет никакой необходимости.

93

Re: WSH: обсуждаем DynamicWrapperX от YMP - 2

vzaitsev пишет:

Вопрос: можно-ли послать комбинацию клавиш именно окну (приложению)?

Можно — например, с помощью функции PostMessage — только нужно знать, какому окну. Кроме родительского окна есть ещё содержащиеся в нём дочерние. Которые ещё в себе могут содержать окна. Посылка родительскому окну (класс AcrobatSDIWindow) не работает. Вероятно, нужно как-то определить, на каком из дочерних окон у Ридера клавиатурный фокус, и посылать конкретно ему. Всё это усложняет задачу.

Кроме того, программа может и не реагировать на сообщения о нажатиях, если видит, что её окно неактивно. Хотя конкретно про Ридер ничего не могу сказать в этом отношении, может, ему и всё равно.

94 (изменено: maksim32, 2016-03-19 09:39:34)

Re: WSH: обсуждаем DynamicWrapperX от YMP - 2

Столкнулся с проблемой: в оконной функции у некоторых сообщений, например WM_NCPAINT и WM_ERASEBKGND параметр wParam иногда получается типа unknown.

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

https://pp.vk.me/c631928/v631928861/1e84e/xQpoTTgDlK4.jpg


DWX.RegisterCallback(MainWndProc, "i=hupp", "r=p"); // HWND,UINT,WPARAM,LPARAM
...
function MainWndProc(hWnd, uMsg, wParam, lParam) {
 if(uMsg == WM_ERASEBKGND) stdout("WM_ERASEBKGND:  wParam = ("+typeof(wParam)+")"+wParam);
 if(uMsg == WM_NCPAINT) stdout("WM_NCPAINT:  wParam = ("+typeof(wParam)+")"+wParam);
 switch(uMsg) {
  case WM_DESTROY:
   DWX.PostQuitMessage(0);
   return 0;
 }
 return DWX.DefWindowProcW(hWnd, uMsg, wParam, lParam);
}

Тут, в wParam, судя по описанию WM_ERASEBKGND и WM_NCPAINT - дескриптор.

Аналогичная программа на C:
https://pp.vk.me/c631928/v631928861/1e868/HqR088uLP4g.jpg

В принципе, решить проблему просто - тип wParam указать не "p", а "h". Но это может всплыть в ином месте, где используется этот тип "p".



YMP пишет:

Поэтому на данный момент разница между "p" и "h", "u" и "l", и т.д. — чисто мнемоническая.

Получается, "p" и "h" не эквивалентны - при работе с "h" проблем не возникает:


// Различия между типами "p" и "h"
function stdout(val){try{WScript.StdOut.WriteLine(val);}catch(e){}} // debug

var DWX;
try{DWX=new ActiveXObject("DynamicWrapperX.2");}
catch(e){WScript.Echo("Ошибка. Не установлен компонент DynamicWrapperX 2.");WScript.Quit();}
if(DWX.Bitness()!=64) WScript.Quit();


var fn0=function(v_P, v_H){
 stdout("("+typeof(v_P)+")"+v_P+", ("+typeof(v_H)+")"+v_H);
 return 0;
}
var lpnf0=DWX.RegisterCallback(fn0, "i=ph", "r=l");
DWX.RegisterAddr(lpnf0, "TestFunction", "i=ph", "r=l");

DWX.TestFunction(-0x8000000000000400, -0x8000000000000400); // минимальное число (при ...401 уже не сработает) (- не "нейтрализуется")
DWX.TestFunction( 0x7FFFFFFFFFFFFFFF,  0x7FFFFFFFFFFFFFFF); // реальное минимальное число
DWX.TestFunction( 0xFFFFFFFFFFFFFBFF,  0xFFFFFFFFFFFFFBFF); // максимальное число
DWX.TestFunction(-0x0000000000000001, -0x0000000000000001); // реальное максимальное число (unsigned, если)
DWX.TestFunction(-150903375, -150903375); // на все отрицательные числа p "ответит" unknown
DWX.TestFunction(-0x7FFFFFFFFFFFFBFF, -0x7FFFFFFFFFFFFBFF); // и тут от p unknown
DWX.TestFunction(-0x7FFFFFFFFFFFFA00, -0x7FFFFFFFFFFFFA00); // тут уже преобразовывается


Версия DWX: 2.1.1.1 x64
Версия JScript: 5.812 x64
Версия Windows: 10.0.10586.104 x64

95

Re: WSH: обсуждаем DynamicWrapperX от YMP - 2

Да, они эквивалентны при передаче числа из скрипта, но не эквивалентны при передаче числа в скрипт (для возвращаемых значений и параметров callback-функций).

Если вы передаёте число из скрипта, то обозначите ли вы его как 0xFFFFFFFFFFFFFFFF или как -1, в памяти будет один и тот же набор битов. Т.е. вызываемой API-функции это без разницы. Она получает набор битов, тип числа там никак не обозначен, и она сама знает, как его интерпретировать в смысле знаковости.

В то же время скриптовый движок может не иметь типа переменной для 64-битных беззнаковых чисел, и втайне от вас поместит 0xFFFFFFFFFFFFFFFF в знаковый тип, т.е. передаст его в DWX как -1. Или вообще его забракует, и тогда вы сами можете попытаться использовать -1, если знаете о том, что в памяти разницы не будет. Первая версия DWX отрицательные числа для указателей не принимала, т.к. это адрес, а адрес не может быть отрицательным. Такой строгий контроль вызывал неудобства в силу вышеозвученных причин, и я его убрал.

Что касается передачи числа извне в скрипт, то тут уже не всё равно, знаковое число или беззнаковое, поскольку его тип должен быть явным образом указан в передаваемой скрипту переменной. Если передать указатель как отрицательное, а вы станете с ним производить какие-то вычисления, вполне логично ожидая, что он положителен, то получится неверный результат. Исходя из этого, тип "p" интерпретируется как положительный, и если величина числа превысит диапазон дробного двойной точности (VT_R8), то используется тип VT_UI8, который JScript'у неизвестен, поэтому и обозначается им как unknown.

Хэндлы в принципе тоже беззнаковый тип, но они используются просто как некие условные числа, идентифицирующие какие-то объекты Винды. Вычислять с ними нечего, максимум можно их сравнить, чтобы узнать, один это объект или разные. Этому их знаковость никак не мешает. Поэтому они интерпретируются DWX как знаковые. Теоретически и там величина числа может выйти за пределы VT_R8, и тогда будет использован VT_I8, который тоже неизвестен JScript'у. Но здесь это, думаю, маловероятно, поскольку не видно смысла использовать такие большие числа для условных идентификаторов. Разве что адрес объекта может использоваться как его идентификатор.

Кстати, wParam в обеих упомянутых вами функциях — это хэндл, поэтому вполне логично использовать для них тип "h".

96 (изменено: Parazit, 2018-03-29 13:45:40)

Re: WSH: обсуждаем DynamicWrapperX от YMP - 2

А как работать со структурами?
Примерчик один можно?

DWX = new ActiveXObject("DynamicWrapperX");
DWX.Register("kernel32.dll", "CreateDirectoryW", "i=wv", "r=l");
a = DWX.CreateDirectoryW("C:\\111", "");

В данном примере, во втором параметре передаётся структура безопасности.
Как это должно выглядить?

97

Re: WSH: обсуждаем DynamicWrapperX от YMP - 2

А вам она там точно нужна? Можно просто нуль передать, типом "p".

DWX = new ActiveXObject("DynamicWrapperX");
DWX.Register("kernel32.dll", "CreateDirectoryW", "i=wp", "r=l");
a = DWX.CreateDirectoryW("C:\\111", 0);

А вообще под структуры выделяется память методом MemAlloc и в неё пишутся значения её членов через NumPut.

98

Re: WSH: обсуждаем DynamicWrapperX от YMP - 2

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

99 (изменено: maksim32, 2018-03-29 15:59:22)

Re: WSH: обсуждаем DynamicWrapperX от YMP - 2

Вот, как пример работы со структурой, с учётом битности хоста. Если нужно много работать со структурами, лучше написать класс, который будет вычислять offset'ы с учетом alignment'ов при инициализации нового типа структуры в зависимости от разрядности хоста и потом по ним получать/записывать данные. Потому что с этими магическими числами-смещениями с увеличением количества структур легко запутаться.

var DWX = new ActiveXObject("DynamicWrapperX.2");
DWX.Register("kernel32", "CreateDirectoryW", "i=wp", "r=l"); // LPCWSTR,LPSECURITY_ATTRIBUTES; BOOL

var NULL = 0, FALSE = 0;

// Если безопасность важна, то нужно выделить под структуру память и заполнить параметрами (причем для хостов разной битности будут разные размеры указателей, соответственно, разные смещения):
var bit = DWX.Bitness();
// для x32 размер структуры 12, т.к. sizeof(DWORD) {4 байта} + sizeof(LPVOID) {4 байта} + sizeof(BOOL) {4 байта}, т.е. все alignment'ы равны 0.
// для x64 размер структуры 24, т.к. sizeof(DWORD) {4 байта} + alignment {4 байта} + sizeof(LPVOID) {8 байт} + sizeof(BOOL) {4 байта} + alignment {4 байта}
var nLength = bit === 32 ? 12 : 24; // sizeof(SECURITY_ATTRIBUTES)
var lpSecAttrib = DWX.MemAlloc(nLength);
DWX.NumPut(nLength, lpSecAttrib, 0, "u"); // DWORD
DWX.NumPut(NULL, lpSecAttrib, bit === 32 ? 4 : 8, "p"); // LPVOID
DWX.NumPut(FALSE, lpSecAttrib, bit === 32 ? 8 : 16, "l"); // BOOL
var bResult = DWX.CreateDirectoryW("New folder (1)", lpSecAttrib);
if(bResult !== FALSE) WScript.Echo("OK (1)");
else WScript.Echo("Error (1)");
DWX.MemFree(lpSecAttrib);

// Если безопасность не важна, то функция может принимать и NULL:
var bResult = DWX.CreateDirectoryW("New folder (2)", NULL);
if(bResult !== FALSE) WScript.Echo("OK (2)");
else WScript.Echo("Error (2)");

100 (изменено: Parazit, 2018-03-29 16:41:23)

Re: WSH: обсуждаем DynamicWrapperX от YMP - 2

maksim32, спасибо.
А почему Bool равен 4 байта? Это результат выравнивания?
И для чего вообще делается выравнивание?