File size: 4,860 Bytes
10865e1
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
import sys

import pythoncom
import win32com.server.policy
from win32com.axscript import axscript
from win32com.axscript.server import axsite
from win32com.axscript.server.error import Exception
from win32com.server import connect, util


class MySite(axsite.AXSite):
    def OnScriptError(self, error):
        exc = error.GetExceptionInfo()
        context, line, char = error.GetSourcePosition()
        print(" >Exception:", exc[1])
        try:
            st = error.GetSourceLineText()
        except pythoncom.com_error:
            st = None
        if st is None:
            st = ""
        text = st + "\n" + (" " * (char - 1)) + "^" + "\n" + exc[2]
        for line in text.splitlines():
            print("  >" + line)


class MyCollection(util.Collection):
    def _NewEnum(self):
        print("Making new Enumerator")
        return util.Collection._NewEnum(self)


class Test:
    _public_methods_ = ["echo"]
    _public_attrs_ = ["collection", "verbose"]

    def __init__(self):
        self.verbose = 0
        self.collection = util.wrap(MyCollection([1, "Two", 3]))
        self.last = ""

    #    self._connect_server_ = TestConnectServer(self)

    def echo(self, *args):
        self.last = "".join(map(str, args))
        if self.verbose:
            for arg in args:
                print(arg, end=" ")
            print()


#    self._connect_server_.Broadcast(last)


#### Connections currently wont work, as there is no way for the engine to
#### know what events we support.  We need typeinfo support.

IID_ITestEvents = pythoncom.MakeIID("{8EB72F90-0D44-11d1-9C4B-00AA00125A98}")


class TestConnectServer(connect.ConnectableServer):
    _connect_interfaces_ = [IID_ITestEvents]

    # The single public method that the client can call on us
    # (ie, as a normal COM server, this exposes just this single method.
    def __init__(self, object):
        self.object = object

    def Broadcast(self, arg):
        # Simply broadcast a notification.
        self._BroadcastNotify(self.NotifyDoneIt, (arg,))

    def NotifyDoneIt(self, interface, arg):
        interface.Invoke(1000, 0, pythoncom.DISPATCH_METHOD, 1, arg)


VBScript = """\
prop = "Property Value"

sub hello(arg1)
   test.echo arg1
end sub
  
sub testcollection
   test.verbose = 1
   for each item in test.collection
     test.echo "Collection item is", item
   next
end sub
"""
if sys.version_info < (3,):
    PyScript = """print "PyScript is being parsed..."\n"""
else:
    PyScript = """print("PyScript is being parsed...")\n"""
PyScript += """\
prop = "Property Value"
def hello(arg1):
   test.echo(arg1)
   pass
   
def testcollection():
   test.verbose = 1
#   test.collection[1] = "New one"
   for item in test.collection:
     test.echo("Collection item is", item)
   pass
"""

ErrScript = """\
bad code for everyone!
"""


def TestEngine(engineName, code, bShouldWork=1):
    echoer = Test()
    model = {
        "test": util.wrap(echoer),
    }

    site = MySite(model)
    engine = site._AddEngine(engineName)
    engine.AddCode(code, axscript.SCRIPTTEXT_ISPERSISTENT)
    try:
        engine.Start()
    finally:
        if not bShouldWork:
            engine.Close()
            return
    doTestEngine(engine, echoer)
    # re-transition the engine back to the UNINITIALIZED state, a-la ASP.
    engine.eScript.SetScriptState(axscript.SCRIPTSTATE_UNINITIALIZED)
    engine.eScript.SetScriptSite(util.wrap(site))
    print("restarting")
    engine.Start()
    # all done!
    engine.Close()


def doTestEngine(engine, echoer):
    # Now call into the scripts IDispatch
    from win32com.client.dynamic import Dispatch

    ob = Dispatch(engine.GetScriptDispatch())
    try:
        ob.hello("Goober")
    except pythoncom.com_error as exc:
        print("***** Calling 'hello' failed", exc)
        return
    if echoer.last != "Goober":
        print("***** Function call didnt set value correctly", repr(echoer.last))

    if str(ob.prop) != "Property Value":
        print("***** Property Value not correct - ", repr(ob.prop))

    ob.testcollection()

    # Now make sure my engines can evaluate stuff.
    result = engine.eParse.ParseScriptText(
        "1+1", None, None, None, 0, 0, axscript.SCRIPTTEXT_ISEXPRESSION
    )
    if result != 2:
        print("Engine could not evaluate '1+1' - said the result was", result)


def dotestall():
    for i in range(10):
        TestEngine("Python", PyScript)
        print(sys.gettotalrefcount())


##  print "Testing Exceptions"
##  try:
##    TestEngine("Python", ErrScript, 0)
##  except pythoncom.com_error:
##    pass


def testall():
    dotestall()
    pythoncom.CoUninitialize()
    print(
        "AXScript Host worked correctly - %d/%d COM objects left alive."
        % (pythoncom._GetInterfaceCount(), pythoncom._GetGatewayCount())
    )


if __name__ == "__main__":
    testall()