Discussion of article "Communicating With MetaTrader 5 Using Named Pipes Without Using DLLs" - page 3

 
Renat:
I think the issue of communication between terminals has a small proportion of application.

But communication with external systems is more important and applicable. That's what the secure channel was opened for.

Nobody is arguing with that, I mean, the declaration of what it was all for. But the problem is how it was implemented. After all, external systems are not necessarily written in C, but can be created in different programming languages. And it is possible to connect to the terminal through a named channel in many programming languages only as a client through file operations. But the technology was chosen client-server, i.e. such that two clients will not meet each other if there is a gap between them without a bridge - gateway. I.e. either client-client technology or a gateway should have been provided. And so it turned out like in grandpa Krylov's fable "The Fox and the Grapes":

Even though the eye sees,

But the eye can't see.

© I. Krylov


It was necessary to look at how others have a similar connection with external systems realised. For example: VMWare, MS SQL Server, MySQL, external modems and so on. Their server part is implemented internally. And it is very convenient to join without any crutches, even through a named channel, or via TCP/IP and other communication channels. And you can even choose, for example, through a named channel, but remotely via TCP/IP with the help of "Named Pipe TCP Proxy" utility. I.e. users do not need to create any additional crutches, but only choose the most suitable client application and immediately connect and work.
 
Yuri, you are clearly confused. Server pipelines can be easily created in other languages. It's just WinAPI.

Take into account that MQL5 is a secure application environment, and clearly a client one, in which it is unreasonable to make server functions.

I am not sure that server functionality was declared. Client functionality was planned and implemented.
 

I think I made the code for the gateway. Haven't tested it yet. I'll download and install MinGW and see what's wrong.

#using <System.Core.dll>

using namespace System;
using namespace System::IO;
using namespace System::IO::Pipes;
using namespace System::Text;
using namespace System::Threading;


public ref class PipeServer
{
private:
       NamedPipeServerStream^ pipeServer1;
       NamedPipeServerStream^ pipeServer2;
    

public:
    static void Main()
    {
        int i;
        Thread server;

        Console::WriteLine("\n*** Named pipe server stream with impersonation example ***\n");
        Console::WriteLine("Waiting for client connect...\n");
        // Create the first subprocess to copy information from named channels
        Thread server = gcnew Thread(gcnew ThreadStart(&ServerThread));
        // Run it
        server->Start();
        Thread::Sleep(250);
        // If the client has crashed
        if (servers != nullptr)
        {
          if (server->Join(250))
                                        {
            Console::WriteLine("Server finished.", server->ManagedThreadId);
            servers = nullptr;
          }
        }
        Console::WriteLine("\nServer threads exhausted, exiting.");
    }

private:
    static void ServerThread()
    {
        int threadId;
        bool needclose = false;
        if (i == 0) 
        {
            // Create two named channels
            pipeServer1 = gcnew NamedPipeServerStream("\\\\.\\pipe\\testpipe1", PipeDirection::InOut, numThreads);
            pipeServer2 = gcnew NamedPipeServerStream("\\\\.\\pipe\\testpipe2", PipeDirection::InOut, numThreads);
        }
                                
        threadId = Thread::CurrentThread->ManagedThreadId;


        // Waiting for a connection from the client
        pipeServer->WaitForConnection();

        Console::WriteLine("Client connected on thread.", threadId);
        try
        {  
          // Depending on the order of the subprocess, copy data from one named channel to another.
          if (i == 0) {
            needclose = true;
            i++;
            // Create another subprocess to copy information from the named channels on the counter
            Thread server = gcnew Thread(gcnew ThreadStart(&ServerThread));
            // Start the subprocess
            server->Start();
            pipeServer1->CopyToAsync(pipeServer2);
          } else {
            pipeServer2->CopyToAsync(pipeServer1);
          }
        }
        // Exception handler for dropped clients 
        catch (IOException^ e)
        {
            Console::WriteLine("ERROR: {0}", e->Message);
        }
        if (needclose) {
          pipeServer1->Close();
          pipeServer2->Close();
        }
     }
};

int main()
{
    PipeServer::Main();
}
 

MinGW installed, configured and bolted to NetBeans.

The idea of creating a full-duplex gateway from two server channels and redirecting information to clients from one channel to the other did not work. If one server subprocess reads a channel and the second one sends something to it, full duplex doesn't work (at least on Windows XP), because sometimes the subprocess that reads from the channel intercepts messages from the subprocess that writes to the same channel and returns the information back.

If you remove one of the subprocesses, the transmission goes by simplex from client to client without any problems.

However, not all is lost, because there is also an overlapped mode, i.e. when not two, but only one channel is created, and several clients connect to it simultaneously. In this case the server does not need to read information from the channel all the time, because everything is based on events. I.e. if any client sent information to the channel, the server reads its event and extracts the transmitted message from there. And to redirect the received information to the second client - it is already a matter of technique. I'm in the process of creating such an implementation.

 

That's it. I've given up. I'm tired of fiddling with C++ code and even through Win API. Not so much coding as digging through scattered scraps of information on MSDN to try to understand how everything should work. Experience is lacking, so sent all this stuff to Service Work. See Redo the C++ code into a two-way full duplex gateway

Maybe someone more experienced can easily handle this task? I don't rule out that the reason for failures is that I couldn't figure out the settings of named channels. I.e. it is possible that in these very settings you need to write something correctly and everything may work. I have not managed to do anything but in simplex mode and start it so far.

 

I decided to try to make friendship between MQL and AutoIt through pipelines.

In short, only one rake, and everywhere :)

Well, I managed to transfer to AutoIt with a bit of luck, only the first 4 bytes had to be discarded, there is some "rubbish". What is this "rubbish"?

Then I tried to transfer to MQL, it's even more fun here - nothing comes at all. Or maybe I don't organise the transfer correctly.... Maybe the whole problem is in those 4 bytes?

What can you tell me?

 
fyords:

I decided to try to make friendship between MQL and AutoIt through pipelines.

In short, only one rake, and everywhere :)

Well, I managed to transfer to AutoIt with a bit of luck, only the first 4 bytes had to be discarded, there is some "rubbish". What is this "rubbish"?

Then I tried to transfer to MQL, it's even more fun here - nothing comes at all. Or maybe I don't organise the transfer correctly.... Maybe the whole problem is in those 4 bytes?

What can you tell me?

Sho, you too?
Клуб Телепатов - MQL4 форум
  • www.mql5.com
Клуб Телепатов - MQL4 форум
 
sergeev:
So, you're in there too?

No, I'm right here.) So, it was like this:

MQL5

#include <Files\FilePipe.mqh>

CFilePipe  ExtPipe;
//+------------------------------------------------------------------+
//| Script programme start function|
//+------------------------------------------------------------------+
void OnStart()
  {
//--- wait for pipe server
   while(!IsStopped())
     {
      if(ExtPipe.Open("\\\\.\\pipe\\MQL5.Pipe.Server",FILE_READ|FILE_WRITE|FILE_BIN|FILE_ANSI)!=INVALID_HANDLE) break;
      Sleep(250);
     }
   Print("Client: pipe opened");
//--- send welcome message
   string msg=__FILE__+" on MQL5 build "+IntegerToString(__MQ5BUILD__);
   //Print(msg);
   
   if(!ExtPipe.WriteString(msg))
     {
      Print("Client: sending welcome message failed");
      return;
     }
  }

AutoIt

#include <NamedPipes.au3>
#include <WinAPI.au3>

$pipe="\\.\pipe\MQL5.Pipe.Server"
$hwnd_pipe=_NamedPipes_CreateNamedPipe($pipe) ;//Creates an instance of a named pipe
_NamedPipes_ConnectNamedPipe($hwnd_pipe) ;//Enables a named pipe server process to wait for a client process to connect
ConsoleWrite(ReadMsg($hwnd_pipe)) ;//Writes data to the STDOUT stream

Func ReadMsg($hPipe) ;//ReadMsg
        Local $bSuccess, $iRead, $pBuffer, $tBuffer, $BUFSIZE=4096

        $tBuffer = DllStructCreate("char Text[4096]")
        $pBuffer = DllStructGetPtr($tBuffer)
        _WinAPI_ReadFile($hPipe, $pBuffer, 4, $iRead, 0)
        While 1
                $bSuccess = _WinAPI_ReadFile($hPipe, $pBuffer, $BUFSIZE, $iRead, 0)
                If $iRead = 0 Then ExitLoop
                If Not $bSuccess Or (_WinAPI_GetLastError() = 234) Then ExitLoop
                Return StringLeft(DllStructGetData($tBuffer, "Text"), $iRead)
        WEnd
 EndFunc
 
 Func WriteMsg($hPipe,$sMessage) ;//WriteMsg
        Local $iWritten, $iBuffer, $pBuffer, $tBuffer

        $iBuffer = StringLen($sMessage) + 1
        $tBuffer = DllStructCreate("char Text[" & $iBuffer & "]")
        $pBuffer = DllStructGetPtr($tBuffer)
        DllStructSetData($tBuffer, "Text", $sMessage)
        If Not _WinAPI_WriteFile($hPipe, $pBuffer, $iBuffer, $iWritten, 0) Then
                LogError("WriteMsg: _WinAPI_WriteFile failed")
        EndIf
EndFunc

This part of the transfer from MQL to AutoIt. It works by.

With a string from Func ReadMsg($hPipe)

_WinAPI_ReadFile($hPipe, $pBuffer, 4, $iRead, 0)

I eat the first 4 bytes and everything works.

Question: what do these first 4 bytes contain?

 
fyords:

I eat out the first 4 bytes and everything works.

Question: what do these first 4 bytes contain?

When transmitting strings, 4 bytes of the string size come first.
 
Dima_S:
Renat, when is it planned to make pips in MT4?
They were made in the last build of MetaTrader 4.