/*
 * Xailer source code:
 *
 * MailSlot.prg
 * Comunicaciones IPC con mailslot
 *
 * Copyright 2003, 2011 Jose Lalin
 * Copyright 2003, 2011 Xailer.com
 * All rights reserved
 *
 */

#include "Xailer.ch"


//------------------------------------------------------------------------------

CLASS XMailSlot FROM TComponent STATIC

PUBLISHED:
   PROPERTY cName    INIT "xmailslot" WRITE INLINE ::SetName( Value, ::cServer )
   PROPERTY cServer  INIT "." WRITE INLINE ::SetName( ::cName, Value )

   EVENT OnOpen( oSender )
   EVENT OnClose( oSender )

PUBLIC:
   METHOD Create() CONSTRUCTOR

   METHOD Close()
   METHOD IsOpen()   INLINE ::hSlot != INVALID_HANDLE_VALUE

RESERVED:
   DATA hSlot  INIT INVALID_HANDLE_VALUE READONLY
   DATA cSlot  INIT "" READONLY

   METHOD SetName( cSlot, cServer )

ENDCLASS

//------------------------------------------------------------------------------

METHOD Create( oParent ) CLASS XMailSlot

   ::Super:Create( oParent )
   ::SetName( ::cName, ::cServer )

RETURN Self

//------------------------------------------------------------------------------

METHOD SetName( cName, cServer ) CLASS XMailSlot

   ::FcName := cName
   ::FcServer := cServer

   ::cSlot := "\\" + ::cServer + "\mailslot\" + ::cName

RETURN Nil

//------------------------------------------------------------------------------

METHOD Close() CLASS XMailSlot

   LOCAL lResult := .F.

   IF ::hSlot != INVALID_HANDLE_VALUE
      lResult := CloseHandle( ::hSlot )
      IF lResult
         ::hSlot := INVALID_HANDLE_VALUE
      ENDIF
      ::OnClose()
   ENDIF

RETURN lResult

//------------------------------------------------------------------------------

CLASS XMailSlotClient FROM XMailSlot

PUBLISHED:
   EVENT OnWrite( oSender, cText )

PUBLIC:
   METHOD Open()
   METHOD Write( cMessage )

ENDCLASS

//------------------------------------------------------------------------------

CLASS XMailSlotServer FROM XMailSlot

PUBLISHED:
   EVENT OnRead( oSender, cText )

PUBLIC:
   METHOD Open()
   METHOD Read()

   METHOD GetMessageCount()
   METHOD HasMessages()       INLINE ::GetMessageCount() > 0

   METHOD SetReadTimeout( nTimeout )

ENDCLASS

//------------------------------------------------------------------------------

#pragma BEGINDUMP

#include <windows.h>
#include <xailer.h>


//------------------------------------------------------------------------------

HB_FUNC_STATIC( CLOSEHANDLE )
{
   hb_retl( CloseHandle( (HANDLE) hb_parnl( 1 ) ) );
}

//------------------------------------------------------------------------------

HB_FUNC_STATIC( XMAILSLOTCLIENT_OPEN )
{
   PHB_ITEM Self = hb_stackSelfItem();
   LPTSTR lpName = XA_ObjGetC( Self, "cSlot" );
   HANDLE hSlot;

   hSlot = CreateFile( lpName, GENERIC_WRITE, FILE_SHARE_READ, (LPSECURITY_ATTRIBUTES) NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, (HANDLE) NULL );
   XA_ObjSendNL( Self, "_hSlot", (LONG) hSlot );
   XA_ObjSend( Self, "OnOpen" );
   hb_retl( hSlot != INVALID_HANDLE_VALUE );
}

//------------------------------------------------------------------------------

HB_FUNC_STATIC( XMAILSLOTCLIENT_WRITE )
{
   PHB_ITEM Self = hb_stackSelfItem();
   HANDLE hSlot = (HANDLE) XA_ObjGetNL( Self, "hSlot" );
   BOOL bResult;
   DWORD cbWritten;

   bResult = WriteFile( hSlot, hb_parc( 1 ), (DWORD) hb_parclen( 1 ), &cbWritten, (LPOVERLAPPED) NULL );
   XA_ObjSendC( Self, "OnWrite", hb_parc( 1 ) );
   hb_retl( bResult );
}

//------------------------------------------------------------------------------

HB_FUNC_STATIC( XMAILSLOTSERVER_OPEN )
{
   PHB_ITEM Self = hb_stackSelfItem();
   LPTSTR lpName = XA_ObjGetC( Self, "cSlot" );
   HANDLE hSlot = CreateMailslot( lpName, 0, MAILSLOT_WAIT_FOREVER, (LPSECURITY_ATTRIBUTES) NULL );

   XA_ObjSendNL( Self, "_hSlot", (LONG) hSlot );
   XA_ObjSend( Self, "OnOpen" );
   hb_retl( hSlot != INVALID_HANDLE_VALUE );
}

//------------------------------------------------------------------------------

HB_FUNC_STATIC( XMAILSLOTSERVER_GETMESSAGECOUNT )
{
   PHB_ITEM Self = hb_stackSelfItem();
   HANDLE hSlot = (HANDLE) XA_ObjGetNL( Self, "hSlot" );
   DWORD dwSize = 0;
   DWORD dwCount = 0;
   BOOL bResult = GetMailslotInfo( hSlot, (LPDWORD) NULL, &dwSize, &dwCount, (LPDWORD) NULL );

   hb_retnl( bResult && !( dwSize == MAILSLOT_NO_MESSAGE ) ? dwCount: 0 );
}

//------------------------------------------------------------------------------

HB_FUNC_STATIC( XMAILSLOTSERVER_READ )
{
   PHB_ITEM Self = hb_stackSelfItem();
   HANDLE hSlot = (HANDLE) XA_ObjGetNL( Self, "hSlot" );
   DWORD dwSize = 0;
   HANDLE hEvent = CreateEvent( NULL, FALSE, FALSE, "XMAILSlotServerRead" );

   if( hEvent )
   {
      BOOL bResult = GetMailslotInfo( hSlot, (LPDWORD) NULL, &dwSize, NULL, (LPDWORD) NULL );

      if( bResult && !( dwSize == MAILSLOT_NO_MESSAGE ) )
      {
         LPTSTR szBuffer = (LPTSTR) GlobalAlloc( GPTR, dwSize + 1 );
         OVERLAPPED ov;
         DWORD dwRead = 0;

         ov.Offset = 0;
         ov.OffsetHigh = 0;
         ov.hEvent = hEvent;

         memset( szBuffer, 0, dwSize );
         bResult = ReadFile( hSlot, szBuffer, dwSize, &dwRead, &ov );

         if( bResult )
         {
            szBuffer[ dwSize ] = '\0';
            hb_retc( szBuffer );
            XA_ObjSendC( Self, "OnRead", szBuffer );
         }
         else
         {
            hb_retc( "" );
            XA_ObjSendC( Self, "OnRead", "" );
         }

         GlobalFree( (HGLOBAL) szBuffer );
      }
      CloseHandle( hEvent );
   }
   else
      hb_retc( "" );
}

//------------------------------------------------------------------------------

HB_FUNC_STATIC( XMAILSLOTSERVER_SETREADTIMEOUT )
{
   PHB_ITEM Self = hb_stackSelfItem();
   HANDLE hSlot = (HANDLE) XA_ObjGetNL( Self, "hSlot" );
   BOOL bSuccess = FALSE;

   if( hSlot != INVALID_HANDLE_VALUE )
      bSuccess = SetMailslotInfo( hSlot, hb_parnl( 1 ) );

   hb_retl( bSuccess );
}

//------------------------------------------------------------------------------

#pragma ENDDUMP
