Copy link to clipboard
Copied
I wrote a new class this morning to try and observe close events for libraries. The idea is that I can find out when my library is closed (via code or user) and carry out some actions.
The class inherits from CObserver and implements AutoAttach, AutoDetach and Update. The subject used by the functions is IID_LIBRARYSERVICE.
My Update function looks like this:
if ((Protocol == IID_ILIBRARYSERVICE) && (Change == kLibraryCloseLibCmdBoss))
{
ICommand *ptrCommand = (ICommand *)ptrChangedBy;
if (ptrCommand != nil)
{
const UIDList List = ptrCommand->GetItemListReference();
if ((List.Length() > 0) && (ptrCommand->GetCommandState() == ICommand::kNotDone))
{
// Do something - iterate through list, although only expect one item.
// Find matching UIDRef of library about to be closed.
}
}
}
In the resource file, I've written an AddIn
AddIn
{
kLibraryBoss,
kInvalidClass,
{
IID_MYLIBRARYOBSERVER, kMyLibraryObserverImpl
}
}
On running the plug-in, I don't get any calls into the code except for CREATE_PMINTERFACE.
There are no samples in the SDK concerning libraries, so I'm uncertain that I'm using the correct subject or boss in the add-in.
Anyone tried to do this? Thanks in advance for any help.
Use IK2ServiceRegistry::QueryDefaultServiceProvider(kLibraryServiceID), it returns a kLibraryProviderBoss.
That boss has the subject to watch.
You'd AutoAttach e.g. during a startup service.
Btw, the itemlist of kLibraryCloseLibCmdBoss is empty. Have a look at its IID_ILIBRARYCMDDATA instead, it specifies the library as source.
As long you use a private IID or a private boss for the observer, it does not really matter where you put it. Sometimes I'd add-in mine onto the observed object (e.g. documen
Copy link to clipboard
Copied
This is really frustrating - if I understand observers derived from CObserver correctly, somewhere else in the code there must be calls to AutoAttach() and AutoDetach(). For document observers, this would normally be done off kxxxyyyDocSignalResponderService signals, but there does not appear to be anything equivalent to these for libraries.
Copy link to clipboard
Copied
Use IK2ServiceRegistry::QueryDefaultServiceProvider(kLibraryServiceID), it returns a kLibraryProviderBoss.
That boss has the subject to watch.
You'd AutoAttach e.g. during a startup service.
Btw, the itemlist of kLibraryCloseLibCmdBoss is empty. Have a look at its IID_ILIBRARYCMDDATA instead, it specifies the library as source.
As long you use a private IID or a private boss for the observer, it does not really matter where you put it. Sometimes I'd add-in mine onto the observed object (e.g. document) even though for go-away notifications I'd choose something longer living. Often I put them on the same private boss that carries the startup service, or any other easily reachable boss - e.g. see how many other observers live on kSessionBoss ...
Dirk
Copy link to clipboard
Copied
Hi Dirk,
Thanks for taking the time to reply to the question - I was getting really getting fed up trying to find a way forward.
I've still got some problems, so I'll tell you what I've done to date.
Resource File
The observer interface ID/implementation pair has now been added to an AddIn on the kSessionBoss.
AddIn
{
kSessionBoss,
kInvalidClass,
{
IID_MYLIBRARYOBSERVER, kMyLibraryObserver
}
}
Startup/Shutdown Service
I've got a startup/shutdown service already in place for other functionality. In my call to StartUp(), I've added the following:
InterfacePtr<IK2ServiceRegistry> ptrRegistry(GetExecutionContextSession(), IID_IK2SERVICEREGISTRY);
InterfacePtr<IK2ServiceProvider> ptrService(ptrRegistry->QueryDefaultServiceProvider(kLibraryServiceID));
InterfacePtr<ILibraryService> ptrLibraryService(ptrService, IID_ILIBRARYSERVICE);
InterfacePtr<IObserver> ptrLibraryObserver(ptrLibraryService, IID_MYLIBRARYOBSERVER);
if (ptrLibraryObserver != NULL)
{
ptrLibraryObserver->AutoAttach();
}
I've run this through the debugger and I get non-null pointers for ptrRegistry, ptrService and ptrLibraryService. However ptrLibraryObserver is returning NULL and consequently we don't call AutoAttach().
I'm still trying to get to grips with the SDK and so I'm certain I'm making a stupid rookie mistake - passing the wrong object as the first argument to ptrLibraryObserver. But I can't quite figure out what I should be passing.
Could you point me in the right direction.
Thanks in advance.
APMABC
Copy link to clipboard
Copied
Dirk, ignore my previous message. I see where I'm going wrong at the moment!
Copy link to clipboard
Copied
Hi Dirk,
Having gone through your post again, I found out I was putting the code in all the wrong places. Obviously didn't drink enough coffee this morning!
StartUp is now...
InterfacePtr<IObserver> ptrLibraryObserver(GetExecutionContextSession(), IID_MYLIBRARYOBSERVER);
if (ptrLibraryObserver != NULL)
{
ptrLibraryObserver->AutoAttach();
}
and with that change everthing started to work. Stupid thing is that the resulting code is really quite simple - I only wish it was so obvious in the samples and documentation! So thank you again for your help!
As you recommended, I use library command data to call GetSourceLibrary() in my observers Update() function. That is returning a pointer to the library being closed.
If I could trouble you on just one more point (it probably should be in a new discussion) - UIDRefs. On opening my library in code, I store the returned UIDRef so I can compare against it when either the code or user closes the library. I've used a similar approach on documents and it works a treat.
Trouble is that although ProcessLibraryOpenLibCmd returns a UIDRef, no other library function appears to consume one so you can get a pointer to a library. I did think that this might work in my CloseLibrary function.
if ((m_LibraryReferenceID != UIDRef::gNull) && m_LibraryReferenceID.ExistsInDB())
{
InterfacePtr<ILibrary> ptrLibrary(m_LibraryReferenceID, UseDefaultIID();
if (ptrLibrary != nil)
{
ptrLibrary->Close();
}
}
But ptrLibrary is NULL and therefore I can't call ptrLibrary->Close(). When the user closes the library, the observer calls an OnCloseLibray function which tries to compare library pointers (one again created from the stored UIDRef) and if they match resets the stored UIDRef. So at the moment, my CloseLibrary and OnCloseLibrary functions aren't working.
Also ExistsInDB is a bit dubious - it will trigger an exception if you pass it an invalid UIDRef!
Cheers,
APMABC
Copy link to clipboard
Copied
Hi APMABC and Dirk,
I know this is an older post but I too am trying to perform a task when a Library is closed and have been working off this post as a reference. I am a newbie to InDesign SDk (little over a month) and am having some trouble getting my code to work.
In my .fr file I am defining the AddIn and Class as follows:
AddIn
{
kSessionBoss,
kInvalidClass,
{
IID_JEMUILIBRARYOBSERVER, kJEMUILibraryObserverImpl,
}
},
Class
{
kJEMUIStartupShutdownBoss,
kInvalidClass,
{
/** Implementation of IStartupShutdownService that installs the Library Observer */
IID_ISTARTUPSHUTDOWN, kJEMUIStartupShutdownImpl,
/** identify the service type */
IID_IK2SERVICEPROVIDER, kCStartupShutdownProviderImpl,
}
},
I have a Startup/Shutdown class with the following startup routine.:
void JEMUIStartupShutdown::Startup()
{
do
{
InterfacePtr<IObserver> libraryObserver(GetExecutionContextSession(), IID_JEMUILIBRARYOBSERVER);
if(libraryObserver != NULL)
{
libraryObserver->AutoAttach();
}
} while(kFalse);
}
And I have a LibraryObserver class with the following AutoAttach:
void JEMUILibraryObserver::AutoAttach()
{
CObserver::AutoAttach();
do
{
InterfacePtr<IK2ServiceRegistry> serviceRegistry(GetExecutionContextSession(), IID_IK2SERVICEREGISTRY);
InterfacePtr<IK2ServiceProvider> serviceProvider(serviceRegistry->QueryDefaultServiceProvider(kLibraryServiceID));
InterfacePtr<ISubject> subject(serviceProvider, UseDefaultIID());
if (subject == nil)
{
ASSERT_FAIL("subject invalid");
break;
}
subject->AttachObserver(this, IID_ILIBRARYCMDDATA);
} while(kFalse);
}
The problem is that when I run the plugin and close a Library it does not appear that the Update routine in the LibraryObserver class is being reached. Unfortunately I do not have the debug version of InDesign yet, but I'm using CAlerts in the Updatet to see if it is getting called.
Could either of you provide me with some help? I'm not sure if I'm attaching with the right subject or PMIID.
Thanks,
Casey
Copy link to clipboard
Copied
The notified protocol is IID_ILIBRARY, that would be the 2nd "interestedIn" argument for subject->AttachObserver. IID_ILIBRARYCMDDATA is only where you later pick up your information.
Besides the 3rd argument to AttachObserver defaults to IID_IOBSERVER - see ISubject.h.
Your observer is not located at IID_IOBSERVER, so you have to provide its IID_JEMUILIBRARYOBSERVER in that "asObserver" argument.
Dirk
Copy link to clipboard
Copied
Hi Dirk,
Thanks for the help. The changes you suggested got me to a point where I am now getting to the Update routine. I am still however having some difficulties and am not sure what I am doing wrong. I am trying to get to the IID_ILIBRARYCMDDATA interface but am having no luck. Below is the code I am trying to get the interface.
void JEMUILibraryObserver::Update(const ClassID& theChange, ISubject* theSubject, const PMIID &protocol, void* changedBy)
{
do
{
if (protocol == IID_ILIBRARY)
{
ICommand* command = (ICommand*)changedBy;
if(command != nil)
{
InterfacePtr<ILibraryCmdData> data(command, IID_ILIBRARYCMDDATA);
if(data != nil)
{
InterfacePtr<ILibrary> theLibrary(data, UseDefaultIID());
if(theLibrary != nil)
{
PMString theFileName = theLibrary->GetFileName();
CAlert::InformationAlert(theFileName);
}
}
}
}
} while(kFalse);
}
The issue is when I run this I am getting an error that the command does not exist. I'm not sure what the right approach is to getting the data and the documentation on Library is lacking. Could you please help me get on track?
Again I really appreciate your help.
Thanks,
Casey
Copy link to clipboard
Copied
Hi Casey,
the original poster was already on the right track watching for
if ((Protocol == IID_ILIBRARYSERVICE) && (Change == kLibraryCloseLibCmdBoss))
therefor I did not repeat that information.
That means you have to subscribe to IID_ILIBRARYSERVICE rather than IID_ILIBRARY, and it always helps to also check the Change parameter, there could be many notifications on the same protocol, each with different understanding of the changedBy parameter.
I'm not sure about the changedBy parameter during IID_ILIBRARY notification, it could be some kind of "Message" record on the stack rather than an IMPUnknown*.
Regards,
Dirk
Copy link to clipboard
Copied
Thanks Dirk, that got me rolling in the right direction. And thank you APMABC for the original post as it too helped me get things started.
Copy link to clipboard
Copied
How can i get the open library event? it will be good if some one send the code snippet
Find more inspiration, events, and resources on the new Adobe Community
Explore Now