-
-
Save FXGears/351a447f47d9356ada6b to your computer and use it in GitHub Desktop.
| ## Based on: http://code.activestate.com/recipes/577654/ | |
| #!/usr/bin/env python | |
| # Send DDE Execute command to running program | |
| from ctypes import POINTER, WINFUNCTYPE, c_char_p, c_void_p, c_int, c_ulong, c_char_p | |
| from ctypes.wintypes import BOOL, DWORD, BYTE, INT, LPCWSTR, UINT, ULONG | |
| import time | |
| # DECLARE_HANDLE(name) typedef void *name; | |
| HCONV = c_void_p # = DECLARE_HANDLE(HCONV) | |
| HDDEDATA = c_void_p # = DECLARE_HANDLE(HDDEDATA) | |
| HSZ = c_void_p # = DECLARE_HANDLE(HSZ) | |
| LPBYTE = c_char_p # POINTER(BYTE) | |
| LPDWORD = POINTER(DWORD) | |
| LPSTR = c_char_p | |
| ULONG_PTR = c_ulong | |
| # See windows/ddeml.h for declaration of struct CONVCONTEXT | |
| PCONVCONTEXT = c_void_p | |
| DMLERR_NO_ERROR = 0 | |
| # Predefined Clipboard Formats | |
| CF_TEXT = 1 | |
| CF_BITMAP = 2 | |
| CF_METAFILEPICT = 3 | |
| CF_SYLK = 4 | |
| CF_DIF = 5 | |
| CF_TIFF = 6 | |
| CF_OEMTEXT = 7 | |
| CF_DIB = 8 | |
| CF_PALETTE = 9 | |
| CF_PENDATA = 10 | |
| CF_RIFF = 11 | |
| CF_WAVE = 12 | |
| CF_UNICODETEXT = 13 | |
| CF_ENHMETAFILE = 14 | |
| CF_HDROP = 15 | |
| CF_LOCALE = 16 | |
| CF_DIBV5 = 17 | |
| CF_MAX = 18 | |
| DDE_FACK = 0x8000 | |
| DDE_FBUSY = 0x4000 | |
| DDE_FDEFERUPD = 0x4000 | |
| DDE_FACKREQ = 0x8000 | |
| DDE_FRELEASE = 0x2000 | |
| DDE_FREQUESTED = 0x1000 | |
| DDE_FAPPSTATUS = 0x00FF | |
| DDE_FNOTPROCESSED = 0x0000 | |
| DDE_FACKRESERVED = (~(DDE_FACK | DDE_FBUSY | DDE_FAPPSTATUS)) | |
| DDE_FADVRESERVED = (~(DDE_FACKREQ | DDE_FDEFERUPD)) | |
| DDE_FDATRESERVED = (~(DDE_FACKREQ | DDE_FRELEASE | DDE_FREQUESTED)) | |
| DDE_FPOKRESERVED = (~(DDE_FRELEASE)) | |
| XTYPF_NOBLOCK = 0x0002 | |
| XTYPF_NODATA = 0x0004 | |
| XTYPF_ACKREQ = 0x0008 | |
| XCLASS_MASK = 0xFC00 | |
| XCLASS_BOOL = 0x1000 | |
| XCLASS_DATA = 0x2000 | |
| XCLASS_FLAGS = 0x4000 | |
| XCLASS_NOTIFICATION = 0x8000 | |
| XTYP_ERROR = (0x0000 | XCLASS_NOTIFICATION | XTYPF_NOBLOCK) | |
| XTYP_ADVDATA = (0x0010 | XCLASS_FLAGS) | |
| XTYP_ADVREQ = (0x0020 | XCLASS_DATA | XTYPF_NOBLOCK) | |
| XTYP_ADVSTART = (0x0030 | XCLASS_BOOL) | |
| XTYP_ADVSTOP = (0x0040 | XCLASS_NOTIFICATION) | |
| XTYP_EXECUTE = (0x0050 | XCLASS_FLAGS) | |
| XTYP_CONNECT = (0x0060 | XCLASS_BOOL | XTYPF_NOBLOCK) | |
| XTYP_CONNECT_CONFIRM = (0x0070 | XCLASS_NOTIFICATION | XTYPF_NOBLOCK) | |
| XTYP_XACT_COMPLETE = (0x0080 | XCLASS_NOTIFICATION ) | |
| XTYP_POKE = (0x0090 | XCLASS_FLAGS) | |
| XTYP_REGISTER = (0x00A0 | XCLASS_NOTIFICATION | XTYPF_NOBLOCK ) | |
| XTYP_REQUEST = (0x00B0 | XCLASS_DATA ) | |
| XTYP_DISCONNECT = (0x00C0 | XCLASS_NOTIFICATION | XTYPF_NOBLOCK ) | |
| XTYP_UNREGISTER = (0x00D0 | XCLASS_NOTIFICATION | XTYPF_NOBLOCK ) | |
| XTYP_WILDCONNECT = (0x00E0 | XCLASS_DATA | XTYPF_NOBLOCK) | |
| XTYP_MONITOR = (0x00F0 | XCLASS_NOTIFICATION | XTYPF_NOBLOCK) | |
| XTYP_MASK = 0x00F0 | |
| XTYP_SHIFT = 4 | |
| TIMEOUT_ASYNC = 0xFFFFFFFF | |
| def get_winfunc(libname, funcname, restype=None, argtypes=(), _libcache={}): | |
| """Retrieve a function from a library, and set the data types.""" | |
| from ctypes import windll | |
| if libname not in _libcache: | |
| _libcache[libname] = windll.LoadLibrary(libname) | |
| func = getattr(_libcache[libname], funcname) | |
| func.argtypes = argtypes | |
| func.restype = restype | |
| return func | |
| DDECALLBACK = WINFUNCTYPE(HDDEDATA, UINT, UINT, HCONV, HSZ, HSZ, HDDEDATA, | |
| ULONG_PTR, ULONG_PTR) | |
| class DDE(object): | |
| """Object containing all the DDE functions""" | |
| AccessData = get_winfunc("user32", "DdeAccessData", LPBYTE, (HDDEDATA, LPDWORD)) | |
| ClientTransaction = get_winfunc("user32", "DdeClientTransaction", HDDEDATA, (LPBYTE, DWORD, HCONV, HSZ, UINT, UINT, DWORD, LPDWORD)) | |
| Connect = get_winfunc("user32", "DdeConnect", HCONV, (DWORD, HSZ, HSZ, PCONVCONTEXT)) | |
| CreateStringHandle = get_winfunc("user32", "DdeCreateStringHandleW", HSZ, (DWORD, LPCWSTR, UINT)) | |
| Disconnect = get_winfunc("user32", "DdeDisconnect", BOOL, (HCONV,)) | |
| GetLastError = get_winfunc("user32", "DdeGetLastError", UINT, (DWORD,)) | |
| Initialize = get_winfunc("user32", "DdeInitializeW", UINT, (LPDWORD, DDECALLBACK, DWORD, DWORD)) | |
| FreeDataHandle = get_winfunc("user32", "DdeFreeDataHandle", BOOL, (HDDEDATA,)) | |
| FreeStringHandle = get_winfunc("user32", "DdeFreeStringHandle", BOOL, (DWORD, HSZ)) | |
| QueryString = get_winfunc("user32", "DdeQueryStringA", DWORD, (DWORD, HSZ, LPSTR, DWORD, c_int)) | |
| UnaccessData = get_winfunc("user32", "DdeUnaccessData", BOOL, (HDDEDATA,)) | |
| Uninitialize = get_winfunc("user32", "DdeUninitialize", BOOL, (DWORD,)) | |
| class DDEError(RuntimeError): | |
| """Exception raise when a DDE errpr occures.""" | |
| def __init__(self, msg, idInst=None): | |
| if idInst is None: | |
| RuntimeError.__init__(self, msg) | |
| else: | |
| RuntimeError.__init__(self, "%s (err=%s)" % (msg, hex(DDE.GetLastError(idInst)))) | |
| class DDEClient(object): | |
| """The DDEClient class. | |
| Use this class to create and manage a connection to a service/topic. To get | |
| classbacks subclass DDEClient and overwrite callback.""" | |
| def __init__(self, service, topic): | |
| """Create a connection to a service/topic.""" | |
| from ctypes import byref | |
| self._idInst = DWORD(0) | |
| self._hConv = HCONV() | |
| self._callback = DDECALLBACK(self._callback) | |
| res = DDE.Initialize(byref(self._idInst), self._callback, 0x00000010, 0) | |
| if res != DMLERR_NO_ERROR: | |
| raise DDEError("Unable to register with DDEML (err=%s)" % hex(res)) | |
| hszService = DDE.CreateStringHandle(self._idInst, service, 1200) | |
| hszTopic = DDE.CreateStringHandle(self._idInst, topic, 1200) | |
| self._hConv = DDE.Connect(self._idInst, hszService, hszTopic, PCONVCONTEXT()) | |
| DDE.FreeStringHandle(self._idInst, hszTopic) | |
| DDE.FreeStringHandle(self._idInst, hszService) | |
| if not self._hConv: | |
| raise DDEError("Unable to establish a conversation with server", self._idInst) | |
| def __del__(self): | |
| """Cleanup any active connections.""" | |
| if self._hConv: | |
| DDE.Disconnect(self._hConv) | |
| if self._idInst: | |
| DDE.Uninitialize(self._idInst) | |
| def advise(self, item, stop=False): | |
| """Request updates when DDE data changes.""" | |
| from ctypes import byref | |
| hszItem = DDE.CreateStringHandle(self._idInst, item, 1200) | |
| hDdeData = DDE.ClientTransaction(LPBYTE(), 0, self._hConv, hszItem, CF_TEXT, XTYP_ADVSTOP if stop else XTYP_ADVSTART, TIMEOUT_ASYNC, LPDWORD()) | |
| DDE.FreeStringHandle(self._idInst, hszItem) | |
| if not hDdeData: | |
| raise DDEError("Unable to %s advise" % ("stop" if stop else "start"), self._idInst) | |
| DDE.FreeDataHandle(hDdeData) | |
| def execute(self, command, timeout=5000): | |
| """Execute a DDE command.""" | |
| pData = c_char_p(command) | |
| cbData = DWORD(len(command) + 1) | |
| hDdeData = DDE.ClientTransaction(pData, cbData, self._hConv, HSZ(), CF_TEXT, XTYP_EXECUTE, timeout, LPDWORD()) | |
| if not hDdeData: | |
| raise DDEError("Unable to send command", self._idInst) | |
| DDE.FreeDataHandle(hDdeData) | |
| def request(self, item, timeout=5000): | |
| """Request data from DDE service.""" | |
| from ctypes import byref | |
| hszItem = DDE.CreateStringHandle(self._idInst, item, 1200) | |
| hDdeData = DDE.ClientTransaction(LPBYTE(), 0, self._hConv, hszItem, CF_TEXT, XTYP_REQUEST, timeout, LPDWORD()) | |
| DDE.FreeStringHandle(self._idInst, hszItem) | |
| if not hDdeData: | |
| raise DDEError("Unable to request item", self._idInst) | |
| if timeout != TIMEOUT_ASYNC: | |
| pdwSize = DWORD(0) | |
| try: | |
| pData = DDE.AccessData(hDdeData, byref(pdwSize)) | |
| except: | |
| pData = None | |
| if not pData: | |
| time.sleep(0.05) | |
| pData = self.request(item) | |
| return pData | |
| def callback(self, value, item=None): | |
| """Calback function for advice.""" | |
| print "%s: %s" % (item, value) | |
| def _callback(self, wType, uFmt, hConv, hsz1, hsz2, hDdeData, dwData1, dwData2): | |
| #if wType == XTYP_ADVDATA: | |
| from ctypes import byref, create_string_buffer | |
| dwSize = DWORD(0) | |
| pData = DDE.AccessData(hDdeData, byref(dwSize)) | |
| if pData: | |
| item = create_string_buffer('\000' * 128) | |
| DDE.QueryString(self._idInst, hsz2, item, 128, 1004) | |
| self.callback(pData, item.value) | |
| DDE.UnaccessData(hDdeData) | |
| return DDE_FACK | |
| def WinMSGLoop(): | |
| """Run the main windows message loop.""" | |
| from ctypes import POINTER, byref, c_ulong | |
| from ctypes.wintypes import BOOL, HWND, MSG, UINT | |
| LPMSG = POINTER(MSG) | |
| LRESULT = c_ulong | |
| GetMessage = get_winfunc("user32", "GetMessageW", BOOL, (LPMSG, HWND, UINT, UINT)) | |
| TranslateMessage = get_winfunc("user32", "TranslateMessage", BOOL, (LPMSG,)) | |
| # restype = LRESULT | |
| DispatchMessage = get_winfunc("user32", "DispatchMessageW", LRESULT, (LPMSG,)) | |
| msg = MSG() | |
| lpmsg = byref(msg) | |
| while GetMessage(lpmsg, HWND(), 0, 0) > 0: | |
| TranslateMessage(lpmsg) | |
| DispatchMessage(lpmsg) | |
| if __name__ == "__main__": | |
| print "load module within your own script.. o_O" |
hi, how can I follow all changes in quotes mt4 dde?
I have a error,can anybody help me please
Task exception was never retrieved
future: <Task finished name='Task-1' coro=<broadcast() done, defined at ssl10.0.py:38> exception=
ython object")>
Traceback (most recent call last):
File "ssl10.0.py", line 40, in broadcast
ms=producer()
File "ssl10.0.py", line 27, in producer
current_quote = QUOTE_client.request(item).split()
File "C:\live\dde_client.py", line 200, in request
pData = self.request(item)
File "C:\live\dde_client.py", line 200, in request
pData = self.request(item)
File "C:\live\dde_client.py", line 200, in request
pData = self.request(item)
[Previous line repeated 984 more times]
File "C:\live\dde_client.py", line 185, in request
hszItem = DDE.CreateStringHandle(self._idInst, item, 1200)
ctypes.ArgumentError: argument 3: <class 'RecursionError'>: maximum recursion depth exceeded whil
Exception in callback _ProactorBasePipeTransport._call_connection_lost(None)
handle: <Handle _ProactorBasePipeTransport._call_connection_lost(None)>
Traceback (most recent call last):
File "C:\ProgramData\Anaconda3\lib\asyncio\events.py", line 81, in _run
self._context.run(self._callback, *self._args)
File "C:\ProgramData\Anaconda3\lib\asyncio\proactor_events.py", line 162, in _call_connection_l
self._sock.shutdown(socket.SHUT_RDWR)
ConnectionResetError: [WinError 10054] 远程主机强迫关闭了一个现有的连接。
new websocket_users: <websockets.server.WebSocketServerProtocol object at 0x0000008D96762E50>
new websocket_users: <websockets.server.WebSocketServerProtocol object at 0x0000008D96762E50>
remove websocket_users: <websockets.server.WebSocketServerProtocol object at 0x0000008D96762E50>
Error in connection handler
Traceback (most recent call last):
File "C:\ProgramData\Anaconda3\lib\site-packages\websockets\server.py", line 191, in handler
await self.ws_handler(self, path)
File "ssl10.0.py", line 64, in handler
CLIENTS.remove(websocket)
KeyError: <websockets.server.WebSocketServerProtocol object at 0x0000008D96762E50>
new websocket_users: <websockets.server.WebSocketServerProtocol object at 0x0000008D968AE910>
I'm not the original author of this code and I don't believe the author I forked this from is either... but I've corrected the indenting issue and handled a problem when running this on a feed from MT4 Server that causes a null point type error (the bug is still there, but now it gets overlooked instead of killing the script.)