Forum > Beginners

Using Dynamic Data Exchange (DDE) for MetaTrader 4 (MT4) [Example DDE Lazarus]

(1/1)

DavidTh30:
Connect Dynamic Data Exchange (DDE) to MetaTrader 4 (MT4)


--- Code: Pascal  [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} ---Type  CurrencyConnect = record    Life:Boolean;    Res: UINT;    g_idInst: DWORD;    MainTopic:PChar;    TopicMT4:HSZ;    ErrorMessageString:String;    Topic1:PChar;  //QUOTE  //Time   //TIMESEC    TopicQUOTE:HSZ;    hCnvTopicQUOTE: DWORD;    Topic2:PChar;  //BID    TopicBID:HSZ;    hCnvTopicBID: DWORD;    Topic3:PChar;  //ASK    TopicASK:HSZ;    hCnvTopicASK: DWORD;    Topic4:PChar;  //HIGH    TopicHIGH:HSZ;    hCnvTopicHIGH: DWORD;    Topic5:PChar;  //LOW    TopicLOW:HSZ;    hCnvTopicLOW: DWORD;  end; type  CurrencyPair = record    Life:Boolean;  //Connect=True, Error/Disconnect=False    Item:PChar;  //EURUSD //GBPUSD //USDJPY //AUDNZD       HSZPair:HSZ;    ErrorMessageString:String;    hDataQUOTE: HDDEDATA;    hDataBID: HDDEDATA;    hDataASK: HDDEDATA;    hDataHIGH: HDDEDATA;    hDataLOW: HDDEDATA;    Tem:PDWORD;    Result_:pbyte;  end;  Function GetDdeError(g_id: DWORD):String;Procedure MainLoop();Function CurrencyGethData(P_:CurrencyPair; M_:CurrencyConnect):String; var  Form1: TForm1;  MainCurrencyConnect:CurrencyConnect;  CurrencyEURUSD:CurrencyPair;  StartLoop, Life:Boolean;  DDECallbackMessage:String;  WM_MY_MESSAGE: UINT; Function TForm1.GetDdeError(g_id: DWORD):String;var  DDEError: Word;begin  GetDdeError:='';  DDEError := DdeGetLastError(g_id);  case DDEError of    DMLERR_ADVACKTIMEOUT: Result := 'Timeout on sync advise request';    DMLERR_BUSY: Result := 'Server is busy';    DMLERR_DATAACKTIMEOUT: Result := 'Timeout on sync data request';    DMLERR_DLL_NOT_INITIALIZED: Result := 'DDEML not initialised';    DMLERR_DLL_USAGE: Result := 'Invalid request';    DMLERR_EXECACKTIMEOUT: Result := 'Timeout on sync exec request';    DMLERR_INVALIDPARAMETER: Result := 'Invalid parameter in request';    DMLERR_LOW_MEMORY: Result := 'Server ran out of buffer memory';    DMLERR_MEMORY_ERROR: Result := 'Memory allocation error';    DMLERR_NO_CONV_ESTABLISHED: Result := 'No conversation established';    DMLERR_NOTPROCESSED: Result := 'Request not processed by server';    DMLERR_POKEACKTIMEOUT: Result := 'Timeout on sync poke request';    DMLERR_POSTMSG_FAILED: Result := 'PostMessage failed';    DMLERR_REENTRANCY: Result := 'Sync request already in progress';    DMLERR_SERVER_DIED: Result := 'Server died';    DMLERR_SYS_ERROR: Result := 'DDEML Internal error';    DMLERR_UNADVACKTIMEOUT: Result := 'Timeout on unadvise request';    DMLERR_UNFOUND_QUEUE_ID: Result := 'Invalid transaction ID';  end;end; Function DDECallback(CallType, Fmt: UINT; Conv: HConv; hsz1, hsz2: HSZ;    Data: HDDEData; Data1, Data2: DWORD): HDDEData; stdcall;begin  Result := 0;  case CallType of    xtyp_Register:      begin        DDECallbackMessage:='xtyp_Register';        Result:=-1;      end;    xtyp_Unregister:      begin        DDECallbackMessage:='xtyp_Unregister';        Result:=-1;      end;    xtyp_xAct_Complete:      begin        DDECallbackMessage:='xtyp_xAct_Complete';      end;    xtyp_Request, Xtyp_AdvData:      begin        DDECallbackMessage:='Xtyp_AdvData';      end;    xtyp_Disconnect:      begin        DDECallbackMessage:='xtyp_Disconnect';        Result:=-1;      end;    XTYP_ERROR:      begin        DDECallbackMessage:='XTYP_ERROR';        Result:=-1;      end;    XTYP_EXECUTE:      begin        DDECallbackMessage:='XTYP_EXECUTE';      end;    XTYPF_NOBLOCK:      begin        DDECallbackMessage:='XTYPF_NOBLOCK';        Result:=-1;      end;    XTYP_CONNECT, XTYP_CONNECT_CONFIRM:      begin        DDECallbackMessage:='XTYP_CONNECT, XTYP_CONNECT_CONFIRM';      end;    XTYP_ADVREQ:      begin        //ShowMessage('XTYP_ADVREQ');        DDECallbackMessage:='XTYP_ADVREQ';      end;    xtyp_Poke:      begin        DDECallbackMessage:='xtyp_Poke';      end;    xtyp_AdvStart:      begin        DDECallbackMessage:='xtyp_AdvStart';      end;    xtyp_AdvStop:      begin        DDECallbackMessage:='xtyp_AdvStop';      end;    DMLERR_SERVER_DIED:      begin        DDECallbackMessage:='DMLERR_SERVER_DIED';      end;    DMLERR_SYS_ERROR:      begin        DDECallbackMessage:='DMLERR_SYS_ERROR';      end;    DMLERR_BUSY:      begin        DDECallbackMessage:='DMLERR_BUSY';      end;    DMLERR_DATAACKTIMEOUT:      begin        DDECallbackMessage:='DMLERR_DATAACKTIMEOUT';      end;    DMLERR_ADVACKTIMEOUT:      begin        DDECallbackMessage:='DMLERR_ADVACKTIMEOUT';      end;  end;end; procedure TForm1.FreeDataHandle(P_:CurrencyPair);begin    DdeFreeDataHandle(P_.hDataQUOTE);    DdeFreeDataHandle(P_.hDataBID);    DdeFreeDataHandle(P_.hDataASK);    DdeFreeDataHandle(P_.hDataHIGH);    DdeFreeDataHandle(P_.hDataLOW);end;   Function TForm1.CurrencyGethData(P_:CurrencyPair; M_:CurrencyConnect):String;var  Buf: String[255];  Tem:String;begin    Tem:=P_.Item+chr(13);    Application.ProcessMessages;     P_.hDataQUOTE := DdeClientTransaction(nil, 0, M_.hCnvTopicQUOTE, P_.HSZPair, CF_TEXT, XTYP_REQUEST, 5000, nil);    if P_.hDataQUOTE<>0 then P_.Result_:=DdeAccessData(P_.hDataQUOTE,P_.Tem);    //DdeGetData(P_.hDataQUOTE, @Buf, SizeOf(Buf), 0);    //DdeGetData(hData, @Buf, 255, 0);    //tem2 := Buf;    //strcopy(Result, PChar(P_.Result_));    if P_.hDataQUOTE=0 then    Tem:=Tem+'QUOTE: N/A' else Tem:=Tem+'QUOTE:'+PChar(P_.Result_)+chr(13);//Tem:='QUOTE:'+PChar(P_.Result_)+chr(13);     //Tem:='QUOTE:'+tem2+chr(13);    Application.ProcessMessages;     P_.hDataBID := DdeClientTransaction(nil, 0, M_.hCnvTopicBID, P_.HSZPair, CF_TEXT, XTYP_REQUEST, 5000, nil);    if P_.hDataBID<>0 then P_.Result_:=DdeAccessData(P_.hDataBID,P_.Tem);    if P_.hDataBID=0 then    Tem:=Tem+'BID: N/A' else Tem:=Tem+'BID:'+PChar(P_.Result_)+chr(13);    Application.ProcessMessages;     P_.hDataASK := DdeClientTransaction(nil, 0, M_.hCnvTopicASK, P_.HSZPair, CF_TEXT, XTYP_REQUEST, 5000, nil);    if P_.hDataASK<>0 then P_.Result_:=DdeAccessData(P_.hDataASK,P_.Tem);    if P_.hDataASK=0 then    Tem:=Tem+'ASK: N/A' else Tem:=Tem+'ASK:'+PChar(P_.Result_)+chr(13);    Application.ProcessMessages;     P_.hDataHIGH := DdeClientTransaction(nil, 0, M_.hCnvTopicHIGH, P_.HSZPair, CF_TEXT, XTYP_REQUEST, 5000, nil);    if P_.hDataHIGH<>0 then P_.Result_:=DdeAccessData(P_.hDataHIGH,P_.Tem);    if P_.hDataHIGH=0 then    Tem:=Tem+'HIGH: N/A' else Tem:=Tem+'HIGH:'+PChar(P_.Result_)+chr(13);    Application.ProcessMessages;     P_.hDataLOW := DdeClientTransaction(nil, 0, M_.hCnvTopicLOW, P_.HSZPair, CF_TEXT, XTYP_REQUEST, 5000, nil);    if P_.hDataLOW<>0 then P_.Result_:=DdeAccessData(P_.hDataLOW,P_.Tem);    if P_.hDataLOW=0 then    Tem:=Tem+'LOW: N/A' else Tem:=Tem+'LOW:'+PChar(P_.Result_);    Result:=Tem;    Application.ProcessMessages;     FreeDataHandle(CurrencyEURUSD);     Application.ProcessMessages;end;  procedure TForm1.MainLoop();begin  if StartLoop = Life then exit;  Life:=StartLoop;  while StartLoop do  begin    EURUSD.Caption := CurrencyGethData(CurrencyEURUSD,MainCurrencyConnect);     if DDECallbackMessage<>'' then Label2.Caption:='Status: '+DDECallbackMessage;    Application.ProcessMessages;  end;end;  procedure TForm1.FormCreate(Sender: TObject);begin  StartLoop:=False;  Life:=False;   MainCurrencyConnect.g_idInst:=0;  MainCurrencyConnect.ErrorMessageString:='';  MainCurrencyConnect.MainTopic:='MT4';  MainCurrencyConnect.Topic1:='QUOTE'; //QUOTE TIME TIMESEC  MainCurrencyConnect.Topic2:='BID';  MainCurrencyConnect.Topic3:='ASK';  MainCurrencyConnect.Topic4:='HIGH';  MainCurrencyConnect.Topic5:='LOW';   CurrencyEURUSD.Item:='EURUSD';  CurrencyEURUSD.ErrorMessageString:='';   MainCurrencyConnect.Res:=DdeInitialize(@MainCurrencyConnect.g_idInst, @DdeCallback, APPCLASS_STANDARD, 0); MainCurrencyConnect.hCnvTopicQUOTE := DdeConnect(MainCurrencyConnect.g_idInst, MainCurrencyConnect.TopicMT4, MainCurrencyConnect.TopicQUOTE, nil);    MainCurrencyConnect.hCnvTopicBID := DdeConnect(MainCurrencyConnect.g_idInst, MainCurrencyConnect.TopicMT4, MainCurrencyConnect.TopicBID, nil);    MainCurrencyConnect.hCnvTopicASK := DdeConnect(MainCurrencyConnect.g_idInst, MainCurrencyConnect.TopicMT4, MainCurrencyConnect.TopicASK, nil);    MainCurrencyConnect.hCnvTopicHIGH := DdeConnect(MainCurrencyConnect.g_idInst, MainCurrencyConnect.TopicMT4, MainCurrencyConnect.TopicHIGH, nil);    MainCurrencyConnect.hCnvTopicLOW := DdeConnect(MainCurrencyConnect.g_idInst, MainCurrencyConnect.TopicMT4, MainCurrencyConnect.TopicLOW, nil);      if MainCurrencyConnect.hCnvTopicQUOTE <> 0 then    begin      DdeClientTransaction(nil, 0, MainCurrencyConnect.hCnvTopicQUOTE, CurrencyEURUSD.HSZPair, CF_TEXT, XTYP_ADVSTART, 50, nil);    end;  end; Function TForm1.CurrencyGethData(P_:CurrencyPair; M_:CurrencyConnect):String;var  Buf: String[255];  Tem:String;begin    Tem:=P_.Item+chr(13);    Application.ProcessMessages;     P_.hDataQUOTE := DdeClientTransaction(nil, 0, M_.hCnvTopicQUOTE, P_.HSZPair, CF_TEXT, XTYP_REQUEST, 5000, nil);    if P_.hDataQUOTE<>0 then P_.Result_:=DdeAccessData(P_.hDataQUOTE,P_.Tem);    //DdeGetData(P_.hDataQUOTE, @Buf, SizeOf(Buf), 0);    //DdeGetData(hData, @Buf, 255, 0);    //tem2 := Buf;    //strcopy(Result, PChar(P_.Result_));    if P_.hDataQUOTE=0 then    Tem:=Tem+'QUOTE: N/A' else Tem:=Tem+'QUOTE:'+PChar(P_.Result_)+chr(13);//Tem:='QUOTE:'+PChar(P_.Result_)+chr(13);     //Tem:='QUOTE:'+tem2+chr(13);    Application.ProcessMessages;     P_.hDataBID := DdeClientTransaction(nil, 0, M_.hCnvTopicBID, P_.HSZPair, CF_TEXT, XTYP_REQUEST, 5000, nil);    if P_.hDataBID<>0 then P_.Result_:=DdeAccessData(P_.hDataBID,P_.Tem);    if P_.hDataBID=0 then    Tem:=Tem+'BID: N/A' else Tem:=Tem+'BID:'+PChar(P_.Result_)+chr(13);    Application.ProcessMessages;     P_.hDataASK := DdeClientTransaction(nil, 0, M_.hCnvTopicASK, P_.HSZPair, CF_TEXT, XTYP_REQUEST, 5000, nil);    if P_.hDataASK<>0 then P_.Result_:=DdeAccessData(P_.hDataASK,P_.Tem);    if P_.hDataASK=0 then    Tem:=Tem+'ASK: N/A' else Tem:=Tem+'ASK:'+PChar(P_.Result_)+chr(13);    Application.ProcessMessages;     P_.hDataHIGH := DdeClientTransaction(nil, 0, M_.hCnvTopicHIGH, P_.HSZPair, CF_TEXT, XTYP_REQUEST, 5000, nil);    if P_.hDataHIGH<>0 then P_.Result_:=DdeAccessData(P_.hDataHIGH,P_.Tem);    if P_.hDataHIGH=0 then    Tem:=Tem+'HIGH: N/A' else Tem:=Tem+'HIGH:'+PChar(P_.Result_)+chr(13);    Application.ProcessMessages;     P_.hDataLOW := DdeClientTransaction(nil, 0, M_.hCnvTopicLOW, P_.HSZPair, CF_TEXT, XTYP_REQUEST, 5000, nil);    if P_.hDataLOW<>0 then P_.Result_:=DdeAccessData(P_.hDataLOW,P_.Tem);    if P_.hDataLOW=0 then    Tem:=Tem+'LOW: N/A' else Tem:=Tem+'LOW:'+PChar(P_.Result_);    Result:=Tem;    Application.ProcessMessages;     FreeDataHandle(P_);     Application.ProcessMessages;end;   procedure TForm1.MainLoop();var  Tem:String;begin  if StartLoop = Life then exit;  Life:=StartLoop;  while StartLoop do  begin    EURUSD.Caption := CurrencyGethData(CurrencyEURUSD,MainCurrencyConnect);     if DDECallbackMessage<>'' then Label2.Caption:='Status: '+DDECallbackMessage;    Application.ProcessMessages;  end;end;    procedure TForm1.FormClose(Sender: TObject; var CloseAction: TCloseAction);begin  StartLoop:=False;  DdeFreeStringHandle(MainCurrencyConnect.g_idInst, MainCurrencyConnect.TopicQUOTE);  DdeFreeStringHandle(MainCurrencyConnect.g_idInst, MainCurrencyConnect.TopicBID);  DdeFreeStringHandle(MainCurrencyConnect.g_idInst, MainCurrencyConnect.TopicASK);  DdeFreeStringHandle(MainCurrencyConnect.g_idInst, MainCurrencyConnect.TopicHIGH);  DdeFreeStringHandle(MainCurrencyConnect.g_idInst, MainCurrencyConnect.TopicLOW);  FreeDataHandle(CurrencyEURUSD);end;
 :) :) :) :) :) :)

DDE4.zip is the client of DDE to connect the MT4.
The code still have a problem with risk data.
Somebody know how to create own DDE server using Pascal?

Thaddy:
You basically need to use lowlevel windows API calls. see msdn https://msdn.microsoft.com/en-us/library/windows/desktop/ms648775(v=vs.85).aspx
See this discussion: http://free-pascal-lazarus.989080.n3.nabble.com/Lazarus-Windows-DDE-td4034195.html
Note that if you have a  Delphi version (pref any of D6 to D2007) with sourcecode you can use their DDE units (the lowlevel classes, no components) without many problems and only on 32 bit windows.

It is easy to translate those examples if you have a little knowledge of C(++) but real programmers do have that, don't you?  :D :D :P.

jamie:
So I take if by your comment 'only on 32 bit windows" that the DDE is not supported for 64 bit OS ?

Thaddy:
It is legacy. But with the winapi it should still work on 64 bit too. E.g.I got a Delphi 2 unit from torry's and all I needed to do was change the integer parameters to PtrUnit.
I am not giving a link or my code, because that code (on torry.net) is a DDE bug fix too and a possible copyright infringement. You will find it...

DavidTh30:
Solve my own problem.   :D :D :D
Here sample project very clear.

Navigation

[0] Message Index

Go to full version