Ted Lyngmo

Member since: Wednesday, 06 September 2017
Last login: 2 days ago
Profile viewed: 98 views

No Rank
Points: 0

Ted Lyngmo replied to the topic 'RS-232 I/O for FT232BL/CP210x' in the forum. 2 days ago

This is a very old (BCB4) component I've written for RS232 communication but it still works and performs very well at even extreme speeds. It could do with some refactoring, but if your goal is just to get communication up and running quickly, it'll do.


TComPort.h

//---------------------------------------------------------------------------

#ifndef TComPortH
#define TComPortH
//---------------------------------------------------------------------------
#include <System.SysUtils.hpp>
#include <System.Classes.hpp>
//---------------------------------------------------------------------------
enum brType {
	 br110=110,      br300=300,      br600=600,
	 br1200=1200,    br2400=2400,    br4800=4800,
	 br9600=9600,    br14400=14400,  br19200=19200,
	 br38400=38400,  br56000=56000,  br57600=57600,
	 br115200=115200,br128000=128000,br256000=256000
};

enum bsType { bs4=4, bs5=5, bs6=6, bs7=7, bs8=8 };
enum paType { paNo=NOPARITY, paOdd=ODDPARITY, paEven=EVENPARITY, paMark=MARKPARITY, paSpace=SPACEPARITY };
enum sbType { sb1_0=ONESTOPBIT, sb1_5=ONE5STOPBITS, sb2_0=TWOSTOPBITS };

enum DtrControl { dtrDisable, dtrEnable, dtrHandshake };
enum RtsControl { rtsDisable, rtsEnable, rtsHandshake, rtsToggle };

typedef void __fastcall (__closure *TNotifyError)( TObject *Sender, DWORD ErrorCode );

class TComPortThread; // Forward declaration

class PACKAGE TComPort : public TComponent
{
private:
	friend class TComPortThread;

	DCB FSetup;
	AnsiString FPortName;

	// Events
	TNotifyError FError;
	TNotifyEvent FOpened, FClosed;
	TNotifyEvent FBreak, FCts, FDsr, FErr, FRing, FRlsd, FRxchar, FRxflag, FTxempty;

	HANDLE Handle;
	TComPortThread *PThread;
protected:
	//- published properties get/set methods
	virtual uint16_t __fastcall GetByteSize();
	virtual void __fastcall SetByteSize( uint16_t x );

	virtual paType __fastcall GetParity();
	virtual void __fastcall SetParity( paType x );

	virtual sbType __fastcall GetStopBits();
	virtual void __fastcall SetStopBits( sbType x );

	virtual DtrControl __fastcall GetfDtrControl();
	virtual void __fastcall SetfDtrControl( DtrControl x );

	virtual RtsControl __fastcall GetfRtsControl();
	virtual void __fastcall SetfRtsControl( RtsControl x );

	virtual bool __fastcall GetfParity();
	virtual void __fastcall SetfParity( bool x );

	virtual bool __fastcall GetfOutxCtsFlow();
	virtual void __fastcall SetfOutxCtsFlow( bool x );

	virtual bool __fastcall GetfOutxDsrFlow();
	virtual void __fastcall SetfOutxDsrFlow( bool x );

	virtual bool __fastcall GetfDsrSensitivity();
	virtual void __fastcall SetfDsrSensitivity( bool x );

	virtual bool __fastcall GetfTXContinueOnXoff();
	virtual void __fastcall SetfTXContinueOnXoff( bool x );

	virtual bool __fastcall GetfOutX();
	virtual void __fastcall SetfOutX( bool x );

	virtual bool __fastcall GetfInX();
	virtual void __fastcall SetfInX( bool x );

	virtual bool __fastcall GetfErrorChar();
	virtual void __fastcall SetfErrorChar( bool x );

	virtual bool __fastcall GetfNull();
	virtual void __fastcall SetfNull( bool x );

	virtual bool __fastcall GetfAbortOnError();
	virtual void __fastcall SetfAbortOnError( bool x );
public:
	__fastcall TComPort(TComponent* Owner);
	__fastcall virtual ~TComPort();

	bool __fastcall Open();
	bool __fastcall Close();
	DWORD __fastcall Read( LPVOID lpBuffer, DWORD nNumberOfBytesToRead );
	DWORD __fastcall Write( LPVOID lpBuffer, DWORD nNumberOfBytesToWrite );

	bool __fastcall EscapeFunction( DWORD Function );
	bool __fastcall SetState();
__published:
	__property AnsiString PortName = { read=FPortName, write=FPortName };

    __property DWORD BaudRate = { read=FSetup.BaudRate, write=FSetup.BaudRate, default=br9600 };        // current baud rate
    __property uint16_t ByteSize = { read=GetByteSize, write=SetByteSize, default=bs8 };                //(BYTE) number of bits/byte, 4-8
	__property paType Parity = { read=GetParity, write=SetParity, default=paNo };                       // 0-4=no,odd,even,mark,space
	__property sbType StopBits = { read=GetStopBits, write=SetStopBits, default=sb1_0 };                // 0,1,2 = 1, 1.5, 2
	__property DtrControl fDtrControl = { read=GetfDtrControl, write=SetfDtrControl };                  //2b DTR flow control type
	__property RtsControl fRtsControl = { read=GetfRtsControl, write=SetfRtsControl };                  //2b RTS flow control type

	__property bool fParity = { read=GetfParity, write=SetfParity, default=true };                      //1b enable parity checking
	__property bool fOutxCtsFlow = { read=GetfOutxCtsFlow, write=SetfOutxCtsFlow };                     //1b CTS output flow control
	__property bool fOutxDsrFlow = { read=GetfOutxDsrFlow, write=SetfOutxDsrFlow };                     //1b DSR output flow control
	__property bool fDsrSensitivity = { read=GetfDsrSensitivity, write=SetfDsrSensitivity };            //1b DSR sensitivity
	__property bool fTXContinueOnXoff = { read=GetfTXContinueOnXoff, write=SetfTXContinueOnXoff };      //1b XOFF continues Tx
	__property bool fOutX = { read=GetfOutX, write=SetfOutX };                                          //1b XON/XOFF out flow control
	__property bool fInX = { read=GetfInX, write=SetfInX };                                             //1b XON/XOFF in flow control
	__property bool fErrorChar = { read=GetfErrorChar, write=SetfErrorChar };                           //1b enable error replacement
	__property bool fNull = { read=GetfNull, write=SetfNull };                                          //1b enable null stripping
	__property bool fAbortOnError = { read=GetfAbortOnError, write=SetfAbortOnError };                  //1b abort reads/writes on error

	__property WORD XonLim = { read=FSetup.XonLim, write=FSetup.XonLim };                               // transmit XON threshold
	__property WORD XoffLim = { read=FSetup.XoffLim, write=FSetup.XoffLim };                            // transmit XOFF threshold

	__property char XonChar = { read=FSetup.XonChar, write=FSetup.XonChar, default='Q'-64 };            // Tx and Rx XON character
	__property char XoffChar = { read=FSetup.XoffChar, write=FSetup.XoffChar, default='S'-64 };         // Tx and Rx XOFF character
	__property char ErrorChar = { read=FSetup.ErrorChar, write=FSetup.ErrorChar };                      // error replacement character
	__property char EofChar = { read=FSetup.EofChar, write=FSetup.EofChar };                            // end of input character
	__property char EvtChar = { read=FSetup.EvtChar, write=FSetup.EvtChar };                            // received event character

	// Events - Application
	__property TNotifyEvent OnOpened = { read=FOpened, write=FOpened }; // Called just after port has been opened
	__property TNotifyEvent OnClosed = { read=FClosed, write=FClosed }; // Called just after port has been closed
	__property TNotifyError OnError = { read=FError, write=FError };

	// Events - Status changes while port is open
	__property TNotifyEvent OnBreak = { read=FBreak, write=FBreak };
    __property TNotifyEvent OnCts = { read=FCts, write=FCts };
    __property TNotifyEvent OnDsr = { read=FDsr, write=FDsr };
    __property TNotifyEvent OnErr = { read=FErr, write=FErr };
    __property TNotifyEvent OnRing = { read=FRing, write=FRing };
    __property TNotifyEvent OnRlsd = { read=FRlsd, write=FRlsd };
    __property TNotifyEvent OnRxchar = { read=FRxchar, write=FRxchar };
    __property TNotifyEvent OnRxflag = { read=FRxflag, write=FRxflag };
	__property TNotifyEvent OnTxempty = { read=FTxempty, write=FTxempty };
};
//---------------------------------------------------------------------------
class TComPortThread : public TThread
{
private:
        TComPort   *FComPort;
        OVERLAPPED osStatus;
		DWORD      ErrorCode;
		DWORD      dwCommEvent;
        void __fastcall CallOpened();
        void __fastcall CallClosed();
        inline void __fastcall SyncError(); // Use in subthread
        void __fastcall CallError(); // Use in main VCL thread
        void __fastcall CallEvent();
protected:
		void __fastcall Execute();
		bool __fastcall SetupPort();
		void __fastcall Work();
public:
		__fastcall TComPortThread( TComPort *ComPort );
		virtual __fastcall ~TComPortThread();
		void __fastcall Close();
};
//---------------------------------------------------------------------------
#endif
TComPort.cpp
//---------------------------------------------------------------------------

#include <vcl.h>

#pragma hdrstop

#include "TComPort.h"
#pragma package(smart_init)
//---------------------------------------------------------------------------
// ValidCtrCheck is used to assure that the components created do not have
// any pure virtual functions.
//

static inline void ValidCtrCheck(TComPort *)
{
    new TComPort(NULL);
}
//---------------------------------------------------------------------------
namespace Tcomport
{
    void __fastcall PACKAGE Register()
    {
         TComponentClass classes[1] = {__classid(TComPort)};
         RegisterComponents(L"Lyncon", classes, 0);
    }
}
//---------------------------------------------------------------------------
__fastcall TComPort::TComPort(TComponent* Owner) :
	TComponent(Owner),
	FSetup(),
	FPortName("\\\\.\\COM1"),
	Handle(INVALID_HANDLE_VALUE),
	PThread(NULL)
{
	// Fixed values (not published)
	FSetup.DCBlength = sizeof( DCB );
	FSetup.fBinary = true;
	FSetup.wReserved = 0;

	// Published with default values:
	BaudRate    = br9600;
	ByteSize    = bs8;
	Parity      = paNo;
	StopBits    = sb1_0;
	XonChar     = 'Q'-64;       // ^Q
	XoffChar    = 'S'-64;       // ^S
	fParity = true;
}
__fastcall TComPort::~TComPort() {
	Close();
}
//------------------------------------------------------------------------------
//- published properties get/set methods
uint16_t __fastcall TComPort::GetByteSize() { return static_cast<uint16_t>(FSetup.ByteSize); }
void __fastcall TComPort::SetByteSize( uint16_t x ) {
	if( x>8 ) x=8;
	else if( x<4 ) x=4;
	FSetup.ByteSize = static_cast<BYTE>(x);
}

paType __fastcall TComPort::GetParity() { return static_cast<paType>(FSetup.Parity); }
void __fastcall TComPort::SetParity( paType x ) { FSetup.Parity = x; }

sbType __fastcall TComPort::GetStopBits() { return static_cast<sbType>(FSetup.StopBits); }
void __fastcall TComPort::SetStopBits( sbType x ) { FSetup.StopBits = x; }

DtrControl __fastcall TComPort::GetfDtrControl() { return static_cast<DtrControl>(FSetup.fDtrControl); }
void __fastcall TComPort::SetfDtrControl( DtrControl x ) { FSetup.fDtrControl = x; }

RtsControl __fastcall TComPort::GetfRtsControl() { return static_cast<RtsControl>(FSetup.fRtsControl); }
void __fastcall TComPort::SetfRtsControl( RtsControl x ) { FSetup.fRtsControl = x; }

bool __fastcall TComPort::GetfParity() { return FSetup.fParity; };
void __fastcall TComPort::SetfParity( bool x ) { FSetup.fParity = x; }

bool __fastcall TComPort::GetfOutxCtsFlow() { return FSetup.fOutxCtsFlow; }
void __fastcall TComPort::SetfOutxCtsFlow( bool x ) { FSetup.fOutxCtsFlow = x; }

bool __fastcall TComPort::GetfOutxDsrFlow() { return FSetup.fOutxDsrFlow; }
void __fastcall TComPort::SetfOutxDsrFlow( bool x ) { FSetup.fOutxDsrFlow = x; }

bool __fastcall TComPort::GetfDsrSensitivity() { return FSetup.fDsrSensitivity; }
void __fastcall TComPort::SetfDsrSensitivity( bool x ) { FSetup.fDsrSensitivity = x; }

bool __fastcall TComPort::GetfTXContinueOnXoff() { return FSetup.fTXContinueOnXoff; }
void __fastcall TComPort::SetfTXContinueOnXoff( bool x ) { FSetup.fTXContinueOnXoff = x; }

bool __fastcall TComPort::GetfOutX() { return FSetup.fOutX; }
void __fastcall TComPort::SetfOutX( bool x ) { FSetup.fOutX = x; }

bool __fastcall TComPort::GetfInX() { return FSetup.fInX; }
void __fastcall TComPort::SetfInX( bool x ) { FSetup.fInX = x; }

bool __fastcall TComPort::GetfErrorChar() { return FSetup.fErrorChar; }
void __fastcall TComPort::SetfErrorChar( bool x ) { FSetup.fErrorChar = x; }

bool __fastcall TComPort::GetfNull() { return FSetup.fNull; }
void __fastcall TComPort::SetfNull( bool x ) { FSetup.fNull = x; }

bool __fastcall TComPort::GetfAbortOnError() { return FSetup.fAbortOnError; }
void __fastcall TComPort::SetfAbortOnError( bool x ) { FSetup.fAbortOnError = x; }
//------------------------------------------------------------------------------
bool __fastcall TComPort::Open() {
	if( Handle == INVALID_HANDLE_VALUE ) {
		try {
			PThread = new TComPortThread(this);
#if __BCPLUSPLUS__ >= 0x0630
            PThread->Start();
#else
            PThread->Resume(); // deprecated in RAD Studio XE, in the year 2010
#endif
		}
		catch( ... ) {
			Handle = INVALID_HANDLE_VALUE;
			if( OnError ) OnError( this, GetLastError() );
		}
	}
	return Handle != INVALID_HANDLE_VALUE;
}
//------------------------------------------------------------------------------
bool __fastcall TComPort::Close() {
	bool retval=false;

	if( Handle != INVALID_HANDLE_VALUE ) {
		PThread->Close();
		retval = true;
	}
	return retval;
}
//------------------------------------------------------------------------------
DWORD __fastcall TComPort::Read( LPVOID lpBuffer, DWORD nNumberOfBytesToRead ) {
	DWORD lNumberOfBytesRead=-1;
	OVERLAPPED osStatus; //should probably be the OVERLAPPed struct in the Thread?
	if( ReadFile(
		Handle,
		lpBuffer,
		nNumberOfBytesToRead,
		&lNumberOfBytesRead,
		&osStatus ) )
	{

	}
	return lNumberOfBytesRead;
}
//------------------------------------------------------------------------------
DWORD __fastcall TComPort::Write(LPVOID lpBuffer, DWORD nNumberOfBytesToWrite ) {
	DWORD lNumberOfBytesWritten=-1;
	OVERLAPPED osStatus; //should probably be the OVERLAPPed struct in the Thread?
	if( WriteFile(
		Handle,
		lpBuffer,
		nNumberOfBytesToWrite,
		&lNumberOfBytesWritten,
		&osStatus ) )
	{

	}
	return lNumberOfBytesWritten;
}

bool __fastcall TComPort::EscapeFunction( DWORD Function ) { return EscapeCommFunction( Handle, Function ); }
bool __fastcall TComPort::SetState() { return SetCommState( Handle, &FSetup ); }
//------------------------------------------------------------------------------
/*
**                            The worker thread
*/
__fastcall TComPortThread::TComPortThread(TComPort *ComPort) :
    TThread(true),
    FComPort(ComPort)
{
    FreeOnTerminate = true;           // destroy thread when Execute() finishes
	FComPort->Handle = CreateFile(
		FComPort->PortName.c_str(),   // Port path, "\\.\COM2"...
		GENERIC_READ | GENERIC_WRITE, // access modes
		0,                            // share mode
		NULL,                         // pointer to security attributes
		OPEN_EXISTING,                // how to create
		FILE_FLAG_OVERLAPPED,         // file attributes
		0                             // handle to file with attributes to copy
	);

	if( FComPort->Handle == INVALID_HANDLE_VALUE ) {

		if( FComPort->OnError )
			FComPort->OnError( FComPort, GetLastError() );// Generate an OnError event

		Terminate(); // Mark thread for termination
	}
}
//---------------------------------------------------------------------------
__fastcall TComPortThread::~TComPortThread() {
}
//---------------------------------------------------------------------------
void __fastcall TComPortThread::Execute() {
	if( !Terminated ) {     // Investigate if this is really needed
		if( SetupPort() ) { // Misc setup stuff

			Synchronize( (TThreadMethod) &CallOpened ); // Generate an OnOpened event

			Work();                          // guess...

			CloseHandle( osStatus.hEvent );  // This handle created in SetupPort()
			CloseHandle( FComPort->Handle ); // Opened in the thread constructor
			FComPort->Handle = INVALID_HANDLE_VALUE;
			Synchronize( (TThreadMethod) &CallClosed ); // Generate an OnClosed event

		} else {
			// Port was never successfully setup and therefore no OnOpen was
			// sent, so we close it without generating an OnClosed event.
			// An OnError event should have been generated in SetupPort()
			// instead.
			CloseHandle( FComPort->Handle );
			FComPort->Handle = INVALID_HANDLE_VALUE;
		}
		FComPort->Handle = INVALID_HANDLE_VALUE;
	}
}

bool __fastcall TComPortThread::SetupPort() {
	bool retval=false;

	osStatus.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); // To be used in WaitCommEvent() calls

	if( osStatus.hEvent ) {

		if( FComPort->SetState() ) {

			retval = SetCommMask( FComPort->Handle,
				(FComPort->OnBreak  ? EV_BREAK  :0) | \
				(FComPort->OnCts    ? EV_CTS    :0) | \
				(FComPort->OnDsr    ? EV_DSR    :0) | \
				(FComPort->OnErr    ? EV_ERR    :0) | \
				(FComPort->OnRing   ? EV_RING   :0) | \
				(FComPort->OnRlsd   ? EV_RLSD   :0) | \
				(FComPort->OnRxchar ? EV_RXCHAR :0) | \
				(FComPort->OnRxflag ? EV_RXFLAG :0) | \
				(FComPort->OnTxempty? EV_TXEMPTY:0) );
/* Other events declared in winbase.h
#define EV_PERR             0x0200  // Printer error occured
#define EV_RX80FULL         0x0400  // Receive buffer is 80 percent full
#define EV_EVENT1           0x0800  // Provider specific event 1
#define EV_EVENT2           0x1000  // Provider specific event 2
*/
		}
		if( !retval ) {
			SyncError();
			CloseHandle( osStatus.hEvent );
		}
	} else SyncError();

	return retval;
}
void __fastcall TComPortThread::Close() {
	Terminate();
	SetEvent( osStatus.hEvent ); // theoretically, it may be closed already ...
}
void __fastcall TComPortThread::Work() {
	BOOL       fWaitingOnStat = FALSE;
	DWORD      dwRes;
	DWORD      dwOvRes;

    while( !Terminated ) {
        if( !fWaitingOnStat ) {
            if( !WaitCommEvent( FComPort->Handle, &dwCommEvent, &osStatus) ) {
                if (GetLastError() == ERROR_IO_PENDING) {
                    fWaitingOnStat = TRUE;
                } else {
                    // error in WaitCommEvent; abort
                    Terminate();
                }
            } else {
                // WaitCommEvent returned immediately.
                // Deal with status event as appropriate.
                Synchronize( (TThreadMethod) &CallEvent );
            }
        }

        if( fWaitingOnStat ) {
            // Wait for an event to occur.
            dwRes = WaitForSingleObject(osStatus.hEvent, INFINITE );

            switch(dwRes) { // Event occurred.
            case WAIT_OBJECT_0:
                if( !GetOverlappedResult( FComPort->Handle, &osStatus, &dwOvRes, FALSE) ) {
                    // An error occurred in the overlapped operation;
                    // call GetLastError to find out what it was
                    // and abort if it is fatal.
                    if( GetLastError() != ERROR_IO_PENDING ) Terminate(); // not likely when GetOverlappedResult() is called with bWait=FALSE

                } else {
                    // Status event is stored in the event flag
                    // specified in the original WaitCommEvent call.
                    // Deal with the status event as appropriate.
                    Synchronize( (TThreadMethod) &CallEvent );
                }
                // Set fWaitingOnStat flag to indicate that a new
                // WaitCommEvent is to be issued.
                fWaitingOnStat = FALSE;
                break;

            case WAIT_TIMEOUT: // not really going to happen - waiting INFINITE
                // Operation isn't complete yet. fWaitingOnStat flag
                // isn't changed since I'll loop back around and I don't want
                // to issue another WaitCommEvent until the first one finishes.
                break;

            // case WAIT_FAILED:
            default:
                // Error in the WaitForSingleObject; abort
                // This indicates a problem with the OVERLAPPED structure's
                // event handle.
                Terminate();
            }
        }
    }
}

void __fastcall TComPortThread::CallEvent() {
	if( dwCommEvent & EV_BREAK )   FComPort->OnBreak( FComPort );
	if( dwCommEvent & EV_RXCHAR )  FComPort->OnRxchar( FComPort );
	if( dwCommEvent & EV_CTS )     FComPort->OnCts( FComPort );
	if( dwCommEvent & EV_DSR )     FComPort->OnDsr( FComPort );
	if( dwCommEvent & EV_ERR )     FComPort->OnDsr( FComPort );
	if( dwCommEvent & EV_RING )    FComPort->OnRing( FComPort );
	if( dwCommEvent & EV_RLSD )    FComPort->OnRlsd( FComPort );
	if( dwCommEvent & EV_RXFLAG )  FComPort->OnRxflag( FComPort );
	if( dwCommEvent & EV_TXEMPTY ) FComPort->OnTxempty( FComPort );
}

void __fastcall TComPortThread::CallOpened() {
	if( FComPort->OnOpened ) FComPort->OnOpened( FComPort );
}

void __fastcall TComPortThread::CallClosed() {
	if( FComPort->OnClosed ) FComPort->OnClosed( FComPort );
}

inline void __fastcall TComPortThread::SyncError() {
	ErrorCode = GetLastError();
	Synchronize( (TThreadMethod) &CallError );
}

void __fastcall TComPortThread::CallError() {
	if( FComPort->OnError ) FComPort->OnError( FComPort, ErrorCode );
}
//---------------------------------------------------------------------------


Read More...

Ted Lyngmo replied to the topic 'Question about #pragma pack(push, 1)' in the forum. 3 days ago

Apparently you can't click the link until you start replying to the message :-D

I wonder if this works then: direct link to the attachment

Read More...

Ted Lyngmo replied to the topic 'Question about #pragma pack(push, 1)' in the forum. 4 days ago

I've attached it as a txt file instead, now with the comments included.

Read More...

Ted Lyngmo replied to the topic 'Question about #pragma pack(push, 1)' in the forum. 4 days ago

Sorry, but no matter what I do, it still says I've got too many links in the message. It's pure code and I've even removed all the comments... How is this a community for programmers? :-)

Read More...

Ted Lyngmo replied to the topic 'Question about #pragma pack(push, 1)' in the forum. 4 days ago

Good, but it sounds painful to work with :-) Did you try to break out that inner struct and "pragma pack" it separately?

The PacketHi and PacketLo and byteOrder fields seems to indicate that you may need to do some byte order conversion when reading/writing the data? Perhaps you should make a proper class out of it and have the in/out operators do the conversion and use the native format in the program you're making? If you do that, you don't have to worry about packing either. Here's a start (without byte order conversion since I don't know if it's fixed or if not, what endianess the byteOrder field signals):

I'll have to split it in several messages because something makes this forum says "Error
You have too many links in your message, please decrease them!". :-)

Read More...

Ted Lyngmo replied to the topic 'Forums unusable' in the forum. 4 days ago

Yet another feature noticed in this forum. It tries to count "links" and rejects messages if it finds "too many".

I wrote a rather lengthy message containing text + pure code blocks. Not a single link- but denied! I thought it was the number of code blocks so I made it into one block but, still denied.

That link counting feature can't have the slightest idea of how to identify a URL/URI. I think it's just counting // which would be a very clumsy way of identifying links in a forum for programmers.

Read More...

Ted Lyngmo replied to the topic 'Forums unusable' in the forum. 4 days ago

100 posts related to programming is a lot for me and I don't think I produce that in a year. If I look at the old forums, I have 117 posts and I was registered in 2006 - but that count is not correct either since I happened to have an older account that was merged with my current one - but the connection to all the posts I made with the older seems lost. I had been using the two accounts in parallell without knowing about it. Also, in the early years, no registration was needed. It should be possible to at least extract the number of posts made in the old forums per user and add that to the current counter to let those of us who's been around for 10-15 years without spamming off the hook.

select user,count(user) as post_count from posts group by user;

Read More...

Ted Lyngmo replied to the topic 'cmath - missing functions?' in the forum. 4 days ago

.... or did you mean that the functions are only missing when compiling for 32 bit target?

Read More...

Ted Lyngmo replied to the topic 'cmath - missing functions?' in the forum. 5 days ago

I don't have a 64 bit Windows machine, that's why didn't dare letting people with 64 bit machines use them, but ok, I'll take your word for it and have now removed that 64 bit guard.

Read More...

Ted Lyngmo replied to the topic 'C++ VCL RadioGroup question' in the forum. 5 days ago

If you want the Items functionality etc. that TRadioGroup has I think you'll need to create your own custom component for that. I tried this and it's working fine:

BorderlessRadioGroup.h

#ifndef BorderlessRadioGroupH
#define BorderlessRadioGroupH
//---------------------------------------------------------------------------
#include <System.SysUtils.hpp>
#include <System.Classes.hpp>
#include <Vcl.Controls.hpp>
//---------------------------------------------------------------------------
//typedef Vcl::Controls::TCustomControl TBorderlessRadioGroupBase;
//typedef Vcl::Stdctrls::TCustomGroupBox TBorderlessRadioGroupBase;
typedef Vcl::Extctrls::TCustomRadioGroup TBorderlessRadioGroupBase;

class PACKAGE TBorderlessRadioGroup : public TBorderlessRadioGroupBase
{
private:
protected:
	virtual void __fastcall Paint(void);
public:
	__fastcall TBorderlessRadioGroup(TComponent* Owner);
__published:
	__property Align = {default=0};
	__property Anchors = {default=3};
	__property BiDiMode;
	__property Caption = {default=0};
	__property Color = {default=-16777211};
	__property Columns = {default=1};
	__property Ctl3D;
	__property DoubleBuffered;
	__property DragCursor = {default=-12};
	__property DragKind = {default=0};
	__property DragMode = {default=0};
	__property Enabled = {default=1};
	__property Font;
	__property ItemIndex = {default=-1};
	__property Items;
	__property Constraints;
	__property ParentBiDiMode = {default=1};
	__property ParentBackground = {default=1};
	__property ParentColor = {default=1};
	__property ParentCtl3D = {default=1};
	__property ParentDoubleBuffered = {default=1};
	__property ParentFont = {default=1};
	__property ParentShowHint = {default=1};
	__property PopupMenu;
	__property ShowHint;
	__property TabOrder = {default=-1};
	__property TabStop = {default=0};
	__property Touch;
	__property Visible = {default=1};
	__property StyleElements = {default=7};
	__property WordWrap = {default=0};
	__property OnClick;
	__property OnContextPopup;
	__property OnDragDrop;
	__property OnDragOver;
	__property OnEndDock;
	__property OnEndDrag;
	__property OnEnter;
	__property OnExit;
	__property OnGesture;
	__property OnStartDock;
	__property OnStartDrag;

};
//---------------------------------------------------------------------------
#endif
BorderlessRadioGroup.cpp
//---------------------------------------------------------------------------
#include <vcl.h>

#pragma hdrstop

#include "BorderlessRadioGroup.h"
#pragma package(smart_init)
//---------------------------------------------------------------------------
// ValidCtrCheck is used to assure that the components created do not have
// any pure virtual functions.
//

static inline void ValidCtrCheck(TBorderlessRadioGroup *)
{
	new TBorderlessRadioGroup(NULL);
}
//---------------------------------------------------------------------------
__fastcall TBorderlessRadioGroup::TBorderlessRadioGroup(TComponent* Owner)
	: TBorderlessRadioGroupBase(Owner)
{
}
//---------------------------------------------------------------------------
namespace Borderlessradiogroup
{
	void __fastcall PACKAGE Register()
	{
		TComponentClass classes[1] = {__classid(TBorderlessRadioGroup)};
		RegisterComponents(L"Lyncon", classes, 0);
	}
}
//---------------------------------------------------------------------------
void __fastcall TBorderlessRadioGroup::Paint(void) {
    // Add painting the Caption here if you want that
}


Read More...

Ted Lyngmo replied to the topic 'Forums unusable' in the forum. 5 days ago

@April Anne: Why is this community forum moderated? It makes the experience even more painful than it needs to be. 1. We are all logged in when we post. 2. You have that fancy captcha thingy to prevent logged in users, who forgot locking the computer whilst leaving the room full of evil robots, from distributing spam. So, what's the worst that could happen if all post were automatically approved?

The timezone difference (I'm in the CET TZ) makes it feel like having snail-mail pen-pals.

Read More...

Ted Lyngmo replied to the topic 'cmath - missing functions?' in the forum. 5 days ago

Hi Nate!

I've made a header file including the functions needed by a json library I'm using:
cmath_missing.hpp

It's a hack - adding functions to the std namespace which shouldn't be done, but I didn't know what else to do. Right now the functions are a mix of home made functions and calls to existing Windows functions.

Example for std::signbit():

namespace std {
    template <typename T>
    bool signbit(T v) {
        return signbit((double)v);
    }
    template <>
    bool signbit(float v) {
        return *((unsigned char*)&v+3) & 0x80;
    }
    template <>
    bool signbit(double v) {
        return *((unsigned char*)&v+7) & 0x80;
    }
    template <>
    bool signbit(long double v) {
        return *((unsigned char*)&v+9) & 0x80;
    }
}

I will not work as-is on _WIN64 or any other platform than _WIN32 but you're welcome to try it out (by removing the guarding !defined(_WIN64) at the top). If you can confirm that it's working on _WIN64 I'll remove that guard.

I've also limited it to clang versions [3.3.1, 3.4.0) since I'm on Builder 10.2.1 and don't know what clang version Builder 10.2.2 and later are based on or if they have fixed proper C++11 headers in those versions.

Remove the guards and please tell me if it works and what Builder version you're on and what clang version it's based on and I'll modify the guards accordingly.

Also, it's incomplete. I've only added what I needed right now. if you need functions that I haven't added yet, please tell me and I'll try to add those too.

People with 10.2.2 or 10.2.3, do you have std::signbit and all the rest of the C++11 cmath functions and is std::char_traits::eof still defined as "static int_type eof()" instead of "static constexpr int_type eof()"?

Br,
Ted

Read More...

Ted Lyngmo replied to the topic 'Question about #pragma pack(push, 1)' in the forum. 6 days ago

Looks ok to me. If you do sizeof(can), do you get 61 or something larger?

Read More...

Ted Lyngmo created a new topic ' Multiple ReadFileEx / OVERLAPPED operations in one thread' in the forum. 6 days ago

Hi!

I'm rewriting some old code that used polling (with a short sleep) to fetch stdout & stderr from a program started with CreateProcess. The goal is to make it free from polling. I've extended OVERLAPPED like this:

struct TPipeOverlapped : public OVERLAPPED {
    TShellThread& shell_thread;
    TThreadMethod event_handler;
    HANDLE pipe;
    char one_char;
    char* buffer;
    DWORD size;
    __fastcall TPipeOverlapped(TShellThread& st, TThreadMethod tm, HANDLE Pipe);
    virtual __fastcall ~TPipeOverlapped();
    BOOL __fastcall ReadFileEx();
    void __fastcall FinishIt();
};

BOOL __fastcall TPipeOverlapped::ReadFileEx() {
    // this "one_char" thing might be removed to use a fixed buffer later
    DWORD rv = ::ReadFileEx( this->pipe, &this->one_char, 1, this, FileIOCompletionRoutine );
    if( rv==FALSE ) {
        // Closing is done elsewhere
        this->pipe = NULL;
    }
    return rv;
}

The FileIOCompletionRoutine will PeekNamedPipe(), allocate a buffer and read any additional data, call the users event handler and then free the buffer. It then calls the TPipeOverlapped's ReadFileEx() to get more events.

This is a somewhat shortened version of my threads code:
void __fastcall TShellThread::Execute() {
    DWORD dwStatus=STILL_ACTIVE;

    if( StdOut.ReadFileEx()==0 || StdErr.ReadFileEx()==0 ) { // hangs here on the second ReadFileEx
        return; // ReadFileEx failed
    }
    while( !Terminated && dwStatus == STILL_ACTIVE ) {
        DWORD wfso = WaitForSingleObjectEx(hProcess, INFINITE, TRUE);
        if( wfso==WAIT_OBJECT_0 ) {
            GetExitCodeProcess(hProcess, &dwStatus);
        }
    }
    StdOut.FinishIt(); // read lingering data in pipe
    StdErr.FinishIt(); // read lingering data in pipe
}

What happens is that the first ReadFileEx succeeds but the second hangs. If I comment out the initial StdErr.ReadFileEx(), I get all data on stdout just fine.

The reason I chose ReadFileEx over ReadFile (+ OVERLAPPED with an event handle) was to avoid only reading one very busy handle (since WaitForMultipleObjectsEx returns the first of all the signalled handles).and not get the data properly interleaved, but I guess I can manually check the state of the stderr event if stdout is firing.

Is it supposed to work to put two OVERLAPPED operations at work in the same thread with ReadFileEx or should I give that up?
If it won't work, will using ReadFile?

Br,
Ted

Read More...

Ted Lyngmo replied to the topic 'How to close gracefully after an unhandled win32 exception' in the forum. 7 days ago

As Roger mentioned, try replacing raw pointers with smart ones. Preferably, get rid of all destructor code all together.

For VCL classes (that must be constructed with "new"), instead of:

class X {
protected:
    TComponent* something;
public:
    X() : something(new TComponent(...)) {}
    virtual ~X() { delete something; }
}

You could do something like this:
class X {
protected:
    std::unique_ptr<TComponent> something = std::make_unique<TComponent>(...);
public:
    X() {}
    virtual ~X() {}
}

Br,
Ted

Read More...

Ted Lyngmo replied to the topic '10.2.1 - Very large 32 bit exe file' in the forum. 7 days ago

> I'm not sure that 2MB is "very large" (one of our main C++ builder windows projects exe file is 18MB.

I'm sure that contains a lot more code than my little program. It uses a json header ( github.com/TedLyngmo/borland_nlohmann_json ) file and a mini XML-creator. Both combined < 70 kB when compiled. The console app makes a TIdHTTP call to fetch a json document and transforms it into XML.

> Why are you so worried about the size I wonder?

It just seems weird. The main Windows application in this project is 2.6 MiB and that contains a large number of VCL components, but it's written in C++ Builder 4 - and now this little console app in 10.2.1 that only uses 2 VCL:s (TidHTTP and the SSL class) takes 2 MiB. It must include stuff it doesn't need.

Also, people usually upgrade the program at around the same time, which usually happens on Saturdays when I'm gaming and then I get lag-spikes :-) I have bandwidth limits in the server but the extra size still makes the download take a 1-2 seconds extra.

> If you use run time linking your exe file will be a lot smaller (but you will face the limitations that run time linking imposes on you).

Yeah, but I really don't like linking with the run time libraries.

Br,
Ted

Read More...

Ted Lyngmo replied to the topic '10.2.1 - Very large 32 bit exe file' in the forum. 1 week ago

I should have mentioned that it's the exe from the release config that is this big. I haven't even debug compiled it once.

I read the links and it turns out that what is said to be the default settings for the release config is not like that for me. Very odd since I've definately not turned on any of those Delphi options - and when I now turned them off they are lit up to show me that they are *not* in the default setting. I also disabled C++ RTTI and disabled incremental linking. Nothing made any noticable difference.

The only thing making a difference was optimizing for size instead of speed. My exe went from 2048 to 2001 KB. :-)

Remy mentioned that "RTTI and Unicode also play a large factor in the EXE size" and since I've disabled RTTI I guess it could be related to Unicode. I have no clue about what "Generics" is though.

Br,
Ted

Read More...