Closed Bug 94214 Opened 23 years ago Closed 22 years ago

On exit, the plugin's NSUnregisterself doesn't get called

Categories

(Core Graveyard :: Plug-ins, defect)

x86
Windows 98
defect
Not set
major

Tracking

(Not tracked)

RESOLVED INVALID

People

(Reporter: chriss, Assigned: serhunt)

Details

I implemented a plugin which has register & unregister entry points based on 
codebase examples, look like:
extern "C" NS_EXPORT nsresult 
NSRegisterSelf(nsISupports *serviceMgr, const char *path)
{
    fprintf(stdout, "NSRegisterSelf: path = %s\n", path);
    nsresult rv;
    nsCString contractID(NS_INLINE_PLUGIN_CONTRACTID_PREFIX);
    nsIServiceManager *sm;
    rv = serviceMgr->QueryInterface(NS_GET_IID(nsIServiceManager), 
                                    (void **)&sm);
    if(NS_FAILED(rv))
        return rv;
    nsIComponentManager *cm;
    rv = sm->GetService(kComponentManagerCID, 
                        NS_GET_IID(nsIComponentManager), 
                        (nsISupports **)&cm);
    if(NS_FAILED(rv)) 
    {
        NS_RELEASE(sm);
        return rv;
    }
    contractID += PLUGIN_MIME_TYPE_1;
    char *buf = (char*)calloc(512, sizeof(char));
    contractID.ToCString(buf, 511);
    rv = cm->RegisterComponent(kPluginCID, 
                             PLUGIN_NAME, 
                             buf, 
                             path, 
                             PR_TRUE, 
                             PR_FALSE/*PR_TRUE*/);
    sm->ReleaseService(kComponentManagerCID, cm);
    NS_RELEASE(sm);
    return rv;
}

extern "C" NS_EXPORT nsresult 
NSUnregisterSelf(nsISupports* serviceMgr, const char *path)
{
    fprintf(stdout, "NSUnregisterSelf: path = %s\n", path);
//{ for debugging
    FILE *fp;
    fp = fopen("log.txt", "a+");
    if(fp)
    {
        fprintf(fp, "NSUnregisterSelf: path = %s\n", path);
        fclose(fp);
    }
//}
    nsresult rv;
    nsIServiceManager *sm;
    rv = serviceMgr->QueryInterface(NS_GET_IID(nsIServiceManager), (void **)
&sm);
    if(NS_FAILED(rv))
	return rv;
    nsIComponentManager *cm;
    rv = sm->GetService(kComponentManagerCID, 
                      NS_GET_IID(nsIComponentManager), 
                      (nsISupports **)&cm);
    if(NS_FAILED(rv)) 
    {
	NS_RELEASE(sm);
	return rv;
    }
    rv = cm->UnregisterComponent(kPluginCID, path);
    sm->ReleaseService(kComponentManagerCID, cm);
    NS_RELEASE(sm);
    return rv;
}

My plugin runs in the embedded browser application and compliant with new 
plugin API requirement. I tested it on both version codebase 0-9-0 and 0-9-2.
It's fine when startup first time, it is registered into component.reg and its 
instance is created and it is running ok so far.
However, when I post a WM_QUIT message to stop the application, the 
plugin's "nsunregisterself" doesn't get called (I didn't see the log file has 
been created) and consequentially the component.reg still has the plugin info. 
Thus, next time I run the process again, the gecko core software thinks my 
plugin instance still exist because it finds the entry in the component.reg and 
thus doesn't instantiate my plugin again. On the other hand, my plugin had been 
destroyed with the embedded browser on previous exit. Thus, my application 
crashes when loading a page containing my plugin's mime type inside EMBED tag 
again.
The above summary is what I understood from my debugging.
Marking NEW we need someone in the Plugins area to take a look at this detailed bug.
Status: UNCONFIRMED → NEW
Ever confirmed: true
Andrei, what do you think about this?
Adding shaver.
NSRegisterSelf and NSUnregisterSelf are deprecated APIs, and support for them
will likely disappear prior to Mozilla 1.0.  Use NSGetModule and the nsIModule
interface instead.

(Note: using NS_IMPL_NSGETMODULE will introduce a binary dependency on a
non-frozen part of the Mozilla API, namely nsGenericModule and its utility
classes.  These classes have changed several times in the past few months, so I
recommend that you implement your nsIModule by hand.  Taking guidance from a
sample JS component may be of use, because all of the API pieces are indicated
there, in working form, and no fragile macros are involved.  You'll need to
translate the code to C++, of course, but that may still be easier than deriving
the correct nsIModule stuff from first principles and header files.)

But your problem goes deeper than that.  Component registration and
unregistration does not -- and must not -- happen at every application start or
stop.  Components are registered through regxpcom or the XPInstall frameworks,
and need to be explicitly unregistered.  Registration data persists, once
entered, across all future application runs, and is used to find the component
when required.  Unregistration need only take place during plugin
deinstallation, and I suspect that many plugins don't bother at all.
Now, it seems like you have another problem here, in that your plugin isn't
being constructed correctly in all cases.  Your sample code doesn't show any
plugin construction, and it's not really clear where that part is going wrong. 
Plugin construction should all go through XPCOM -- if it's not, av/peterl,
please jump in, and please file or cite a bug to fix it -- and the XPCOM
component manager uses the registry data to create component instances whether
the registration is new or old.

It's not clear to me why your plugin isn't available on the second run, but I'm
sorry to tell you that following the examples in the codebase is a near-certain
way to drive yourself crazy.
Some general tips to help you perhaps solve this problem:
 - the only things you should be doing in your nsIModule::registerSelf and
nsIModule::unregisterSelf methods are component registration things.  It looks
like you've got the right approach in your NSRegisterSelf parts, so that's
probably fine.

 - if your plugin lives in your application, you may want to create and register
the factory object on application startup, using the
nsIComponentManager::registerFactory method, and passing PR_FALSE for the
aPersist flag.  This will keep the registration data from being written into the
 component registry on disk, though that should only be a problem if you
sometimes run Mozilla or a different Mozilla-based application on the same registry.

I wish I could help more; if you can attach your plugin source or provide an URL
to it, the plugin guys or I may be able to provide more helpful guidance.

(Regardless, of course, we shouldn't crash just because a component isn't there.
 Is something in the plugin code failing to check the return value from a
CreateInstance call?  What does the stack look like when you crash?)
based on shaver's comments and and no response from reporter in 9 months, 
marking bug as invalid.
Status: NEW → RESOLVED
Closed: 22 years ago
Resolution: --- → INVALID
Product: Core → Core Graveyard
You need to log in before you can comment on or make changes to this bug.