Advertisement
Guest User

Untitled

a guest
Oct 16th, 2018
102
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 9.92 KB | None | 0 0
  1. # -*- coding: utf-8 -*-
  2.  
  3. from ctypes import POINTER, WINFUNCTYPE, c_char_p, c_void_p, c_int, c_ulong, c_char_p
  4. from ctypes.wintypes import BOOL, DWORD, BYTE, INT, LPCWSTR, UINT, ULONG
  5.  
  6. # DECLARE_HANDLE(name) typedef void *name;
  7. HCONV     = c_void_p    # = DECLARE_HANDLE(HCONV)
  8. HDDEDATA  = c_void_p    # = DECLARE_HANDLE(HDDEDATA)
  9. HSZ       = c_void_p    # = DECLARE_HANDLE(HSZ)
  10. LPBYTE    = c_char_p   # POINTER(BYTE)
  11. LPDWORD   = POINTER(DWORD)
  12. LPSTR    = c_char_p
  13. ULONG_PTR = c_ulong
  14.  
  15. # Описание структуры CONVCONTEXT см. в windows/ddeml.h
  16. PCONVCONTEXT = c_void_p
  17.  
  18. DMLERR_NO_ERROR = 0
  19.  
  20. # Predefined Clipboard Formats
  21. CF_TEXT         =  1
  22. CF_BITMAP       =  2
  23. CF_METAFILEPICT =  3
  24. CF_SYLK         =  4
  25. CF_DIF          =  5
  26. CF_TIFF         =  6
  27. CF_OEMTEXT      =  7
  28. CF_DIB          =  8
  29. CF_PALETTE      =  9
  30. CF_PENDATA      = 10
  31. CF_RIFF         = 11
  32. CF_WAVE         = 12
  33. CF_UNICODETEXT  = 13
  34. CF_ENHMETAFILE  = 14
  35. CF_HDROP        = 15
  36. CF_LOCALE       = 16
  37. CF_DIBV5        = 17
  38. CF_MAX          = 18
  39.  
  40. DDE_FACK          = 0x8000
  41. DDE_FBUSY         = 0x4000
  42. DDE_FDEFERUPD     = 0x4000
  43. DDE_FACKREQ       = 0x8000
  44. DDE_FRELEASE      = 0x2000
  45. DDE_FREQUESTED    = 0x1000
  46. DDE_FAPPSTATUS    = 0x00FF
  47. DDE_FNOTPROCESSED = 0x0000
  48.  
  49. DDE_FACKRESERVED  = (~(DDE_FACK | DDE_FBUSY | DDE_FAPPSTATUS))
  50. DDE_FADVRESERVED  = (~(DDE_FACKREQ | DDE_FDEFERUPD))
  51. DDE_FDATRESERVED  = (~(DDE_FACKREQ | DDE_FRELEASE | DDE_FREQUESTED))
  52. DDE_FPOKRESERVED  = (~(DDE_FRELEASE))
  53.  
  54. XTYPF_NOBLOCK        = 0x0002
  55. XTYPF_NODATA         = 0x0004
  56. XTYPF_ACKREQ         = 0x0008
  57.  
  58. XCLASS_MASK          = 0xFC00
  59. XCLASS_BOOL          = 0x1000
  60. XCLASS_DATA          = 0x2000
  61. XCLASS_FLAGS         = 0x4000
  62. XCLASS_NOTIFICATION  = 0x8000
  63.  
  64. XTYP_ERROR           = (0x0000 | XCLASS_NOTIFICATION | XTYPF_NOBLOCK)
  65. XTYP_ADVDATA         = (0x0010 | XCLASS_FLAGS)
  66. XTYP_ADVREQ          = (0x0020 | XCLASS_DATA | XTYPF_NOBLOCK)
  67. XTYP_ADVSTART        = (0x0030 | XCLASS_BOOL)
  68. XTYP_ADVSTOP         = (0x0040 | XCLASS_NOTIFICATION)
  69. XTYP_EXECUTE         = (0x0050 | XCLASS_FLAGS)
  70. XTYP_CONNECT         = (0x0060 | XCLASS_BOOL | XTYPF_NOBLOCK)
  71. XTYP_CONNECT_CONFIRM = (0x0070 | XCLASS_NOTIFICATION | XTYPF_NOBLOCK)
  72. XTYP_XACT_COMPLETE   = (0x0080 | XCLASS_NOTIFICATION )
  73. XTYP_POKE            = (0x0090 | XCLASS_FLAGS)
  74. XTYP_REGISTER        = (0x00A0 | XCLASS_NOTIFICATION | XTYPF_NOBLOCK )
  75. XTYP_REQUEST         = (0x00B0 | XCLASS_DATA )
  76. XTYP_DISCONNECT      = (0x00C0 | XCLASS_NOTIFICATION | XTYPF_NOBLOCK )
  77. XTYP_UNREGISTER      = (0x00D0 | XCLASS_NOTIFICATION | XTYPF_NOBLOCK )
  78. XTYP_WILDCONNECT     = (0x00E0 | XCLASS_DATA | XTYPF_NOBLOCK)
  79. XTYP_MONITOR         = (0x00F0 | XCLASS_NOTIFICATION | XTYPF_NOBLOCK)
  80.  
  81. XTYP_MASK            = 0x00F0
  82. XTYP_SHIFT           = 4
  83.  
  84. TIMEOUT_ASYNC        = 0xFFFFFFFF
  85.  
  86. def get_winfunc(libname, funcname, restype=None, argtypes=(), _libcache={}):
  87.     """Retrieve a function from a library, and set the data types."""
  88.     from ctypes import windll
  89.  
  90.     if libname not in _libcache:
  91.         _libcache[libname] = windll.LoadLibrary(libname)
  92.     func = getattr(_libcache[libname], funcname)
  93.     func.argtypes = argtypes
  94.     func.restype = restype
  95.  
  96.     return func
  97.  
  98.  
  99. DDECALLBACK = WINFUNCTYPE(HDDEDATA, UINT, UINT, HCONV, HSZ, HSZ, HDDEDATA,
  100.                           ULONG_PTR, ULONG_PTR)
  101.  
  102. class DDE(object):
  103.     """Object containing all the DDE functions"""
  104.     AccessData         = get_winfunc("user32", "DdeAccessData",          LPBYTE,   (HDDEDATA, LPDWORD))
  105.     ClientTransaction  = get_winfunc("user32", "DdeClientTransaction",   HDDEDATA, (LPBYTE, DWORD, HCONV, HSZ, UINT, UINT, DWORD, LPDWORD))
  106.     Connect            = get_winfunc("user32", "DdeConnect",             HCONV,    (DWORD, HSZ, HSZ, PCONVCONTEXT))
  107.     CreateStringHandle = get_winfunc("user32", "DdeCreateStringHandleW", HSZ,      (DWORD, LPCWSTR, UINT))
  108.     Disconnect         = get_winfunc("user32", "DdeDisconnect",          BOOL,     (HCONV,))
  109.     GetLastError       = get_winfunc("user32", "DdeGetLastError",        UINT,     (DWORD,))
  110.     Initialize         = get_winfunc("user32", "DdeInitializeW",         UINT,     (LPDWORD, DDECALLBACK, DWORD, DWORD))
  111.     FreeDataHandle     = get_winfunc("user32", "DdeFreeDataHandle",      BOOL,     (HDDEDATA,))
  112.     FreeStringHandle   = get_winfunc("user32", "DdeFreeStringHandle",    BOOL,     (DWORD, HSZ))
  113.     QueryString        = get_winfunc("user32", "DdeQueryStringA",        DWORD,    (DWORD, HSZ, LPSTR, DWORD, c_int))
  114.     UnaccessData       = get_winfunc("user32", "DdeUnaccessData",        BOOL,     (HDDEDATA,))
  115.     Uninitialize       = get_winfunc("user32", "DdeUninitialize",        BOOL,     (DWORD,))
  116.  
  117. class DDEError(RuntimeError):
  118.     """Exception raise when a DDE error occurs."""
  119.     def __init__(self, msg, idInst=None):
  120.         if idInst is None:
  121.             RuntimeError.__init__(self, msg)
  122.         else:
  123.             RuntimeError.__init__(self, "%s (err=%s)" % (msg, hex(DDE.GetLastError(idInst))))
  124.  
  125. class DDEClient(object):
  126.     """The DDEClient class.
  127.  
  128.    Use this class to create and manage a connection to a service/topic.  To get
  129.    classbacks subclass DDEClient and overwrite callback."""
  130.  
  131.     def __init__(self, service, topic):
  132.         """Create a connection to a service/topic."""
  133.         from ctypes import byref
  134.  
  135.         self._idInst = DWORD(0)
  136.         self._hConv = HCONV()
  137.  
  138.         self._callback = DDECALLBACK(self._callback)
  139.         res = DDE.Initialize(byref(self._idInst), self._callback, 0x00000010, 0)
  140.         if res != DMLERR_NO_ERROR:
  141.             raise DDEError("Unable to register with DDEML (err=%s)" % hex(res))
  142.  
  143.         hszService = DDE.CreateStringHandle(self._idInst, service, 1200)
  144.         hszTopic = DDE.CreateStringHandle(self._idInst, topic, 1200)
  145.         self._hConv = DDE.Connect(self._idInst, hszService, hszTopic, PCONVCONTEXT())
  146.         DDE.FreeStringHandle(self._idInst, hszTopic)
  147.         DDE.FreeStringHandle(self._idInst, hszService)
  148.         if not self._hConv:
  149.             raise DDEError("Unable to establish a conversation with server", self._idInst)
  150.  
  151.     def __del__(self):
  152.         """Cleanup any active connections."""
  153.         if self._hConv:
  154.             DDE.Disconnect(self._hConv)
  155.         if self._idInst:
  156.             DDE.Uninitialize(self._idInst)
  157.  
  158.     def advise(self, item, stop=False):
  159.         """Request updates when DDE data changes."""
  160.         from ctypes import byref
  161.  
  162.         hszItem = DDE.CreateStringHandle(self._idInst, item, 1200)
  163.         hDdeData = DDE.ClientTransaction(LPBYTE(), 0, self._hConv, hszItem, CF_TEXT, XTYP_ADVSTOP if stop else XTYP_ADVSTART, TIMEOUT_ASYNC, LPDWORD())
  164.         DDE.FreeStringHandle(self._idInst, hszItem)
  165.         if not hDdeData:
  166.             raise DDEError("Unable to %s advise" % ("stop" if stop else "start"), self._idInst)
  167.         DDE.FreeDataHandle(hDdeData)
  168.  
  169.     def execute(self, command, timeout=5000):
  170.         """Execute a DDE command."""
  171.         pData = c_char_p(command)
  172.         cbData = DWORD(len(command) + 1)
  173.         hDdeData = DDE.ClientTransaction(pData, cbData, self._hConv, HSZ(), CF_TEXT, XTYP_EXECUTE, timeout, LPDWORD())
  174.         if not hDdeData:
  175.             raise DDEError("Unable to send command", self._idInst)
  176.         DDE.FreeDataHandle(hDdeData)
  177.  
  178.     def request(self, item, timeout=5000):
  179.         """Request data from DDE service."""
  180.         from ctypes import byref
  181.  
  182.         hszItem = DDE.CreateStringHandle(self._idInst, item, 1200)
  183.         hDdeData = DDE.ClientTransaction(LPBYTE(), 0, self._hConv, hszItem, CF_TEXT, XTYP_REQUEST, timeout, LPDWORD())
  184.         DDE.FreeStringHandle(self._idInst, hszItem)
  185.         if not hDdeData:
  186.             raise DDEError("Unable to request item", self._idInst)
  187.  
  188.         if timeout != TIMEOUT_ASYNC:
  189.             pdwSize = DWORD(0)
  190.             pData = DDE.AccessData(hDdeData, byref(pdwSize))
  191.         if not pData:
  192.             DDE.FreeDataHandle(hDdeData)
  193.             raise DDEError("Unable to access data", self._idInst)
  194.             # TODO: use pdwSize
  195.             DDE.UnaccessData(hDdeData)
  196.         else:
  197.             pData = None
  198.             DDE.FreeDataHandle(hDdeData)
  199.         return pData
  200.  
  201.     def callback(self, value, item=None):
  202.         """Calback function for advice."""
  203.         print "%s: %s" % (item, value)
  204.  
  205.     def _callback(self, wType, uFmt, hConv, hsz1, hsz2, hDdeData, dwData1, dwData2):
  206.         #if wType == XTYP_ADVDATA:
  207.         from ctypes import byref, create_string_buffer
  208.  
  209.         dwSize = DWORD(0)
  210.         pData = DDE.AccessData(hDdeData, byref(dwSize))
  211.         if pData:
  212.             item = create_string_buffer('\000' * 128)
  213.             DDE.QueryString(self._idInst, hsz2, item, 128, 1004)
  214.             self.callback(pData, item.value)
  215.             DDE.UnaccessData(hDdeData)
  216.         return DDE_FACK
  217.         return 0
  218.  
  219. def WinMSGLoop():
  220.     """Run the main windows message loop."""
  221.     from ctypes import POINTER, byref, c_ulong
  222.     from ctypes.wintypes import BOOL, HWND, MSG, UINT
  223.  
  224.     LPMSG = POINTER(MSG)
  225.     LRESULT = c_ulong
  226.     GetMessage = get_winfunc("user32", "GetMessageW", BOOL, (LPMSG, HWND, UINT, UINT))
  227.     TranslateMessage = get_winfunc("user32", "TranslateMessage", BOOL, (LPMSG,))
  228.     # restype = LRESULT
  229.     DispatchMessage = get_winfunc("user32", "DispatchMessageW", LRESULT, (LPMSG,))
  230.  
  231.     msg = MSG()
  232.     lpmsg = byref(msg)
  233.     while GetMessage(lpmsg, HWND(), 0, 0) > 0:
  234.         TranslateMessage(lpmsg)
  235.         DispatchMessage(lpmsg)
  236.  
  237. if __name__ == "__main__":
  238.     dde = DDEClient("MT4", "quote") # Создали экземпляр клиента DDE.
  239.     dde.advise("EURUSD") # Подписались на получение котировок для символа EURUSD.
  240.     dde.advise("GBPUSD") # Подписались на получение котировок для символа GBPUSD.
  241.     dde.advise("USDJPY") # Подписались на получение котировок для символа USDJPY.
  242.     WinMSGLoop()         # Запустили цикл обработки сообщений.
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement