Введение в использование скриптовых движков: Часть 2 — Архив WASM.RU
Введение
Если вы помните, в предыдущей статье было рассказано об основах управления скриптовыми движками, в частности о том, как заставить выполняться простейший скрипт. В том примере было мало интересного - скрипт жил сам по себе и, отработав, просто возвращал управление основной программе. Сейчас настало время рассмотреть более полезные техники, а именно, как передать скрипту какие-нибудь параметры и наоборот - получить от него информацию (например, о результатах работы). В качестве иллюстрации рассмотрим такой пример:
Сделаем так, чтобы текст в EditBox’е можно было изменять из скрипта.
В прошлый раз я говорил о том, что необходимым условием для использования COM-объекта является знание структуры его интерфейсов. Однако далеко не всегда такое возможно, как например в нашем случае. Например, так будет выглядеть скрипт, устанавливающий содержимое контрола Edit равным "some text":
Edit1.Text = "some sext"
Edit1 - это имя нашего объекта, а Text - свойство, подлежащее установке. Ясно, что никаких данных о структуре интерфейса из этого извлечь нельзя, поэтому нужно располагать некоторым средством, позволяющим вызывать методы по их именам. Такое средство есть, в COM оно известно, как "позднее связывание" (late binding).
LATE BINDING.
Скажу сразу, что здесь мы рассмотрим только тот минимум, что необходим для работы. Как уже было сказано выше, позднее связывание применяется в тех случаях, когда по каким-либо причинам невозможно (или неудобно) предоставить информацию о структуре интерфейса.
Выходом является использование интерфейса IDispatch, который возволяет вызвать нужную процедуру по ее имени. Он содержит следующие методы:
- GetTypeInfoCount
- GetTypeInfo
- GetIDsOfNames
- Invoke
(нет необходимости говорить о том, что IDispatch тоже наследуется от IUnknown).
Из этих методов нам интересны два последних, обычно их использование выглядит так: сначала методу GetIDsOfNames передается массив с адресами имен нужного метода (свойства) и его параметров, он этот массив просматривает и устанавливает соответствие между именем и некоторым числом, представляющим собой уникальный (в пределах интефейса) ID (обычно говорят “DISPID”) данного элемента. Далее этот DISPID передается методу Invoke, который и производит вызов процедуры.
Имя объекта
С именем объекта все гораздо проще – достаточно указать движку, что за именем “Edit1” скрывается объект.
Делается это при помощи вызова IActiveScript::AddNamedItem.
HRESULT AddNamedItem(LPCOLESTR pstrName, DWORD dwFlags);
pstrName – указатель на имя в формате WideCharacter.
dwFlags может принимать разные значения, в зависимости от поставленной задачи, мы укажем флаг SCRIPTITEM_ISVISIBLE, показывающий, что pstrName – это имя объекта и мы предоставляем средства для доступа к его методам и свойствам.
mov edx, [pIActiveScript] mov edx, [edx] push SCRIPTITEM_ISVISIBLE push Item_name push [pIActiveScript] call dword [edx + AddNamedItem]Теперь, когда движок встретит конструкцию Edit1.Method он вызовет метод IActiveScriptSite::GetItemInfo, чтобы получить интерфейс IDispatch, который контролирует данный объект.
HRESULT GetItemInfo(LPCOLESTR pstrName, DWORD dwReturnMask, IUnknown **ppunkItem, ITypeInfo **ppTypeInfo);
pstrName – указатель на имя объекта.
dwReturnMask – показывает, какая именно информация запрашивается. Может принимать значения:
- SCRIPTINFO_IUNKNOWN – запрашивается IUnknown
- SCRIPTINFO_ITYPEINFO – запрашивается ITypeInfo
ppunkItem, ppTypeInfo – адреса переменных, в которые будут помещены указатели на интерфейсы. Здесь есть один момент, который заслуживает внимания – дело в том, что вышеописанный IDispatch – не едиственный способ осуществить связывание имен. В качестве альтернативы может использоваться интерфейс ITypeInfo, но мы не будем его реализовывать и все сделаем через IDispatch, поэтому если наш метод GetItemInfo получает параметр dwReturnMask с установленным SCRIPTINFO_ITYPEINFO, он должен будет вернуть 0 в ppTypeInfo.
Код (Text):
proc IActiveScriptSite_GetItemInfo, pi, pstrName, dwReturnMask, ppunkItem, ppTypeInfo enter ;Сравниваем переданное имя с “Edit1”. invoke lstrcmpW, [pstrName], Item_name test eax, eax jz @F mov eax, TYPE_E_ELEMENTNOTFOUND return @@: mov eax, [dwReturnMask] cmp eax, SCRIPTINFO_IUNKNOWN jz .IUnknown cmp eax, SCRIPTINFO_ALL_FLAGS jz .IUnknown cmp eax, SCRIPTINFO_ITYPEINFO jz .ITypeInfo mov eax, E_INVALIDARG return .IUnknown: mov eax, [ppunkItem] mov edx, IDispatch mov [eax], edx mov edx, [edx] push IDispatch call dword [edx + Addref] .ITypeInfo: mov eax, [ppTypeInfo] test eax, eax jz @F and dword [eax], 0 @@: mov eax, S_OK returnТеперь, чтобы вызвать нужный метод движок предпримет следующие действия:
- Использует метод QueryInterface, полученного IUnknown для получения указателя на IDispatch.
- С помощью GetIDsOfNames преобразует имена методов (свойств) в их идентификаторы.
- Вызовет нужный код с помощью Invoke
Следовательно, первое, что нам нужно сделать – подправить метод IUnknown::QueryInterface :
Код (Text):
proc IActiveScriptSite_QueryInterface, pi, iid, ppvObject enter invoke IsEqualGUID, [iid], IID_IUnknown test eax, eax jnz .s_ok_unk invoke IsEqualGUID, [iid], IID_IActiveScriptSite test eax, eax jnz .s_ok_unk invoke IsEqualGUID, [iid], IID_IActiveScriptSiteWindow test eax, eax jnz .s_ok_acw invoke IsEqualGUID, [iid], IID_IDispatch test eax, eax jnz .s_ok_dsp .NoInterface: mov eax, E_NOINTERFACE return .s_ok: mov edx, [pIActiveScriptSite] mov edx, [edx] push [pIActiveScriptSite] call dword [edx + Addref] mov eax, S_OK return .s_ok_unk: mov eax, [ActiveScriptSiteObject] mov eax, [eax] mov edx, [ppvObject] mov [edx], eax jmp .s_ok .s_ok_acw: mov eax, [ActiveScriptSiteObject] mov eax, [eax + 4] mov edx, [ppvObject] mov [edx], eax jmp .s_ok .s_ok_dsp: ;если iid == IDispath, то вернем указатель на него. mov eax, [ActiveScriptSiteObject] mov eax, IDispatch mov edx, [ppvObject] mov [edx], eax jmp .s_okТеперь QueryInterface способен воспринимать GUID IDispatch (00020400-0000-0000-C000-000000000046), а сам IDispatch будет выглядеть так:
Код (Text):
IDispatch dd IDispatch_vtable ;первые 3 – методы IUnknown, общие для всех интерфейсов нашего объекта. IDispatch_vtable dd IActiveScriptSite_QueryInterface dd IActiveScriptSite_AddRef dd IActiveScriptSite_Release dd IDispatch_GetTypeInfoCount dd IDispatch_GetTypeInfo dd IDispatch_GetIDsOfNames dd IDispatch_InvokeМетоды GetTypeInfoCount и GetTypeInfo мы здесь рассматривать не будем – заменим их чем-нибудь вроде этого:
Код (Text):
proc IDispatch_GetTypeInfoCount, pi, pctinfo enter mov eax, [pctinfo] mov dword [eax], 0 mov eax, S_OK return proc IDispatch_GetTypeInfo, pi, iTInfo, lcid, ppTInfo enter mov eax, DISP_E_BADINDEX returnА вот без Invoke и GetIDsOfNames не обойтись.
HRESULT GetIDsOfNames(REFIID riid, OLECHAR FAR* FAR* rgszNames, unsigned int cNames, LCID lcid, DISPID FAR* rgDispId);
riid – reserved (всегда 0).
rgszNames – указатель на массив указателей на строки, содержащие имена (первый представляет собой имя метода/свойства, следующие - имена параметров).
cNames – количество элементов массива.
rgDispId – указатель на массив, в который будут помещены ID, соответствующие именам из rgszNames. Если имя не опознано, то в соответствующий элемент массива rgDispId должно быть помещено значение -1.
lcid нам не понадобится, т.к. предполагаем, что имена будут только на английском.
Вот примерная (и не совсем корректная) реализация:
Код (Text):
proc IDispatch_GetIDsOfNames, pi, riid, rgszNames, cNames, lcid, rgDispId enter pushad mov esi, [rgszNames] mov ebx, [rgDispId] lodsd invoke lstrcmpW, eax, szSetText test eax, eax jnz @F ;Пусть DISPID будет равен 1 mov dword [ebx], 1 popad mov eax, S_OK return @@: or dword [ebx], -1 popad ;Было передано имя несуществующего элемента. mov eax, DISP_E_UNKNOWNNAME returnПозволю себе сделать небольшое отступление, перед тем, как привести исходный код метода Invoke. Дело в том, что IDispatch представляет из себя только диспетчер, который вызывает нужную процедуру в зависимости от переданного DISPID, поэтому нам нужно написать код, устанавливающий текст в EditBox’е (правда, текст этот надо сначала привести в божеский вид):
Код (Text):
proc SetText, pNewText enter pushad mov ebx, [pNewText] ;определим необходимое кол-во памяти. invoke WideCharToMultiByte, CP_ACP, 0, ebx, -1, 0, 0, 0, 0 push MEM_DECOMMIT push eax invoke VirtualAlloc, 0, eax, MEM_COMMIT, PAGE_READWRITE pop ecx push ecx push eax invoke WideCharToMultiByte, CP_ACP, 0, ebx, -1, eax, ecx, 0, 0 invoke GetDlgItem, [hWnd], 1002 mov ecx, [esp] invoke SetWindowTextA, eax, ecx invoke VirtualFree popad mov eax, S_OK returnТеперь займемся самим методом IDispatch::Invoke
HRESULT Invoke(DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS FAR* pDispParams, VARIANT FAR* pVarResult, EXCEPINFO FAR* pExcepInfo, unsigned int FAR* puArgErr);
dispIdMember – вызываемый ID (в нашем случае 1).
riid - Reserved. Должен быть IID_NULL.
wFlags может принимать значения:
- DISPATCH_METHOD
- DISPATCH_PROPERTYGET
- DISPATCH_PROPERTYPUT (в нашем случае будет именно это значение)
pDispParams – указатель на структуру DISPPARAMS, через которую передаются параметры.
Код (Text):
typedef struct FARSTRUCT tagDISPPARAMS{ VARIANTARG FAR* rgvarg; DISPID FAR* rgdispidNamedArgs; Unsigned int cArgs; Unsigned int cNamedArgs; } DISPPARAMS;Так как параметр нам передается всего один (строка), то достаточно разобрать только rgvarg. Единственная проблема – элемент этого массива – указатель не на саму строку, а на структуру VARIANTARG:
Код (Text):
typedef struct FARSTRUCT tagVARIANT VARIANTARG; typedef struct tagVARIANT { VARTYPE vt; unsigned short wReserved1; unsigned short wReserved2; unsigned short wReserved3; union { Byte bVal; // VT_UI1. Short iVal; // VT_I2. long lVal; // VT_I4. float fltVal; // VT_R4. double dblVal; // VT_R8. VARIANT_BOOL boolVal; // VT_BOOL. SCODE scode; // VT_ERROR. CY cyVal; // VT_CY. DATE date; // VT_DATE. BSTR bstrVal; // VT_BSTR. DECIMAL FAR* pdecVal; //VT_BYREF|VT_DECIMAL. IUnknown FAR* punkVal; // VT_UNKNOWN. IDispatch FAR* pdispVal; //VT_DISPATCH. SAFEARRAY FAR* parray; // VT_ARRAY|*. Byte FAR* pbVal; //VT_BYREF|VT_UI1. short FAR* piVal; //VT_BYREF|VT_I2. long FAR* plVal; //VT_BYREF|VT_I4. float FAR* pfltVal; //VT_BYREF|VT_R4. double FAR* pdblVal; //VT_BYREF|VT_R8. VARIANT_BOOL FAR* pboolVal; //VT_BYREF|VT_BOOL. SCODE FAR* pscode; //VT_BYREF|VT_ERROR. CY FAR* pcyVal; //VT_BYREF|VT_CY. DATE FAR* pdate; //VT_BYREF|VT_DATE. BSTR FAR* pbstrVal; //VT_BYREF|VT_BSTR. IUnknown FAR* FAR* ppunkVal; //VT_BYREF|VT_UNKNOWN. IDispatch FAR* FAR* ppdispVal; //VT_BYREF|VT_DISPATCH. SAFEARRAY FAR* FAR* pparray; // VT_ARRAY|*. VARIANT FAR* pvarVal; //VT_BYREF|VT_VARIANT. void FAR* byref; // GenericByRef. char cVal; // VT_I1. unsigned short uiVal; // VT_UI2. unsigned long ulVal; // VT_UI4. int intVal; // VT_INT. unsigned int uintVal; // VT_UINT. char FAR * pcVal; //VT_BYREF|VT_I1. unsigned short FAR * puiVal; //VT_BYREF|VT_UI2. unsigned long FAR * pulVal; //VT_BYREF|VT_UI4. int FAR * pintVal; //VT_BYREF|VT_INT. unsigned int FAR * puintVal; //VT_BYREF|VT_UINT. }; };Как видите, сам указатель находится по смещению +08 от начала структуры.
Вот теперь можно привести код Invoke:
Код (Text):
proc IDispatch_Invoke, pi, dispIdMember, riid, lcid, wFlags, pDispParams, \ pVarResult, pExcepInfo, puArgErr enter mov eax, [dispIdMember] dec eax jnz IDispatch_Invoke.notfound mov edx, [pDispParams] mov edx, [edx] mov edx, [edx + 8] push edx call SetText mov eax, S_OK return .notfound: mov eax, DISP_E_MEMBERNOTFOUND returnКод приложения
Код (Text):
;--------------------------------------------------------------------- ; RunScript.asm ;--------------------------------------------------------------------- format PE GUI 4.0 entry start include 'RunScript.inc' section '.scrpt' code readable executable start: invoke GetModuleHandleA, 0 mov [hInst], eax invoke DialogBoxParamA, eax, 1000, HWND_DESKTOP, DlgProc, 0 invoke ExitProcess, 0 proc DlgProc, hwnd, msg, wparam, lparam enter cmp [msg], WM_INITDIALOG jz wminitdialog cmp [msg], WM_COMMAND jz wmcommand cmp [msg], WM_CLOSE jz wmclose sub eax, eax jmp finish wminitdialog: mov eax, [hwnd] mov [hWnd], eax invoke VirtualAlloc, 0, MAX_PATH, MEM_COMMIT, PAGE_READWRITE mov [szFileName], eax call StartScriptEngine jmp processed wmcommand: cmp [wparam], BN_CLICKED shl 16 + 1001 jnz processed mov eax, [szFileName] mov ecx, 257 @@: mov byte [eax], 0 inc eax dec ecx jnz @B push szFilter push szTitle push dword [hwnd] call GetFileName mov ecx, [szFileName] mov ecx, [ecx] jecxz processed call LoadScript test eax, eax jz processed push eax call RunScript jmp processed wmclose: invoke VirtualFree, [szFileName], MAX_PATH, MEM_DECOMMIT mov edx, [pIActiveScript] push edx mov edx, [edx] call dword [edx + Close] mov edx, [pIActiveScriptParse] push edx mov edx, [edx] call dword [edx + Release] mov edx, [pIActiveScript] push edx mov edx, [edx] push [pIActiveScript] call dword [edx + Release] mov edx, [pIActiveScriptSite] push edx mov edx, [edx] call dword [edx + Release] invoke EndDialog, [hwnd], 0 processed: sub eax, eax inc eax finish: return proc StartScriptEngine enter invoke CoInitialize, 0 invoke CoCreateInstance, CLSID_VBScript, 0, CLSCTX_INPROC_SERVER, \ IID_IActiveScript, pIActiveScript test eax, eax js error.create_instance invoke LocalAlloc, LMEM_FIXED, 16 test eax, eax jz error.alloc mov [ActiveScriptSiteObject], eax mov dword [eax], IActiveScriptSite mov dword [eax + 04], IActiveScriptSiteWindow mov dword [eax + 08], IDispatch mov dword [eax + 12], 1 mov edx, [pIActiveScript] mov edx, [edx] push pIActiveScriptParse push IID_IActiveScriptParse push [pIActiveScript] call dword [edx + QueryInterface] test eax, eax js .ok mov edx, IActiveScriptSite mov [pIActiveScriptSite], edx .ok: sub eax, eax return error: .alloc: mov eax, E_OUTOFMEMORY return .create_instance: sub eax, eax dec eax return proc LoadScript enter invoke CreateFileA, [szFileName], GENERIC_READ, FILE_SHARE_READ, NULL, \ OPEN_EXISTING, FILE_ATTRIBUTE_ARCHIVE, NULL test eax, eax jz LoadScript.finish mov [hFile], eax invoke GetFileSize, eax, 0 mov [FileSize], eax mov ecx, eax inc eax inc eax shl eax, 1 push eax add eax, ecx mov [buffer_size], eax invoke VirtualAlloc, 0, eax, MEM_COMMIT, PAGE_READWRITE mov [pMemory], eax add eax, dword [FileSize] inc eax mov [pScript], eax push eax lea ecx, [esp] invoke ReadFile, [hFile], [pMemory], [FileSize], ecx, NULL pop ecx invoke CloseHandle, [hFile] pop eax invoke MultiByteToWideChar, 0, 0, [pMemory], -1, [pScript], eax mov eax, [pScript] .finish: return proc RunScript, lpScript enter mov edx, [pIActiveScriptSite] mov edx, [edx] push [pIActiveScriptSite] call dword [edx + Addref] mov edx, [pIActiveScript] mov edx, [edx] push [pIActiveScriptSite] push [pIActiveScript] call dword [edx + SetScriptSite] mov edx, [pIActiveScriptParse] mov edx, [edx] push [pIActiveScriptParse] call dword [edx + InitNew] mov edx, [pIActiveScript] mov edx, [edx] push SCRIPTITEM_ISVISIBLE push Item_name push [pIActiveScript] call dword [edx + AddNamedItem] mov edx, [pIActiveScriptParse] mov edx, [edx] mov eax, [lpScript] sub ecx, ecx push ecx push ecx push ecx push ecx push ecx push ecx push ecx push ecx push eax push [pIActiveScriptParse] call dword [edx + ParseScriptText] mov edx, [pIActiveScript] mov edx, [edx] push SCRIPTSTATE_CONNECTED push [pIActiveScript] call dword [edx + SetScriptState] invoke VirtualFree, [pMemory], [buffer_size], MEM_DECOMMIT return proc IActiveScriptSite_GetLCID, pi, plcid enter mov eax, E_NOTIMPL return proc IActiveScriptSite_GetItemInfo, pi, pstrName, dwReturnMask, ppunkItem, ppTypeInfo enter invoke lstrcmpW, [pstrName], Item_name test eax, eax jz @F mov eax, TYPE_E_ELEMENTNOTFOUND return @@: mov eax, [dwReturnMask] cmp eax, SCRIPTINFO_IUNKNOWN jz .IUnknown cmp eax, SCRIPTINFO_ALL_FLAGS jz .IUnknown cmp eax, SCRIPTINFO_ITYPEINFO jz .ITypeInfo mov eax, E_INVALIDARG return .IUnknown: mov eax, [ppunkItem] mov edx, IDispatch mov [eax], edx mov edx, [edx] push IDispatch call dword [edx + Addref] .ITypeInfo: mov eax, [ppTypeInfo] test eax, eax jz @F and dword [eax], 0 @@: mov eax, S_OK return proc IActiveScriptSite_GetDocVersionString, pi, pbstrVersionString enter mov eax, E_NOTIMPL return proc IActiveScriptSite_OnScriptTerminate, pi, pvarResult, pexcepinfo enter mov eax, S_OK return proc IActiveScriptSite_OnStateChange, pi, ssScriptState enter mov eax, S_OK return proc IActiveScriptSite_OnScriptError, pi, pase enter invoke MessageBoxA, 0, mess1, mess1_title, MB_OK + MB_ICONERROR mov eax, S_OK return proc IActiveScriptSite_OnEnterScript, pi enter mov eax, S_OK return proc IActiveScriptSite_OnLeaveScript, pi enter mov eax, S_OK return proc IActiveScriptSite_AddRef, pi enter mov ecx, [ActiveScriptSiteObject] inc dword [ecx + 12] mov eax, [ecx + 12] return proc IActiveScriptSite_Release, pi enter mov ecx, [ActiveScriptSiteObject] dec dword [ecx + 12] mov eax, [ecx + 12] test eax, eax jnz @F invoke LocalFree, ecx @@: return proc IActiveScriptSite_QueryInterface, pi, iid, ppvObject enter invoke IsEqualGUID, [iid], IID_IUnknown test eax, eax jnz .s_ok_unk invoke IsEqualGUID, [iid], IID_IActiveScriptSite test eax, eax jnz .s_ok_unk invoke IsEqualGUID, [iid], IID_IActiveScriptSiteWindow test eax, eax jnz .s_ok_acw invoke IsEqualGUID, [iid], IID_IDispatch test eax, eax jnz .s_ok_dsp .NoInterface: mov eax, E_NOINTERFACE return .s_ok: mov edx, [pIActiveScriptSite] mov edx, [edx] push [pIActiveScriptSite] call dword [edx + Addref] mov eax, S_OK return .s_ok_unk: mov eax, [ActiveScriptSiteObject] mov eax, [eax] mov edx, [ppvObject] mov [edx], eax jmp .s_ok .s_ok_acw: mov eax, [ActiveScriptSiteObject] mov eax, [eax + 4] mov edx, [ppvObject] mov [edx], eax jmp .s_ok .s_ok_dsp: mov eax, [ActiveScriptSiteObject] mov eax, [eax + 8] mov edx, [ppvObject] mov [edx], eax jmp .s_ok proc IActiveScriptSiteWindow_GetWindow, pi, phwnd enter mov ecx, [phwnd] mov eax, [hWnd] mov [ecx], eax mov eax, S_OK return proc IActiveScriptSiteWindow_EnableModeless, pi, fEnable enter mov eax, S_OK return proc IDispatch_GetTypeInfoCount, pi, pctinfo enter mov eax, [pctinfo] mov dword [eax], 0 mov eax, S_OK return proc IDispatch_GetTypeInfo, pi, iTInfo, lcid, ppTInfo enter mov eax, DISP_E_BADINDEX return proc IDispatch_GetIDsOfNames, pi, riid, rgszNames, cNames, lcid, rgDispId enter pushad mov esi, [rgszNames] mov ebx, [rgDispId] lodsd invoke lstrcmpW, eax, szSetText test eax, eax jnz @F mov dword [ebx], 1 popad mov eax, S_OK return @@: or dword [ebx], -1 popad mov eax, DISP_E_UNKNOWNNAME return proc SetText, pNewText enter pushad mov ebx, [pNewText] invoke WideCharToMultiByte, CP_ACP, 0, ebx, -1, 0, 0, 0, 0 push MEM_DECOMMIT push eax invoke VirtualAlloc, 0, eax, MEM_COMMIT, PAGE_READWRITE pop ecx push ecx push eax invoke WideCharToMultiByte, CP_ACP, 0, ebx, -1, eax, ecx, 0, 0 invoke GetDlgItem, [hWnd], 1002 mov ecx, [esp] invoke SetWindowTextA, eax, ecx invoke VirtualFree popad mov eax, S_OK return proc IDispatch_Invoke, pi, dispIdMember, riid, lcid, wFlags, pDispParams, pVarResult, \ pExcepInfo, puArgErr enter mov eax, [dispIdMember] dec eax jnz IDispatch_Invoke.notfound mov edx, [pDispParams] mov edx, [edx] mov edx, [edx + 8] push edx call SetText mov eax, S_OK return .notfound: mov eax, DISP_E_MEMBERNOTFOUND return proc GetFileName, hParent, lpTitle, lpFilter enter mov eax, [hParent] mov [ofn.hwndOwner], eax mov eax, [hInst] mov [ofn.hInstance], eax mov eax, [lpFilter] mov [ofn.lpstrFilter], eax mov eax, [szFileName] mov [ofn.lpstrFile], eax mov [ofn.nMaxFile], MAX_PATH mov eax, [lpTitle] mov [ofn.lpstrTitle], eax mov [ofn.Flags], OFN_EXPLORER or OFN_FILEMUSTEXIST or OFN_LONGNAMES invoke GetOpenFileName, ofn return section '.data' data readable writeable ofn OPENFILENAMEA mess1 db "Cant't parse it!", 0 mess1_title db 'script engine', 0 szFilter db 'VBScripts', 0, '*.vbs', 0, \ 'All files', 0, '*.*', 0, 0 szTitle db 'Just open script-file...', 0 szFileName dd 0 hInst dd 0 ActiveScriptSiteObject dd 0 hWnd dd 0 hFile dd 0 FileSize dd 0 buffer_size dd 0 pMemory dd 0 pScript dd 0 Item_name dw "E", "d", "i", "t", "1", 0 szSetText dw "S", "e", "t", "T", "e", "x", "t", 0 pIActiveScript dd 0 pIActiveScriptParse dd 0 pIActiveScriptSite dd 0 CLSID_VBScript GUID 0b54f3741h, 5b07h, 11cfh, 0a4h, 0b0h, 0, 0aah, 0, \ 4ah, 55h, 0e8h IID_IActiveScript GUID 0bb1a2ae1h, 0a4f9h, 11cfh, 8fh, 20h, 0, 80h, \ 5fh, 2ch, 0d0h, 64h IID_IActiveScriptParse GUID 0bb1a2ae2h, 0a4f9h, 11cfh, 8fh, 20h, 0, \ 80h, 5fh, 2ch, 0d0h, 64h IID_IActiveScriptSite GUID 0d57d7817h, 0e9b7h, 04a82h, 85h, 74h, 01h, \ 0d0h, 0f9h, 3dh, 61h, 70h IID_IActiveScriptSiteWindow GUID 0d10f6761h, 083e9h, 011cfh, 8fh, 20h, \ 0, 80h, 5fh, 2ch, 0d0h, 64h IID_IUnknown GUID 0, 0, 0, 0ch, 0, 0, 0, 0, 0, 0, 46h IID_IDispatch GUID 00020400h, 0, 0, 0c0h, 0, 0, 0, 0, 0, 0, 46h IActiveScriptSite dd IActiveScriptSite_vtable IActiveScriptSiteWindow dd IActiveScriptSiteWindow_vtable IDispatch dd IDispatch_vtable IActiveScriptSite_vtable dd IActiveScriptSite_QueryInterface dd IActiveScriptSite_AddRef dd IActiveScriptSite_Release dd IActiveScriptSite_GetLCID dd IActiveScriptSite_GetItemInfo dd IActiveScriptSite_GetDocVersionString dd IActiveScriptSite_OnScriptTerminate dd IActiveScriptSite_OnStateChange dd IActiveScriptSite_OnScriptError dd IActiveScriptSite_OnEnterScript dd IActiveScriptSite_OnLeaveScript IActiveScriptSiteWindow_vtable dd IActiveScriptSite_QueryInterface dd IActiveScriptSite_AddRef dd IActiveScriptSite_Release dd IActiveScriptSiteWindow_GetWindow dd IActiveScriptSiteWindow_EnableModeless IDispatch_vtable dd IActiveScriptSite_QueryInterface dd IActiveScriptSite_AddRef dd IActiveScriptSite_Release dd IDispatch_GetTypeInfoCount dd IDispatch_GetTypeInfo dd IDispatch_GetIDsOfNames dd IDispatch_Invoke QueryInterface = 0 Addref = 04h Release = 08h Close = 1ch SetScriptSite = 0ch InitNew = 0ch ParseScriptText = 14h SetScriptState = 14h AddNamedItem = 20h section '.idata' import data readable writeable library kernel32, 'kernel32.dll', \ user32, 'user32.dll', \ ole32, 'ole32.dll', \ comdlg32, 'comdlg32.dll' import kernel32, ExitProcess, 'ExitProcess', \ LocalAlloc, 'LocalAlloc', \ LocalFree, 'LocalFree', \ GetModuleHandleA, 'GetModuleHandleA', \ CreateFileA, 'CreateFileA', \ CloseHandle, 'CloseHandle', \ ReadFile, 'ReadFile', \ GetFileSize, 'GetFileSize', \ MultiByteToWideChar, 'MultiByteToWideChar', \ WideCharToMultiByte, 'WideCharToMultiByte', \ VirtualAlloc, 'VirtualAlloc', \ VirtualFree, 'VirtualFree', \ lstrcmpW, 'lstrcmpW' import ole32, CoInitialize, 'CoInitialize', \ CoCreateInstance, 'CoCreateInstance', \ IsEqualGUID, 'IsEqualGUID' import user32, DialogBoxParamA, 'DialogBoxParamA', \ EndDialog, 'EndDialog', \ MessageBoxA, 'MessageBoxA', \ SetWindowTextA, 'SetWindowTextA', \ GetDlgItem, 'GetDlgItem' import comdlg32, GetOpenFileName, 'GetOpenFileNameA' section '.rsrc' resource data readable directory RT_DIALOG, dialogs resource dialogs, 1000, LANG_ENGLISH+SUBLANG_DEFAULT, main_dlg dialog main_dlg, 'RunScript', 70, 70, 170, 70, \ WS_CAPTION + WS_POPUP + WS_SYSMENU + DS_MODALFRAME dialogitem 'BUTTON', 'Execute Script!', 1001, 52, 35, 55, 15, \ WS_VISIBLE + WS_TABSTOP + BS_PUSHBUTTON dialogitem 'EDIT', '', 1002, 10, 15, 150, 15, WS_VISIBLE + WS_BORDER + WS_TABSTOP enddialog ;--------------------------------------------------------------------- ; RunScript.inc ;--------------------------------------------------------------------- include 'include\win32ax.inc' CLSCTX_INPROC_SERVER equ 1 CLSCTX_INPROC_HANDLER equ 2 CLSCTX_LOCAL_SERVER equ 4 CLSCTX_INPROC_SERVER16 equ 8 CLSCTX_REMOTE_SERVER equ 10h CLSCTX_INPROC_HANDLER16 equ 20h CLSCTX_INPROC_SERVERX86 equ 40h CLSCTX_INPROC_HANDLERX86 equ 80h CLSCTX_ESERVER_HANDLER equ 100h E_NOTIMPL equ 80004001h E_NOINTERFACE equ 80004002h E_INVALIDARG equ 80070057h TYPE_E_ELEMENTNOTFOUND equ 8002802Bh S_OK equ 0 LMEM_FIXED equ 0h E_OUTOFMEMORY equ 8007000Eh SCRIPTSTATE_UNINITIALIZED equ 0h SCRIPTSTATE_STARTED equ 1h SCRIPTSTATE_CONNECTED equ 2h SCRIPTSTATE_DISCONNECTED equ 3h SCRIPTSTATE_CLOSED equ 4h SCRIPTSTATE_INITIALIZED equ 5h CP_ACP equ 0 SCRIPTITEM_ISVISIBLE equ 000000002h SCRIPTITEM_ISSOURCE equ 000000004h SCRIPTITEM_GLOBALMEMBERS equ 000000008h SCRIPTITEM_ISPERSISTENT equ 000000040h SCRIPTITEM_CODEONLY equ 000000200h SCRIPTITEM_NOCODE equ 000000400h SCRIPTITEM_ALL_FLAGS equ 00000064eh SCRIPTINFO_IUNKNOWN equ 000000001h SCRIPTINFO_ITYPEINFO equ 000000002h SCRIPTINFO_ALL_FLAGS equ 000000003h CC_STDCALL equ 4h DISPATCH_METHOD equ 1 DISPATCH_PROPERTYGET equ 2 DISPATCH_PROPERTYPUT equ 4 DISPATCH_PROPERTYPUTREF equ 8 DISP_E_BADINDEX equ 8002000Bh DISP_E_MEMBERNOTFOUND equ 80020003h DISP_E_UNKNOWNNAME equ 80020006h VT_EMPTY equ 0 VT_NULL equ 1 VT_I2 equ 2 VT_I4 equ 3 VT_R4 equ 4 VT_R8 equ 5 VT_CY equ 6 VT_DATE equ 7 VT_BSTR equ 8 VT_DISPATCH equ 9 VT_ERROR equ 10 VT_BOOL equ 11 VT_VARIANT equ 12 VT_UNKNOWN equ 13 VT_DECIMAL equ 14 VT_I1 equ 16 VT_UI1 equ 17 VT_UI2 equ 18 VT_UI4 equ 19 VT_I8 equ 20 VT_UI8 equ 21 VT_INT equ 22 VT_UINT equ 23 VT_VOID equ 24 VT_HRESULT equ 25 VT_PTR equ 26 VT_SAFEARRAY equ 27 VT_CARRAY equ 28 VT_USERDEFINED equ 29 VT_LPSTR equ 30 VT_LPWSTR equ 31 VT_RECORD equ 36 VT_FILETIME equ 64 VT_BLOB equ 65 VT_STREAM equ 66 VT_STORAGE equ 67 VT_STREAMED_OBJECT equ 68 VT_STORED_OBJECT equ 69 VT_BLOB_OBJECT equ 70 VT_CF equ 71 VT_CLSID equ 72 VT_BSTR_BLOB equ 0fffh VT_VECTOR equ 1000h VT_ARRAY equ 2000h VT_BYREF equ 4000h VT_RESERVED equ 8000h VT_ILLEGAL equ 0ffffh VT_ILLEGALMASKED equ 0fffh VT_TYPEMASK equ 0fffh struc GUID dd1, dw1, dw2, db1, db2, db3, db4, db5, db6, db7, db8 { .dd1 dd dd1 .dw1 dw dw1 .dw2 dw dw2 .db1 db db1 .db2 db db2 .db3 db db3 .db4 db db4 .db5 db db5 .db6 db db6 .db7 db db7 .db8 db db8 } MAX_PATH equ 260 struc OPENFILENAMEA { .lStructSize dd 4ch .hwndOwner dd 0 .hInstance dd 0 .lpstrFilter dd 0 .lpstrCustomFilter dd 0 .nMaxCustFilter dd 0 .nFilterIndex dd 0 .lpstrFile dd 0 .nMaxFile dd 0 .lpstrFileTitle dd 0 .nMaxFileTitle dd 0 .lpstrInitialDir dd 0 .lpstrTitle dd 0 .Flags dd 0 .nFileOffset dw 0 .nFileExtension dw 0 .lpstrDefExt dd 0 .lCustData dd 0 .lpfnHook dd 0 .lpTemplateName dd 0 } struct OPENFILENAMEAПродолжение ожидается...
Файл к статье © Hangatyr
Введение в использование скриптовых движков: Часть 2
Дата публикации 24 фев 2004