Watch, Follow, &
Connect with Us

For forums, blogs and more please visit our
Developer Tools Community.


Welcome, Guest
Guest Settings
Help

Thread: Delphi style classes must be constructed using operator new



Permlink Replies: 2 - Last Post: Jan 29, 2018 12:03 AM Last Post By: roca robin Threads: [ Previous | Next ]
roca robin

Posts: 140
Registered: 9/10/06
Delphi style classes must be constructed using operator new
Click to report abuse...   Click to reply to this thread Reply
  Posted: Jan 12, 2018 10:01 AM
I'm a Delphi user, but I need to shift to c++builder,

so I'm troubled with the line below, how to correct the codes properly?

void __fastcall VariantToStream(const OleVariant *v, TMemoryStream Stream )
{
void *p;
Stream.Position = 0;
Stream.Size = VarArrayHighBound( v, 1 ) - VarArrayLowBound( v, 1 ) + 1;
p = VarArrayLock( v );
Stream.Write(p, Stream.Size );
VarArrayUnlock( v );
Stream.Position = 0;
}

void __fastcall VariantToJPEGToBMP(OleVariant *aValue, TJPEGImage &aJPEG, TBitmap &aBMP )
{
TMemoryStream *Stream = new TMemoryStream();
try
{
VariantToStream(aValue, *Stream ); //ERROR LINE on compile TIME //Delphi style classes must be constructed using operator new
aJPEG.LoadFromStream(Stream);
aBMP.Assign(&aJPEG);
}
__finally
{
aValue = 0;
Stream->Free();
}
}


I corrected the code with this, and NO ERROR line, BUT errors during RUN-TIME, ERROR says "invalid argument"

void __fastcall VariantToStream(const OleVariant *v, TMemoryStream &Stream )
{
void *p;
Stream.Position = 0;
Stream.Size = VarArrayHighBound( v, 1 ) - VarArrayLowBound( v, 1 ) + 1;
p = VarArrayLock( v );
Stream.Write(p, Stream.Size );
VarArrayUnlock( v );
Stream.Position = 0;
}

void __fastcall VariantToJPEGToBMP(OleVariant *aValue, TJPEGImage &aJPEG, TBitmap &aBMP )
{
TMemoryStream *Stream;
try
{
Stream = new TMemoryStream();
VariantToStream(aValue, *Stream );
aJPEG.LoadFromStream(Stream);
aBMP.Assign(&aJPEG);
}
__finally
{
Stream->Free();
}
}

Remy Lebeau (Te...


Posts: 9,447
Registered: 12/23/01
Re: Delphi style classes must be constructed using operator new
Click to report abuse...   Click to reply to this thread Reply
  Posted: Jan 12, 2018 11:15 AM   in response to: roca robin in response to: roca robin
roca robin wrote:

so I'm troubled with the line below, how to correct the codes
properly?

In standard C++, an instance of a class can be constructed on the stack or the heap. It doesn't care where it is allocated. Objects constructed on the stack have automatic lifetime management (they are destroyed when they go out of scope), whereas objects on the heap have manual lifetime management (you have to explicitly destroy them).

Delphi-style classes are derived from TObject, which has special handling in C++Builder, as it is part of the compatibility layer between C++Builder and Delphi libraries.

In Delphi, all class object instances are allocated on the heap only, never on the stack. That is what the C++ error message is telling you. You are trying to construct a TObject-derived class on the stack. You need to do what the error message says - construct your object on the heap instead.

void __fastcall VariantToStream(const OleVariant *v, TMemoryStream Stream )

TMemoryStream is derived from TObject, so it can't be constructed on the call stack. IOW, you can't pass it by value. You need to change the Stream parameter to use a TMemoryStream* pointer instead.

Also, OleVariant is not a TObject descendant, so there is no reason to pass the OleVariant by pointer. You should pass it by value, or at least by const reference. Especially since the VarArray...() functions you are calling do not take an OleVariant* pointer as input, they take a Variant by const reference instead.

Stream.Position = 0;
Stream.Size = VarArrayHighBound( v, 1 ) - VarArrayLowBound( v, 1 ) + 1;
p = VarArrayLock( v );
Stream.Write(p, Stream.Size );
VarArrayUnlock( v );
Stream.Position = 0;

After changing the Stream parameter to a pointer, you need to access the Stream's members using the '->' operator instead of the '.' operator.

void __fastcall VariantToJPEGToBMP(OleVariant *aValue, TJPEGImage &aJPEG, TBitmap &aBMP ) {

Same issues here. TJPEGImage and TBitmap are TObject descendants, so they need to be constructed on the heap and should be passed by pointer. And no need to pass the OleVariant by pointer.

VariantToStream(aValue, *Stream ); //ERROR LINE on compile TIME //Delphi style classes must be constructed using operator new

You are allocating the original Stream object on the heap (good), but since the function parameter is passed by value, the compiler is trying to copy-construct a new object on the call stack, and that is where the error is coming from. Change the parameter to a pointer instead, and get rid of the use of the '*' dereference operator.

Stream->Free();

Don't call Free() directly. The Stream object was constructed using 'new', so use 'delete' to destroy it. TObject::Free() calls the same class destructor that 'delete' calls, but 'delete' is the standard C++ way to release memory allocated with 'new'.

I corrected the code with this, and NO ERROR line, BUT errors during
RUN-TIME,

That is likely due to your use of an OleVariant* pointer. Like I said, the VarArray...() functions take a Variant as input. Variant has a constructor that accepts a Variant* as input. And OleVariant derives
from Variant. So, when calling the VarArray...() functions, you are constructing a new Variant that contains a pointer to the original OleVariant, which is not what you want. Get rid of the pointer.

The final code should look more like this:

void __fastcall VariantToStream(const OleVariant &v, TMemoryStream *Stream)
{
    void *p = VarArrayLock( v );
    try
    {
        int size = VarArrayHighBound( v, 1 ) - VarArrayLowBound( v, 1 ) + 1;
        Stream->Size = size;
        Stream->Position = 0;
        Stream->Write(p, size);
    }
    __finally
    {
        VarArrayUnlock( v );
    }
}
 
void __fastcall VariantToJPEGToBMP(const OleVariant &aValue, TJPEGImage *aJPEG, TBitmap *aBMP)
{
    TMemoryStream *Stream = new TMemoryStream;
    try
    {
        VariantToStream(aValue, Stream);
        Stream->Position = 0;
        aJPEG->LoadFromStream(Stream);
        aBMP->Assign(aJPEG);
    }
    __finally
    {
        delete Stream;
    }
}


On a side note, you can eliminate VariantToStream() altogether if you use TCustomMemoryStream instead of TMemoryStream, then you can load the JPEG data directly from the OleVariant's data without having to make a copy of the data first:

class TReadOnlyMemoryStream : public TCustomMemoryStream
{
public:
    __fastcall TReadMemoryStream(void *APtr, int ASize)
    {
        SetPointer(APtr, ASize);
    }
 
    int __fastcall Write(const void *Buffer, int Count)
    {
        return 0;
    }
};
 
void __fastcall VariantToJPEGToBMP(const OleVariant &aValue, TJPEGImage *aJPEG, TBitmap *aBMP)
{
    void *p = VarArrayLock( aValue );
    try
    {
        int size = VarArrayHighBound( aValue, 1 ) - VarArrayLowBound( aValue, 1 ) + 1;
        TReadOnlyMemoryStream *Stream = new TReadOnlyMemoryStream(p, size);
        try
        {
            aJPEG->LoadFromStream(Stream);
            aBMP->Assign(aJPEG);
        }
        __finally
        {
            delete Stream;
        }
    }
    __finally
    {
        VarArrayUnlock( aValue );
    }
}


And if the caller does not actually need the JPEG data, then the TJPEGImage object should be moved inside the function:

void __fastcall VariantToBMPViaJPEG(const OleVariant &aValue, TBitmap *aBMP)
{
    void *p = VarArrayLock( aValue );
    try
    {
        int size = VarArrayHighBound( aValue, 1 ) - VarArrayLowBound( aValue, 1 ) + 1;
        TJPEGImage *JPG = new TJPEGImage;
        try
        {
            TReadOnlyMemoryStream *Stream = new TReadOnlyMemoryStream(p, size);
            try
            {
                JPG->LoadFromStream(Stream);
            }
            __finally
            {
                delete Stream;
            }
            aBMP->Assign(JPG);
        }
        __finally
        {
            delete JPG;
        }
    }
    __finally
    {
        VarArrayUnlock( aValue );
    }
}


--
Remy Lebeau (TeamB)
roca robin

Posts: 140
Registered: 9/10/06
Re: Delphi style classes must be constructed using operator new
Click to report abuse...   Click to reply to this thread Reply
  Posted: Jan 13, 2018 12:29 AM   in response to: Remy Lebeau (Te... in response to: Remy Lebeau (Te...
some error's fixed,
It's working good now,
thank you
Legend
Helpful Answer (5 pts)
Correct Answer (10 pts)

Server Response from: ETNAJIVE02