Cannot access BaseDocument in Free() method



  • On 07/08/2013 at 16:16, xxxxxxxx wrote:

    User Information:
    Cinema 4D Version:    
    Platform:      
    Language(s) :

    ---------
    Hi, I am implementing the Free() method in my tag.
    But cannot access the BaseDocument.

    void MyTag::Free(GeListNode* node)
    {
        BaseTag* tag = (BaseTag* ) node; 
        BaseDocument* doc = tag->GetDocument(); 
        // doc == null  
    }
    

    There may be several reasons reason I want the document. For example, when my tag is being removed, it also removes a helper object. If, in case, the user invokes Undo, the tag is inserted again. But the helper object is gone forever. I imagine, if I wrap the removal of the helper object in an undo block, the helper object will also be inserted again..? 
    Well, regardless of this being a good or bad idea, I still want the document to be accessible.

    -Ingvar



  • On 08/08/2013 at 00:26, xxxxxxxx wrote:

    Is the helper object an actual object (BaseObject derived) that is in the document? Then, yes, you need to add an undo for it explicitly.  Any association with the tag (such as a BaseLink) will not automatically restore it on an undo.

    doc->StartUndo();  
    // Add undo for both elements being deleted *before* deletion!  
    doc->AddUndo(UNDOTYPE_DELETE, myTag);  
    doc->AddUndo(UNDOTYPE_DELETE, myObject);  
    // Remove from document (required!)  
    myTag->Remove();  
    myObject->Remove();  
    // Free instances  
    BaseTag::Free(myTag);  
    BaseObject::Free(myObject);  
    doc->EndUndo();
    

    Your problem may be that since the tag needs to be removed from the document list before freeing it, it can not possibly be associated with the document any longer.  My suggestion is a class member to store the BaseDocument beforehand and use it in your Free() method



  • On 08/08/2013 at 01:29, xxxxxxxx wrote:

    What's wrong with:

      
    void MyTag::Free(GeListNode* node)   
    {   
        BaseDocument* doc = node->GetDocument();   
    }   
    

    Steve



  • On 08/08/2013 at 03:59, xxxxxxxx wrote:

    Originally posted by xxxxxxxx

    What's wrong with:

     
    void MyTag::Free(GeListNode* node)   
    {   
      BaseDocument* doc = node->GetDocument();   
    }   
    

    Steve

    What is wrong is that doc is NULL.
    That is the very reason I started this thread.



  • On 08/08/2013 at 04:01, xxxxxxxx wrote:

    Originally posted by xxxxxxxx

    Your problem may be that..
    [..]

    myTag->Remove();  
    
    

    Hi Robert,
    my problem is just this: The doc is NULL, that is the reason I started this thread.
    I just cannot get hold of any BaseDocument in the Free() method.

    Apart from that, the tag is not removed programmatically. It is removed by the user, when the user deletes it. I suppose an undo here is inappropriate, and that the helper object has to be created again, if the user hits undo, in order to bring the tag back again.
    I see no way to bring back the helper object in the same operation when the user invokes undo.

    Edited:
    I can store the BaseDocument as a variable, at an earlier stage of the tag's life cycle, and it seems that this works ok. But I would rather get hold if it directly, in the Free() method.



  • On 08/08/2013 at 04:28, xxxxxxxx wrote:

    Lo and behold - I found a solution!! 😄

    void MyTag::Free(GeListNode* node)
    {
    \> if(__HelperObject)
    \> 
    \> {
    \> 
    \>   	__BaseDocument->AddUndo(UNDOTYPE_DELETE, __HelperObject);
    \> 
    \>   	__HelperObject->Remove(); 
    \> 
    \> }
    }
    

    This works like magic! I have stored __BaseDocument at an earlier stage of the tag's life cycle, now it comes in handy, since node->GetDocument() returns NULL.
    And - even more interesting, it seems that the Free() method is already "inside" a doc->StartUnd() .. doc->EndUndo().

    So when the user manually deletes the tag, and then invokes undo, the tag, and the helper object, reappears!!
    So now all is just fine, only one issue remains - I cannot get hold of the BaseDocument inside the Free() method.



  • On 08/08/2013 at 04:49, xxxxxxxx wrote:

    Just one question, why do you use double underscore (_ _) in variable names?
    In C++ this is reserved for implementation.  (like __declspec, __forceinline ...)

    http://stackoverflow.com/questions/228783/what-are-the-rules-about-using-an-underscore-in-a-c-identifier



  • On 08/08/2013 at 04:56, xxxxxxxx wrote:

    Originally posted by xxxxxxxx

    Just one question, why do you use double underscore (_ _) in variable names?

    See my signature 😂



  • On 08/08/2013 at 04:58, xxxxxxxx wrote:

    I'd chose a more elegant solution. It is quite possible that your Helper Object has been removed by
    someone (user, module, whatever) and removing the Helper Object in that case can lead to a
    crash.You can create an invisible tag sitting on the helper object. This tag should check if _your tag_
    still exists, and if it does not, it can remove the object. (Choose to do this in a Message() calle since
    scene modifications in TagData::Execute() or similar methods is not recommended by MAXON).

    Best,
    -Niklas



  • On 08/08/2013 at 05:10, xxxxxxxx wrote:

    Originally posted by xxxxxxxx

    What is wrong is that doc is NULL. That is the very reason I started this thread.

    My point was why are you using such a convoluted method to get the document, but hey, just carry on.

    To answer your question it appears that once Free() is called, the node has been removed from the document and therefore GetDocument() will always return null.



  • On 08/08/2013 at 05:31, xxxxxxxx wrote:

    Originally posted by xxxxxxxx

    My point was why are you using such a convoluted method to get the document, but hey, just carry on.

    Sorry about that, did not mean to be rude. I overlooked the direct method, I am using your code now.

    Originally posted by xxxxxxxx

    To answer your question it appears that once Free() is called, the node has been removed from the document and therefore GetDocument() will always return null.

    Ok, that seems to be correct! Nevertheless, storing the document as a variable seems to work just fine.



  • On 08/08/2013 at 05:33, xxxxxxxx wrote:

    Originally posted by xxxxxxxx

    I'd chose a more elegant solution. It is quite possible that your Helper Object has been removed by
    someone (user, module, whatever) and removing the Helper Object in that case can lead to a
    crash.You can create an invisible tag sitting on the helper object. This tag should check if _your tag_
    still exists, and if it does not, it can remove the object. (Choose to do this in a Message() calle since
    scene modifications in TagData::Execute() or similar methods is not recommended by MAXON).

    Thanks Niklas! Yes, this is an elegant solution. In my case, however, the helper object is totally invisible. It does not appear in the work space, it is also hidden in the object browser. The user has no knowledge about its existence. So I can use the more simpler method in this case.



  • On 08/08/2013 at 05:56, xxxxxxxx wrote:

    Originally posted by xxxxxxxx

    Thanks Niklas! Yes, this is an elegant solution. In my case, however, the helper object is totally invisible. It does not appear in the work space, it is also hidden in the object browser. The user has no knowledge about its existence. So I can use the more simpler method in this case.

    May I ask you why you even need this helper object then?



  • On 08/08/2013 at 06:45, xxxxxxxx wrote:

    Originally posted by xxxxxxxx

    May I ask you why you even need this helper object then?

    The only solution I found so far, here is the problem:  
    https://plugincafe.maxon.net/topic/7246/8326_constrain-rotation-to-object-with-skewed-axis&KW=



  • On 08/08/2013 at 07:14, xxxxxxxx wrote:

    My suggestion is the best response.  If the helper object is not in the document, you need to invoke more in-depth methods (like CopyTo()) to ensure that the class membership is retained upon an undo.  That is, the object must be literally recognized during the free process and then reinstated during the undo process.  CopyTo() is there to transport non-C4D relevant data/memory/information between various processes such as copies for undo or render and such.  Think of it as memory you have allocated for the tag that must be reallocated when it is restored because it is not handled directly by C4D.  Some of the information must be retained in the BaseContainer/Description of the tag so that the helper object can be 'reconstructed' on a user undo process.

    Welcome to the wonderful world of the C4D SDK API. :)



  • On 08/08/2013 at 08:54, xxxxxxxx wrote:

    Ok Robert,
    but what is wrong with my approach, posted Today** at 1:28pm?
    It works just fine!



  • On 08/08/2013 at 09:12, xxxxxxxx wrote:

    Times are displayed based on the timezone here.

    I already told you: It might crash in various situations. Unless you do not own an object, you should not store a pointer to it and assume it is valid anytime. And in this case, when the object is inserted in the document, you are not the owner of the object.



  • On 08/08/2013 at 09:17, xxxxxxxx wrote:

    The code has been modified in the mean time. I keep the BaseDocument, and search for the object to be removed, by the name. By doing this, I am not storing a pointer to it.
    But I do store a pointer to the BaseDocument.



  • On 08/08/2013 at 19:20, xxxxxxxx wrote:

    Simply create a LINK description in your tag and set it to the helper object.  If the object is deleted by the user, for instance, BaseLink knows about it.


Log in to reply