This version of this document is no longer maintained. For the latest documentation, see http://www.qnx.com/developers/docs. |
The following code takes the name of the plugin to load and a pointer to the MvPluginCtrl_t structure and then tries to open the plugin. When the plugin is opened, MvInit() is called to obtain the function pointers to command(), terminate(), and get_item().
int LoadDll( const char *name, MvPluginCtrl_t *pctrl ) { char *path; if( ( path = strdup(name) ) != NULL ) { void *dll; if( ( dll = dlopen( path, RTLD_LOCAL ) ) != NULL ) { MvInitF_t *init; pctrl->APIversion = MV_API_VERSION; pctrl->MinorVersion = MV_MINOR_API_VERSION; pctrl->name = path; if( ( init = dlsym( dll, "MvInit" ) ) != NULL ) { if( init( pctrl ) == 0 ) // calling plugin init function { // MvInit succeeded pctrl->dll_handle = dll; // Increment count of loaded plugins atomic_add_value( &g_plugin_count, 1 ); return 0; } else { dprintf((1, "LoadDll(): MvInit() in \"%s\" failed\n", name )); } } else { dprintf((1, "LoadDll(): MvInit not found in \"%s\" (%s)\n", name, dlerror() )); } pctrl->name = NULL; dlclose( dll ); } else { dprintf((1, " LoadDll(): dlopen(\"%s\") failed (%s)\n", name, dlerror() )); } free( path ); } else { dprintf((1, "LoadDll(): no memory\n" )); } return -1; }
To unload a plugin, you send the plugin a stop (CMD_PLUGIN_STOP) and a close command (CMD_PLUGIN_CLOSE), followed by a call to the terminate() function pointer. After this, you can safely dlclose() the plugin.
// phplay's plugin termination structure. typedef struct { pthread_mutex_t mutex; // The mutex to block on before closing the dll pthread_attr_t attr; plugin_ctrl_t *pctrl; // plugin control structure } plugin_terminate_t; // workproc to invoke phplay's terminate_plugin() function int invoke_terminate_method( void *data ) { plugin_ctrl_t *pc = (plugin_ctrl_t *) data; terminate_plugin( pc, (pc == (plugin_ctrl_t *) mplayer.pctrl) ? PLG_F_BASEINIT|PLG_F_BASECLEAN : 0 ); return Pt_END; } // dlclose-thread startup function void *dlclose_plugin( void *data ) { plugin_terminate_t *pt = (plugin_terminate_t *) data; unsigned u; if ( NULL == data ) return NULL; pthread_mutex_lock( &pt->mutex ); pthread_mutex_unlock( &pt->mutex ); pthread_mutex_destroy( &pt->mutex ); // Permit the vcb (which caused this thread to be // created) to safely return and the plugin to // free the plugin control structure. sched_yield(); delay( 50 ); dlclose( pt->pctrl->mv.dll_handle ); u = atomic_sub_value( &g_plugin_count, 1 ); free( (void *) pt->pctrl->mv.name ); free( (void *) pt->pctrl ); // NB: This frees the plugin_ctrl_t structure allocated by load_plugin() free( data ); return NULL; } // pc - phplay's plugin control structure (different from MvPluginCtrl_t) // // flags // PLG_F_DEAD - the plugin is known to be in the MV_DEAD state. // PLG_F_BASECLEAN - clean up the base window if the plugin still controlls it // PLG_F_BASEINIT - perform more base-window and playlist reinitializations // void terminate_plugin( plugin_ctrl_t *pc, int flags ) { PtArg_t arg; plugin_terminate_t *pt = NULL; int ri=EINVAL, rl=EINVAL, rc=EINVAL, klozing=0; if ( NULL == pc ) return; if ( PLG_F_DEAD & flags ) { // The plugin is dead. Unload it. if ( !(PLG_F_DEAD & pc->flags) ) { klozing = 1; pc->flags |= PLG_F_DEAD|PLG_F_TERMINATE; if ( pc->video_wgt ) { // destroy the video window if necessary PtDestroyWidget( pc->video_wgt ); mplayer.playback_parms.video_wgt = NULL; pc->video_wgt = NULL; } if ( pt = (plugin_terminate_t *) calloc( 1, sizeof( plugin_terminate_t ) ) ) pt->pctrl = pc; if ( pt && EOK == pthread_attr_init( &pt->attr ) && EOK == pthread_attr_setdetachstate( &pt->attr, PTHREAD_CREATE_DETACHED ) && EOK == (ri = pthread_mutex_init( &pt->mutex, NULL )) && EOK == (rl = pthread_mutex_lock( &pt->mutex )) ) rc = pthread_create( NULL, &pt->attr, dlclose_plugin, (void *) pt )) } } else if ( !(PLG_F_TERMINATE & pc->flags ) ) { // Terminate the plugin. MvCommandData_t cmdData; memset( &cmdData, 0x0, sizeof( MvCommandData_t ) ); // Send stop command mplayer.playIsSet = FALSE; mplayer.played = FALSE; cmdData.pluginCtrl = &pc->mv; cmdData.cmdType = CMD_PLUGIN_STOP; cmdData.which = MVP_NONE; pc->mv.calls->command( &cmdData ); // Send close command cmdData.pluginCtrl = &pc->mv; cmdData.cmdType = CMD_PLUGIN_CLOSE; cmdData.which = MVP_NONE; pc->mv.calls->command( &cmdData ); // Invoke terminate method pc->flags |= PLG_F_TERMINATE; pc->mv.calls->terminate( (MvPluginCtrl_t *) pc ); } // end else if // // Clean up the base window if the plugin was controlling it. // if ( pc == mplayer.pctrl && (flags & PLG_F_BASECLEAN) && !(pc->flags & PLG_F_BASECLEAN)) { pc->flags |= PLG_F_BASECLEAN; mplayer.pctrl = NULL; mplayer.pluginIsLoaded = FALSE; mplayer.playIsSet = (mplayer.bStartupOnPlay) ? FALSE : TRUE; // change mplayer icon mplayer.iconImage = ApGetImageRes(mplayer.dbase,"mediaPane"); PtSetResource( ABW_icon_pane, Pt_ARG_LABEL_IMAGE, mplayer.iconImage, 0 ); // init ring buffer state info PtSetResource( ABW_statusBar, Pt_ARG_TEXT_STRING, "", 0 ); HideClientArea( 0 ); InitAudio( FALSE ); // unlock Advance Dialog widgets if dialog box is displayed if( mplayer.bAdvanceDlg ) OnAdvanceDlg(NULL,NULL,NULL); // Reinitialize if necessary if ( flags & PLG_F_BASEINIT ) { mplayer.played = FALSE; ControllerDeleteAll(); SetStopEjectButton( FALSE ); SetPlayPauseButton( TRUE ); // reset cursor position PtSetResource( ABW_curpos, Pt_ARG_GAUGE_VALUE, 0, 0 ); // reset base Info Label PtSetResource( ABW_baseInfo, Pt_ARG_TEXT_STRING, "Photon Media Player", 0 ); PtSetResource( ABW_playlistEditorDlg, Pt_ARG_WINDOW_TITLE, PL_TXT_TITLE, 0 ); } } // Handle the case where a dlclose thread may have been created. if ( klozing ) { if ( EOK == rl ) // mutex was locked pthread_mutex_unlock( &pt->mutex ); // Wake up the dlclose thread. if ( EOK == rc ) // dlclose thread was created return; // The dlclose-thread will destroy the mutex and free the termination structure. // Failed to create dlclose thread. // Clean up as much as possible. if ( EOK == ri ) // mutex was initialized pthread_mutex_destroy( &pt->mutex ); free( (void *) pt->pctrl->mv.name ); free( (void *) pt->pctrl ); // NB: This frees the plugin_ctrl_t structure allocated by load_plugin() free( pt ); } }