123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100 |
- # Implements _both_ a connectable client, and a connectable server.
- #
- # Note that we cheat just a little - the Server in this demo is not created
- # via Normal COM - this means we can avoid registering the server.
- # However, the server _is_ accessed as a COM object - just the creation
- # is cheated on - so this is still working as a fully-fledged server.
-
- import pythoncom
- import win32com.server.connect
- import win32com.server.util
- from pywin32_testutil import str2bytes
- from win32com.server.exception import Exception
-
- # This is the IID of the Events interface both Client and Server support.
- IID_IConnectDemoEvents = pythoncom.MakeIID("{A4988850-49C3-11d0-AE5D-52342E000000}")
-
- # The server which implements
- # Create a connectable class, that has a single public method
- # 'DoIt', which echos to a single sink 'DoneIt'
-
-
- class ConnectableServer(win32com.server.connect.ConnectableServer):
- _public_methods_ = [
- "DoIt"
- ] + win32com.server.connect.ConnectableServer._public_methods_
- _connect_interfaces_ = [IID_IConnectDemoEvents]
-
- # The single public method that the client can call on us
- # (ie, as a normal COM server, this exposes just this single method.
- def DoIt(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)
-
-
- # Here is the client side of the connection world.
- # Define a COM object which implements the methods defined by the
- # IConnectDemoEvents interface.
- class ConnectableClient:
- # This is another cheat - I _know_ the server defines the "DoneIt" event
- # as DISPID==1000 - I also know from the implementation details of COM
- # that the first method in _public_methods_ gets 1000.
- # Normally some explicit DISPID->Method mapping is required.
- _public_methods_ = ["OnDoneIt"]
-
- def __init__(self):
- self.last_event_arg = None
-
- # A client must implement QI, and respond to a query for the Event interface.
- # In addition, it must provide a COM object (which server.util.wrap) does.
- def _query_interface_(self, iid):
- import win32com.server.util
-
- # Note that this seems like a necessary hack. I am responding to IID_IConnectDemoEvents
- # but only creating an IDispatch gateway object.
- if iid == IID_IConnectDemoEvents:
- return win32com.server.util.wrap(self)
-
- # And here is our event method which gets called.
- def OnDoneIt(self, arg):
- self.last_event_arg = arg
-
-
- def CheckEvent(server, client, val, verbose):
- client.last_event_arg = None
- server.DoIt(val)
- if client.last_event_arg != val:
- raise RuntimeError("Sent %r, but got back %r" % (val, client.last_event_arg))
- if verbose:
- print("Sent and received %r" % val)
-
-
- # A simple test script for all this.
- # In the real world, it is likely that the code controlling the server
- # will be in the same class as that getting the notifications.
- def test(verbose=0):
- import win32com.client.connect
- import win32com.client.dynamic
- import win32com.server.policy
-
- server = win32com.client.dynamic.Dispatch(
- win32com.server.util.wrap(ConnectableServer())
- )
- connection = win32com.client.connect.SimpleConnection()
- client = ConnectableClient()
- connection.Connect(server, client, IID_IConnectDemoEvents)
- CheckEvent(server, client, "Hello", verbose)
- CheckEvent(server, client, str2bytes("Here is a null>\x00<"), verbose)
- CheckEvent(server, client, "Here is a null>\x00<", verbose)
- val = "test-\xe0\xf2" # 2 extended characters.
- CheckEvent(server, client, val, verbose)
- if verbose:
- print("Everything seemed to work!")
- # Aggressive memory leak checking (ie, do nothing!) :-) All should cleanup OK???
-
-
- if __name__ == "__main__":
- test(1)
|