CArchive and COleVariant deserialization issue

Michael 21 Reputation points
2021-12-08T16:54:56.287+00:00

Hi together,

while debugging an access violation bug in a programm i came across this code in "olevar.cpp" (MSVC 14.16.27023) at line 984 (Operator: "CArchive& AFXAPI operator>>(CArchive& ar, COleVariant& varSrc)"):

156061-msvc-olevar-carchive-operator.png

Wouldn't it be better to set "bstrVal" to a valid pointer of a string with null size instead of setting it to NULL, when a BSTR with null size is deserialized?

Now that i know what the code does i can work around, but I think it's a bug, isn't it?

Greetings

C++
C++
A high-level, general-purpose programming language, created as an extension of the C programming language, that has object-oriented, generic, and functional features in addition to facilities for low-level memory manipulation.
3,637 questions
{count} votes

Accepted answer
  1. RLWA32 43,306 Reputation points
    2021-12-09T02:56:20.683+00:00

    No, it's not a bug. The guide referenced in my comments above says the following

    1) If you write a function which takes an argument of type BSTR then you are required to accept NULL as a valid BSTR and treat it the same as a pointer to a zero-length BSTR. COM uses this convention, as do both Visual Basic and VBScript, so if you want to play well with others you have to obey this convention. If a string variable in VB happens to be an empty string then VB might pass it as NULL or as a zero-length buffer -- it is entirely dependent on the internal workings of the VB program.

    That's not usually the case with PWSZ-based code. Usually NULL is intended to mean "this string value is missing", not as a synonym for an empty string.

    0 comments No comments

1 additional answer

Sort by: Most helpful
  1. Scottish Kilt 1 Reputation point
    2021-12-09T05:14:31.437+00:00

    I am running into an issue regarding serialization with MFC CArchive in a small project I am working on.

    I got storing into the archive and then to a file working fine (I hope so) but reading from the file returns the object's properties as NULL.

    Basically what I am trying to achieve is storing last up to 10 sales into an archive and loading back in when desired into a CTypedPtrArray
    Both Sale and Mainstore are declared as serializable (Not sure about the latter if it is required) including the appropriate IMPLEMENT_SERIAL in the respective classes and there is an empty constructor for Sale (as well as MainStore) that I tried to leave empty or tried to initialize the properties as NULL but still no luck.

    I have been trying for days to get serializing working and it seems I am missing just a little detail but cannot figure what that is.

    Any help with regards to why I am receiving NULL will be much appreciated and if there is any missing info in my post I will edit it accordingly.

    Edit:

    So my Sale::Serialize function was indeed empty but when reading back from the archive I get an error that says that no operator ">>" matches these operands

    void Sale::Serialize(CArchive& ar)
    {
    CObject::Serialize(ar);
    if (ar.IsStoring())
    {
    ar << computer;
    ar << customer;
    ar << dateAndTime;
    }
    else
    {
    ar >> computer;
    ar >> customer;
    ar >> dateAndTime;
    }

    }
    Edit 2:

    Added Serialization to the Customer and Computer as well and edited ar>>dateAndTime to ar>> dateAndTime. Both the char and and Customer classes no longer give me syntax error. However Computer still does. Computer is an abstract class that inherits (as I read online on how to serialize abstract class) from CObject and has void Serialize function while the childs DECLARE/IMPLEMENT_SERIAL like so IMPLEMENT_SERIAL(ChildClass,Computer,1) .

    c++
    mfc
    Share
    Improve this question
    Follow
    edited Jul 21 at 20:08

    double-beep
    4,1711212 gold badges2727 silver badges3838 bronze badges
    asked Jun 5 at 17:25

    lolsniperftw
    3144 bronze badges
    In the storing code you store objects (or array elements or structures) but in the loading code you read pointers. Also, the storing code could be further improved (store the last, up to 10 elements of the array - that check (if #items<10) could be changed. And you seem to reverse the items' order. And your data structures could be improved too, eg why have two separate arrays for sales and last 10 sales, it's hard to maintain and synchronize. –
    Constantine Georgiou
    Jun 6 at 1:08
    Aren't the elements in sales1 also pointers so I am also storing pointers to the objects and not objects themselves so the storing and loading are using the same thing. I am confused. –
    lolsniperftw
    Jun 6 at 4:11
    Have you tried to change Sale* pNewSale to Sale* pNewSale = new Sale and then Serialise? At the moment your element is a pointer to nothing so it is not possible to read it into anything. –
    Andrew Truckle
    Jun 6 at 6:59
    Do I understand correctly? The entries of lastUpTo10Sales are not null, but the properties customer, computer, etc. are null? That would indicate an error in Sale::Serialize; your MainStore::Serialize does not look wrong. –
    j6t
    Jun 6 at 7:11
    2
    @ANDO MFC's deserializer constructs objects. You are not required to create an object the deserializer writes into. Instead, it uses the (static) class members provided by the IMPLEMENT_DYNCREATE macro to construct instances of CObject-derived classes. If you new an instance yourself prior to deserializing, you are just creating a memory leak. –
    IInspectable
    Jun 6 at 16:23