Using named pipes

 

Hi,

I'm trying to use this article https://www.mql5.com/en/articles/115 to create a named pipe, but it is not working. Actually the problem happens when I try to create it. Here's the simplified code:

cnamedpipes_simple.mqh:

//+------------------------------------------------------------------+
//|                                           cnamedpipes_simple.mqh |
//|                                      Copyright 2010, Investeo.pl |
//|                                                http:/Investeo.pl |
//+------------------------------------------------------------------+
#property copyright "Copyright 2010, Investeo.pl"
#property link      "http:/Investeo.pl"

#include <WinAPI\fileapi.mqh>
#include <WinAPI\errhandlingapi.mqh>

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
enum ENUM_PIPE_MODE
  {
   PIPE_TYPE_RW_BYTE=0,
   PIPE_TYPE_READ_MESSAGE=2,
   PIPE_TYPE_WRITE_MESSAGE=4,
  };

#define PIPE_WAIT 0
#define PIPE_NOWAIT 1

#define ERROR_PIPE_CONNECTED 535
#define ERROR_BROKEN_PIPE 109

#define INVALID_HANDLE_VALUE -1
#define GENERIC_READ  0x80000000
#define GENERIC_WRITE  0x40000000
#define PIPE_ACCESS_OUTBOUND 0x00000002
#define PIPE_ACCESS_INBOUND  0x00000001
#define PIPE_ACCESS_DUPLEX   0x00000003
#define OPEN_EXISTING  3
#define PIPE_UNLIMITED_INSTANCES 255
#define MQLTICK_SIZE 40
#define PIPE_BUFFER_SIZE 4096
#define STR_SIZE 255

#define PIPE_PREFIX "\\\\.\\pipe\\ThePipe_"

#import "kernel32.dll"
//int CreateNamedPipeW(string pipeName,ulong openMode,int pipeMode,int maxInstances,int outBufferSize,int inBufferSize,int defaultTimeOut,int security);
//int CreateNamedPipe(string lpName, uint dwOpenMode, uint dwPipeMode, uint nMaxInstances, uint nOutBufferSize, uint nInBufferSize, uint nDefaultTimeOut, int lpSecurityAttributes);
HANDLE CreateNamedPipeA(string lpName,
                        uint dwOpenMode,
                        uint dwPipeMode,
                        uint nMaxInstances,
                        uint nOutBufferSize,
                        uint nInBufferSize,
                        uint nDefaultTimeOut,
                        uint lpSecurityAttributes);
int CloseHandle(HANDLE fileHandle);
#import

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
class CNamedPipe
  {
private:
   HANDLE            hPipe; // pipe handle
   string            pipeNumber;
   string            pipeNamePrefix;
   int               BufferSize;

protected:

public:
                     CNamedPipe();
                    ~CNamedPipe();

   bool              Create(int account);
   int               Close();
   uint              WriteANSI(string message);
   string            ReadANSI();
  };
//+------------------------------------------------------------------+
//| CNamedPipe constructor
//+------------------------------------------------------------------+
CNamedPipe::CNamedPipe(void)
  {
   pipeNamePrefix=PIPE_PREFIX;
   BufferSize=PIPE_BUFFER_SIZE;
   hPipe=INVALID_HANDLE_VALUE;
   uint err=kernel32::GetLastError();
  }
//+------------------------------------------------------------------+
//| CNamedPipe destructor
//+------------------------------------------------------------------+
CNamedPipe::~CNamedPipe(void)
  {
   if(hPipe!=INVALID_HANDLE_VALUE)
     {
      CloseHandle(hPipe);
     }
  }
//+------------------------------------------------------------------+
/// Create() : try to create a new instance of Named Pipe
/// \param account - source terminal account number
/// \return true - if created, false otherwise
//+------------------------------------------------------------------+
bool CNamedPipe::Create(int account=0)
  {
   if(account==0)
      pipeNumber=IntegerToString(AccountInfoInteger(ACCOUNT_LOGIN));
   else
      pipeNumber=IntegerToString(account);

   string fullPipeName=pipeNamePrefix+pipeNumber;

   hPipe=CreateNamedPipeA(fullPipeName,
                          PIPE_ACCESS_DUPLEX,
                          PIPE_TYPE_RW_BYTE,
                          PIPE_UNLIMITED_INSTANCES,
                          BufferSize*sizeof(ushort),
                          BufferSize*sizeof(ushort),
                          0,
                          NULL);

   if(hPipe==INVALID_HANDLE_VALUE)
      return false;
   else
      return true;

  }

//+------------------------------------------------------------------+
/// Close() : close pipe handle
/// \return 0 if successfull, non-zero otherwise
//+------------------------------------------------------------------+
int CNamedPipe::Close(void)
  {
   return CloseHandle(hPipe);
  }

//+------------------------------------------------------------------+
/// WriteANSI() : write ANSI string to a pipe                        |
/// \param message - string to send                                  |
/// \return number of bytes written to a pipe                        |
//+------------------------------------------------------------------+
uint CNamedPipe::WriteANSI(string message)
  {
   ushort buffer[];
   uint number_of_bytes_to_write=0;
   uint number_of_bytes_written=0;

   number_of_bytes_to_write = StringToShortArray(message, buffer);
   if(!WriteFile(hPipe,buffer,number_of_bytes_to_write,number_of_bytes_written,NULL))
     {
      Print(kernel32::GetLastError());
     }
   return number_of_bytes_written;
  }

//+------------------------------------------------------------------+
/// ReadANSI(): read ANSI string from a pipe
/// \return unicode string (MQL5 string)
//+------------------------------------------------------------------+
string CNamedPipe::ReadANSI()
  {
   ushort buffer[];
   uint number_of_bytes_to_read=2;
   uint number_of_bytes_read;
   string ret;

   ReadFile(hPipe,buffer,number_of_bytes_to_read,number_of_bytes_read,NULL);
   if(number_of_bytes_read!=0)
     {
      ret=ShortArrayToString(buffer);
     }

   return ret;
  }
//+------------------------------------------------------------------+

NamedPipesServer.mq5:

//+------------------------------------------------------------------+
//|                                             NamedPipesServer.mq5 |
//|                                      Copyright 2020, CompanyName |
//|                                       http://www.companyname.net |
//+------------------------------------------------------------------+
#include "cnamedpipes_simple.mqh"

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void OnStart()
  {
   CNamedPipe pipe;
   if(pipe.Create(1)==true)
     {
      if(!pipe.WriteANSI("a"))
        {
         Print(kernel32::GetLastError());
        }
      else
        {
         Print(pipe.ReadANSI());
        }
      pipe.Close();
     }
  }
//+------------------------------------------------------------------+

Here is the problem when I try to create it:

Any help is appreciated.

Thank you. 

A DLL-free solution to communicate between MetaTrader 5 terminals using Named Pipes
A DLL-free solution to communicate between MetaTrader 5 terminals using Named Pipes
  • www.mql5.com
The article describes how to implement Interprocess Communication between MetaTrader 5 client terminals using named pipes. For the use of the named pipes, the CNamedPipes class is developed. For the test of its use and to measure the connection throughput, the tick indicator, the server and client scripts are presented. The use of named pipes is sufficient for real-time quotes.
 

Try it again with 

CreateNamedPipeW
 
lippmaje:

Try it again with 

Thank you, but actually I tried with:

  • CreateNamedPipeW
  • CreateNamedPipe
  • CreateNamedPipeA

I'm afraid the function signature is wrong, but I've checked at Microsoft site and it seems OK.

CreateNamedPipeA function (winbase.h) - Win32 apps
CreateNamedPipeA function (winbase.h) - Win32 apps
  • 2018.12.05
  • windows-sdk-content
  • docs.microsoft.com
Creates an instance of a named pipe and returns a handle for subsequent pipe operations.
 

Proper function call should be CreateNamedPipeW. Check that sizes of all arguments match with sizeof() operator.

(ps Ignore the link to order_calc_margin, it's auto-generated whenever you type 'check'.)

 
lippmaje:

Proper function call should be CreateNamedPipeW. Check that sizes of all arguments match with sizeof() operator.

(ps Ignore the link to order_calc_margin, it's auto-generated whenever you type 'check'.)

Trying with CreateNamedPipeW() and changing sizeof to other types, I still got the same error with this output:

Access violation at 0x00007FFADD6F6A1C read to 0x00007FF600000010
   crash -->  00007FFADD6F6A1C 837A1000          cmp        dword [rdx+0x10], 0x0
              00007FFADD6F6A20 448D4102          lea        r8d, [rcx+0x2]
              00007FFADD6F6A24 488B4208          mov        rax, [rdx+0x8]
              00007FFADD6F6A28 410F45C8          cmovnz     ecx, r8d
              00007FFADD6F6A2C 488945B8          mov        [rbp-0x48], rax
              00007FFADD6F6A30 894DB0            mov        [rbp-0x50], ecx
              00007FFADD6F6A33 4885C0            test       rax, rax

00: 0x00007FFADD6F6A1C
01: 0x000001F49977A3C4
02: 0x000001F49BFCFB80
03: 0x000001F49BECE1A8
04: 0x000001F499779B70
05: 0x0000000000000206
 
Felipe Augusto Torres Maggico:

Trying with CreateNamedPipeW() and changing sizeof to other types, I still got the same error with this output:

This is the signature that works:

int CreateNamedPipeW(string pipeName,ulong openMode,ulong pipeMode,int maxInstances,int outBufferSize,int inBufferSize,int defaultTimeOut,int security);

It is working and creating the named pipe.

Now I got kernel32::GetLastError() = 536 when calling WriteFile() from .\MQL5\Include\WinAPI\fileapi.mqh. Any ideas?

 
Felipe Augusto Torres Maggico:

This is the signature that works:

It is working and creating the named pipe.

Now I got kernel32::GetLastError() = 536 when calling WriteFile() from .\MQL5\Include\WinAPI\fileapi.mqh. Any ideas?

ERROR_PIPE_LISTENING (https://docs.microsoft.com/en-us/windows/win32/debug/system-error-codes--500-999-)

536 (0x218)

Waiting for a process to open the other end of the pipe.

Let's try to fix it.

System Error Codes (500-999) (WinError.h) - Win32 apps
System Error Codes (500-999) (WinError.h) - Win32 apps
  • 2019.07.18
  • Karl-Bridge-Microsoft
  • docs.microsoft.com
Describes error codes 500-999 defined in the WinError.h header file and is intended for developers.
 
Felipe Augusto Torres Maggico:

This is the signature that works:

It is working and creating the named pipe.

👍

 

Hi all, I've working on this code and I still can't get it working.

Here's the library code:

//+------------------------------------------------------------------+
//|                                           cnamedpipes_simple.mqh |
//|                                      Copyright 2010, Investeo.pl |
//|                                                http:/Investeo.pl |
//+------------------------------------------------------------------+
#property copyright "Copyright 2010, Investeo.pl"
#property link      "http:/Investeo.pl"

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
#include <WinAPI\fileapi.mqh>
#include <WinAPI\errhandlingapi.mqh>

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
#define PIPE_TYPE_RW_BYTE       0
#define PIPE_TYPE_READ_MESSAGE  2
#define PIPE_TYPE_WRITE_MESSAGE 4

#define PIPE_WAIT   0
#define PIPE_NOWAIT 1

#define ERROR_PIPE_CONNECTED 535
#define ERROR_BROKEN_PIPE    109

#define INVALID_HANDLE_VALUE -1
#define GENERIC_READ         0x80000000
#define GENERIC_WRITE        0x40000000
#define PIPE_ACCESS_OUTBOUND 0x00000002
#define PIPE_ACCESS_INBOUND  0x00000001
#define PIPE_ACCESS_DUPLEX   0x00000003
#define OPEN_EXISTING        3
#define PIPE_UNLIMITED_INSTANCES 255
#define PIPE_BUFFER_SIZE         4096
#define STR_SIZE 255

#define PIPE_PREFIX "\\\\.\\pipe\\ThePipe_"

#import "kernel32.dll"
int CreateNamedPipeW(string pipeName,ulong openMode,ulong pipeMode,int maxInstances,int outBufferSize,int inBufferSize,int defaultTimeOut,int security);
bool ConnectNamedPipe(HANDLE pipeHandle,int overlapped);
int CloseHandle(HANDLE fileHandle);
int WaitNamedPipeW(string lpNamedPipeName,int nTimeOut);
#import

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
class CNamedPipe
  {
private:
   HANDLE            hPipe;

public:
                     CNamedPipe();
                    ~CNamedPipe();

   bool              Create(const int iId);
   bool              Connect();
   int               Close();
   uint              WriteANSI(const string message);
   string            ReadANSI();
   bool              Open(const int iId);
  };
//+------------------------------------------------------------------+
//| CNamedPipe constructor
//+------------------------------------------------------------------+
CNamedPipe::CNamedPipe(void) :
   hPipe(INVALID_HANDLE_VALUE)
  {
  }
//+------------------------------------------------------------------+
//| CNamedPipe destructor
//+------------------------------------------------------------------+
CNamedPipe::~CNamedPipe(void)
  {
   if(hPipe!=INVALID_HANDLE_VALUE)
     {
      CloseHandle(hPipe);
     }
  }
//+------------------------------------------------------------------+
/// Create() : try to create a new instance of Named Pipe
/// \param account - source terminal account number
/// \return true - if created, false otherwise
//+------------------------------------------------------------------+
bool CNamedPipe::Create(const int iId)
  {
   const string fullPipeName=PIPE_PREFIX+IntegerToString(iId);

   hPipe=CreateNamedPipeW(fullPipeName,
                          (GENERIC_READ|GENERIC_WRITE|PIPE_ACCESS_DUPLEX),
                          PIPE_TYPE_RW_BYTE,
                          PIPE_UNLIMITED_INSTANCES,
                          PIPE_BUFFER_SIZE*sizeof(ushort),
                          PIPE_BUFFER_SIZE*sizeof(ushort),
                          NULL,
                          NULL);

   return (hPipe==INVALID_HANDLE_VALUE);
  }

//+------------------------------------------------------------------+
/// Connect() : wait for a client to connect to a pipe
/// \return true - if connected, false otherwise.
//+------------------------------------------------------------------+
bool CNamedPipe::Connect(void)
  {
   if(ConnectNamedPipe(hPipe,NULL)==false)
      return(kernel32::GetLastError()==ERROR_PIPE_CONNECTED);
   else
      return true;
  }

//+------------------------------------------------------------------+
/// Close() : close pipe handle
/// \return 0 if successfull, non-zero otherwise
//+------------------------------------------------------------------+
int CNamedPipe::Close(void)
  {
   return CloseHandle(hPipe);
  }

//+------------------------------------------------------------------+
/// WriteANSI() : write ANSI string to a pipe                        |
/// \param message - string to send                                  |
/// \return number of bytes written to a pipe                        |
//+------------------------------------------------------------------+
uint CNamedPipe::WriteANSI(const string message)
  {
   ushort buffer[];
   uint number_of_bytes_to_write=0;
   uint number_of_bytes_written=0;

   number_of_bytes_to_write = StringToShortArray(message, buffer);
   WriteFile(hPipe,buffer,number_of_bytes_to_write,number_of_bytes_written,NULL);
   Print("Writing error: "+IntegerToString(kernel32::GetLastError()));
   return number_of_bytes_written;
  }

//+------------------------------------------------------------------+
/// ReadANSI(): read ANSI string from a pipe
/// \return unicode string (MQL5 string)
//+------------------------------------------------------------------+
string CNamedPipe::ReadANSI()
  {
   ushort buffer[];
   uint number_of_bytes_to_read=2;
   uint number_of_bytes_read;
   string ret;

   ReadFile(hPipe,buffer,number_of_bytes_to_read,number_of_bytes_read,NULL);
   if(number_of_bytes_read!=0)
     {
      ret=ShortArrayToString(buffer);
     }

   return ret;
  }
//+------------------------------------------------------------------+
/// Open() : try to open previously created pipe
/// \param account - source terminal account number
/// \return true - if successfull, false otherwise
//+------------------------------------------------------------------+
bool CNamedPipe::Open(const int iId)
  {
   const string fullPipeName=PIPE_PREFIX+IntegerToString(iId);

   if(hPipe==INVALID_HANDLE_VALUE)
     {
      if(WaitNamedPipeW(fullPipeName,5000)==0)
        {
         Print("Pipe "+fullPipeName+" busy.");
         return false;
        }

      hPipe=CreateFileW(fullPipeName,(GENERIC_READ|GENERIC_WRITE),NULL,NULL,OPEN_EXISTING,NULL,NULL);
      if(hPipe==INVALID_HANDLE_VALUE)
        {
         Print("Pipe open failed");
         return false;
        }

     }
   return true;
  }
//+------------------------------------------------------------------+

Here's the server code:

//+------------------------------------------------------------------+
//|                                             NamedPipesServer.mq5 |
//+------------------------------------------------------------------+
#property service

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
#include "cnamedpipes_simple.mqh"

//+------------------------------------------------------------------+
//| Service program start function                                   |
//+------------------------------------------------------------------+
void OnStart()
  {
   CNamedPipe pipe;
   if(pipe.Create(1))
     {
      if(pipe.Connect())
        {
         const uint ui=pipe.WriteANSI("a");
         Print("Wrote "+IntegerToString(ui)+" bytes");
        }
      Print("10 seconds to close the pipe");
      Sleep(10000);
      pipe.Close();
     }
  }
//+------------------------------------------------------------------+

Here's the client code:

//+------------------------------------------------------------------+
//|                                             NamedPipesClient.mq5 |
//+------------------------------------------------------------------+
#property service

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
#include "cnamedpipes_simple.mqh"

//+------------------------------------------------------------------+
//| Service program start function                                   |
//+------------------------------------------------------------------+
void OnStart()
  {
   CNamedPipe pipe;
   while(!pipe.Open(1))
     {
      Print("Pipe not created, retrying in 5 seconds...");
      Sleep(5000);
     }
   Print("Reading pipe in 5 seconds...");
   Sleep(5000);
   Print("Read: "+pipe.ReadANSI());
  }
//+------------------------------------------------------------------+

When I have the server running and start the client, I see 2 pipes created (1 using Create() from server and another using Open() from client). The thing is that the server detects the client is connected, and the client reads an empty pipe (I believe the one it created, even using OPEN_EXISTING):

Please let me know if someone can help me here.

Thank you.

 

I have a very similar error...This Access Violation is very crazy...

I dont know if in my case as I am using this with my personal applicative made in Visual Studio so  I dont know if maybe the Common Folder rules influences...

I create in the mt5 a server and connect with my app. In mt4 I use it for years...But in mt5 I never made it work...


For me this code works fine until "Conneted Pipe"

string PipeName = "\\\\.\\pipe\\teste";
    int    PipeMode = PIPE_TYPE_BYTE  | PIPE_READMODE_BYTE  | PIPE_WAIT;
    hPipe      = CreateNamedPipeW(PipeName, PIPE_ACCESS_DUPLEX, PipeMode, PIPE_UNLIMITED_INSTANCES, 255, 255, 1000, NULL);
    BufferSize = PIPE_BUFFER_SIZE;
    if (hPipe == INVALID_HANDLE_VALUE)
    {
        err = GetLastError();
        //Print("error(", err1, "): ", ErrorDescription(err1));
        Print("CreateNamedPipe failed");
    }
    else
    {
        Print("Named Pipe was created");
    }
    while (true)
    {
        Print("standy by");
      
        bool fConnected = ConnectNamedPipe(hPipe, NULL) != 0;
        Print("Conected PipeServer");
        if (fConnected)
        {

My problen is that now I need to use this code ReadFile(hPipe,bytesToRead,sizeof(int),bytesRead,0); and here the Access Violation happens.


If hope it help you

 
"access violation" error is killing me too. Did you manage to fix it? I would really appreciate 
Reason: