Antonio
1-) Fiz algumas alteracoes no fonte COMM.C para FWH.
Espero que sirva outros usuarios.
2-) Gostaria muito que se agregasse as futuras versoes de FWH
(nao estou sendo pretencioso). Acontece que a toda atualizacao
recompilo o codigo e atacho a FIVEHC.LIB
3-) Segue pequeno exemplo de como usar SetCommState() em
WinXP/NT que é uma dor de cabeça para muitos usuarios.
/////////////////
COMM.C
////////////////
#include <WinTen.h>
#include <Windows.h>
#include <ClipApi.h>
#ifdef __FLAT__
int OpenComm( LPCSTR lpszDevControl, unsigned int cbInQueue,
unsigned int cbOutQueue );
int CloseComm( int idComDev );
int FlushComm( int idComDev, int fnQueue );
int WriteComm( int idComDev, LPCVOID lpvBuf, int cbWrite );
int ReadComm( int idComDev, LPVOID lpvBuf, int cbRead );
int GetCommError( int idComDev, COMSTAT * lpStat );
BOOL EnableCommNotification( int idComDev, HWND hwnd,
int cbWriteNotify, int cbOutQueue );
DWORD ThreadCommNotification( LPVOID data );
int GetCommHandle( int idComDev );
#endif
//----------------------------------------------------------------------------//
CLIPPER OPENCOMM( PARAMS ) // cPortName, nInQueue, nOutQueue --> nPortId
{
WORD cbInQueue = IF( ISNUM( 2 ), _parni( 2 ), 1024 );
WORD cbOutQueue = IF( ISNUM( 3 ), _parni( 3 ), 128 );
_retni( OpenComm( _parc( 1 ), cbInQueue, cbOutQueue ) );
}
//----------------------------------------------------------------------------//
CLIPPER CLOSECOMM( PARAMS )
{
_retl( CloseComm( _parni( 1 ) ) == 0 );
}
//----------------------------------------------------------------------------//
CLIPPER WRITECOMM( PARAMS )
{
_retni( WriteComm( _parni( 1 ), _parc( 2 ), _parclen( 2 ) ) );
}
//----------------------------------------------------------------------------//
CLIPPER READCOMM( PARAMS ) // ( nId, @ cBuffer ) --> nBytesRead
{
_retni( ReadComm( _parni( 1 ), _parc( 2 ), _parclen( 2 ) ) );
}
//----------------------------------------------------------------------------//
#ifdef __HARBOUR__
CLIPPER BUILDCOMMDCB( PARAMS ) // () cInfoDef, @ cDeviceBlock --> lOk
#else
CLIPPER BUILDCOMMD( PARAMS ) // CB() cInfoDef, @ cDeviceBlock --> lOk
#endif
{
DCB dcb;
#ifdef __FLAT__
if( BuildCommDCB( _parc( 1 ), &dcb ) ) // OK
#else
if( BuildCommDCB( _parc( 1 ), &dcb ) == 0 ) // OK
#endif
{
_storclen( ( char * ) &dcb, sizeof( dcb ), 2 );
_retl( TRUE );
}
else // Error
{
_storc( "", 2 );
_retl( FALSE );
}
}
//----------------------------------------------------------------------------//
/*
#ifdef __HARBOUR__
CLIPPER GETCOMMSTATE( PARAMS ) // () cInfoDef, @ cDeviceBlock --> lOk
#else
CLIPPER GETCOMMSTA( PARAMS ) // TE() cInfoDef, @ cDeviceBlock --> lOk
#endif
{
DCB dcb;
#ifdef __FLAT__
if( GetCommState( (HANDLE) GetCommHandle( _parni( 1 ) ), &dcb ) ) // OK
#else
if( GetCommState( ( int ) GetCommHandle( _parni( 1 ) ), &dcb ) == 0 ) // OK
#endif
{
_storclen( ( char * ) &dcb, sizeof( dcb ), 2 );
_retl( TRUE );
}
else // Error
{
_storc( "", 2 );
_retl( FALSE );
}
}
*/
//----------------------------------------------------------------------------//
/*
#ifdef __HARBOUR__
CLIPPER GETCOMMHANDLE( PARAMS ) // () idCommDev ==> nHandle
#else
CLIPPER GETCOMMHAN( PARAMS ) //DLE()
#endif
{
_retni( GetCommHandle( _parni( 1 ) ) );
}
*/
//----------------------------------------------------------------------------//
#ifdef __HARBOUR__
CLIPPER SETCOMMSTATE( PARAMS ) // ()
#else
CLIPPER SETCOMMSTA( PARAMS ) // TE()
#endif
{
#ifdef __FLAT__
_retl( SetCommState( (HANDLE) GetCommHandle( _parni( 1 ) ), ( DCB FAR * ) _parc( 2 ) ) );
#else
_retl( SetCommState( ( DCB FAR * ) _parc( 1 ) ) == 0 );
#endif
}
//----------------------------------------------------------------------------//
CLIPPER FLUSHCOMM( PARAMS )
{
_retni( FlushComm( _parni( 1 ), _parni( 2 ) ) );
}
//----------------------------------------------------------------------------//
#ifdef __HARBOUR__
CLIPPER GETCOMMERROR( PARAMS ) // ()
#else
CLIPPER GETCOMMERR( PARAMS ) // OR()
#endif
{
COMSTAT stat;
_retni( GetCommError( _parni( 1 ), ( PCOUNT() > 1 ) ? &stat: 0 ) );
if( ( int ) PCOUNT() > 1 )
_storclen( ( char * ) &stat, sizeof( COMSTAT ), 2 );
}
//----------------------------------------------------------------------------//
#ifdef __HARBOUR__
CLIPPER ENABLECOMMNOTIFICATION( PARAMS ) // ( nComDev, hWnd, nInBytes, nOutBytes )
// --> <lSuccess>
#else
CLIPPER ENABLECOMM( PARAMS ) // NOTIFICATION( nComDev, hWnd, nInBytes, nOutBytes )
#endif // --> <lSuccess>
{
_retl( EnableCommNotification( _parni( 1 ), ( HWND ) _parni( 2 ),
_parni( 3 ), _parni( 4 ) ) );
}
//----------------------------------------------------------------------------//
#ifdef __HARBOUR__
CLIPPER ESCAPECOMMFUNCTION( PARAMS ) // ( nComDev, nFunctionCode )
// --> <lSuccess>
#else
CLIPPER ESCAPECOMM( PARAMS ) // FUNCTION( nComDev, nFunctionCode )
// --> <lSuccess>
#endif
{
_retl( ! EscapeCommFunction( ( HANDLE ) _parnl( 1 ), _parni( 2 ) ) );
}
//----------------------------------------------------------------------------//
#ifdef __FLAT__
typedef struct _tagCOMMST
{
HANDLE hComm;
HANDLE hThread;
HWND hWndEv;
int cbWriteNotify;
int cbOutQueue;
}COMMST, *LPCOMMST;
int OpenComm( LPCSTR lpszDevControl, UINT cbInQueue, UINT cbOutQueue )
{
char port[ 16 ];
HANDLE hComm;
LPCOMMST Com = ( LPCOMMST ) LocalLock( LocalAlloc( LPTR, sizeof( COMMST ) ) );
COMMTIMEOUTS ct;
wsprintf( port, "\\%s", lpszDevControl );
Com->hComm = CreateFile( port, GENERIC_WRITE | GENERIC_READ, 0, NULL,
OPEN_EXISTING, 0, NULL );
SetupComm( Com->hComm, cbInQueue, cbOutQueue );
ct.ReadIntervalTimeout = MAXDWORD;
ct.ReadTotalTimeoutMultiplier = 0;
ct.ReadTotalTimeoutConstant = 0;
ct.WriteTotalTimeoutMultiplier = 10;
ct.WriteTotalTimeoutConstant = 1000;
SetCommTimeouts( Com->hComm, &ct );
return ( int ) Com;
}
int CloseComm( int idComDev )
{
int nRet;
LPCOMMST Com = ( LPCOMMST )idComDev;
TerminateThread( Com->hThread, 0 );
nRet = ( int )( CloseHandle( Com->hComm ) ? 0 : -1 );
LocalFree( LocalHandle( ( LPVOID ) Com ) );
return nRet;
}
int FlushComm( int idComDev, int fnQueue )
{
LPCOMMST Com = ( LPCOMMST )idComDev;
return ( int ) FlushFileBuffers( Com->hComm );
}
int GetCommHandle( int idComDev )
{
LPCOMMST Com = ( LPCOMMST )idComDev;
return ( int ) Com->hComm ;
}
int WriteComm( int idComDev, LPCVOID lpvBuf, int cbWrite )
{
DWORD dw = 0;
LPCOMMST Com = ( LPCOMMST )idComDev;
WriteFile( Com->hComm, lpvBuf, ( DWORD )cbWrite, &dw, NULL );
return ( int ) dw ? dw : -1;
}
int ReadComm( int idComDev, LPVOID lpvBuf, int cbRead )
{
DWORD dw = 0;
LPCOMMST Com = ( LPCOMMST )idComDev;
ReadFile( Com->hComm, lpvBuf, ( DWORD )cbRead, &dw, NULL );
return ( int ) dw ? dw : -1;
}
//COMSTAT existen en 16 y en 32
int GetCommError( int idComDev, COMSTAT * lpStat )
{
LPCOMMST Com = ( LPCOMMST )idComDev;
DWORD nRetErrors = 0;
ClearCommError( Com->hComm, &nRetErrors, lpStat );
return ( int )nRetErrors;
}
DWORD ThreadCommNotification( LPVOID data )
{
LPCOMMST Com = ( LPCOMMST )data;
DWORD dwEvtMask;
int dwReceived = 0, dwSent = 0;
GetCommMask( Com->hComm, &dwEvtMask );
SetCommMask( Com->hComm, EV_RXCHAR | EV_RXFLAG | dwEvtMask );
for( ; ; )
{
WaitCommEvent( Com->hComm, &dwEvtMask, NULL );
if( dwEvtMask & EV_RXCHAR )
{
dwReceived++;
if( dwReceived == Com->cbWriteNotify )
{
dwReceived = 0;
PostMessage( Com->hWndEv, WM_COMMNOTIFY, ( WPARAM )Com, ( LPARAM )0x01 ); //CN_RECEIVE
}
}
else
{
if( dwSent & EV_RXFLAG )
{
dwSent++;
if( dwSent == Com->cbOutQueue )
{
dwSent = 0;
PostMessage( Com->hWndEv, WM_COMMNOTIFY, ( WPARAM )Com, ( LPARAM )0x02 ); //CN_TRANSMIT
}
}
}
PostMessage( Com->hWndEv, WM_COMMNOTIFY, ( WPARAM )Com, ( LPARAM )0x04 ); //CN_EVENT
}
// return 0;
}
BOOL EnableCommNotification( int idComDev, HWND hwnd, int cbWriteNotify, int cbOutQueue )
{
LPCOMMST Com = ( LPCOMMST )idComDev;
DWORD ThId;
Com->hWndEv = hwnd;
Com->cbWriteNotify = cbWriteNotify;
Com->cbOutQueue = cbOutQueue;
Com->hThread = CreateThread( NULL, NULL,
( LPTHREAD_START_ROUTINE )ThreadCommNotification,( LPVOID ) Com, NULL, &ThId );
return TRUE;
}
#endif
//----------------------------------------------------------------------------//
/////////////////
SAMPLE PRG
////////////////
// Teste de uso da porta COMM
//
// exemplo de uso de porta COMM
//
/*
... sua rotina
nPortA:= InitComm( "COM1", "19200,n,8,1" )
if nPortA > 0
// ... Porta aberta com sucesso...
endif
nPortB:= InitComm( "COM2", "4800,n,8,1" ) // usando uma outra porta
if nPortB > 0
// ... Porta aberta com sucesso...
endif
... sua rotina
if nPortA > 0 // COMM aberta
CloseComm( nPortA )
endif
if nPortB > 0 // COMM aberta
CloseComm( nPortB )
endif
... sua rotina
QUIT
*/
////////////////////////////////////////////////
// InitComm( c_Porta_Comm, cProperties ) //Ex: InitiComm( "COM1", "4800,n,8,1" )
////////////////////////////////////////////////
Function InitComm( cPort, cProp )
local nComm, sComm:="", lOkComm:= .f.
if empty( cPort)
cPort:= "COM1"
endif
if empty( cProp )
cProp:= "19200,n,8,1"
endif
if ( nComm := OpenComm( cPort, 2048, 512 ) ) < 1
MsgStop( cPort + " - Nao disponivel.")
retu 0
endif
if !BuildCommDcb( cPort + ":" + cProp, @sComm )
MsgStop( cPort + " - Nao ativa.")
CloseComm( nComm )
retu 0
endif
sComm:= AdjustDCB( sComm ) // corrige DCB
if !SetCommState( nComm, sComm)
MsgStop( cPort + " - Nao ativa.")
CloseComm( nComm )
retu 0
endif
if !writeComm(nComm, "}}}}}}" )<>6
MsgStop( cPort + " - falha gravacao.")
CloseComm( nComm )
retu 0
endif
if !FlushComm(nComm,0) = 1
MsgStop( cPort + " - falha fluxo.")
CloseComm( nComm )
retu 0
endif
retu nComm
Function AdjustDCB( _dcb )
// Obs
//
// no WinXp/NT, a funcao BuildCommDCB() retorna estrutura DCB com valores
// de threshold para XonLim e XoffLim, e, se o controle de fluxo nao estiver
// configurado para Xon/Xoff a funcao SetCommState() retorna falso.
// A solucao esta em zerar os valores de threshold para XonLim e XoffLim
// _dcb:= subs( _dcb,1,14) + L2Bin( 0 ) + subs( _dcb,19 ) // XonLim,XoffLim set to 0
// retu ( _dcb )
// Obs 2
// Consulte estrutura DCB p/ alterar outros valores conforme necessidade
// Ex.: Setar Binary Mode e habilitar DTR
//
// habilitar DTR eh obrigatorio para quem utiliza conversor RS232<->485
// e tambem para alguns conversores USB<->RS232
//
// 1h=binary_mode_true + 10h=Ctr_DTR_Enable == 11h == chr(17)
// alterar byte 9 do DCB ( total da estrutura DCB = 28 bytes )
// _dcb:= subs( _dcb, 1, + chr( 17 ) + chr( 0 ) + subs( _dcb, 10, 4) + ;
// L2Bin( 0 ) + subs( _dcb, 19 )
// retu ( _dcb )
retu subs( _dcb,1,14) + L2Bin( 0 ) + subs( _dcb,19 )
[/list]