IFormatServiceCallbackPtr not identical to IFormatServiceCallback* ?!

Hi,

I’m struggling a bit with the formatting service that is described in chapter 12…

If MyFormatImplementation::CreateInstance( ) returns a IFormatServiceCallbackPtr  everything is fine, but

If MyFormatImplementation::CreateInstance( ) returns a pointer to IFormatServiceCallback the plugin builds, but crashes EndNoteX4.   Why??

If I use IFormatServiceCallbackPtr  the next question is how to retrieve my formatted references? The documentation says:

// After this call the stream string in ‘pMyCallback’ contains
// all the records formatted as a bibliography in Numbered style

But how do I access m_wOut ?  I can’t cast pMyCallback to MyFormatImplementation* and if I make CreateInstance return a MyFormatImplementation* (which gives me access to m_wOut), the plugin builds but crashes EndNote :frowning:

Nihilit

1 Like

Hello,

Chapter 4 covers the difference between the smart pointer (Ptr) and the raw pointer (*) thoroughly.  But I think I see what your crash issue might be.  The crash is usually due to the raw pointer getting freed by a smart pointer going out of scope when there aren’t enough reference counts for it.  The solution you came up with (to return a smart pointer) works because returning a smart pointer from CreateInstance would add a reference count to the object, thus preventing it from getting freed.  It might also leak the object, so isn’t necessary.  You might have been led astray by a typo I just noticed in the Chapter 12 documentation.

Based on a code snippet you included in a different post, I think you are doing this *inside* you CreateInstance() function:

IFormatServiceCallbackPtr p = new CBaseObject< MyFormatImplementation >();

I actually see that this is what the sample code in Chapter 12 says to do, but that’s incorrect (we’ll log a bug about this typo).  The line should read:

IFormatServiceCallback* p = new CBaseObject< MyFormatImplementation >();

and if you look at the comments in that sample code just after this statement, it actually says, “note that we didn’t use a smart pointer above,” when in fact we accidentally did.

Normally, you want to use smart pointers since they do all the reference counting for you.  The exception are in cases like CreateInstance() where you are generating an object for a caller who you expect will do that reference counting.  In other words, CreateInstance() just creates the raw pointer and returns the raw pointer, but not reference counted.  The function that calls CreateInstance(), however, is obliged to assign the result to a smart pointer thus providingt the first reference count.  So use the line above *in* CreateInstance(), and use the line below when *calling* CreateInstance():

IFormatServiceCallbackPtr pMyCallback = MyFormatImplementation::CreateInstance( /* your params here */ );

What is happening in your CreateInstance() function right now is that the raw pointer is being assigned to a smart pointer, which gives it a reference count of 1.  But when your CreateInstance() function finishes, that smart pointer goes out of scope, which frees the raw pointer in it (since it had only that one reference count).  So by the time you actually return out of CreateInstance() back to the place where it is being assigned to a variable, your callback object has already been freed.  Then when you use it later, it crashes because it doesn’t actually exist anymore.

Whether this works or not, I always recommend that everyone read Chapter 4, even if they don’t read anything else. That chapter covers in great detail the differences between the smart pointer (Ptr) and the raw pointer (*) and covers the various reasons why not handling these types quite right can lead to memory leaks or crashes.

Hope this helps.

1 Like

For the second part of your question, it looks like you are trying to build from the skeleton code in Chapter 12.  In that code we use an ‘m_wOut’ string stream to dump our formatted text into.  Just to be clear, we aren’t necessarily advocating this as the way to structure your code.  It’s just a a hello-world style sample, to help show the various pieces you’d need to assemble, step-by-step when making your own stuff.  As such, ‘m_wOut’ in that sample was really just a placeholder - it could just as easily have been ‘cout’ or a file dump.  I apologize if you already understood all that, I just wanted to note that for anyone else who reads this thread in the future. 

In any case, if you really want to dump your content into an object like m_wOut and have it survive to some later time, possibly after your callback object has been freed, I’d recommend that you create your data storage object outside of your Format Calback object and then pass it in to your CreateInstance() function to make it available to your callback.  That way your callback object is simply using this data storage object, but not freeing it if/when the callback is freed (because it sounds like perhaps the callback is once again being freed at some point before you attempt to access m_wOut).  Once again, a read of Chapter 4 is always recommended, especially if you run into any crashes when working with RSServices based objects.

1 Like

Hi,

finally I managed to create my plugin and I thought I give you some feedback.

So, first of all many thanks for the quick hints that were really helpful.

But you should really update the RDK 2.5 PDF manual. It is one thing if certain points are not mentioned, but it is really a big problem, if in reality they simply don’t work as described (e.g. some APIs deprecated, although mentioned in the manual).

Anyway, I now finished my plugin, that looks for a group set called “FreeMind” and exports the references contained in this group set as FreeMind map. I posted it at the FreeMind webpage, https://sourceforge.net/projects/freemind/forums/forum/22101/topic/4397132/index/page/1, for anybody interested.

Cheers,

1 Like