Введение в использование скриптовых движков: Часть 2 — Архив WASM.RU

Все статьи

Введение в использование скриптовых движков: Часть 2 — Архив WASM.RU

Введение

Если вы помните, в предыдущей статье было рассказано об основах управления скриптовыми движками, в частности о том, как заставить выполняться простейший скрипт. В том примере было мало интересного - скрипт жил сам по себе и, отработав, просто возвращал управление основной программе. Сейчас настало время рассмотреть более полезные техники, а именно, как передать скрипту какие-нибудь параметры и наоборот - получить от него информацию (например, о результатах работы). В качестве иллюстрации рассмотрим такой пример:

screenshot

Сделаем так, чтобы текст в 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.

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

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

  1. Использует метод QueryInterface, полученного IUnknown для получения указателя на IDispatch.
  2. С помощью GetIDsOfNames преобразует имена методов (свойств) в их идентификаторы.
  3. Вызовет нужный код с помощью Invoke

Следовательно, первое, что нам нужно сделать – подправить метод IUnknown::QueryInterface :

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 будет выглядеть так:

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 мы здесь рассматривать не будем – заменим их чем-нибудь вроде этого:

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 нам не понадобится, т.к. предполагаем, что имена будут только на английском.

Вот примерная (и не совсем корректная) реализация:

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’е (правда, текст этот надо сначала привести в божеский вид):

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, через которую передаются параметры.

typedef struct FARSTRUCT tagDISPPARAMS{
VARIANTARG FAR* rgvarg;
   DISPID FAR* rgdispidNamedArgs;
   Unsigned int cArgs;
   Unsigned int cNamedArgs;
} DISPPARAMS;

Так как параметр нам передается всего один (строка), то достаточно разобрать только rgvarg. Единственная проблема – элемент этого массива – указатель не на саму строку, а на структуру VARIANTARG:

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:

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

Код приложения

;---------------------------------------------------------------------
; 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

Продолжение ожидается...

Файл к статье

2002-2013 (c) wasm.ru