;-------------------------------------------------------------------------------
; Active Script demo app
; copyright 2001 Ernest Murphy 1/8/01
; 
; For educational use only. Any commercial re-use only by written license
;
;-------------------------------------------------------------------------------
.386
.model flat,stdcall
option casemap:none
.NOLIST
;-------------------------------------------------------------------------------

include \masm32\include\windows.inc
include \masm32\include\user32.inc
include \masm32\include\kernel32.inc
include \masm32\include\comctl32.inc
include \masm32\include\ole32.inc
include \masm32\include\oleaut32.inc

include \masm32\COM\include\oaidl.inc
include \masm32\COM\include\colib.inc
include \masm32\COM\include\L.inc
include \masm32\COM\include\ACTIVSCP.inc    ; NEW colib file
include IScriptText.inc

includelib \masm32\COM\colib\colib.lib
includelib \masm32\lib\user32.lib
includelib \masm32\lib\kernel32.lib
includelib \masm32\lib\ole32.lib 
includelib \masm32\lib\oleaut32.lib 
includelib \masm32\lib\COMCTL32.LIB

.LISTALL
;-------------------------------------------------------------------------------
; PROTOS
StartScriptEngine   proto
RunScript           proto
WinMain             proto :DWORD,:DWORD,:DWORD,:DWORD
ScriptDlgProc       proto :DWORD,:DWORD,:DWORD,:DWORD
LoadScript          proto :DWORD
lstrcmpiW           proto :DWORD,:DWORD

 ; as of CoLib 1.1, ClassMap is no longer required
 ; PUBLIC ClassMap     ; thanks to Maurice MONTGENIE for pointing out this ommision
 ;                     ; (Resolves a LINK problem in that DllGetClassObject IS linked,
 ;                     ; but not called. That object needs this definition)
 ;                     ; (When colib2 is released and we can delete this again)
;-------------------------------------------------------------------------------
.data
 ; ClassMap        DWORD       NULL        ; also needed with the PUBLIC up there
ClassName       BYTE        "SimpleWinClass",0
AppName         BYTE        "Scripter Test App",0
MenuName        BYTE        "FirstMenu",0
ButtonClassName BYTE        "button",0
ButtonText      BYTE        "Run Script",0
ScriptFile      BYTE        "MyScript.vbs",0
EditClassName   BYTE        "edit",0
;TestString      BYTE        "Wow! I'm in an edit box now",0
wsApplication   wchar       L(<Application\0>)
pwsApplication  EQU         OFFSET wsApplication
ButtonHeight    EQU         25
MinWidth        EQU         75
MinHeight       EQU         75

hwndScriptBox   DWORD       0
pIAS            DWORD       0       ; IActiveScript of script engine
pIASP           DWORD       0       ; IActiveScriptParse of script engine
pASSite         DWORD       0       ; IActiveScriptSite of this exe
pScrText        DWORD       0       ; IScriptText object of this exe

InitComCtrls    INITCOMMONCONTROLSEX {SIZEOF INITCOMMONCONTROLSEX, ICC_BAR_CLASSES} 

; describe the interface classes inside the .exe
;-------------------------------------------------------------------------------
; ScriptText interface
ScriptTextClass ClassItem { pCLSID_ScriptText, DISPINTERFACE + SUPPLY_TYPE_INFO, \
                            OFFSET ScriptTextTypeLibInfo, OFFSET ScriptTextIMap, \
                            NULL, NULL, NULL, SIZEOF ScriptTextObject }


; describe the ScriptText object's interfaces
ScriptTextIMap  InterfaceItem { pIID_IScriptText,  OFFSET vtableIScriptText }
            END_INTERFACE_MAP

; describe the type libraries
ScriptTextTypeLibInfo   TypeLibInfo     { pLIBID_ScriptText, 1, 0 }     

; the ScriptText object needs no data members
ScriptTextObjData   STRUCT                  ; ScriptText object private data struct

ScriptTextObjData   ENDS

; step 2
ScriptTextObject    STRUCT
    ObjectData0     ObjectData      { } ; base values
;   ScriptTextObjData0  ScriptTextObjData   { } ; custom object data does not exist
    ObjectEntry0    ObjectEntry     { } ; delegated Unknown
    ObjectEntry1    ObjectEntry     { } ; IScriptText
ScriptTextObject    ENDS

; fill in the vtable
vtableIScriptText       IScriptText     { pvtIDispatch, SetText}


;-------------------------------------------------------------------------------
; ActiveScriptSite interface
ActiveScriptSiteClass    ClassItem { NULL, NULL, \
                                     NULL, OFFSET ActiveScriptSiteIMap,      \
                                     NULL, NULL, NULL, SIZEOF ActiveScriptSiteObject }
;DISPINTERFACE + SUPPLY_TYPE_INFO

; describe the ActiveScriptSite object's interfaces
ActiveScriptSiteIMap  InterfaceItem { pIID_IActiveScriptSite,  OFFSET vtableIActiveScriptSite }
                      InterfaceItem { pIID_IActiveScriptSiteWindow,  OFFSET vtableIActiveScriptSiteWindow }
                      END_INTERFACE_MAP

; the ActiveScriptSite object needs no data members
ActiveScriptSiteObjData   STRUCT                  ; ActiveScriptSite object private data struct
ActiveScriptSiteObjData   ENDS

; step 2
ActiveScriptSiteObject    STRUCT
    ObjectData0     ObjectData      { } ; base values
;   ActiveScriptSiteObjData0  ActiveScriptSiteObjData   { } ; custom object data does not exist
    ObjectEntry0    ObjectEntry     { } ; delegated Unknown
    ObjectEntry1    ObjectEntry     { } ; IActiveScriptSite
    ObjectEntry2    ObjectEntry     { } ; IActiveScriptSiteWindow
ActiveScriptSiteObject    ENDS

; fill in the vtable
vtableIActiveScriptSite     DWORD       pvtIUnknown
                            DWORD       IActiveScriptSite_GetLCID
                            DWORD       IActiveScriptSite_GetItemInfo
                            DWORD       IActiveScriptSite_GetDocVersionString
                            DWORD       IActiveScriptSite_OnScriptTerminate
                            DWORD       IActiveScriptSite_OnStateChange
                            DWORD       IActiveScriptSite_OnScriptError
                            DWORD       IActiveScriptSite_OnEnterScript
                            DWORD       IActiveScriptSite_OnLeaveScript
                            
vtableIActiveScriptSiteWindow DWORD     pvtIUnknown
                            DWORD       IActiveScriptSiteWindow_GetWindow
                            DWORD       IActiveScriptSiteWindow_EnableModeless


; define the interface IID's
DeclareGuid     IID_IScriptText
DeclareGuid     CLSID_ScriptText
DeclareGuid     LIBID_ScriptText
DeclareGuid     IID_IActiveScriptSite
DeclareGuid     IID_IActiveScriptSiteWindow

DeclareGuid     CLSID_VBScript          ; change to CLSID_JScript for Java!!!
DeclareGuid     IID_IActiveScript
DeclareGuid     IID_IActiveScriptParse

;-------------------------------------------------------------------------------
.data?

hWndApp         DWORD       ?
hInstance       DWORD       ?
hHeap           DWORD       ?
CommandLine     DWORD       ?
hwndButton      DWORD       ?
hwndEdit        DWORD       ?
hwndScript      DWORD       ?
hwndStatBar     DWORD       ?
buffer          BYTE        512 dup(?)
SizeReadWrite   DWORD       ?

;-------------------------------------------------------------------------------
.const
ButtonID        EQU         1
EditID          EQU         2
MEMSIZE         EQU         65535
APP_ICON        EQU         500

abcd            RASENTRYNAMEA {}


APP_ICON            EQU         500
IDM_VIEWSCRIPT      EQU         1001
IDM_EXIT            EQU         1004

IDD_SCRIPT_BOX      EQU         3000
IDC_SCRIPT          EQU         3001
IDC_SCRIPT_STAT     EQU         3002
IDR_SCRIPT_MENU     EQU         3100
IDM_SCRIPT_NEW      EQU         3101
IDM_SCRIPT_OPEN     EQU         3102
IDM_SCRIPT_SAVE     EQU         3103
IDM_SCRIPT_SAVEAS   EQU         3104
IDM_SCRIPT_PRINT    EQU         3105
IDM_SCRIPT_CLOSE    EQU         3106

packedDW UNION 
    value DWORD ? 
    STRUCT 
        loword WORD ? 
        hiword WORD ? 
    ENDS 
packedDW ENDS

;-------------------------------------------------------------------------------
.code
start:
    invoke GetModuleHandle, NULL
    mov    hInstance,eax
    invoke GetCommandLine
    mov CommandLine,eax
    invoke GetProcessHeap 
    mov hHeap, eax
    invoke InitCommonControlsEx, ADDR InitComCtrls
    invoke WinMain, hInstance,NULL,CommandLine, SW_SHOWDEFAULT
    invoke ExitProcess,eax

;-------------------------------------------------------------------------------
WinMain proc hInst:HINSTANCE,hPrevInst:HINSTANCE,CmdLine:LPSTR,CmdShow:DWORD
    LOCAL wc:WNDCLASSEX
    LOCAL msg:MSG

    mov wc.cbSize,SIZEOF WNDCLASSEX
    mov wc.style, CS_HREDRAW or CS_VREDRAW
    mov wc.lpfnWndProc, OFFSET WndProc
    mov wc.cbClsExtra,NULL
    mov wc.cbWndExtra,NULL
    push hInst
    pop wc.hInstance
    mov wc.hbrBackground,COLOR_BTNFACE+1
    mov wc.lpszMenuName,OFFSET MenuName
    mov wc.lpszClassName,OFFSET ClassName
    invoke LoadIcon, hInstance, APP_ICON
    mov wc.hIcon,eax
    mov wc.hIconSm,eax
    invoke LoadCursor,NULL,IDC_ARROW
    mov wc.hCursor,eax
    invoke RegisterClassEx, addr wc
    invoke CreateWindowEx,WS_EX_CLIENTEDGE,ADDR ClassName,ADDR AppName,\
           WS_OVERLAPPEDWINDOW,150,150,\
           600,300,NULL,NULL,\
           hInst,NULL
    mov hWndApp,eax
    invoke ShowWindow, hWndApp,SW_SHOWNORMAL
    invoke UpdateWindow, hWndApp
    .WHILE TRUE
                invoke GetMessage, ADDR msg,NULL,0,0
                .BREAK .IF (!eax)
                invoke TranslateMessage, ADDR msg
                invoke DispatchMessage, ADDR msg
    .ENDW
    mov     eax,msg.wParam
    ret
WinMain endp
;-------------------------------------------------------------------------------
WndProc proc hWnd:HWND, uMsg:UINT, wParam:WPARAM, lParam:LPARAM
    LOCAL  rc:RECT
    LOCAL wplace:WINDOWPLACEMENT
;-----------------------------------------------------------
    .IF uMsg==WM_CREATE
        invoke CreateWindowEx,WS_EX_CLIENTEDGE, ADDR EditClassName,NULL,\
                        WS_CHILD or WS_VISIBLE or WS_BORDER or ES_LEFT or\
                        ES_AUTOHSCROLL or ES_MULTILINE,\
                        1,1,286,240,hWnd,EditID,hInstance,NULL
        mov  hwndEdit,eax
        invoke SetFocus, hwndEdit
        invoke CreateWindowEx,NULL, ADDR ButtonClassName,ADDR ButtonText,\
                        WS_CHILD or WS_VISIBLE or BS_DEFPUSHBUTTON,\
                        2,241,285,25,hWnd,ButtonID,hInstance,NULL
        mov  hwndButton,eax
        invoke StartScriptEngine
;-----------------------------------------------------------
    .ELSEIF uMsg==WM_DESTROY
        .IF pIAS
            coinvoke pIAS, IActiveScript, Close
            mov pIAS, 0
        .ENDIF
        .IF pIASP
            coinvoke pIASP, IUnknown, Release
            mov pIASP, 0
        .ENDIF
        .IF pIAS
            coinvoke pIAS, IUnknown, Release
            mov pIAS, 0
        .ENDIF
        .IF pASSite
            coinvoke pASSite, IUnknown, Release
            mov pASSite, 0
        .ENDIF
        invoke PostQuitMessage,NULL
;-----------------------------------------------------------
    .ELSEIF uMsg==WM_COMMAND
        mov eax,wParam
        .IF lParam
            .IF ax==ButtonID
                shr eax,16
                .IF ax==BN_CLICKED
                    invoke RunScript
                    ;coinvoke pScrText, IScriptText, SetText, NULL
                .ENDIF
            .ENDIF
        .ENDIF
;-----------------------------------------------------------
    .ELSEIF uMsg==WM_SIZE
        movsx edx, (packedDW PTR lParam).loword     
        movsx ebx, (packedDW PTR lParam).hiword     
        .IF (edx < MinWidth) || (ebx < MinHeight)
            invoke GetWindowRect, hWndApp, ADDR rc
            movsx edx, (packedDW PTR lParam).loword 
            movsx ebx, (packedDW PTR lParam).hiword 
            .IF edx <= MinWidth
                mov edx, rc.left
                add edx, MinWidth
            .ELSE
                mov edx, rc.right
                sub edx, rc.left
            .ENDIF
            .IF ebx <= MinHeight
                mov ebx, rc.top
                add ebx, MinHeight
                mov ebx, MinHeight + ButtonHeight + ButtonHeight / 2; KLUDGE !!!!!
            .ELSE
                mov ebx, rc.top
                sub ebx, rc.bottom
            .ENDIF
            invoke MoveWindow, hWndApp, rc.left, rc.top, edx, ebx, TRUE
        .ELSE
            sub ebx, ButtonHeight
            invoke MoveWindow, hwndEdit, 0, 0, edx, ebx, FALSE
            movsx edx, (packedDW PTR lParam).loword ; get the low word,Specifies the new width 
            mov eax, edx
            sub edx, ButtonHeight
            movsx ebx, (packedDW PTR lParam).hiword  ; get the high word, Specifies the new height 
            sub ebx, ButtonHeight
            invoke MoveWindow, hwndButton, 0, ebx, eax, ButtonHeight, TRUE
        .ENDIF
;-----------------------------------------------------------
    .ELSE
        invoke DefWindowProc,hWnd,uMsg,wParam,lParam
        ret
    .ENDIF
    xor    eax,eax
    ret
WndProc endp

;-------------------------------------------------------------------------------
SetText PROC  this_:DWORD, pNewText:DWORD
    LOCAL cCount:DWORD, psBuf:DWORD
    
    invoke SendMessage, hwndEdit, EM_SETSEL, 0, -1  ; select all text
    invoke SendMessage, hwndEdit, WM_CLEAR, 0, 0    ; clear selection
    invoke SysStringLen, pNewText
    inc eax
    mov cCount, eax
    invoke HeapAlloc, hHeap, NULL, eax
    mov psBuf, eax
    invoke WideCharToMultiByte, CP_ACP, 0, pNewText, -1, 
                                psBuf, cCount, NULL, NULL
    invoke SendMessage, hwndEdit, WM_SETTEXT, NULL, psBuf
    invoke SysFreeString, pNewText
    invoke HeapFree, hHeap, NULL, psBuf
    xor eax, eax        ; return S_OK
    ret
SetText ENDP

;-------------------------------------------------------------------------------
IActiveScriptSiteWindow_GetWindow PROC this_:DWORD, phwnd:DWORD
    mov ecx, phwnd
    mov eax, hWndApp
    mov [ecx], eax
    xor eax, eax        ; return S_OK    
    ret
IActiveScriptSiteWindow_GetWindow ENDP    

;-------------------------------------------------------------------------------
IActiveScriptSiteWindow_EnableModeless PROC this_:DWORD, fEnable:DWORD
    xor eax, eax        ; return S_OK    
    ret
IActiveScriptSiteWindow_EnableModeless ENDP    

;-------------------------------------------------------------------------------
IActiveScriptSite_GetLCID PROC this_:DWORD, pLCID:DWORD
    mov eax, E_NOTIMPL
    ret
IActiveScriptSite_GetLCID ENDP    

;-------------------------------------------------------------------------------
IActiveScriptSite_GetItemInfo PROC this_:DWORD, pstrName:DWORD, dwReturnMask:DWORD, 
                 ppunkItem:DWORD, ppTypeInfo:DWORD
    .IF (dwReturnMask & SCRIPTINFO_IUNKNOWN) 
        .IF !ppunkItem     ; check we didn't get a non-null pointer
            mov eax, E_INVALIDARG
            jmp IActiveScriptSite_GetItemInfo_Done
        .ENDIF
    .ENDIF
    .IF (dwReturnMask & SCRIPTINFO_ITYPEINFO) 
        .IF !ppTypeInfo     ; check we didn't get a non-null pointer
            mov eax, E_INVALIDARG
            jmp IActiveScriptSite_GetItemInfo_Done
        .ENDIF
    .ENDIF
    ; check if we were asked for a valid object
    ; note we use the "W" or Unicode version of compare
    invoke lstrcmpiW, pstrName, ADDR wsApplication    
    .IF eax     ; test if pstrName == "Application"
        mov eax, TYPE_E_ELEMENTNOTFOUND
        jmp IActiveScriptSite_GetItemInfo_Done
    .ELSE
        .IF (dwReturnMask & SCRIPTINFO_IUNKNOWN)
            mov ecx, ppunkItem
            mov eax, pScrText            
            mov [ecx], eax
            coinvoke pScrText, IUnknown, AddRef
            jmp IActiveScriptSite_GetItemInfo_Done
        .ENDIF
        .IF (dwReturnMask & SCRIPTINFO_ITYPEINFO) 
            coinvoke pScrText, IDispatch, GetTypeInfo, 0, NULL, ppTypeInfo
            jmp IActiveScriptSite_GetItemInfo_Done
        .ENDIF
    .ENDIF
IActiveScriptSite_GetItemInfo_Done:
    ret
IActiveScriptSite_GetItemInfo ENDP    

;-------------------------------------------------------------------------------
IActiveScriptSite_GetDocVersionString PROC this_:DWORD,pbstrVersionString:DWORD
    mov eax, E_NOTIMPL
    ret
IActiveScriptSite_GetDocVersionString ENDP    

;-------------------------------------------------------------------------------
IActiveScriptSite_OnScriptTerminate PROC this_:DWORD, pvarResult:DWORD, pexcepinfo:DWORD
    xor eax, eax        ; return S_OK
    ret
IActiveScriptSite_OnScriptTerminate ENDP    

;-------------------------------------------------------------------------------
IActiveScriptSite_OnStateChange PROC this_:DWORD, ssScriptState :DWORD
    xor eax, eax        ; return S_OK
    ret
IActiveScriptSite_OnStateChange ENDP    

;-------------------------------------------------------------------------------
IActiveScriptSite_OnScriptError PROC this_:DWORD, pase:DWORD
    xor eax, eax        ; return S_OK
    ret
IActiveScriptSite_OnScriptError ENDP    

;-------------------------------------------------------------------------------
IActiveScriptSite_OnEnterScript PROC this_:DWORD
    xor eax, eax        ; return S_OK
    ret
IActiveScriptSite_OnEnterScript ENDP    

;-------------------------------------------------------------------------------
IActiveScriptSite_OnLeaveScript PROC this_:DWORD
    xor eax, eax        ; return S_OK
    ret
IActiveScriptSite_OnLeaveScript ENDP    

;-------------------------------------------------------------------------------
StartScriptEngine PROC
    invoke CoInitialize, NULL
    ; AllocObject is from colib, it's otherwise been used as
    ;  the DllGetClassObject Object maker method
    ;  but it works just fine if called by itself
    invoke AllocObject, ADDR pASSite, OFFSET ActiveScriptSiteClass, NULL, NULL
    .IF_FAILED
        jmp BadStart
    .ENDIF
    invoke AllocObject, ADDR pScrText, OFFSET ScriptTextClass, NULL, NULL
    .IF_FAILED
        jmp BadStart
    .ENDIF
    invoke CoCreateInstance, pCLSID_VBScript, NULL, CLSCTX_INPROC_SERVER, pIID_IActiveScript, ADDR pIAS
    .IF_SUCCEEDED
        coinvoke pIAS, IUnknown, QueryInterface, pIID_IActiveScriptParse, ADDR pIASP
        .IF_FAILED            ; bad engine start
            coinvoke pIAS, IUnknown, Release,
        .ENDIF
    .ENDIF
    xor eax, eax
    ret
BadStart:
    mov eax, S_FALSE
    ret
StartScriptEngine ENDP

;-------------------------------------------------------------------------------
RunScript PROC    
    LOCAL ei:EXCEPINFO, pszScriptText:DWORD, pwszScriptText:DWORD, cChars:DWORD
    LOCAL bstrScriptText:DWORD

 ;    // Give engine your IActiveScriptSite interface...
    coinvoke pASSite, IUnknown, AddRef
    coinvoke pIAS, IActiveScript, SetScriptSite, pASSite
 ;    // Give the engine a chance to initialize itself...
    coinvoke pIASP, IActiveScriptParse, InitNew
 ;    // Add a root-level item to the engine's name space...
    coinvoke pIAS, IActiveScript, AddNamedItem, ADDR wsApplication, SCRIPTITEM_ISVISIBLE
 ;    // Get the script
    invoke LoadScript, ADDR pwszScriptText
 ;    // change the scriptlet to a bstr...   
    invoke SysAllocString, pwszScriptText
    mov bstrScriptText, eax
    coinvoke pIASP, IActiveScriptParse, ParseScriptText, bstrScriptText, ADDR wsApplication, NULL, NULL, 0, 0, 0, NULL, ADDR ei
    invoke SysFreeString, bstrScriptText
    invoke HeapFree, hHeap, NULL, pwszScriptText
 ;    // Set the engine state. This line actually triggers the execution of the script.
    coinvoke pIAS, IActiveScript, SetScriptState, SCRIPTSTATE_CONNECTED
    ret
RunScript ENDP

;-------------------------------------------------------------------------------
LoadScript PROC ppwszScriptText:DWORD
    LOCAL hFile:DWORD, hMapFile:DWORD, pszScriptText:DWORD, cSize:DWORD, pEnd:DWORD
    LOCAL pwszST:DWORD
    invoke CreateFile,ADDR ScriptFile,
                      GENERIC_READ, 
                      FILE_SHARE_READ, NULL,
                      OPEN_EXISTING, FILE_ATTRIBUTE_ARCHIVE, NULL
    mov hFile,eax
    invoke CreateFileMapping,hFile,NULL,PAGE_READONLY,0,0,NULL
    mov hMapFile, eax
    invoke MapViewOfFile, hMapFile, FILE_MAP_READ, 0, 0, 0
    mov pszScriptText,eax
    invoke GetFileSize, hFile, NULL
    mov cSize, eax
    add eax, pszScriptText
    inc eax
    mov pEnd, eax
    mov [pEnd], 0
    invoke SendMessage, hwndEdit, WM_SETTEXT, NULL, pszScriptText
    mov eax, cSize
    inc eax
    rol eax, 1  ; eax <- 2* file size + 1
    invoke HeapAlloc, hHeap, NULL, eax
    mov pwszST, eax
    invoke MultiByteToWideChar, CP_ACP, 0, pszScriptText, -1, pwszST, cSize
    mov ecx, ppwszScriptText
    mov eax, pwszST
    mov [ecx], eax
    invoke UnmapViewOfFile,pszScriptText
    invoke CloseHandle, hMapFile
    invoke CloseHandle, hFile
    ret
LoadScript ENDP
;-------------------------------------------------------------------------------

end start
